feat: UI polish v2 + installable PWA with offline audio

Phase 1 — Vietnamese-safe font + master empty state:
- Add @fontsource/roboto-condensed (700 weight, all subsets including
  Vietnamese). font-display:swap. tan-tan-num now resolves the bundled
  face on Android instead of system Arial Narrow.
- New MasterEmptyState.svelte: ghost 11×9 grid + "Chế độ Quản trò"
  pill + readiness microcopy. Replaces the bare line of text in
  MasterPanel's no-game state.

Phase 2 — Mode picker icons, color picker layout, header polish:
- Inline SVG glyphs above each mode button (player card / megaphone /
  two stacked cards). Communicates role at a glance.
- Color picker wrapped in a single bordered card with "Tuỳ chỉnh"
  and "Mẫu sẵn" sub-headers.
- "Mặc định" → "Đặt lại" with a bordered chip style — clearer
  affordance than the previous near-invisible footer link.
- Header subline: drop tracking-[0.28em] all-caps SaaS look; replace
  with dash-flanked lantern band ("— 🏮 Hội chợ TN1 —") for
  fairground mood.

Phase 3 — Installable PWA + offline audio:
- @vite-pwa/sveltekit with autoUpdate. Precache app shell (~353 KB
  → 213 entries) PLUS the default voice's 92 clips so first-install
  is fully offline-capable. Alternate voices fall through to a
  CacheFirst runtime rule (cached on first play, 30-day TTL,
  maxEntries: 400 for future-proofing).
- New static/manifest.webmanifest (Lô tô — Hội chợ TN1, theme #1565c0,
  background #0a0f1f, standalone, vi).
- Icons: 192/512 standard + 512 maskable, generated from a single
  rose-amber-gradient SVG source.
- app.html: manifest link, dual theme-color meta (light + dark),
  apple-touch-icon, apple-mobile-web-app-capable for proper
  standalone launch on iOS Safari.
- _headers: add manifest-src + worker-src to CSP; no-cache on /sw.js
  and /manifest.webmanifest so deploys propagate.

Tests: 115/115 pass. Build clean (305 precache entries, 0 glob
warnings).

Reviewer concerns (addressed):
- maxEntries bumped 200 → 400 (was barely enough for 2 voices).
- Default voice precached so offline-first promise holds without
  requiring users to play every clip online first.
- "do NOT add skipWaiting" comment added next to autoUpdate.
This commit is contained in:
tiennm99 committed 2026-04-27 20:35:59 +07:00
1 parent f7cbb6e1c7
commit f899b09631
24 files changed
+5756 -68

No files matched your search

+21 -6
View File
@@ -35,6 +35,7 @@ All colors have corresponding `dark:` variants. Tailwind's `prefers-color-scheme
## Typography
- **Font**: Geist Sans (Google Fonts), fallback to Arial/Helvetica.
- **Grid numbers**: Roboto Condensed (self-hosted via @fontsource/roboto-condensed, font-display: swap) in `tan-tan-num` stack, bold weight.
- **Headings**: Extrabold (font-extrabold) for main title, bold (font-bold) for secondary.
- **Body**: Regular weight, slate-600 (light) / slate-400 (dark).
- **Emphasis**: `<strong>` for important copy (e.g., button labels in instructions).
@@ -65,12 +66,19 @@ All colors have corresponding `dark:` variants. Tailwind's `prefers-color-scheme
## Settings & UI Toggles
### Mode Picker (SettingsButton)
Three-way toggle in settings modal:
- **Player mode** (`mode: "player"`) — PlayerBoard only, default UX for players
- **Master mode** (`mode: "master"`) — MasterPanel only, host-only view (e.g., projector)
- **Both mode** (`mode: "both"`) — PlayerBoard + MasterPanel stacked inline, master auto-ticks player board on draw
Three-way segmented picker in settings modal with inline SVG glyphs:
- **Player mode** (rectangle icon) — PlayerBoard only, default UX for players
- **Master mode** (rounded ellipse icon) — MasterPanel only, host-only view (e.g., projector)
- **Both mode** (double-box icon) — PlayerBoard + MasterPanel stacked inline, master auto-ticks player board on draw
Mode selection is persisted to localStorage and applied immediately.
SVG icons hand-drawn from primitives (no icon library). Selection persisted to localStorage.
### Color Picker (SettingsButton)
Grouped card with two sub-sections:
- **Mẫu** (Presets): 10 Excel color swatches in a flex row (purple, blue, cyan, green, yellow, orange, red, pink, gray, black)
- **Tuỳ chỉnh** (Custom): Native `<input type="color">` for custom hex entry
Card has rounded border, shadow, padding. Compact layout fits mobile.
## Component Patterns
@@ -159,5 +167,12 @@ Keep emojis rare; use for celebration only.
- Focus states: Implicit via Tailwind (`focus:ring-2`), add if extending components.
- Contrast: Tailwind slate/indigo/emerald combos meet WCAG AA.
- Dark mode: Respects `prefers-color-scheme`, not forced.
- SVG glyphs: Simple, high-contrast shapes (no fill patterns); keyboard-navigable via fieldset + label.
Last reviewed: 2026-04-26
## PWA Features
- **Install Prompt**: Native browser-driven (no custom banner). Manifest enables Android/iOS install.
- **Offline**: App shell precache enables instant load. Audio cached on first play.
- **Auto-Update**: SW detects new version; user sees reload toast (non-intrusive).
Last reviewed: 2026-04-27