Skip to content

Commit

Permalink
feat: Added working search filters
Browse files Browse the repository at this point in the history
  • Loading branch information
LynithDev committed Sep 6, 2024
1 parent 5012f2c commit 3025502
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 131 deletions.
2 changes: 2 additions & 0 deletions apps/desktop/src/api/commands/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub async fn get_provider_package_version(
pub struct ProviderSearchQuery {
query: Option<String>,
limit: Option<u8>,
offset: Option<u32>,
game_versions: Option<Vec<String>>,
categories: Option<Vec<String>>,
loaders: Option<Vec<Loader>>,
Expand All @@ -69,6 +70,7 @@ pub async fn search_provider_packages(provider: Providers, query: ProviderSearch
.search(
query.query,
query.limit,
query.offset,
query.game_versions,
query.categories,
query.loaders,
Expand Down
8 changes: 5 additions & 3 deletions apps/frontend/src/ui/components/content/SearchResults.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import type { ProviderSearchResults, Providers, SearchResult } from '@onelauncher/client/bindings';
import type { Providers, SearchResult } from '@onelauncher/client/bindings';
import { ChevronDownIcon, Download01Icon, HeartIcon } from '@untitled-theme/icons-solid';
import { For, Match, Show, Switch, createSignal } from 'solid-js';
import Button from '../base/Button';
import useBrowser from '~ui/hooks/useBrowser';
import useSettings from '~ui/hooks/useSettings';
import { abbreviateNumber } from '~utils';

type SearchResultsContainerProps = ProviderSearchResults & {
interface SearchResultsContainerProps {
provider: Providers;
results: SearchResult[];
header: string;
category: string;
collapsable?: boolean;
};
}

function SearchResultsContainer(props: SearchResultsContainerProps) {
const { settings } = useSettings();
Expand Down
18 changes: 17 additions & 1 deletion apps/frontend/src/ui/hooks/useBrowser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useNavigate } from '@solidjs/router';
import { type Accessor, type Context, For, type ParentProps, type Setter, Show, createContext, createEffect, createSignal, onMount, untrack, useContext } from 'solid-js';
import { type Accessor, type Context, For, type ParentProps, type Setter, Show, createContext, createEffect, createSignal, on, onMount, untrack, useContext } from 'solid-js';
import type { Cluster, ManagedPackage, PackageType, ProviderSearchQuery, ProviderSearchResults, Providers } from '@onelauncher/client/bindings';
import useCommand, { tryResult } from './useCommand';
import { useRecentCluster } from './useCluster';
Expand Down Expand Up @@ -46,6 +46,7 @@ export function BrowserProvider(props: ParentProps) {
const [searchOptions, setSearchOptions] = createSignal<ProviderSearchQuery>({
query: '',
limit: 20,
offset: 0,
categories: null,
game_versions: null,
loaders: null,
Expand Down Expand Up @@ -119,6 +120,21 @@ export function BrowserProvider(props: ParentProps) {
setCluster(recentCluster());
});

createEffect(on(cluster, (cluster) => {
if (cluster !== undefined)
setSearchOptions((prev) => {
const opts: ProviderSearchQuery = {
...prev,
game_versions: [cluster.meta.mc_version],
};

if (cluster.meta.loader !== undefined)
opts.loaders = [cluster.meta.loader];

return opts;
});
}));

return (
<BrowserContext.Provider value={controller}>
{props.children}
Expand Down
21 changes: 15 additions & 6 deletions apps/frontend/src/ui/hooks/usePagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,34 @@ import { ChevronLeftIcon, ChevronRightIcon } from '@untitled-theme/icons-solid';
import { For, Show, createSignal } from 'solid-js';
import Button from '~ui/components/base/Button';

interface PaginationOptions {
export interface PaginationOptions {
itemsCount: () => number;
itemsPerPage: () => number;
initialPage?: () => number;
};

function usePagination(options: PaginationOptions) {
const [page, setPage] = createSignal(Math.max(1, options.initialPage?.() || 1));
function usePagination(initialOptions: PaginationOptions) {
const [options, setOptions] = createSignal(initialOptions);

// eslint-disable-next-line solid/reactivity -- -
const [page, setPage] = createSignal(Math.max(1, options().initialPage?.() || 1));

const next = () => setPage(page => page + 1);
const prev = () => setPage(page => page - 1);

const totalPages = () => Math.ceil(options.itemsCount() / options.itemsPerPage());
const totalPages = () => Math.ceil(options().itemsCount() / options().itemsPerPage());

const hasNext = () => page() < totalPages();
const hasPrev = () => page() > 1;

const offset = () => (page() - 1) * options.itemsPerPage();
const offset = () => (page() - 1) * options().itemsPerPage();

// Exported
function reset(options: PaginationOptions) {
setOptions(options);
setPage(1);
}

// Navigation
function getVisiblePageNumbers(page: number) {
const pages: number[] = [];

Expand Down Expand Up @@ -97,6 +105,7 @@ function usePagination(options: PaginationOptions) {
hasPrev,
totalPages,
offset,
reset,
Navigation,
};
}
Expand Down
23 changes: 0 additions & 23 deletions apps/frontend/src/ui/pages/browser/BrowserCategory.tsx

This file was deleted.

9 changes: 8 additions & 1 deletion apps/frontend/src/ui/pages/browser/BrowserMain.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChevronRightIcon } from '@untitled-theme/icons-solid';
import { Show } from 'solid-js';
import { Show, onMount } from 'solid-js';
import type { ManagedPackage } from '@onelauncher/client/bindings';
import { BrowserContent } from './BrowserRoot';
import useBrowser from '~ui/hooks/useBrowser';
Expand All @@ -10,6 +10,13 @@ import SearchResultsContainer from '~ui/components/content/SearchResults';
function BrowserMain() {
const browser = useBrowser();

onMount(() => {
browser.setSearchQuery(prev => ({
...prev,
categories: [],
}));
});

return (
<BrowserContent>
<div class="flex flex-col gap-8">
Expand Down
3 changes: 3 additions & 0 deletions apps/frontend/src/ui/pages/browser/BrowserPackage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ function BrowserSidebar(props: { package: ManagedPackage; authors: ManagedUser[]
{' '}
<span class="text-fg-primary">{props.package.provider}</span>
</p>
<Show when={props.package.is_archived === true}>
<p class="w-fit rounded-full bg-code-warn/10 px-2 py-1 text-xs text-code-warn">Archived</p>
</Show>
</div>

<p class="max-h-22 flex-1 overflow-hidden text-sm text-fg-secondary line-height-snug">{props.package.description}</p>
Expand Down
81 changes: 45 additions & 36 deletions apps/frontend/src/ui/pages/browser/BrowserRoot.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Route } from '@solidjs/router';
import { Route, useLocation } from '@solidjs/router';
import { For, type JSX, type ParentProps } from 'solid-js';
import { SearchMdIcon, Settings01Icon } from '@untitled-theme/icons-solid';
import type { PackageType } from '@onelauncher/client/bindings';
import BrowserMain from './BrowserMain';
import BrowserCategory from './BrowserCategory';
import BrowserPackage from './BrowserPackage';
import BrowserSearch from './BrowserSearch';
import Button from '~ui/components/base/Button';
Expand All @@ -15,7 +13,6 @@ function BrowserRoutes() {
return (
<>
<Route path="/" component={BrowserMain} />
<Route path="/category" component={BrowserCategory} />
<Route path="/package" component={BrowserPackage} children={<BrowserPackage.Routes />} />
<Route path="/search" component={BrowserSearch} />
</>
Expand Down Expand Up @@ -60,27 +57,49 @@ function BrowserToolbar() {
);
}

export interface BrowserSidebarCategory {
name: string;
sub: [string, string][];
};
function BrowserCategories() {
const browser = useBrowser();
const location = useLocation();

const getEnabledCategories = () => browser.searchQuery().categories || [];

const isEnabled = (category: string) => {
return getEnabledCategories().includes(category);
};

const toggleCategory = (category: string) => {
const enabledCategories = getEnabledCategories();
const index = enabledCategories.indexOf(category);
if (index > -1)
enabledCategories.splice(index, 1);
else
enabledCategories.push(category);

browser.setSearchQuery(prev => ({
...prev,
categories: enabledCategories,
}));

if (!location.pathname.includes('/search'))
browser.search();
};

function BrowserCategories(props: { categories: BrowserSidebarCategory[] }) {
return (
<div class="top-0 grid grid-cols-[1fr_auto] h-fit min-w-50 gap-y-6">
<div />
<div class="flex flex-col gap-y-6">
<For each={props.categories.concat(browserCategories.provider())}>
<For each={browserCategories.byPackageType(browser.packageType())}>
{category => (
<div class="flex flex-col gap-y-2">
<h6 class="my-1">{category.name}</h6>
<For each={category.sub}>
{sub => (
<a
href={sub[1]}
class="text-md text-fg-primary capitalize hover:text-fg-secondary"
children={sub[0]}
/>
<p
class={`text-md capitalize text-fg-primary hover:text-fg-primary-hover ${isEnabled(sub) ? 'text-opacity-100! hover:text-opacity-90!' : 'text-opacity-60! hover:text-opacity-70!'}`}
onClick={() => toggleCategory(sub)}
>
{sub}
</p>
)}
</For>
</div>
Expand All @@ -97,31 +116,21 @@ function BrowserSidebar() {
return (
<div class="flex flex-col gap-y-4">
<div class="flex flex-col gap-y-1">
<h6 class="my-1">Active Cluster</h6>
<Button
buttonStyle="secondary"
children={controller.cluster()?.meta.name || 'None'}
iconLeft={<Settings01Icon />}
onClick={controller.displayClusterSelector}
/>
</div>

<div class="flex flex-col gap-y-1">
<h6 class="my-1">Search Filters</h6>
<div class="flex flex-col gap-y-1">
<h6 class="my-1">Active Cluster</h6>
<Button
buttonStyle="secondary"
children={controller.cluster()?.meta.name || 'None'}
iconLeft={<Settings01Icon />}
onClick={controller.displayClusterSelector}
/>
</div>
</div>
</div>
);
}

export type BrowserContentProps = ParentProps & {
categories?: BrowserSidebarCategory[];
};

const categories = (packageType: PackageType) => browserCategories.byPackageType(packageType);

export function BrowserContent(props: BrowserContentProps) {
const browser = useBrowser();

export function BrowserContent(props: ParentProps) {
return (
<div class="relative h-full flex flex-1 flex-col items-center gap-2">
<div class="h-full w-full max-w-screen-xl flex flex-1 flex-col items-center gap-y-2">
Expand All @@ -132,7 +141,7 @@ export function BrowserContent(props: BrowserContentProps) {
</div>

<div class="grid grid-cols-[220px_auto_220px] w-full max-w-screen-xl gap-x-6 pb-8">
<BrowserCategories categories={categories(browser.packageType()).concat(props.categories || [])} />
<BrowserCategories />

<div class="h-full flex flex-col gap-y-4">
<div class="h-full flex-1">
Expand Down
49 changes: 37 additions & 12 deletions apps/frontend/src/ui/pages/browser/BrowserSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,53 @@ import SearchResultsContainer from '~ui/components/content/SearchResults';
import Spinner from '~ui/components/Spinner';
import useBrowser from '~ui/hooks/useBrowser';
import useCommand from '~ui/hooks/useCommand';
import usePagination, { type PaginationOptions } from '~ui/hooks/usePagination';

function BrowserSearch() {
const browser = useBrowser();

const [results, { refetch }] = useCommand(() => bridge.commands.searchProviderPackages('Modrinth', browser.searchQuery()));

createEffect(on(() => browser.searchQuery().query, () => {
const paginationOptions = (): PaginationOptions => ({
itemsCount: () => results()?.total || 0,
itemsPerPage: () => browser.searchQuery().limit || 20,
});

const pagination = usePagination(paginationOptions());

createEffect(on(browser.searchQuery, () => {
refetch();
}));

createEffect(on(() => results()?.total, (curr, prev) => {
if (curr !== prev)
pagination.reset(paginationOptions());
}));

createEffect(on(pagination.page, () => {
browser.setSearchQuery(prev => ({
...prev,
offset: pagination.offset(),
}));
}));

return (
<BrowserContent>
<Spinner.Suspense>
<Show when={results() !== undefined}>
<SearchResultsContainer
category="test"
header="Results"
provider="Modrinth"
results={results()!.results}
/>
</Show>
</Spinner.Suspense>
<pagination.Navigation />

<div class="my-2">
<Spinner.Suspense>
<Show when={results() !== undefined}>
<SearchResultsContainer
category="test"
header="Results"
provider="Modrinth"
results={results()!.results}
/>
</Show>
</Spinner.Suspense>
</div>

<pagination.Navigation />
</BrowserContent>
);
}
Expand Down
Loading

0 comments on commit 3025502

Please sign in to comment.