From 7eb96808b00e4fe900a2d5b51eaacd294bd75d86 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 30 Apr 2026 19:32:02 +0700 Subject: [PATCH] feat(master): add auto-call countdown indicator Visible countdown ring + seconds number above the hero token while auto-call runs. Host now sees exactly when the next number fires instead of staring at a static caption. - AutoCountdown.svelte: pure visual component, props-driven, rAF loop, SVG ring via stroke-dashoffset, prefers-reduced-motion fallback - MasterPanel.svelte: tickCount $state bumped per draw + on every (re-)arm of the auto-call $effect (covers speed-slider mid-run) --- web/docs/codebase-summary.md | 3 +- web/src/lib/AutoCountdown.svelte | 101 +++++++++++++++++++++++++++++++ web/src/lib/MasterPanel.svelte | 21 +++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 web/src/lib/AutoCountdown.svelte diff --git a/web/docs/codebase-summary.md b/web/docs/codebase-summary.md index 222c4c5..fe06f9d 100644 --- a/web/docs/codebase-summary.md +++ b/web/docs/codebase-summary.md @@ -14,7 +14,8 @@ | `src/lib/PlayerBoard.svelte` | Reusable player card (9×9 grid rendered as 3 stacked 3×9 mini-cards: Tân Tân / An khang thịnh vượng / Tân Tân tốt nhất). Tall (3:4 on mobile; 3:5 on sm+) cells with condensed bold black numbers (`tan-tan-num` font stack w/ self-hosted Roboto Condensed), white number cells, purple empty cells (dark mode dims via `filter:brightness(0.85)`). Handles crossed state, animated cross-out (200 ms `cross-draw` keyframe), `active:scale-90` press, 10 ms haptic on tap. Two header actions: "Tạo bảng mới" / "Xoá đánh dấu". First-run state shows a faded preview card. Bingo popup tiers: row 1 = standard celebration; row 3+ = falling-emoji confetti rain via CSS `confetti-fall`. Toast "Chờ N" + audio. Accepts `storagePrefix` prop for multi-card isolation. | | `src/lib/SettingsButton.svelte` | Gear icon + modal (responsive `max-w-sm sm:max-w-md`). 6 fieldsets: Giao diện (theme pills), Chế độ (3-way mode picker w/ SVG glyphs: player/master/both), Chế độ quản trò (switch row), Tự động xổ (switch + speed slider), Âm thanh (two switches + voice picker), Màu ô trống (10 Excel swatches + custom input in bordered card w/ "Tuỳ chỉnh"/"Mẫu" sub-headers). Boolean toggles use a shared `switchRow` snippet (`role="switch"` + keyboard support). Reset-to-default button. Mounted on `/`. | | `src/lib/MasterEmptyState.svelte` | Empty board placeholder for first-run master (mirrors PlayerBoard's preview UX). Displays faded 11×9 grid with "Ấn để bắt đầu ván mới" hint. | -| `src/lib/MasterPanel.svelte` | Host controls. New game / draw, large "Số vừa xổ" hero token (160 px mobile, 224 px sm+) with `aria-live="assertive"` + auto `scrollIntoView` on each new draw, "Thứ tự đã xổ" history list, 11×9 last-digit-aligned tracking grid (with circular tokens + draw-order overlay). Publishes draws to `call-bus` for player auto-tick. "Xổ số" / "Bắt đầu / Dừng" button bound to auto-call. Mounted conditionally on `/` when `settings.mode !== "player"`; the wrapping section uses `transition:slide` for smooth toggle-in. | +| `src/lib/MasterPanel.svelte` | Host controls. New game / draw, large "Số vừa xổ" hero token (160 px mobile, 224 px sm+) with `aria-live="assertive"` + auto `scrollIntoView` on each new draw, "Thứ tự đã xổ" history list, 11×9 last-digit-aligned tracking grid (with circular tokens + draw-order overlay). Publishes draws to `call-bus` for player auto-tick. "Xổ số" / "Bắt đầu / Dừng" button bound to auto-call. While auto-call runs, mounts `` above the hero (driven by `tickCount` $state, bumped on draw and on every (re-)arm of the auto-call $effect). Mounted conditionally on `/` when `settings.mode !== "player"`; the wrapping section uses `transition:slide` for smooth toggle-in. | +| `src/lib/AutoCountdown.svelte` | Visual countdown for auto-call. Props-driven (`running`, `duration`, `tickKey`) — parent owns the `setInterval`, this component just renders. SVG ring with `stroke-dashoffset` controlled by elapsed-time progress (rAF loop while running) plus centered seconds-remaining number. `prefers-reduced-motion` clamps `dashOffset = 0` (static full ring). `role="timer"` + `aria-live="off"` so screen readers don't announce every second. | | `src/lib/PageFooter.svelte` | Footer with tagline ("Made by miti99 with ❤️ SVG icon") + link. Mounted on `/`. | ### Game Logic & Coordination diff --git a/web/src/lib/AutoCountdown.svelte b/web/src/lib/AutoCountdown.svelte new file mode 100644 index 0000000..b13a4d1 --- /dev/null +++ b/web/src/lib/AutoCountdown.svelte @@ -0,0 +1,101 @@ + + +
+ + + + + + {secondsRemaining} + +
diff --git a/web/src/lib/MasterPanel.svelte b/web/src/lib/MasterPanel.svelte index d14afda..6cd463f 100644 --- a/web/src/lib/MasterPanel.svelte +++ b/web/src/lib/MasterPanel.svelte @@ -79,6 +79,7 @@