first success!

This commit is contained in:
2026-02-05 03:14:01 -08:00
parent fa949b98c2
commit 2b51beff34
2 changed files with 311 additions and 2 deletions

View File

@@ -1,2 +1,117 @@
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
<script lang="ts">
import { desc } from "drizzle-orm";
import { onMount } from "svelte";
import { db, overwriteDatabaseFile } from "$lib/db/client-db";
import { animeTable } from "$lib/db/schema";
type AnimeListItem = {
annId: number;
mainName: string;
year: number;
seasonId: number;
};
const SEED_URL = "/data/amq.sqlite";
const SEED_VERSION = "amq.sqlite.v1"; // bump when static/data/amq.sqlite changes
const SEED_KEY = "amq.seed.version";
let status = $state<"idle" | "loading" | "ready" | "error">("idle");
let error = $state<string | null>(null);
let anime = $state<AnimeListItem[]>([]);
async function ensureSeeded() {
const current = localStorage.getItem(SEED_KEY);
if (current === SEED_VERSION) return;
const res = await fetch(SEED_URL, { cache: "no-cache" });
if (!res.ok) {
throw new Error(
`Failed to fetch seed DB: ${res.status} ${res.statusText}`,
);
}
const stream = res.body;
if (stream) {
await overwriteDatabaseFile(stream);
} else {
const blob = await res.blob();
await overwriteDatabaseFile(blob);
}
localStorage.setItem(SEED_KEY, SEED_VERSION);
}
onMount(() => {
(async () => {
status = "loading";
error = null;
try {
await ensureSeeded();
const rows = await db
.select({
annId: animeTable.annId,
mainName: animeTable.mainName,
year: animeTable.year,
seasonId: animeTable.seasonId,
})
.from(animeTable)
.orderBy(
desc(animeTable.year),
desc(animeTable.seasonId),
desc(animeTable.annId),
)
.limit(20);
anime = rows;
status = "ready";
} catch (e) {
error = e instanceof Error ? e.message : String(e);
status = "error";
}
})();
});
function seasonName(seasonId: number) {
// matches your Season enum mapping (0..3)
switch (seasonId) {
case 0:
return "Winter";
case 1:
return "Spring";
case 2:
return "Summer";
case 3:
return "Fall";
default:
return `Season ${seasonId}`;
}
}
</script>
<h1 class="text-2xl font-semibold">AMQ Browser</h1>
{#if status === "loading"}
<p class="mt-3 text-sm text-muted-foreground">Loading client database…</p>
{: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>
<ul class="mt-4 space-y-2">
{#each anime as a (a.annId)}
<li class="rounded border px-3 py-2">
<div class="font-medium">{a.mainName}</div>
<div class="text-sm text-muted-foreground">
{a.year}
{seasonName(a.seasonId)} • ANN {a.annId}
</div>
</li>
{/each}
</ul>
{/if}