Split the app into the three pages the navbar promises, each with one job: - / (home) -> read-only roster, no mutation controls - /add -> create only, redirects to / on success - /edit -> update + delete only (picker, plus /edit?id=<uuid> deep links) Data layer (src/lib/students.ts) is the single source of truth: - zod studentDraftSchema validates form input (trims name, lowercases email, coerces yearLevel to an int 1-5, restricts course to a known list) - studentSchema = draft + id + createdAt, so types come from z.infer - versioned key it3206.students.v1, validated on read *and* write; corrupt or missing data degrades to an empty list instead of throwing - typed CRUD helpers; useSyncExternalStore hook with a stable snapshot cache, a window event and the storage event so every island and other tabs re-render Footer "clear local storage" is now wired to clearStudents() (confirm dialog, label feedback) instead of being inert, and the layout switched to min-h-svh + an in-flow footer so it no longer overlaps long lists. Footer padding clears the Astro dev toolbar, which was covering the link in dev. Also adds zod, plus @astrojs/check + typescript@^6 as dev deps so astro check runs (TS 7 does not expose the API astro check needs yet).
17 lines
619 B
Plaintext
17 lines
619 B
Plaintext
---
|
|
import MainLayout from "../layouts/MainLayout.astro";
|
|
---
|
|
|
|
<MainLayout title="Not found">
|
|
<div class="flex flex-col items-center gap-3 text-center">
|
|
<p class="text-xs font-medium tracking-[0.3em] text-white/40 uppercase">404</p>
|
|
<h1 class="text-2xl font-semibold tracking-tight">Page not found</h1>
|
|
<p class="text-sm text-white/50">
|
|
That route does not exist. The list is over here.
|
|
</p>
|
|
<a href="/" class="mt-2 underline underline-offset-4 text-white/70 hover:text-white transition-colors">
|
|
back to the list
|
|
</a>
|
|
</div>
|
|
</MainLayout>
|