list: prototype without nested params
This commit is contained in:
@@ -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">
|
||||||
<ChipGroup
|
<Label for="list-username">Username</Label>
|
||||||
label="Status"
|
<Input id="list-username" bind:value={params.username} />
|
||||||
items={AnimeListWatchStatus.options.map((v) => ({
|
</div>
|
||||||
label: v.toUpperCase(),
|
<div class="flex flex-col gap-2">
|
||||||
value: v,
|
<Label for="list-status">Status</Label>
|
||||||
}))}
|
<ChipGroup
|
||||||
bind:value={params.list.status}
|
items={AnimeListWatchStatus.options.map((v) => ({
|
||||||
/>
|
label: v.toUpperCase(),
|
||||||
|
value: v,
|
||||||
|
}))}
|
||||||
|
bind:value={params.status}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button type="submit">Search</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -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([]),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ const songTypesCodec = z.codec(z.string(), z.array(AmqSongLinkType), {
|
|||||||
decode: (str) =>
|
decode: (str) =>
|
||||||
str
|
str
|
||||||
? decodeURIComponent(str)
|
? decodeURIComponent(str)
|
||||||
.split(SEP)
|
.split(SEP)
|
||||||
.map((s) => AmqSongLinkTypeMap[s as keyof typeof AmqSongLinkTypeMap])
|
.map((s) => AmqSongLinkTypeMap[s as keyof typeof AmqSongLinkTypeMap])
|
||||||
: [],
|
: [],
|
||||||
encode: (arr) =>
|
encode: (arr) =>
|
||||||
arr
|
arr
|
||||||
? encodeURIComponent(
|
? encodeURIComponent(
|
||||||
arr.map((a) => AmqSongLinkTypeMapReverse[a]).join(SEP),
|
arr.map((a) => AmqSongLinkTypeMapReverse[a]).join(SEP),
|
||||||
)
|
)
|
||||||
: "",
|
: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user