fix: browser category selector
This commit is contained in:
parent
2593b293de
commit
089fbd3e26
3 changed files with 53 additions and 14 deletions
|
|
@ -1,17 +1,16 @@
|
||||||
import type { ClusterModel } from '@/bindings.gen';
|
import type { ClusterModel, Provider, SearchQuery } from '@/bindings.gen';
|
||||||
import { bindings } from '@/main';
|
import { bindings } from '@/main';
|
||||||
import { PROVIDERS } from '@/utils';
|
import { PROVIDERS } from '@/utils';
|
||||||
import { useCommand } from '@onelauncher/common';
|
import { useCommand } from '@onelauncher/common';
|
||||||
import { createContext, useContext, useMemo, useState } from 'react';
|
import { createContext, useContext, useMemo, useState } from 'react';
|
||||||
|
|
||||||
type Provider = typeof PROVIDERS[number];
|
|
||||||
|
|
||||||
export interface BrowserControllerType {
|
export interface BrowserControllerType {
|
||||||
cluster: ClusterModel | undefined;
|
cluster: ClusterModel | undefined;
|
||||||
setCluster: (cluster: ClusterModel | undefined) => void;
|
setCluster: (cluster: ClusterModel | undefined) => void;
|
||||||
provider: Provider;
|
provider: Provider;
|
||||||
setProvider: (provider: Provider) => void;
|
setProvider: (provider: Provider) => void;
|
||||||
|
query: SearchQuery;
|
||||||
|
setQuery: (query: SearchQuery) => void;
|
||||||
search: () => void;
|
search: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,14 +27,23 @@ export function BrowserProvider(props: any) {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
const [cluster, setCluster] = useState<ClusterModel | undefined>(undefined);
|
const [cluster, setCluster] = useState<ClusterModel | undefined>(undefined);
|
||||||
const [provider, setProvider] = useState<Provider>(PROVIDERS[0]);
|
const [provider, setProvider] = useState<Provider>(PROVIDERS[0]);
|
||||||
|
const [query, setQuery] = useState<SearchQuery>({
|
||||||
|
filters: null,
|
||||||
|
query: null,
|
||||||
|
limit: 18 as unknown as bigint,
|
||||||
|
offset: null,
|
||||||
|
sort: null,
|
||||||
|
});
|
||||||
|
|
||||||
const context = useMemo<BrowserControllerType>(() => ({
|
const context = useMemo<BrowserControllerType>(() => ({
|
||||||
cluster,
|
cluster,
|
||||||
setCluster,
|
setCluster,
|
||||||
provider,
|
provider,
|
||||||
setProvider,
|
setProvider,
|
||||||
|
query,
|
||||||
|
setQuery,
|
||||||
search: () => {},
|
search: () => {},
|
||||||
}), [cluster, provider]);
|
}), [cluster, provider, query]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserContext.Provider value={context}>
|
<BrowserContext.Provider value={context}>
|
||||||
|
|
@ -43,3 +51,7 @@ export function BrowserProvider(props: any) {
|
||||||
</BrowserContext.Provider>
|
</BrowserContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useBrowserSearch(provider: Provider, query: SearchQuery) {
|
||||||
|
return useCommand('searchPackages', () => bindings.core.searchPackages(provider, query));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import OneConfigLogo from '@/assets/logos/oneconfig.svg';
|
import OneConfigLogo from '@/assets/logos/oneconfig.svg';
|
||||||
import { useBrowserContext } from '@/hooks/useBrowser';
|
import { useBrowserContext, useBrowserSearch } from '@/hooks/useBrowser';
|
||||||
import { Button, Show } from '@onelauncher/common/components';
|
import { Button, Show } from '@onelauncher/common/components';
|
||||||
import { createFileRoute } from '@tanstack/react-router';
|
import { createFileRoute, useSearch } from '@tanstack/react-router';
|
||||||
import { ChevronRightIcon } from '@untitled-theme/icons-react';
|
import { ChevronRightIcon } from '@untitled-theme/icons-react';
|
||||||
import { BrowserLayout } from './route';
|
import { BrowserLayout } from './route';
|
||||||
|
|
||||||
|
|
@ -20,6 +20,8 @@ function RouteComponent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Featured() {
|
function Featured() {
|
||||||
|
const context = useBrowserContext();
|
||||||
|
const search = useBrowserSearch(context.provider, context.query);
|
||||||
return (
|
return (
|
||||||
<Show when>
|
<Show when>
|
||||||
<div className="flex flex-col gap-y-1">
|
<div className="flex flex-col gap-y-1">
|
||||||
|
|
@ -48,6 +50,12 @@ function Featured() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{search.status}
|
||||||
|
{search.isSuccess && (
|
||||||
|
<>
|
||||||
|
{search.data.items.map(item => <p key={item.id}>{item.name}</p>)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
import type { Filters } from '@/bindings.gen';
|
||||||
import ProviderIcon from '@/components/content/ProviderIcon';
|
import ProviderIcon from '@/components/content/ProviderIcon';
|
||||||
|
import { BrowserProvider, useBrowserContext } from '@/hooks/useBrowser';
|
||||||
|
import { useClusters } from '@/hooks/useCluster';
|
||||||
import { PROVIDERS } from '@/utils';
|
import { PROVIDERS } from '@/utils';
|
||||||
import { browserCategories } from '@/utils/browser';
|
import { browserCategories } from '@/utils/browser';
|
||||||
import { Button, Dropdown, Show, TextField } from '@onelauncher/common/components';
|
import { Dropdown, Show, TextField } from '@onelauncher/common/components';
|
||||||
import { createFileRoute, Outlet } from '@tanstack/react-router';
|
import { createFileRoute, Outlet } from '@tanstack/react-router';
|
||||||
import { SearchMdIcon } from '@untitled-theme/icons-react';
|
import { SearchMdIcon } from '@untitled-theme/icons-react';
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/app/browser')({
|
export const Route = createFileRoute('/app/browser')({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
|
|
@ -70,9 +72,9 @@ function BrowserSidebar() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-y-1">
|
<div className="flex flex-col gap-y-1">
|
||||||
<h6 className="my-1">Provider</h6>
|
<h6 className="my-1">Provider</h6>
|
||||||
<Dropdown>
|
<Dropdown onSelectionChange={id => context.setProvider(id as typeof context.provider)} selectedKey={context.provider}>
|
||||||
{PROVIDERS.map(provider => (
|
{PROVIDERS.map(provider => (
|
||||||
<Dropdown.Item key={provider}>
|
<Dropdown.Item id={provider} key={provider}>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<ProviderIcon className="size-4 mr-2 self-center" provider={provider} />
|
<ProviderIcon className="size-4 mr-2 self-center" provider={provider} />
|
||||||
{provider}
|
{provider}
|
||||||
|
|
@ -86,8 +88,23 @@ function BrowserSidebar() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultFilters:Filters = {
|
||||||
|
categories: null,
|
||||||
|
game_versions: null,
|
||||||
|
loaders: null,
|
||||||
|
package_types: null
|
||||||
|
}
|
||||||
|
|
||||||
function BrowserCategories() {
|
function BrowserCategories() {
|
||||||
const categories = browserCategories.byPackageType('mod', 'Modrinth');
|
const context = useBrowserContext();
|
||||||
|
const categories = browserCategories.byPackageType('mod', context.provider);
|
||||||
|
|
||||||
|
function switchCategory(category:string){
|
||||||
|
if(context.query.filters?.categories?.includes(category))
|
||||||
|
context.setQuery({...context.query, filters: {...defaultFilters, ...context.query.filters, categories: (context.query.filters?.categories ?? []).filter(cat=>cat!==category)}})
|
||||||
|
else
|
||||||
|
context.setQuery({...context.query, filters: {...defaultFilters, ...context.query.filters, categories: [...(context.query.filters?.categories ?? []), category]}})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="top-0 grid grid-cols-[1fr_auto] h-fit min-w-50 gap-y-6">
|
<div className="top-0 grid grid-cols-[1fr_auto] h-fit min-w-50 gap-y-6">
|
||||||
|
|
@ -95,11 +112,13 @@ function BrowserCategories() {
|
||||||
<div className="flex flex-col gap-y-6">
|
<div className="flex flex-col gap-y-6">
|
||||||
<Show when>
|
<Show when>
|
||||||
<div className="flex flex-col gap-y-2">
|
<div className="flex flex-col gap-y-2">
|
||||||
<h6 className="my-1">Categories</h6>
|
<h6 className="my-1 uppercase">Categories</h6>
|
||||||
{categories.map(category => (
|
{categories.map(category => (
|
||||||
<p
|
<p
|
||||||
className="text-md capitalize opacity-100 hover:opacity-90 text-fg-primary hover:text-fg-primary-hover"
|
aria-selected={context.query.filters?.categories?.includes(category.id)}
|
||||||
|
className="text-md capitalize opacity-60 hover:opacity-90 text-fg-primary hover:text-fg-primary-hover aria-selected:opacity-100"
|
||||||
key={category.id}
|
key={category.id}
|
||||||
|
onClick={()=>switchCategory(category.id)}
|
||||||
>
|
>
|
||||||
{category.display}
|
{category.display}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue