chore: sync docs with single-page app, fix jsconfig

- docs: drop stale /master route refs (system-architecture page flow,
  client-only file list, basePath profiles; pdr architecture section
  + acceptance items; codebase-summary mounted-on notes; code-standards
  link example; deployment-guide redirect explanation)
- roadmap: drop "Currently Implemented Features" section (lives in git
  log + plans + pdr/codebase-summary)
- jsconfig: extend .svelte-kit/tsconfig.json (clears SvelteKit warning,
  picks up generated paths/aliases)
This commit is contained in:
2026-04-27 07:44:19 +07:00
parent 31125443e9
commit e2c116abe2
7 changed files with 57 additions and 87 deletions
+2 -2
View File
@@ -127,8 +127,8 @@ function randomANumberInRow(weights) {
## Internal Navigation
- Use `import { base } from '$app/paths'` for internal links to preserve basePath across deployments.
- Example: `<a href="{base}/master">Host page</a>` works on root (`""`) and subpath (`/loto`) equally.
- Use `import { base } from '$app/paths'` for internal links/asset URLs to preserve basePath across deployments.
- Example: `<img src="{base}/icon.svg">` resolves on both root (`""`) and subpath (`/loto`) builds.
## Import Organization
+2 -2
View File
@@ -12,9 +12,9 @@
| File | Purpose |
|------|---------|
| `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:5 on mobile; wider on sm+) cells with condensed bold black numbers (`tan-tan-num` font stack), white number cells, purple empty cells by default. Handles crossed state, bingo popup, "Chờ X" toast. Accepts `storagePrefix` prop for multi-card isolation. Empty cells use `--empty-cell-bg` CSS var from settings store. |
| `src/lib/SettingsButton.svelte` | Gear icon + modal. 4 fieldsets: Giao diện (theme auto/light/dark), Chế độ quản trò (master mode toggle), Tự động xổ (auto-call + speed 110s), Màu ô trống (10 Excel color swatches). Reset-to-default button. Mounted on both `/` and `/master` headers. |
| `src/lib/SettingsButton.svelte` | Gear icon + modal. 4 fieldsets: Giao diện (theme auto/light/dark), Chế độ quản trò (master mode toggle), Tự động xổ (auto-call + speed 110s), Màu ô trống (10 Excel color swatches). Reset-to-default button. Mounted on `/`. |
| `src/lib/MasterPanel.svelte` | Host controls. New game / draw, "Số vừa xổ" hero token, "Thứ tự đã xổ" history list, 11×9 last-digit-aligned tracking grid (with circular tokens + draw-order overlay). No host's own player card (the player already has one above). "Xổ số" / "Bắt đầu / Dừng" button bound to auto-call. Mounted conditionally on `/` when `settings.masterMode === true`. |
| `src/lib/PageFooter.svelte` | Footer with tagline ("Made by miti99 with ❤️ SVG icon") + link. Mounted on `/` and `/master`. |
| `src/lib/PageFooter.svelte` | Footer with tagline ("Made by miti99 with ❤️ SVG icon") + link. Mounted on `/`. |
### Game Logic
| File | Purpose |
+8 -5
View File
@@ -35,9 +35,11 @@ No GitHub Actions involved; no repo secrets needed.
## GitHub Pages (redirect-only)
`.github/workflows/deploy-github-pages.yml` no longer builds the app.
It generates two tiny HTML pages (`/loto/index.html` and
`/loto/master/index.html`) that immediately redirect to the canonical
URL on Cloudflare Pages.
It generates a tiny HTML page at `/loto/index.html` that immediately
redirects to the canonical URL on Cloudflare Pages, plus a copy at
`/loto/master/index.html` to catch legacy `/master` bookmarks (the app
itself is single-page now; Cloudflare's `_redirects` collapses unknown
paths back to `/`).
The redirect uses both `<meta http-equiv="refresh">` (no-JS fallback)
and a tiny inline script that preserves path / query / hash:
@@ -46,8 +48,9 @@ and a tiny inline script that preserves path / query / hash:
location.replace("https://loto.miti99.com" + path + search + hash);
```
So `tiennm99.github.io/loto/``loto.miti99.com/` and
`tiennm99.github.io/loto/master``loto.miti99.com/master`.
So `tiennm99.github.io/loto/``loto.miti99.com/` and any legacy
`tiennm99.github.io/loto/master` link`loto.miti99.com/` (after the
intermediate `/master` redirect is collapsed by `_redirects`).
The redirect runs on every push to `main`. If you want full GH Pages
serving back (instead of the redirect), restore the prior version of
+4 -31
View File
@@ -1,35 +1,8 @@
# Development Roadmap
This document tracks **future work only**. Completed features live in git commit history, not here.
## Currently Implemented Features
The app is fully functional for core gameplay (Lô tô hội chợ Tân Tân variant):
- 9×9 player card with **exactly 5 per row and 5 per column**, columns
ascending top-to-bottom
- Cell marking (toggle crossed state); player can keep playing after Kinh
- Bingo detection and "Kinh!" celebration popup
- "Chờ X" waiting notifications
- Host number drawing from 190 deck
- 11×9 last-digit-aligned master board with draw-order overlay for fast
Kinh verification
- Player card rendered as 3 stacked Tân Tân mini-cards
(Minh Tân / Loại đặc biệt / Tấn tài tấn lộc) with cross-hatch dividers
- Settings modal: 4 fieldsets (theme auto/light/dark, master mode toggle,
auto-call speed 110s, 10 color presets), persisted to `loto_settings`
- Theme switcher (auto detects OS pref, explicit light/dark modes)
- Master mode toggle (shows MasterPanel on `/`)
- Auto-call timer with speed slider
- Mobile-responsive cells (aspect-ratio + text scaling)
- MasterPanel extracted component (reused on `/` and `/master`)
- PageFooter with tagline + creator link
- Host's own player card (isolated instance)
- localStorage persistence
- Dark mode
- Mobile responsive
- Offline capable
- Unit tests (Vitest: 26 game-logic tests + 27 settings-store tests, 53 total passing)
covering constraint validation, persistence, theme/master-mode/auto-call logic, and error handling
This document tracks **future work only**. Completed features live in
git commit history and `plans/`, not here. For "what's in the app right
now", see `docs/project-overview-pdr.md` and `docs/codebase-summary.md`.
## Idea Phase
@@ -63,7 +36,7 @@ Full undo/redo stack with history navigation. Adds complexity to state managemen
### Component Tests (Planned)
- PlayerBoard with mocked localStorage, $state/$derived verification
- Master page with different game states
- MasterPanel with different game states
### E2E Tests
- Player flow: generate card → click cells → verify bingo popup
+6 -6
View File
@@ -71,11 +71,11 @@ That format is intentionally out of scope.
## Architecture Overview
Two public pages:
1. **`/`** — Player page. Generate a card, click cells to mark them, see bingo popup and waiting toasts.
2. **`/master`** — Host page. Control number drawing, view 9×10 master board (tracking called vs uncalled), and host's own player card.
Single page (`/`):
- Always renders the player card (generate, mark, bingo popup, "Chờ N" toasts).
- When `settings.masterMode === true`, mounts MasterPanel below the player card — host controls, draw history, and the host's own player card.
State is entirely client-side. Each page/card instance uses a unique localStorage prefix (e.g., `"loto"` for player, `"loto_master"` for host's state, `"loto_master_card"` for host's player card).
State is entirely client-side. Each card / panel instance uses a unique localStorage prefix (`"loto"` for the player card, `"loto_master"` for host draw state, `"loto_master_card"` for the host's own card).
## Deployment
@@ -104,8 +104,8 @@ State is entirely client-side. Each page/card instance uses a unique localStorag
- [x] Master mode toggle to show MasterPanel on player page.
- [x] Auto-call timer (110s speed) with start/stop button.
- [x] Mobile-responsive layout (aspect-square sm:aspect-[3/5] cells, text scaling).
- [x] MasterPanel extracted; mounted conditionally on `/` and directly on `/master`.
- [x] PageFooter with tagline + link on both pages.
- [x] MasterPanel extracted; mounted conditionally on `/` when master mode is on.
- [x] PageFooter with tagline + link.
## Visual Language
+32 -31
View File
@@ -7,20 +7,15 @@ Entry (+layout.svelte)
├─ 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 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
├─ [if settings.masterMode === true]
│ └─ Mount MasterPanel (host controls + draw history)
└─ PageFooter (tagline + miti99 link)
└─ /master (Host Page)
├─ MasterPanel (state, controls, draw history; same as above)
├─ Back link to /
└─ PageFooter
─ / (single page)
├─ Load loto_grid, loto_crossed from localStorage
├─ 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
├─ [if settings.masterMode === true]
│ └─ Mount MasterPanel (host controls + draw history)
└─ PageFooter (tagline + miti99 link)
```
## State Model
@@ -67,32 +62,38 @@ All keys are JSON stringified. Corruption is silent (returns null).
## basePath & Asset Resolution
### Production Mode
### Production (Cloudflare Pages, default)
```
NODE_ENV=production
npm run build
basePath="" (root)
Output: build/index.html
Deploy: loto.miti99.com (root domain)
```
### Production (GitHub Pages, manual)
```
npm run build:gh
basePath="/loto"
Output: /loto/index.html, /loto/_next/...
GitHub Pages serves: https://user.github.io/loto
Output: build/index.html with /loto prefix
Deploy: https://tiennm99.github.io/loto
```
### Development Mode (Local)
### Development (Local)
```
NEXT_DEV_PROFILE not set
npm run dev
basePath="" (empty)
Dev server: http://localhost:3000
Dev server: http://localhost:5173
```
### Code-Server Mode
### Development (Code-Server)
```
NEXT_DEV_PROFILE=codeserver
CODESERVER_HOST=<proxy-host>
CODESERVER_PORT=3000 (or env)
npm run dev:codeserver
.env.local: CODESERVER_HOST + CODESERVER_PORT
basePath="/absproxy/{PORT}"
HMR Origin: CODESERVER_HOST
Access: https://<proxy>/absproxy/3000/
Access: https://<proxy>/absproxy/{PORT}/
```
**Note**: `/absproxy/{port}` preserves the basePath through the proxy. `/proxy/{port}` strips it before forwarding, breaking HMR.
**Note**: Use `/absproxy/{port}` `/proxy/{port}` strips the path prefix and breaks the SvelteKit base path.
## Client-Only Architecture
@@ -102,9 +103,9 @@ All pages are client-only (no SSR) because:
- State initialization (grid, crossed) must run in browser
Files that are client-only:
- `src/routes/+page.svelte` (player page)
- `src/routes/master/+page.svelte` (host page)
- `src/lib/PlayerBoard.svelte` (shared component)
- `src/routes/+page.svelte` (single page)
- `src/lib/PlayerBoard.svelte` (player card component)
- `src/lib/MasterPanel.svelte` (host panel, mounted when `settings.masterMode`)
## Data Flow: Mark a Cell
+3 -10
View File
@@ -1,14 +1,7 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"target": "es2022",
"allowJs": true,
"checkJs": false,
"paths": {
"$lib": ["./src/lib"],
"$lib/*": ["./src/lib/*"]
}
},
"include": ["src/**/*", "vite.config.js", "svelte.config.js"]
"checkJs": false
}
}