Some checks failed
CI / v3 / Check ui (pull_request) Failing after 15s
CI / v3 / Test backend (pull_request) Failing after 16s
CI / v3 / Docker / backend (pull_request) Has been skipped
CI / v3 / Docker / runner (pull_request) Has been skipped
CI / v3 / Docker / ui (pull_request) Has been skipped
- Remove all pre-v3 code: scraper, ui-v2, backend v1, ios v1+v2, legacy CI workflows - Flatten v3/ contents to repo root - Add Doppler secrets management (project=libnovel, config=prd) - Add justfile with doppler run wrappers for all docker compose commands - Strip hardcoded env fallbacks from docker-compose.yml - Add minimal README.md - Clean up .gitignore
72 lines
2.5 KiB
Markdown
72 lines
2.5 KiB
Markdown
# 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 legacy `writable` stores for new code.
|
|
- Navigation: `goto()` from `$app/navigation`; `page` from `$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`.
|