tiennm99 fba3e9183b fix(ui): four small bugs surfaced after the UI/UX merge
1. Settings gear was unclickable because H1's `drop-shadow` filter
   created a stacking context that painted the H1 over the absolutely-
   positioned trigger. Bump gear wrapper to z-10.
   (src/routes/+page.svelte)

2. Switch rows in settings had a dead zone — `<label>` wrapped a
   `<span role=switch>` (not a labelable element), so taps on the
   text fell through. Move role/click/keydown to the wrapping div
   so the whole row toggles. Pill stays decorative.
   (src/lib/SettingsButton.svelte)

3. Empty cells used `dark:[filter:brightness(...)]` which creates a
   per-cell stacking context — same hazard class as bug #1. Replace
   with a pointer-events-none overlay span (`hidden dark:block`).
   (src/lib/PlayerBoard.svelte)

4. Audio cache never evicted on voice swap, leaking ~92 Audio
   elements per change over a session. New `clearAudioCache()` in
   voice.js, called from `pickVoice` when the id actually changes.
   (src/lib/voice.js, src/lib/SettingsButton.svelte)

Tests 98/98 pass; build clean.
2026-04-27 09:51:49 +07:00
2026-04-26 19:16:46 +07:00

Lô tô

Bàn số của trò chơi "Lô tô" — SvelteKit app.

Single page (/). The host enables "Chế độ quản trò" in settings to reveal the master panel inline below their player card; called numbers get spoken aloud in Vietnamese using bundled MP3 clips (no runtime TTS).

See docs/ for architecture, code standards, and deployment.

Development

npm install
npm run dev

Inside code-server (reverse proxy)

cp .env.example .env.local
# edit .env.local: set CODESERVER_HOST and CODESERVER_PORT
npm run dev:codeserver

Open https://<CODESERVER_HOST>/absproxy/<CODESERVER_PORT>/.

Use /absproxy/{port}/, not /proxy/{port}/ — the latter strips the path prefix and breaks the SvelteKit base path.

Build

npm run build         # default — root basePath, for Cloudflare Pages
npm run build:gh      # /loto basePath, for tiennm99.github.io/loto manual export

Static export to build/. Deployed to Cloudflare Pages from main (set up via the CF dashboard — see docs/deployment-guide.md).

Regenerating audio

Vietnamese voice clips live in static/audio/{voiceId}/. Generated once with edge-tts (free, no API key) — runtime never calls TTS. To regenerate (e.g., to add a new voice that Microsoft ships, or to change wording):

pip install edge-tts
python3 scripts/generate-audio.py

The script auto-discovers every vi-* voice and writes a manifest the app reads on next reload.

S
Description
Lô Tô (Vietnamese lottery bingo) number board — Next.js web app
Readme
4.1 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 89.9%
CSS 8%
JavaScript 2.1%