31 Commits
Author SHA1 Message Date
tiennm99 124d65f800 build(web): upgrade to SvelteKit 3 and adapter-static 4, move the PWA to vite-plugin-pwa 2026-10-12 11:44:09 +07:00
tiennm99 28825b78e4 chore: move TODO.md to the repo root and drop the redundant serialize-javascript override 2026-10-12 11:28:53 +07:00
tiennm99 2831953380 fix(web): unclipped PWA icons, deck validation parity, player-tap audio unlock, manifest-based PWA check, vitest security bump 2026-10-12 09:46:33 +07:00
tiennm99 3544748888 fix(ci): generate .svelte-kit via prepare script so svelte-check passes on fresh installs 2026-09-01 08:44:52 +07:00
tiennm99 0593672afd fix(web): service-worker registration, base-path handling, PWA verification, multi-tab protocol, update prompt, focus trap, iOS audio unlock, checkJs fixes 2026-09-01 00:11:29 +07:00
tiennm99 1c1bab8733 build: move web/ from pnpm to npm
Replace pnpm-lock.yaml with package-lock.json and drop pnpm-workspace.yaml.
The three security overrides move to package.json#overrides, which npm reads
natively; allowBuilds for esbuild is unnecessary because npm runs dependency
build scripts by default.

android/build:web drove the web build through corepack pnpm, so it would have
broken once web/pnpm-lock.yaml was gone. It now uses npm --prefix.

