Initial commit: Shelfless – alternative Audiobookshelf frontend

React + Vite + TypeScript SPA covering the full ABS feature set (library
browsing, item detail, metadata/cover editing, podcasts, player with session
sync, admin: users/libraries/scanner/server settings). Dev uses a dynamic
CORS proxy; production is served by server/index.mjs (static + reverse proxy
to ABS_URL). Includes systemd unit and installer under deploy/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-06-02 20:23:04 +02:00
commit 83d8b7b99d
93 changed files with 9790 additions and 0 deletions

88
design-system/MASTER.md Normal file
View File

@@ -0,0 +1,88 @@
# Shelfless — Design System (MASTER)
Single source of truth for visual + interaction design. Grounded in ui-ux-pro-max
(Podcast Platform #27 + Music Streaming #45 + Book & Reading Tracker #135 → **Dark Mode
(OLED) + Minimalism** with a literary-warm note) and the project brief.
When building any page: read this file first. A page-specific override under
`design-system/pages/<page>.md` (if present) takes precedence over these rules.
---
## Principles
- Dark theme by default. One consistent accent color, never competing accents.
- Generous whitespace, clear type hierarchy, content (covers) first.
- Subtle micro-animations only (cover hover, player slide-in). No motion overload.
- NO AI-slop: no purple gradients, no glassmorphism overload, no card-in-card nesting.
- NO online badge, user counter, activity feed, or "welcome back" banner.
- Reference feel: Plex overview (but cleaner), Spotify player (but less cluttered).
## Typography
Both verified as Google variable fonts. **No Inter / Roboto / Space Grotesk.**
- Headings / titles / section headers: **Fraunces** (serif, literary, optical sizing).
- Body / UI: **Hanken Grotesk** (humanist grotesque, highly readable).
- Numbers in player timers, durations, data tables: `font-variant-numeric: tabular-nums`.
- Type scale (px): 12 · 14 · 16 · 18 · 24 · 32 · 48. Body 16px, line-height 1.51.6.
- Weight hierarchy: headings 500700, body 400, labels/nav-active 500.
- Loaded locally via `@fontsource-variable/fraunces` + `@fontsource-variable/hanken-grotesk`
(no hard CDN dependency); `font-display: swap`.
## Color tokens (CSS custom properties on `:root`, dark default)
All foreground/background pairs verified ≥4.5:1 (text) / ≥3:1 (large/UI).
| Token | Value | Use |
|------------------|-----------|--------------------------------------|
| `--bg` | `#0C0A09` | app background (warm near-black) |
| `--surface` | `#1C1917` | cards, sidebar, panels |
| `--surface-2` | `#292524` | raised surfaces, player bar, inputs |
| `--border` | `#3F3B38` | borders/dividers (visible in dark) |
| `--text` | `#FAFAF9` | primary text |
| `--text-muted` | `#A8A29E` | secondary text (≥4.5:1 on `--bg`) |
| `--accent` | `#F59E0B` | accent (default Amber) |
| `--on-accent` | `#0C0A09` | text/icon on accent fills |
| `--destructive` | `#EF4444` | delete / danger |
| `--success` | `#22C55E` | progress / completed |
Accent is themeable via `data-accent` on `<html>`; options in Settings:
- `amber` #F59E0B (default) · `teal` #14B8A6 · `coral` #FB7185 · `green` #22C55E · `blue` #3B82F6.
Tailwind maps `bg`, `surface`, `surface-2`, `border`, `text`, `text-muted`, `accent`,
`on-accent`, `destructive`, `success` to these variables (`colors` in tailwind.config).
## Spacing, radius, elevation
- 4/8px spacing rhythm. Section spacing tiers 16 / 24 / 32 / 48.
- Radius ~1012px on cards/buttons/inputs (`--radius: 0.625rem`). 0px never; no huge pills.
- Elevation: one consistent shadow scale; modals/player use a slightly stronger shadow.
Avoid random shadow values.
## Motion (respect `prefers-reduced-motion`)
- Durations 150300ms; enter ease-out, exit ~6070% shorter.
- Animate only `transform` / `opacity` (never width/height/top/left).
- Cover hover: `scale(1.0 → 1.03)` + subtle lift/shadow.
- Player bar: slide-up + fade on first appearance.
- Skeleton shimmer while loading (>300ms). Visible 2px accent focus ring.
- Max 12 animated elements per view.
## Component guidelines
- **MediaCard**: cover (book 2:3 / podcast 1:1), rounded, hover-lift. Progress strip at
bottom in `--accent`, shown only when progress > 0%. Subtle check overlay when finished.
- **Sidebar**: `--surface` bg; active item = accent indicator bar + medium weight; always
icon + label (never icon-only); collapsible to icon mode; on mobile → bottom nav (≤5).
- **PlayerBar**: fixed bottom, `--surface-2`; tabular-nums times; draggable progress bar
with accent only on the playhead/fill; touch targets ≥44px.
- **Grid**: responsive `auto-fill minmax(...)`, `gap-6`. Virtualize only if a single page
renders 50+ items (infinite scroll paginates, so usually fine).
- **Modal**: scrim 4060% black; animate from trigger (scale+fade); Esc/close affordance;
focus trap + return focus; confirm before destructive/unsaved-dismiss.
- **Table** (admin users): `aria-sort`, tabular-nums, row hover; destructive actions
visually separated from normal ones.
- **Forms**: visible labels (not placeholder-only), error below field, helper text,
loading state on submit, password show/hide toggle, autofocus first invalid field.
## Icons
Lucide React only. Consistent stroke width; one icon size scale (sm/md=24/lg). No emoji.
## Anti-patterns (do not do)
Purple/indigo gradients · glassmorphism overload · card-in-card-in-card · emoji icons ·
online/user-count/activity-feed/welcome banners · icon-only nav · hover-only interactions ·
animating layout properties · gray-on-gray low contrast · raw hex in components (use tokens).