mirror of
https://github.com/tiennm99/sokoban.git
synced 2026-09-02 08:21:06 +00:00
chore: drop orphan Phaser-era assets
bg.png (295 KB) and logo.png (24 KB) had zero references in src, index.html, or any CSS, but matched the workbox precache glob and shipped to every install. Removing them drops the precache from 555 KB to 235 KB (-58%). Update the docs note. Also add the review-fixes plan to plans/.
This commit is contained in:
@@ -25,7 +25,7 @@ src/
|
||||
public/
|
||||
├── style.css # Legacy file — theme now lives in src/app.css
|
||||
├── favicon.png
|
||||
└── assets/ # bg.png, logo.png (unused, reserved)
|
||||
└── assets/ # qr.jpg (donate VietQR)
|
||||
```
|
||||
|
||||
## Data flow
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Phase 01 — Triage & Merge Dependabot PRs
|
||||
|
||||
**Priority:** High
|
||||
**Status:** pending
|
||||
**Effort:** ~S (3 PRs, all transitive devDeps, all MERGEABLE)
|
||||
|
||||
## Context
|
||||
|
||||
3 open dependabot PRs against `tiennm99/sokoban` main:
|
||||
|
||||
| # | Bump | Fixes |
|
||||
|---|------|-------|
|
||||
| 7 | postcss 8.5.3 → 8.5.12 | GHSA-qx2v-qp2m-jg93 |
|
||||
| 5 | rollup 4.40.0 → 4.60.2 | GHSA-mw96-cpmx-2vgc |
|
||||
| 4 | picomatch 4.0.2 → 4.0.4 | GHSA-c2c7-rcm5-vvqj + GHSA-3v7f-55p6-f55p |
|
||||
|
||||
All transitive devDeps. None ship to browser. Each PR touches `package-lock.json` only.
|
||||
|
||||
## Risks
|
||||
|
||||
- **Lockfile rebase**: when we regenerated `package-lock.json` during the earlier rebase, our local versions may already be ≥ the dependabot target. In that case dependabot will auto-close on push, or `gh pr merge` will succeed as a no-op. Either is fine.
|
||||
- **Conflict with our lockfile**: possible since we just touched it. PR mergeable status is reported as YES (snapshot 20:55), but verify per-PR before merge.
|
||||
- **Build break**: rollup major bump (4.40 → 4.60) is the highest risk; verify `npm run build` after each merge.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Snapshot current versions:
|
||||
```bash
|
||||
npm ls postcss rollup picomatch 2>&1 | head -20
|
||||
```
|
||||
2. For each PR (in order: #4 → #5 → #7, smallest blast radius first):
|
||||
- `gh pr view <num> --json mergeable,mergeStateStatus`
|
||||
- If mergeable + clean: `gh pr merge <num> --squash --auto` (or `--merge` if user prefers; squash keeps history clean for transitive bumps)
|
||||
- If conflict: `gh pr comment <num> --body "Conflicts with current lockfile after recent rebase. Closing — local has acceptable version."` then close
|
||||
3. After each merge: `git pull --rebase`, then `npm run build`, expect green.
|
||||
4. After all PRs: `npm audit` → confirm postcss/rollup/picomatch chains are gone. Note any remaining vulns (expected: serialize-javascript via @rollup/plugin-terser via workbox-build via vite-plugin-pwa).
|
||||
|
||||
## Decision tree per PR
|
||||
|
||||
```
|
||||
Is PR mergeable?
|
||||
├── YES + clean
|
||||
│ └── gh pr merge --squash → pull → build → next
|
||||
├── MERGEABLE but lockfile-stale
|
||||
│ └── Local already at target version → close PR with comment
|
||||
└── CONFLICT
|
||||
└── Close PR with comment; rely on next dependabot run
|
||||
```
|
||||
|
||||
## Todo
|
||||
|
||||
- [ ] Snapshot current versions of postcss, rollup, picomatch
|
||||
- [ ] Triage PR #4 (picomatch)
|
||||
- [ ] Triage PR #5 (rollup)
|
||||
- [ ] Triage PR #7 (postcss)
|
||||
- [ ] Pull main after each merge
|
||||
- [ ] Build verification after each merge
|
||||
- [ ] Final `npm audit` — note residual vulns
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- All 3 dependabot PRs are either merged or closed-with-comment (not stuck)
|
||||
- `npm run build` passes after each merge
|
||||
- `npm audit` shows reduced or unchanged vuln count, never increased
|
||||
|
||||
## Next
|
||||
|
||||
- Phase 02: modal a11y + simplifier hygiene wins
|
||||
@@ -0,0 +1,167 @@
|
||||
# Phase 02 — Modal A11y + Simplifier Hygiene Wins
|
||||
|
||||
**Priority:** Medium
|
||||
**Status:** pending
|
||||
**Effort:** ~M (touches 4-5 files, ~30 LOC saved net)
|
||||
|
||||
## Context
|
||||
|
||||
- Reviewer C3: DonateModal lacks auto-focus on open and focus-restore on close.
|
||||
- Simplifier #12: `.overlay`/`.dialog` CSS duplicated between GameView and DonateModal — extract to `app.css`.
|
||||
- Simplifier #13: `touch-action: manipulation` + `-webkit-tap-highlight-color: transparent` repeated; could move to global `button { }` in `app.css`.
|
||||
- Simplifier #1: `level-parser.js` has `key as cellKey` re-export — only used inside `board-model.js`; alias is purely cosmetic. Drop or pick one name.
|
||||
- Simplifier #3: `BoardModel.isSolved` has `if (this.boxes.length === 0) return false;` — Microban guarantees ≥1 box, but the guard is also cheap to keep. Inline the early-return into the return expression for one-line clarity.
|
||||
- Simplifier #4: `LevelSelectView` declared `completedCount` as `$state` but never reassigns it — should be `const`.
|
||||
- Simplifier #7: `Board.svelte` redeclares `DIRS` array inside `$derived.by` — move to module scope.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- `LevelSelectView.completedCount` not refreshing on return-from-game — separate bug, not a simplification (would belong in a future bugfix plan).
|
||||
- DonateModal extraction into a store (only 2 callsites).
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
app.css + .overlay / .dialog shared classes
|
||||
+ global button { touch-action; -webkit-tap-highlight-color }
|
||||
|
||||
GameView.svelte remove .overlay / .dialog scoped CSS, use shared
|
||||
DonateModal.svelte remove .overlay / .dialog scoped CSS, use shared
|
||||
+ auto-focus CLOSE on open, restore on close
|
||||
MobileControls.svelte remove now-redundant button styles
|
||||
AppButton.svelte remove now-redundant touch-action / tap-highlight
|
||||
|
||||
level-parser.js drop `key as cellKey` re-export
|
||||
board-model.js import key directly (rename usages)
|
||||
board-model.js inline isSolved guard
|
||||
LevelSelectView.svelte $state completedCount → const completedCount
|
||||
Board.svelte hoist DIRS to module scope
|
||||
```
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### A. Modal a11y — DonateModal focus management
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
let { open = false, onClose } = $props();
|
||||
let dialogEl = $state();
|
||||
let prevFocus = $state(null);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
prevFocus = document.activeElement;
|
||||
// Focus the dialog itself (tabindex=-1) so initial Tab lands on first button.
|
||||
queueMicrotask(() => dialogEl?.focus());
|
||||
} else if (prevFocus instanceof HTMLElement) {
|
||||
prevFocus.focus();
|
||||
prevFocus = null;
|
||||
}
|
||||
});
|
||||
|
||||
function onKey(e) { if (open && e.key === 'Escape') onClose(); }
|
||||
function onBackdropClick(e) { if (e.target === e.currentTarget) onClose(); }
|
||||
</script>
|
||||
...
|
||||
<div class="dialog" bind:this={dialogEl} role="dialog" ...>
|
||||
```
|
||||
|
||||
### B. Shared dialog CSS — `app.css`
|
||||
|
||||
```css
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(12, 16, 24, 0.72);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
animation: dialog-fade-in 180ms ease;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
background: var(--panel);
|
||||
border: 2px solid var(--accent);
|
||||
border-radius: var(--radius-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
@keyframes dialog-fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
```
|
||||
|
||||
GameView's `.dialog` and DonateModal's `.dialog` keep their unique padding/gap/max-width as scoped overrides. Only the structural rules move.
|
||||
|
||||
### C. Global button base in `app.css`
|
||||
|
||||
```css
|
||||
button {
|
||||
font-family: inherit;
|
||||
touch-action: manipulation;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
```
|
||||
|
||||
Remove the equivalent rules from `AppButton.svelte` and `MobileControls.svelte` (`.action`, `.arrow`).
|
||||
|
||||
### D. Simplifier nits
|
||||
|
||||
- `level-parser.js`: change `export { key as cellKey }` to `export { key as cellKey, key }` (or pick one name and delete the alias plus update the one importer).
|
||||
- Cleanest: delete the alias, export `cellKey` directly and rename the internal `key` function.
|
||||
- Update `board-model.js` import.
|
||||
- `board-model.js`: `isSolved()` becomes `return this.boxes.length > 0 && this.boxes.every(b => this.isTarget(b.x, b.y));`
|
||||
- `LevelSelectView.svelte`: `let completedCount = $state(...)` → `const completedCount = ...` (already declared once, never reassigned).
|
||||
- `Board.svelte`: hoist `const DIRS = [...]` above `<script>` body's `$derived.by` block (or simply outside the destructured arrow).
|
||||
|
||||
## Related Code Files
|
||||
|
||||
**Modify**
|
||||
- `src/app.css` — add shared `.overlay/.dialog`, global `button` rules
|
||||
- `src/views/GameView.svelte` — remove duplicated dialog CSS
|
||||
- `src/views/DonateModal.svelte` — remove duplicated dialog CSS, add focus mgmt
|
||||
- `src/views/AppButton.svelte` — drop now-global touch-action/tap-highlight
|
||||
- `src/views/MobileControls.svelte` — drop now-global touch-action/tap-highlight from `.action`/`.arrow`
|
||||
- `src/lib/core/level-parser.js` — collapse `key`/`cellKey` to single name
|
||||
- `src/lib/core/board-model.js` — update import; inline isSolved guard
|
||||
- `src/views/LevelSelectView.svelte` — `$state` → `const`
|
||||
- `src/views/Board.svelte` — hoist `DIRS`
|
||||
|
||||
## Todo
|
||||
|
||||
- [ ] Add shared `.overlay/.dialog` rules + global `button` to `app.css`
|
||||
- [ ] Remove duplicated CSS from `GameView.svelte` and `DonateModal.svelte`
|
||||
- [ ] Add `dialogEl` ref + `$effect` for focus mgmt in `DonateModal.svelte`
|
||||
- [ ] Drop redundant button styles from `AppButton.svelte` and `MobileControls.svelte`
|
||||
- [ ] Collapse `key`/`cellKey` alias in `level-parser.js` + update import
|
||||
- [ ] Inline `isSolved` length guard in `board-model.js`
|
||||
- [ ] Make `completedCount` const in `LevelSelectView.svelte`
|
||||
- [ ] Hoist `DIRS` in `Board.svelte`
|
||||
- [ ] Build clean
|
||||
- [ ] Manual: open menu donate modal → verify focus lands on dialog → Tab cycles → Esc closes → focus returns to DONATE button
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- Build clean
|
||||
- DonateModal focus management works on both menu and win-screen entry points
|
||||
- No visual regressions in dialogs (overlay, padding, fade-in)
|
||||
- Net LOC reduction ≥ 15 lines
|
||||
- All keyboard shortcuts still work as before
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Removing scoped CSS misses a unique rule | Diff before/after computed style in DevTools for both dialogs |
|
||||
| Global `button` rule affects unstyled `<button>` outside AppButton/MobileControls | Codebase audit shows AppButton + MobileControls are the only button consumers; level-select buttons in `LevelSelectView` already pick up `font-family: inherit`. `touch-action: manipulation` is universally safe. |
|
||||
| Renaming `cellKey` breaks something in `microban-levels.js` | Levels file is data, no imports. Safe. |
|
||||
|
||||
## Next
|
||||
|
||||
- Phase 03: PWA precache cleanup + residual vuln override
|
||||
@@ -0,0 +1,102 @@
|
||||
# Phase 03 — PWA Precache Cleanup + Residual Vuln Override
|
||||
|
||||
**Priority:** Low
|
||||
**Status:** pending
|
||||
**Effort:** ~S (file deletion + maybe 5 LOC `package.json`)
|
||||
|
||||
## Context
|
||||
|
||||
- Debugger Issue 2: `public/assets/bg.png` (295 KB) and `public/assets/logo.png` (24 KB) have **zero references** in any source file. Phaser-era leftovers. They match `**/*.png` and end up in the workbox precache, ~73% of the 435 KB precache total.
|
||||
- Security/Reviewer: after Phase 01 merges 3 dependabot PRs, the remaining vuln chain is `serialize-javascript` (via `@rollup/plugin-terser` via `workbox-build` via `vite-plugin-pwa`). No clean fix without a `vite-plugin-pwa` major downgrade — `npm overrides` is the surgical alternative.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Adding meta CSP header (separate hardening pass)
|
||||
- Replacing icons with hand-crafted maskable variants
|
||||
|
||||
## Decision points (need user input)
|
||||
|
||||
1. **Delete `public/assets/bg.png` and `logo.png`?**
|
||||
- Pros: 320 KB off the precache, faster install, cleaner repo.
|
||||
- Risk: extremely low — grep confirms zero references in `src/`, `index.html`, or `public/`. They're Phaser leftovers.
|
||||
- **Auto mode policy:** destructive (file deletion); requires explicit confirmation before running.
|
||||
|
||||
2. **For residual `serialize-javascript` chain after Phase 01 merges, choose one:**
|
||||
- **Option A — Wait & monitor.** Future workbox/vite-plugin-pwa releases bump the chain. `npm audit` lists 1-2 remaining highs in build-only deps. Practical risk near zero.
|
||||
- **Option B — `npm overrides`.** Pin `serialize-javascript` to a fixed version via `package.json` overrides. ~3 LOC. Surgical, keeps current major of `vite-plugin-pwa`.
|
||||
- **Option C — Major downgrade.** `npm audit fix --force` → `vite-plugin-pwa@0.19.8`. Loses recent features. Not recommended.
|
||||
|
||||
**Recommendation:** Option B if `npm audit` still flags it after Phase 01. Skip if Phase 01 happens to clear it.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Confirm and delete orphan assets
|
||||
|
||||
```bash
|
||||
# Confirm zero references
|
||||
grep -rIn -E '(bg\.png|logo\.png)' src/ index.html public/ 2>/dev/null || echo "No references found"
|
||||
# Delete
|
||||
rm public/assets/bg.png public/assets/logo.png
|
||||
# Build and verify precache count drops
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Step 2 (conditional): npm overrides for residual vuln
|
||||
|
||||
If `npm audit` after Phase 01 still flags `serialize-javascript`:
|
||||
|
||||
```jsonc
|
||||
// package.json
|
||||
{
|
||||
"overrides": {
|
||||
"serialize-javascript": ">=7.0.5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
rm package-lock.json && npm install
|
||||
npm audit
|
||||
npm run build
|
||||
```
|
||||
|
||||
Verify `serialize-javascript` chain is silent in `npm audit`.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
**Modify**
|
||||
- `package.json` — possibly add `overrides` block
|
||||
|
||||
**Delete (with user confirmation)**
|
||||
- `public/assets/bg.png`
|
||||
- `public/assets/logo.png`
|
||||
|
||||
## Todo
|
||||
|
||||
- [ ] User confirms asset deletion
|
||||
- [ ] Grep confirms zero references
|
||||
- [ ] Delete bg.png, logo.png
|
||||
- [ ] Build → verify precache count drops by 2 entries (~320 KB)
|
||||
- [ ] Run `npm audit` after Phase 01 merges
|
||||
- [ ] If `serialize-javascript` still flagged: add `overrides` block, regenerate lockfile, verify build + audit
|
||||
- [ ] Commit + push
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- Workbox precache drops below 250 KB total
|
||||
- `npm audit` flags zero highs in app deps (build-only deps OK if documented)
|
||||
- Game still works in browser (assets weren't actually used — verify by running dev server post-delete)
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| One of the orphan PNGs is referenced from a CSS we missed | Grep across all files, not just src/. Test build after delete. |
|
||||
| `npm overrides` causes peer-dep mismatch | Run `npm install` and check warnings; rollback by removing the block if needed |
|
||||
| User actually wants to keep bg.png for future use | Skip Step 1 — the precache cost is the only real downside |
|
||||
|
||||
## Next
|
||||
|
||||
- Plan complete → archive via `/ck:plan archive` to journal
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Review Fixes & Dependabot PRs
|
||||
date: 2026-04-27
|
||||
status: pending
|
||||
branch: main
|
||||
mode: fast
|
||||
blockedBy: []
|
||||
blocks: []
|
||||
---
|
||||
|
||||
# Review Fixes & Dependabot PRs
|
||||
|
||||
Address the deferred items from the whole-project review pass and triage the 3 open dependabot PRs (all marked MERGEABLE).
|
||||
|
||||
## Goal
|
||||
|
||||
Close out review findings: ship the modal a11y polish, the simplifier wins worth doing, the PWA precache cleanup, and merge the dep bumps so `npm audit` is mostly clean. No new feature work.
|
||||
|
||||
## Phases
|
||||
|
||||
| # | File | Title | Status | Independently shippable |
|
||||
|---|------|-------|--------|-------------------------|
|
||||
| 01 | [phase-01-dependabot-prs.md](phase-01-dependabot-prs.md) | Triage & merge dependabot PRs | pending | Yes |
|
||||
| 02 | [phase-02-modal-a11y-and-hygiene.md](phase-02-modal-a11y-and-hygiene.md) | Modal a11y + simplifier hygiene wins | pending | Yes |
|
||||
| 03 | [phase-03-pwa-cleanup.md](phase-03-pwa-cleanup.md) | PWA precache cleanup + residual vuln override | pending | Yes (needs user confirm for asset deletion) |
|
||||
|
||||
## Open dependabot PRs (snapshot 2026-04-27 20:55)
|
||||
|
||||
| # | Title | Mergeable | Fixes |
|
||||
|---|-------|-----------|-------|
|
||||
| 7 | postcss 8.5.3 → 8.5.12 | YES | GHSA-qx2v-qp2m-jg93 (XSS in CSS stringify) |
|
||||
| 5 | rollup 4.40.0 → 4.60.2 | YES | GHSA-mw96-cpmx-2vgc (path traversal) |
|
||||
| 4 | picomatch 4.0.2 → 4.0.4 | YES | GHSA-c2c7-rcm5-vvqj (ReDoS) + GHSA-3v7f-55p6-f55p |
|
||||
|
||||
Each is a transitive devDep — no app code change. Build must still pass after each merge.
|
||||
|
||||
## Reports
|
||||
|
||||
- [code-reviewer-260427-2036-whole-project-review.md](../reports/code-reviewer-260427-2036-whole-project-review.md)
|
||||
- [code-simplifier-260427-2036-whole-project-audit.md](../reports/code-simplifier-260427-2036-whole-project-audit.md)
|
||||
- [debugger-260427-2040-project-health.md](../reports/debugger-260427-2040-project-health.md)
|
||||
- [security-scan-260427-2050-whole-project.md](../reports/security-scan-260427-2050-whole-project.md)
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Adding meta CSP header (separate hardening pass)
|
||||
- Reducing GameView.svelte below 200 LOC (simplifier said leave as-is)
|
||||
- Most simplifier proposals (small, deferred)
|
||||
- New features
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- 3 dependabot PRs merged (or closed if our lockfile already satisfies the bump after rebase)
|
||||
- `npm audit` shows zero high vulns or only the unfixable `serialize-javascript` chain (with documented `overrides` if we choose that route)
|
||||
- DonateModal auto-focuses CLOSE button on open and restores prior focus on close
|
||||
- Win + DonateModal share overlay/dialog CSS (no duplication)
|
||||
- Build clean throughout
|
||||
- Desktop and mobile gameplay unchanged
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 296 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
Reference in New Issue
Block a user