diff options
Diffstat (limited to 'frontend/src/lib/filter')
-rw-r--r-- | frontend/src/lib/filter/ComicFilterForm.svelte | 85 | ||||
-rw-r--r-- | frontend/src/lib/filter/TagFilterForm.svelte | 32 | ||||
-rw-r--r-- | frontend/src/lib/filter/components/ComicFilterGroup.svelte | 27 | ||||
-rw-r--r-- | frontend/src/lib/filter/components/Filter.svelte | 26 | ||||
-rw-r--r-- | frontend/src/lib/filter/components/FilterForm.svelte | 36 | ||||
-rw-r--r-- | frontend/src/lib/filter/components/TagFilterGroup.svelte | 14 |
6 files changed, 98 insertions, 122 deletions
diff --git a/frontend/src/lib/filter/ComicFilterForm.svelte b/frontend/src/lib/filter/ComicFilterForm.svelte index 13b5320..7f0058d 100644 --- a/frontend/src/lib/filter/ComicFilterForm.svelte +++ b/frontend/src/lib/filter/ComicFilterForm.svelte @@ -1,48 +1,61 @@ <script lang="ts"> - import { page } from '$app/stores'; import { artistList, characterList, circleList, comicTagList, worldList } from '$gql/Queries'; - import { ComicFilterContext, getFilterContext } from '$lib/Filter'; + import { categories, censorships, languages, ratings } from '$lib/Enums'; + import { ComicFilterContext } from '$lib/Filter.svelte'; import { getContextClient } from '@urql/svelte'; - import ComicFilterGroup from './components/ComicFilterGroup.svelte'; + import Filter from './components/Filter.svelte'; import FilterForm from './components/FilterForm.svelte'; const client = getContextClient(); - $: tagsQuery = comicTagList(client, { forFilter: true }); - $: artistsQuery = artistList(client); - $: charactersQuery = characterList(client); - $: circlesQuery = circleList(client); - $: worldsQuery = worldList(client); + let { filter }: { filter: ComicFilterContext } = $props(); - $: tags = $tagsQuery.data?.comicTags.edges; - $: artists = $artistsQuery.data?.artists.edges; - $: characters = $charactersQuery.data?.characters.edges; - $: circles = $circlesQuery.data?.circles.edges; - $: worlds = $worldsQuery.data?.worlds.edges; + let tagsQuery = $derived(comicTagList(client, { forFilter: true })); + let artistsQuery = $derived(artistList(client)); + let charactersQuery = $derived(characterList(client)); + let circlesQuery = $derived(circleList(client)); + let worldsQuery = $derived(worldList(client)); - const filter = getFilterContext<ComicFilterContext>(); - const apply = () => $filter.apply($page.url.searchParams); + let tags = $derived($tagsQuery.data?.comicTags.edges); + let artists = $derived($artistsQuery.data?.artists.edges); + let characters = $derived($charactersQuery.data?.characters.edges); + let circles = $derived($circlesQuery.data?.circles.edges); + let worlds = $derived($worldsQuery.data?.worlds.edges); </script> -<FilterForm type="grid" on:submit={apply}> - <ComicFilterGroup - slot="include" - type="include" - bind:controls={$filter.include.controls} - {tags} - {artists} - {characters} - {circles} - {worlds} - /> - <ComicFilterGroup - slot="exclude" - type="exclude" - bind:controls={$filter.exclude.controls} - {tags} - {artists} - {characters} - {circles} - {worlds} - /> +<FilterForm type="grid" apply={filter.apply} expanded={filter.excludes > 0}> + {#snippet include(type)} + <Filter + {type} + title="Tags" + options={tags} + filter={filter.include.tags} + --grid-column="span 2" + /> + <Filter {type} title="Artists" options={artists} filter={filter.include.artists} /> + <Filter {type} title="Circles" options={circles} filter={filter.include.circles} /> + <Filter {type} title="Characters" options={characters} filter={filter.include.characters} /> + <Filter {type} title="Worlds" options={worlds} filter={filter.include.worlds} /> + <Filter {type} title="Categories" options={categories} filter={filter.include.categories} /> + <Filter {type} title="Ratings" options={ratings} filter={filter.include.ratings} /> + <Filter {type} title="Censorship" options={censorships} filter={filter.include.censorships} /> + <Filter {type} title="Languages" options={languages} filter={filter.include.languages} /> + {/snippet} + {#snippet exclude(type)} + <Filter + {type} + title="Tags" + options={tags} + filter={filter.exclude.tags} + --grid-column="span 2" + /> + <Filter {type} title="Artists" options={artists} filter={filter.exclude.artists} /> + <Filter {type} title="Circles" options={circles} filter={filter.exclude.circles} /> + <Filter {type} title="Characters" options={characters} filter={filter.exclude.characters} /> + <Filter {type} title="Worlds" options={worlds} filter={filter.exclude.worlds} /> + <Filter {type} title="Categories" options={categories} filter={filter.exclude.categories} /> + <Filter {type} title="Ratings" options={ratings} filter={filter.exclude.ratings} /> + <Filter {type} title="Censorship" options={censorships} filter={filter.exclude.censorships} /> + <Filter {type} title="Languages" options={languages} filter={filter.exclude.languages} /> + {/snippet} </FilterForm> diff --git a/frontend/src/lib/filter/TagFilterForm.svelte b/frontend/src/lib/filter/TagFilterForm.svelte index be5996e..280db8a 100644 --- a/frontend/src/lib/filter/TagFilterForm.svelte +++ b/frontend/src/lib/filter/TagFilterForm.svelte @@ -1,31 +1,23 @@ <script lang="ts"> - import { page } from '$app/stores'; import { namespaceList } from '$gql/Queries'; - import { TagFilterContext, getFilterContext } from '$lib/Filter'; + import { TagFilterContext } from '$lib/Filter.svelte'; import { getContextClient } from '@urql/svelte'; + import Filter from './components/Filter.svelte'; import FilterForm from './components/FilterForm.svelte'; - import TagFilterGroup from './components/TagFilterGroup.svelte'; const client = getContextClient(); - $: namespaceQuery = namespaceList(client); - $: namespaces = $namespaceQuery.data?.namespaces.edges; + let { filter }: { filter: TagFilterContext } = $props(); - const filter = getFilterContext<TagFilterContext>(); - const apply = () => $filter.apply($page.url.searchParams); + let namespaceQuery = $derived(namespaceList(client)); + let namespaces = $derived($namespaceQuery.data?.namespaces.edges); </script> -<FilterForm on:submit={apply}> - <TagFilterGroup - slot="include" - type="include" - bind:controls={$filter.include.controls} - {namespaces} - /> - <TagFilterGroup - slot="exclude" - type="exclude" - bind:controls={$filter.exclude.controls} - {namespaces} - /> +<FilterForm apply={filter.apply} expanded={filter.excludes > 0}> + {#snippet include(type)} + <Filter {type} title="Namespaces" options={namespaces} filter={filter.include.namespaces} /> + {/snippet} + {#snippet exclude(type)} + <Filter {type} title="Namespaces" options={namespaces} filter={filter.exclude.namespaces} /> + {/snippet} </FilterForm> diff --git a/frontend/src/lib/filter/components/ComicFilterGroup.svelte b/frontend/src/lib/filter/components/ComicFilterGroup.svelte deleted file mode 100644 index d302de4..0000000 --- a/frontend/src/lib/filter/components/ComicFilterGroup.svelte +++ /dev/null @@ -1,27 +0,0 @@ -<script lang="ts"> - import { categories, censorships, languages, ratings } from '$lib/Enums'; - import { ComicFilterControls } from '$lib/Filter'; - import type { ListItem } from '$lib/Utils'; - import { setContext } from 'svelte'; - import Filter from './Filter.svelte'; - - export let tags: ListItem[] | undefined; - export let artists: ListItem[] | undefined; - export let circles: ListItem[] | undefined; - export let characters: ListItem[] | undefined; - export let worlds: ListItem[] | undefined; - export let controls: ComicFilterControls; - export let type: 'include' | 'exclude'; - - setContext('filter-type', type); -</script> - -<Filter title="Tags" options={tags} bind:filter={controls.tags} --grid-column="span 2" /> -<Filter title="Artists" options={artists} bind:filter={controls.artists} /> -<Filter title="Circles" options={circles} bind:filter={controls.circles} /> -<Filter title="Characters" options={characters} bind:filter={controls.characters} /> -<Filter title="Worlds" options={worlds} bind:filter={controls.worlds} /> -<Filter title="Categories" options={categories} bind:filter={controls.categories} /> -<Filter title="Ratings" options={ratings} bind:filter={controls.ratings} /> -<Filter title="Censorship" options={censorships} bind:filter={controls.censorships} /> -<Filter title="Languages" options={languages} bind:filter={controls.languages} /> diff --git a/frontend/src/lib/filter/components/Filter.svelte b/frontend/src/lib/filter/components/Filter.svelte index ead5c4d..c164cbb 100644 --- a/frontend/src/lib/filter/components/Filter.svelte +++ b/frontend/src/lib/filter/components/Filter.svelte @@ -1,17 +1,19 @@ <script lang="ts"> - import { Association, Enum } from '$lib/Filter'; + import { Association, Enum, type FilterType } from '$lib/Filter.svelte'; import type { ListItem } from '$lib/Utils'; import Select from '$lib/components/Select.svelte'; - import { getContext } from 'svelte'; - export let title: string; - const context: 'include' | 'exclude' = getContext('filter-type'); - $: exclude = context === 'exclude'; + interface Props { + title: string; + type: FilterType; + options: ListItem[] | undefined; + filter: Association<string> | Enum<string>; + } - const id = `${context}-${title.toLowerCase()}`; + let { title, type, options, filter }: Props = $props(); + let exclude = $derived(type === 'exclude'); - export let options: ListItem[] | undefined; - export let filter: Association<string> | Enum<string>; + const id = `${type}-${title.toLowerCase()}`; </script> <div class:exclude class="filter-container"> @@ -24,7 +26,7 @@ title="matches all" class:active={filter.mode === 'all'} class="btn btn-xs" - on:click={() => (filter.mode = 'all')} + onclick={() => (filter.mode = 'all')} > ∀ </button> @@ -33,7 +35,7 @@ title="matches any of" class:active={filter.mode === 'any'} class="btn btn-xs" - on:click={() => (filter.mode = 'any')} + onclick={() => (filter.mode = 'any')} > ∃ </button> @@ -42,7 +44,7 @@ title="matches exactly" class:active={filter.mode === 'exact'} class="btn btn-xs" - on:click={() => (filter.mode = 'exact')} + onclick={() => (filter.mode = 'exact')} > = </button> @@ -53,7 +55,7 @@ title="empty" class:active={filter.empty} class="btn btn-xs" - on:click={() => (filter.empty = !filter.empty)} + onclick={() => (filter.empty = !filter.empty)} > ∅ </button> diff --git a/frontend/src/lib/filter/components/FilterForm.svelte b/frontend/src/lib/filter/components/FilterForm.svelte index 6fc4c90..ed58ed9 100644 --- a/frontend/src/lib/filter/components/FilterForm.svelte +++ b/frontend/src/lib/filter/components/FilterForm.svelte @@ -1,30 +1,40 @@ <script lang="ts"> + import { page } from '$app/state'; import Expander from '$lib/components/Expander.svelte'; - import { getFilterContext } from '$lib/Filter'; + import type { FilterType } from '$lib/Filter.svelte'; + import type { Snippet } from 'svelte'; - const filter = getFilterContext(); - export let type: 'grid' | 'row' = 'row'; + interface Props { + type?: 'grid' | 'row'; + include?: Snippet<[FilterType]>; + exclude?: Snippet<[FilterType]>; + expanded: boolean; + apply: (params: URLSearchParams) => void; + } + + let { type = 'row', include, exclude, expanded: initialExpanded, apply }: Props = $props(); - let exclude = false; + let expanded = $state(initialExpanded); - $: if ($filter.exclude.size > 0) { - exclude = true; + function onsubmit(event: SubmitEvent) { + event.preventDefault(); + apply(page.url.searchParams); } </script> -<form on:submit|preventDefault class="gap-0"> +<form {onsubmit} class="gap-0"> {#if type === 'grid'} <div class="flex flex-col gap-4 px-2 md:grid md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6"> - <slot name="include" /> + {@render include?.('include')} </div> <div class="my-2 flex justify-start"> - <Expander title="Exclude" bind:expanded={exclude} /> + <Expander title="Exclude" bind:expanded /> </div> - {#if exclude} + {#if expanded} <div class="flex flex-col gap-4 bg-rose-950/50 p-2 md:grid md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6" > - <slot name="exclude" /> + {@render exclude?.('exclude')} </div> {/if} {:else} @@ -32,10 +42,10 @@ class="flex flex-wrap justify-center gap-2 [&>*]:basis-full xl:[&>*]:basis-1/3 2xl:[&>*]:basis-1/5" > <div class="p-2"> - <slot name="include" /> + {@render include?.('include')} </div> <div class="bg-rose-950/50 p-2"> - <slot name="exclude" /> + {@render exclude?.('exclude')} </div> </div> {/if} diff --git a/frontend/src/lib/filter/components/TagFilterGroup.svelte b/frontend/src/lib/filter/components/TagFilterGroup.svelte deleted file mode 100644 index 83b6997..0000000 --- a/frontend/src/lib/filter/components/TagFilterGroup.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<script lang="ts"> - import { TagFilterControls } from '$lib/Filter'; - import type { ListItem } from '$lib/Utils'; - import { setContext } from 'svelte'; - import Filter from './Filter.svelte'; - - export let namespaces: ListItem[] | undefined; - export let controls: TagFilterControls; - export let type: 'include' | 'exclude'; - - setContext('filter-type', type); -</script> - -<Filter title="Namespaces" options={namespaces} bind:filter={controls.namespaces} /> |