feat(ui): big bundle — settings (theme/master/auto), purple default, mobile fit, master extraction

Settings expansion: 4 new keys (theme auto/light/dark, masterMode,
autoCallEnabled, autoCallSpeed 1-10) with per-key validators that
preserve old saved data. Default empty-cell color flipped from Tân
Tân blue to Excel Standard Purple #7030A0; preset palette swapped
to Office's 10 standard colors (5x2 grid). 15 new tests, 53 total.

Theme system: Tailwind v4 @variant dark (.dark *); applyTheme()
toggles <html class="dark"> based on settings.theme; auto mode
mirrors prefers-color-scheme via matchMedia listener (cleanly torn
down when switching modes). Existing dark-mode CSS converted from
@media to :where(.dark) selectors.

Mobile fit: PlayerBoard cells aspect-square on mobile, sm:aspect-[3/5]
desktop. Number text scales text-base sm:text-2xl md:text-3xl. Page
padding tightened (px-2 py-4 sm:px-3 sm:py-12). Container bumped
max-w-lg to max-w-2xl.

Header / footer: removed instructions toggle and "Trang quản trò"
link from player page. New PageFooter.svelte (tagline + Made by
miti99 with [SVG heart] link); also duplicated in PlayerBoard's
closing section-label band per request. Heart is inline SVG (red),
not emoji.

Master mode: extracted everything from /master route into reusable
MasterPanel.svelte. /master route slimmed to header + MasterPanel
+ footer. / mounts MasterPanel conditionally when settings.masterMode.
Storage prefixes unchanged.

Master tracking grid removed: per request, the 11x9 ones-digit
master board is gone. Host still gets controls, "Số vừa xổ" hero,
draw history list, and their own player card. Player card is enough.

Auto-call: single $effect lifecycle keyed on (autoRunning,
settings.autoCallSpeed, settings.autoCallEnabled). Setup / clear
setInterval cleanly across speed changes, master-mode toggle off,
component unmount, and "user disabled auto" mid-run. Button toggles
"Xổ số" -> "Bắt đầu / Dừng". Speed slider in Settings (only visible
when master mode is on). aria-label / aria-valuetext on slider.

Code-review nice-to-fixes applied: folded the two MasterPanel $effects
into one, removed muddled onkeydown on the SettingsButton modal
backdrop, added slider a11y attrs.

Docs: PDR / codebase-summary / system-architecture / development-roadmap
/ code-standards all synced to the new state.
This commit is contained in:
tiennm99 committed 2026-04-27 01:26:21 +07:00
1 parent 96a652f381
commit 0bc27f2897
23 files changed
+2056 -425

No files matched your search

+21 -9
View File
@@ -4,22 +4,23 @@
```
Entry (+layout.svelte)
├─ onMount: loadSettings() — restore emptyCellColor from loto_settings,
│ apply to --empty-cell-bg CSS variable before pages render
├─ onMount: loadSettings() — restore all 5 settings keys from loto_settings,
│ apply CSS vars, toggle <html class="dark"> on theme/OS pref, setup auto-call effect
│
├─ / (Player Page)
│ ├─ Load loto_grid, loto_crossed from localStorage
│ ├─ Display 9×9 grid (empty cells use --empty-cell-bg from settings)
│ ├─ Display 9×9 PlayerBoard (empty cells use --empty-cell-bg from settings)
│ ├─ Generate new grid on button click
│ ├─ Mark/unmark cells on click
│ └─ Show bingo popup + "Chờ X" toasts
│ ├─ Show bingo popup + "Chờ X" toasts
│ ├─ [if settings.masterMode === true]
│ │ └─ Mount MasterPanel (host controls + draw history)
│ └─ PageFooter (tagline + miti99 link)
│
└─ /master (Host Page)
├─ Load loto_master (called/remaining)
├─ Display 11×9 master board (empty cells use --empty-cell-bg)
├─ Draw button shows next called number (highlighted in red)
├─ Display host's own card (loto_master_card prefix)
└─ New Game button resets called/remaining
├─ MasterPanel (state, controls, draw history; same as above)
├─ Back link to /
└─ PageFooter
```
## State Model
@@ -34,10 +35,20 @@ Each row has exactly 5 non-zero numbers AND each column has exactly 5
(constraint-aware picker — no slack). Numbers within a column are sorted
ascending top-to-bottom (lô tô hội chợ Tân Tân convention).
### Settings (`loto_settings`)
```
theme: "auto" | "light" | "dark" // Display mode
masterMode: boolean // Show MasterPanel on /
autoCallEnabled: boolean // Enable auto-call timer
autoCallSpeed: number (1–10) // Speed in seconds
emptyCellColor: "#rrggbb" // Hex color (default #7030A0 Excel Purple)
```
### Host State (`storagePrefix="loto_master"`)
```
called: number[] // [5, 23, 67, ...] — drawn in order
remaining: number[] // [1, 2, 3, ...] minus called — shuffled initially
autoRunning: boolean // Auto-call timer active
```
### Host's Card (`storagePrefix="loto_master_card"`)
@@ -134,3 +145,4 @@ Files that are client-only:
All state is localStorage. No API calls. Fully functional offline after initial load.
Last reviewed: 2026-04-27
Last synced: 2026-04-27 (6-phase refactor)