Files
shelfless/design-system/MASTER.md
Scarriffle 83d8b7b99d 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>
2026-06-02 20:23:04 +02:00

89 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).