Fresh resolution picks up patched versions the old lockfile had pinned below,
so npm audit reports no advisories where pnpm audit reported eight.
2026-08-17 11:54:24 +07:00
dependabot[bot]andtiennm99 fac70e53e2 chore(deps): bump the minor-and-patch group with 13 updates (#28)
Bumps the minor-and-patch group with 13 updates:

| Package | From | To |
| --- | --- | --- |
| [@fontsource/roboto-condensed](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/roboto-condensed) | `5.2.8` | `5.3.0` |
| [@sveltejs/kit](https://github.com/sveltejs/kit/tree/HEAD/packages/kit) | `2.61.1` | `2.70.1` |
| [@sveltejs/vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte/tree/HEAD/packages/vite-plugin-svelte) | `7.1.2` | `7.2.0` |
| [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.0` | `4.3.3` |
| [eslint](https://github.com/eslint/eslint) | `10.4.0` | `10.7.0` |
| [eslint-plugin-svelte](https://github.com/sveltejs/eslint-plugin-svelte/tree/HEAD/packages/eslint-plugin-svelte) | `3.17.1` | `3.22.0` |
| [globals](https://github.com/sindresorhus/globals) | `17.6.0` | `17.7.0` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.9.0` | `20.11.0` |
| [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) | `5.55.9` | `5.56.7` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.0` | `4.3.3` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.16` | `8.1.5` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.7` | `4.1.10` |
| [lightningcss-linux-x64-gnu](https://github.com/parcel-bundler/lightningcss) | `1.32.0` | `1.33.0` |


Updates `@fontsource/roboto-condensed` from 5.2.8 to 5.3.0
- [Changelog](https://github.com/fontsource/font-files/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/roboto-condensed)

Updates `@sveltejs/kit` from 2.61.1 to 2.70.1
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/version-3/packages/kit/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/kit@2.70.1/packages/kit)

Updates `@sveltejs/vite-plugin-svelte` from 7.1.2 to 7.2.0
- [Release notes](https://github.com/sveltejs/vite-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/vite-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/vite-plugin-svelte/commits/@sveltejs/vite-plugin-svelte@7.2.0/packages/vite-plugin-svelte)

Updates `@tailwindcss/vite` from 4.3.0 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/@tailwindcss-vite)

Updates `eslint` from 10.4.0 to 10.7.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.4.0...v10.7.0)

Updates `eslint-plugin-svelte` from 3.17.1 to 3.22.0
- [Release notes](https://github.com/sveltejs/eslint-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/eslint-plugin-svelte/commits/eslint-plugin-svelte@3.22.0/packages/eslint-plugin-svelte)

Updates `globals` from 17.6.0 to 17.7.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0)

Updates `happy-dom` from 20.9.0 to 20.11.0
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.9.0...v20.11.0)

Updates `svelte` from 5.55.9 to 5.56.7
- [Release notes](https://github.com/sveltejs/svelte/releases)
- [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.56.7/packages/svelte)

Updates `tailwindcss` from 4.3.0 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/tailwindcss)

Updates `vite` from 8.0.16 to 8.1.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.1.5/packages/vite)

Updates `vitest` from 4.1.7 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest)

Updates `lightningcss-linux-x64-gnu` from 1.32.0 to 1.33.0
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.32.0...v1.33.0)

---
updated-dependencies:
- dependency-name: "@fontsource/roboto-condensed"
  dependency-version: 5.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@sveltejs/kit"
  dependency-version: 2.70.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@sveltejs/vite-plugin-svelte"
  dependency-version: 7.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: eslint
  dependency-version: 10.7.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: eslint-plugin-svelte
  dependency-version: 3.22.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: globals
  dependency-version: 17.7.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: happy-dom
  dependency-version: 20.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: svelte
  dependency-version: 5.56.7
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: tailwindcss
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: vite
  dependency-version: 8.1.5
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: vitest
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: lightningcss-linux-x64-gnu
  dependency-version: 1.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: tiennm99 <tiennm99@outlook.com>
2026-07-21 23:13:56 +07:00
tiennm99 8f7aad1ba5 fix(deps): resolve vite dependabot advisories 2026-06-23 15:25:26 +07:00
tiennm99 d31cdcda4a fix(deps): resolve dependabot advisories 2026-06-03 09:38:29 +07:00
dependabot[bot] 9b73cdb4f9 chore(deps-dev): bump globals from 15.15.0 to 17.6.0 (#18)
Bumps [globals](https://github.com/sindresorhus/globals) from 15.15.0 to 17.6.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.15.0...v17.6.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-version: 17.6.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:36:28 +07:00
dependabot[bot] 866a331eb5 chore(deps-dev): bump vite from 7.3.3 to 8.0.14 (#19)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.3.3 to 8.0.14.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.14/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.14
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:30:24 +07:00
dependabot[bot] c2b6fc3c2d chore(deps-dev): bump eslint from 9.39.4 to 10.4.0 (#16)
Bumps [eslint](https://github.com/eslint/eslint) from 9.39.4 to 10.4.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v9.39.4...v10.4.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.4.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:30:19 +07:00
dependabot[bot] 60c21cdf3e chore(deps-dev): bump @sveltejs/vite-plugin-svelte from 6.2.4 to 7.1.2 (#17)
Bumps [@sveltejs/vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte/tree/HEAD/packages/vite-plugin-svelte) from 6.2.4 to 7.1.2.
- [Release notes](https://github.com/sveltejs/vite-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/vite-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/vite-plugin-svelte/commits/@sveltejs/vite-plugin-svelte@7.1.2/packages/vite-plugin-svelte)

---
updated-dependencies:
- dependency-name: "@sveltejs/vite-plugin-svelte"
  dependency-version: 7.1.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:23:53 +07:00
dependabot[bot] 2e63cd63d1 chore(deps-dev): bump @eslint/js from 9.39.4 to 10.0.1 (#15)
Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.4 to 10.0.1.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/commits/v10.0.1/packages/js)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 10.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:23:49 +07:00
dependabot[bot] 87803c06b4 chore(deps-dev): bump eslint-plugin-svelte from 2.46.1 to 3.17.1 (#14)
Bumps [eslint-plugin-svelte](https://github.com/sveltejs/eslint-plugin-svelte/tree/HEAD/packages/eslint-plugin-svelte) from 2.46.1 to 3.17.1.
- [Release notes](https://github.com/sveltejs/eslint-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/eslint-plugin-svelte/commits/eslint-plugin-svelte@3.17.1/packages/eslint-plugin-svelte)

---
updated-dependencies:
- dependency-name: eslint-plugin-svelte
  dependency-version: 3.17.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:23:45 +07:00
dependabot[bot] 98731beead chore(deps-dev): bump the minor-and-patch group with 3 updates (#13)
Bumps the minor-and-patch group with 3 updates: [@sveltejs/kit](https://github.com/sveltejs/kit/tree/HEAD/packages/kit), [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@sveltejs/kit` from 2.59.1 to 2.61.0
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/main/packages/kit/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/kit@2.61.0/packages/kit)

Updates `svelte` from 5.55.5 to 5.55.9
- [Release notes](https://github.com/sveltejs/svelte/releases)
- [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.55.9/packages/svelte)

Updates `vitest` from 4.1.5 to 4.1.7
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.7/packages/vitest)

---
updated-dependencies:
- dependency-name: "@sveltejs/kit"
  dependency-version: 2.61.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: svelte
  dependency-version: 5.55.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: vitest
  dependency-version: 4.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 18:08:17 +07:00
tiennm99 0485e09f68 chore: migrate from npm to pnpm 2026-05-13 10:21:00 +07:00
tiennm99 8fc3ec6ebd ci(deploy): switch from Cloudflare Pages to GitHub Pages
Migrate build and deployment pipeline from Cloudflare Pages to GitHub Pages.
Adds production-ready deploy workflow in deploy-github-pages.yml with proper
artifact handling. Removes Cloudflare-specific tooling: wrangler config, _headers,
_redirects, and CSP hash injection scripts (no longer needed with GitHub Pages
static hosting). Updates package.json build scripts and all project documentation
to reflect new deployment target and simplified architecture.
2026-05-09 23:25:06 +07:00
tiennm99 3fd02c14a2 ci(csp): replace 'unsafe-inline' with sha256 hash at build time
Postbuild script computes SHA-256 of every inline <script> in
build/index.html and rewrites build/_headers — replacing the
script-src 'unsafe-inline' relaxation with the matching hashes. The
hash regenerates per build (SvelteKit bootstrap embeds a per-build
registration call) so the script must run on every build; chain it
into both `npm run build` and `build:gh`.

verify-build extended to assert build/_headers script-src no longer
contains 'unsafe-inline', so the inject step's output is enforced in
CI. style-src 'unsafe-inline' stays — Svelte's `style:` directives
emit inline attributes that hashes can't cover.
2026-04-28 11:09:32 +07:00
tiennm99 a6c10aa67f ci: add inline-script guard for built index.html
SvelteKit emits one inline bootstrap <script> in build/index.html and
the CSP in static/_headers is relaxed to `script-src 'unsafe-inline'`
to admit it. If a SvelteKit upgrade adds another inline block, the
relaxation no longer matches reality and the new block could ship
unhashed.

`npm run verify:build` reads build/index.html, counts inline scripts
(no `src=`), and fails when count > EXPECTED_INLINE (1). New GH
Actions workflow runs test + build + verify on push/PR to main.

Mutation-tested locally: setting EXPECTED_INLINE=0 fails as expected,
restored to 1 passes.
2026-04-28 10:55:43 +07:00
tiennm99 87eed879ef chore(deps): override transitive vulns — serialize-javascript + cookie
`@vite-pwa/sveltekit` pulled in `serialize-javascript@6.0.2` via
workbox-build → @rollup/plugin-terser, which is flagged for High RCE
(GHSA-5c6j-r48x-rmvq) and Medium DoS (GHSA-qj8w-gfj5-8c6v). Both fix
to >=7.0.5.

Also opportunistically bump `cookie` past 0.7.0 (Low GHSA-pxg6-pf52-xh8x)
via @sveltejs/kit — was the last-remaining Dependabot Low.

Build-time tooling only — neither package ships to the browser. Pinned
via npm `overrides` rather than `audit fix --force` because the latter
would downgrade @vite-pwa/sveltekit to 0.0.1 (breaking).

npm audit: 0 vulnerabilities. Tests 115/115. Build clean.
2026-04-27 20:43:32 +07:00
tiennm99 f899b09631 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.
2026-04-27 20:35:59 +07:00
tiennm99 5665663533 test: vitest setup + 38 tests for game-logic and settings-store
Adds vitest + happy-dom as devDependencies and npm scripts test
(one-shot) and test:watch. No SvelteKit/vite reconfig needed —
vitest auto-picks up the existing vite plugin chain.

game-logic.test.js (26 tests): generateGrid shape invariants
(9x9, exact 5/row, exact 5/col, no duplicates) over 200 random
trials; per-column number ranges (col 0 = 1-9, col 8 = 80-90);
ascending-within-column rule; isRowComplete/getWaitingNumber edge
cases; full save/load roundtrip for the persistence layer
including corrupt-JSON and wrong-shape rejection.

settings-store.test.js (12 tests): defaults frozen, load with
valid/invalid/corrupt payloads, hex regex rejects shorthand,
save persists to localStorage and pushes CSS var, reset returns
to brown default. Uses happy-dom env for localStorage and
documentElement.

code-standards.md: documents the rune globals declaration and the
.svelte.js convention for rune-using non-component modules.
2026-04-27 00:13:58 +07:00
tiennm99 222cc97fa8 fix(deps): pin lightningcss-linux-x64-gnu so CF Pages build resolves
Cloudflare Pages build failed with:
  Error: Cannot find module '../lightningcss.linux-x64-gnu.node'

Tailwind 4 → @tailwindcss/vite → lightningcss has per-platform native
binaries shipped as optional npm packages. The lockfile generated on
this dev box (linux-arm64) only carried the arm64 binaries, so CF on
linux-x64 was missing the matching platform-specific package.

Adding lightningcss-linux-x64-gnu to optionalDependencies pins it into
the lockfile. On non-x64-linux machines npm skips it silently due to
the platform mismatch; CF Pages on linux-x64 will install it.

Pinned to 1.32.0 to match the parent dep already resolved.
2026-04-26 21:21:37 +07:00
tiennm99 ee48e162d2 refactor: rewrite from Next.js + React to SvelteKit + Svelte 5
Full stack swap to enable future extension (more pages / load functions /
backend) while keeping JSDoc-only code style.

Stack:
- SvelteKit 2 + adapter-static
- Svelte 5 runes ($state, $derived, $effect, $props)
- Vite 7 + @sveltejs/vite-plugin-svelte 6
- Tailwind 4 (Vite plugin)
- ESLint 9 (flat) + eslint-plugin-svelte
- Pure JS + JSDoc, no TypeScript

Source moves:
- app/page.jsx              → src/routes/+page.svelte
- app/master/page.jsx       → src/routes/master/+page.svelte
- app/layout.jsx            → src/routes/+layout.svelte (+ +layout.js)
- components/player-board.jsx → src/lib/PlayerBoard.svelte
- lib/game-logic.js         → src/lib/game-logic.js (verbatim)
- next.config.mjs           → svelte.config.js + vite.config.js
- app/globals.css           → src/app.css
- (new)                     → src/app.html

Behavior preserved: PlayerBoard with bingo "Kinh!" popup + waiting "Chờ X"
toast, master 9x10 tracking board with shuffled draw, host's own player
card via storagePrefix="loto_master_card", localStorage prefix model
(loto_*, loto_master, loto_master_card_*), basePath dual mode (CF default
empty, BUILD_PROFILE=gh → /loto, codeserver dev → /absproxy/{port}).

A11y kept from prior hardening: role-correct buttons, aria-pressed on
cells, role=dialog modal with Escape, role=status toast.

Plans: ts-to-jsdoc plan marked completed; sveltekit-refactor plan tracks
the work above. Docs under ./docs/ rewritten by docs-manager subagent to
match the SvelteKit terminology.
2026-04-26 21:03:41 +07:00
tiennm99 bbdd2b449b refactor: cf-only deploy via dashboard, drop gh actions
- Default `npm run build` now produces a root-relative build (CF Pages
  custom domain at loto.miti99.com). The /loto basePath is opt-in via
  `npm run build:gh` for the rare manual GH Pages export.
- Removed both GitHub Actions deploy workflows (.github/workflows/) and
  the dangling `build:cf` script (it was identical to `build` after the
  default flip).
- next.config.mjs: simplified basePath logic — only `BUILD_PROFILE=gh`
  toggles a non-empty path; everything else (CF, local dev) is root.
2026-04-26 20:32:04 +07:00
tiennm99 3ab09dc4ba feat: add explicit gh and cf build profiles
Two named build scripts replace the prior CF_PAGES auto-detect:

  npm run build:gh  → BUILD_PROFILE=gh, basePath /loto
                      target: https://tiennm99.github.io/loto
  npm run build:cf  → BUILD_PROFILE=cf, basePath ""
                      target: https://loto.miti99.com (CF Pages custom domain)

Both deploy workflows now use the matching profile script. The legacy
`npm run build` keeps its prior behaviour (defaults to /loto basePath) so
nothing else in the toolchain breaks. NEXT_BASE_PATH still wins for any
one-off custom-domain build.

CF_PAGES auto-detection removed — explicit profiles are clearer than
relying on the host injecting a magic env var, and dashboard users should
just set the build command to `npm run build:cf`.
2026-04-26 20:28:30 +07:00
tiennm99 95545c9308 refactor: convert from TypeScript to JavaScript with JSDoc
Author types in JSDoc comments. jsconfig.json keeps checkJs: true so
the editor's bundled TS server still validates them; CI can validate
with npx -p typescript tsc --noEmit on demand.

Renames (history preserved via git mv):
- next.config.ts        -> next.config.mjs
- app/layout.tsx        -> app/layout.jsx
- app/page.tsx          -> app/page.jsx
- app/master/page.tsx   -> app/master/page.jsx
- components/player-board.tsx -> components/player-board.jsx
- lib/game-logic.ts     -> lib/game-logic.js
- tsconfig.json         -> jsconfig.json (same @/* alias)

Drops typescript and @types/node, @types/react, @types/react-dom
from devDependencies. Removes vendored next-env.d.ts. eslint config
no longer pulls in eslint-config-next/typescript.

Behavior unchanged. Build, lint, and dev profiles verified.
2026-04-26 19:45:36 +07:00
tiennm99 254a6dc39a refactor: move shared modules out of app/
`app/` should hold route segments only. Game logic and the player-card
component are imported by both routes, so they belong outside:

  app/loto-game-logic.ts   -> lib/game-logic.ts
  app/loto-player-board.tsx -> components/player-board.tsx

Imports use the existing @/* alias. Drops the redundant `loto-` prefix.
Also fixes the package name from the scaffold default.
2026-04-26 19:34:37 +07:00
tiennm99 400c55bef8 feat: add codeserver dev profile
NEXT_DEV_PROFILE=codeserver wires basePath, assetPrefix, and
allowedDevOrigins from CODESERVER_HOST/PORT in .env.local. Use
/absproxy/{port} so code-server preserves the path prefix and Next's
basePath matches the incoming request.

Run with `npm run dev:codeserver` and access via
https://<host>/absproxy/<port>/.
2026-04-26 19:16:46 +07:00
tiennm99 7f25a8e462 feat: convert to Next.js with TypeScript and Tailwind CSS
Replace vanilla HTML/JS/CSS with Next.js App Router, TypeScript,
and Tailwind CSS. Responsive design with dark mode support.
All original game logic preserved: grid generation, click-to-cross,
localStorage persistence.
2026-04-04 21:51:07 +07:00