list: prototype without nested params

This commit is contained in:
2026-02-13 00:32:47 -08:00
parent 21d62f8c6f
commit a144baba2b
3 changed files with 44 additions and 36 deletions

View File

@@ -4,32 +4,44 @@
import { SearchParamsSchema } from "./schema"; import { SearchParamsSchema } from "./schema";
import { ChipGroup } from "$lib/components/ui/chip-group"; import { ChipGroup } from "$lib/components/ui/chip-group";
import { AnimeListWatchStatus } from "$lib/utils/list"; import { AnimeListWatchStatus } from "$lib/utils/list";
import NativeSelect from "$lib/components/ui/native-select/native-select.svelte";
import NativeSelectOption from "$lib/components/ui/native-select/native-select-option.svelte";
import Input from "$lib/components/ui/input/input.svelte";
import { Label } from "$lib/components/ui/label";
import { Button } from "$lib/components/ui/button";
let { data }: { data: PageData } = $props(); let { data }: { data: PageData } = $props();
const params = useSearchParams(SearchParamsSchema, { const params = useSearchParams(SearchParamsSchema, {
pushHistory: false, showDefaults: true,
updateURL: false,
}); });
</script> </script>
<h1 class="text-2xl font-semibold">List Search WIP</h1> <h1 class="text-2xl font-semibold">List Search WIP</h1>
<form> <form class="flex flex-wrap gap-2">
<label for="list-kind">Kind</label> <div class="flex flex-col gap-2">
<!-- nested stuff won't work with useSearchParams --> <Label for="list-kind">Kind</Label>
<select id="list-kind" bind:value={params.list.kind}> <NativeSelect id="list-kind" bind:value={params.kind}>
<option value="mal">MAL</option> <NativeSelectOption value="mal">MAL</NativeSelectOption>
<option value="anilist">AniList</option> <NativeSelectOption value="anilist">AniList</NativeSelectOption>
<option value="kitsu">Kitsu</option> <NativeSelectOption value="kitsu">Kitsu</NativeSelectOption>
</select> </NativeSelect>
<label for="list-username">Username</label> </div>
<input id="list-username" bind:value={params.list.username} /> <div class="flex flex-col gap-2">
<Label for="list-username">Username</Label>
<Input id="list-username" bind:value={params.username} />
</div>
<div class="flex flex-col gap-2">
<Label for="list-status">Status</Label>
<ChipGroup <ChipGroup
label="Status"
items={AnimeListWatchStatus.options.map((v) => ({ items={AnimeListWatchStatus.options.map((v) => ({
label: v.toUpperCase(), label: v.toUpperCase(),
value: v, value: v,
}))} }))}
bind:value={params.list.status} bind:value={params.status}
/> />
</div>
<Button type="submit">Search</Button>
</form> </form>

View File

@@ -1,19 +1,15 @@
import { AnimeList, AnimeListWatchStatus } from "$lib/utils/list"; import { AnimeListKind, AnimeListWatchStatus } from "$lib/utils/list";
import { z } from "zod"; import { z } from "zod";
const fieldSep = ":"; const valueSep = ".";
const valueSep = ",";
const listCodec = z.codec(z.string(), AnimeList, { const statusCodec = z.codec(z.string(), z.array(AnimeListWatchStatus), {
decode: (s) => { decode: (s) => s ? decodeURIComponent(s).split(valueSep).map((s) => AnimeListWatchStatus.parse(s)) : [],
const [kind, ...rest] = decodeURIComponent(s).split(fieldSep); encode: (v) => v.length ? encodeURIComponent(v.join(valueSep)) : "",
const status = rest.pop()?.split(valueSep).map((v) => AnimeListWatchStatus.parse(v)) ?? []; })
const username = rest.join("");
return AnimeList.parse({ kind, username, status });
},
encode: (list) => encodeURIComponent(`${list.kind}${fieldSep}${list.username}${fieldSep}${list.status?.join(valueSep)}`),
});
export const SearchParamsSchema = z.object({ export const SearchParamsSchema = z.object({
list: listCodec.default({ kind: "mal", username: "", status: [] }), kind: AnimeListKind.default("mal"),
username: z.string().optional().default(""),
status: statusCodec.default([]),
}) })