- New Go backend binary (backend + runner) replacing old scraper/ - Rename SCRAPER_API_URL → BACKEND_API_URL in UI env and docker-compose - Rename scraperFetch → backendFetch across all 19 UI server files - Remove SCRAPER_PROXY env var and proxy transport from browser.Config - Add Meilisearch, Valkey, Caddy to docker-compose - Add docs/: api-endpoints.md, request-flow.mermaid.md, data-flow.mermaid.md
2.5 KiB
LibNovel UI — Agent Context
SvelteKit 2 + Svelte 5 frontend. Node adapter for production; served behind Caddy.
Design System
ACTIVE_STYLE: branded
Custom amber + zinc dark palette. No shadcn CLI defaults — primitives are hand-authored to match.
| Token | Value |
|---|---|
| Accent | #f59e0b (amber-400) |
| Surface-1 | zinc-900 |
| Surface-2 | zinc-800 |
| Surface-3 | zinc-700 |
| Text-primary | zinc-100 |
| Text-secondary | zinc-400 |
| Destructive | red-400 |
Tailwind
Version: 4 — configured entirely via @theme {} in src/app.css and the @tailwindcss/vite plugin.
There is no tailwind.config.ts — do not create one.
Do not run npx shadcn-svelte add ... — primitives are hand-authored in $lib/components/ui/.
shadcn-svelte Primitives
All in src/lib/components/ui/:
| Component | Variants / Notes |
|---|---|
button |
default / secondary / outline / ghost / destructive / link; sizes: default / sm / lg / icon |
badge |
default / secondary / outline / destructive |
card |
Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter |
textarea |
bindable value prop |
dialog |
Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter |
separator |
horizontal / vertical |
Always use cn() from $lib/utils — never template-literal class conditionals.
Svelte 5 Conventions
@Observable/ runes ($state,$derived,$effect,$props()) for all new code.- Do not add
ObservableObject/@Published— they don't exist in Svelte; don't introduce legacywritablestores for new code. - Navigation:
goto()from$app/navigation;pagefrom$app/state.
iOS/UX Skill
For any view work, load the ios-ux skill at task start:
skill({ name: "ios-ux" })
Key Files
| File | Role |
|---|---|
src/app.css |
Tailwind v4 @theme tokens — source of truth for all design tokens |
src/lib/utils.ts |
cn() helper (clsx + tailwind-merge) |
src/lib/types.ts |
Shared client-safe domain types |
src/routes/+layout.svelte |
Root layout: sticky nav, persistent <audio> element, mini-player bar |
src/lib/audio.svelte.ts |
Global audio store (Svelte 5 runes class) |
src/lib/components/ui/ |
shadcn-style UI primitives |
Persistent Audio Element
The <audio> element in +layout.svelte must never be conditionally rendered (no {#if}).
Conditional rendering destroys and recreates the element, triggering onpause mid-playback.
Keep it always in the DOM; control it via audioStore.