success pt. 5 search box

This commit is contained in:
2026-02-05 03:49:33 -08:00
parent b8b99a0f3e
commit e69f228172

View File

@@ -1,15 +1,22 @@
<script lang="ts">
import { onMount } from "svelte";
import { db, ensureSeeded, getAnimeList } from "$lib/db/client-db";
import {
db,
ensureSeeded,
getAnimeList,
searchAnimeByName,
} from "$lib/db/client-db";
let status = $state<"idle" | "loading" | "ready" | "error">("idle");
let error = $state<string | null>(null);
let query = $state("");
let isSearching = $state(false);
type AnimeItem = Awaited<ReturnType<typeof getAnimeList>>[number];
let anime = $state<AnimeItem[]>([]);
onMount(() => {
(async () => {
async function loadInitial() {
status = "loading";
error = null;
@@ -21,9 +28,42 @@
error = e instanceof Error ? e.message : String(e);
status = "error";
}
})();
}
onMount(() => {
void loadInitial();
});
// Debounced search
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
function scheduleSearch(nextQuery: string) {
query = nextQuery;
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(async () => {
if (status !== "ready") return;
const q = query.trim();
try {
isSearching = true;
if (!q) {
anime = await getAnimeList(db, 20);
} else {
anime = await searchAnimeByName(db, q, 20);
}
} catch (e) {
error = e instanceof Error ? e.message : String(e);
status = "error";
} finally {
isSearching = false;
}
}, 200);
}
function seasonName(seasonId: number) {
switch (seasonId) {
case 0:
@@ -47,7 +87,28 @@
{:else if status === "error"}
<p class="mt-3 text-sm text-red-600">Error: {error}</p>
{:else if status === "ready"}
<p class="mt-3 text-sm text-muted-foreground">Showing {anime.length} anime</p>
<div class="mt-3 flex flex-col gap-2">
<label class="text-sm text-muted-foreground" for="anime-search">
Search anime
</label>
<input
id="anime-search"
class="rounded border px-3 py-2 text-sm"
placeholder="Type to search by name…"
value={query}
oninput={(e) =>
scheduleSearch((e.currentTarget as HTMLInputElement).value)}
autocomplete="off"
spellcheck={false}
/>
<p class="text-sm text-muted-foreground">
{#if isSearching}
Searching…
{:else}
Showing {anime.length} anime
{/if}
</p>
</div>
<ul class="mt-4 space-y-2">
{#each anime as a (a.annId)}