From 007f50cbba1544d8c880af087b83ed3bbe90280b Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Mon, 21 Sep 2026 17:01:24 +0700 Subject: [PATCH] docs(reports): record the whole-game UX pass implementation --- ...fullstack-developer-260921-1632-ux-pass.md | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 plans/reports/fullstack-developer-260921-1632-ux-pass.md diff --git a/plans/reports/fullstack-developer-260921-1632-ux-pass.md b/plans/reports/fullstack-developer-260921-1632-ux-pass.md new file mode 100644 index 0000000..00fa4ac --- /dev/null +++ b/plans/reports/fullstack-developer-260921-1632-ux-pass.md @@ -0,0 +1,59 @@ +# Whole-game UX pass — implementation report + +Branch: `worktree-agent-a4990d1e576b04b80` +Worktree: `/workspace/tiennm99/noitu/.claude/worktrees/agent-a4990d1e576b04b80` +Base: fast-forwarded to `dev` `8c5bb8b` before starting (had `room-session.svelte.js`, `ArmedButton.svelte`, `chat-panel.test.js`). +Source: `plans/reports/ui-ux-designer-260921-1529-whole-game-ux-review.md`. + +## Per-item summary + +- **#1** Already done on `dev` (in-room rules links are `target="_blank"`). No change. +- **#2** Landing: `howToPlay`/`howToPlayExample` line added between the tagline and the nickname field (`routes/+page.svelte`). `ChainHistory.svelte`'s opening row gets an `openingCaption` line styled like `.corrected`. +- **#3** `GameBoard.svelte` header: `ConnectionBadge` gained a `compact` prop (dot-only, `sr-only` label, while `status === 'open'`); "Luật chơi" is now a 44px `.icon-button` anchor with `aria-label`; the room-code/difficulty `.mode` line moved from the header into `.prompt`, under the syllable. Chat pill kept its `data-testid="chat-pill"`/`chatOpen` `aria-label`; visible text dropped to an emoji + `sr-only` title + bare unread number (aria-label unchanged, still spells it out). `room-code`, `player-count`, `scoreboard`, `chat-toggle` testids untouched (they live in `RoomCodePanel`/`Lobby`/`ScoreBoard`/`ChatPanel`, not this file). +- **#4** `WordInput.svelte`: suggestion/report moved onto their own `.fixes` row at a 36px floor; suggestion is accent-filled ("primary"), report stays outlined. Classes kept as `suggestion`/`report` (plus `fix`) so `word-input.test.js`'s selectors still match. `useSuggestion`/`report` logic untouched — still fill-only, field still uncontrolled. +- **#5** "Bí từ" and "Đầu hàng" now share one `.secondary` row, both `ArmedButton`, both always mounted while `phase === 'playing' && !iAmOut`, disabled off-turn via `ArmedButton`'s own disarm-on-disable behaviour rather than being mounted/unmounted. +- **#6** Spectating box (`.spectating`, `data-testid="eliminated"`, moved here from `PlayerStatus.svelte`) now shows `youAreOut` plus the elimination suggestions or `noSuggestions`; the duplicate banner in `PlayerStatus.svelte` (and its `.banner.gone` style) is removed. `game-shape.js`'s `Elimination` typedef gained `syllable`; `game-apply.js` captures `state.currentSyllable` into it at knockout. `GameOverPanel.svelte` now reads `elimination.syllable` instead of the (possibly-moved-on) `game.state.currentSyllable`. +- **#7** `rejectMessages[NOT_YOUR_TURN]` extended to name the race for a submitted word. `errorMessages.not_your_turn` rewritten for the resign/claim race and routed (`game-apply.js`) into `state.claimError` alongside `not_a_dead_end`, so it renders beside the secondary row rather than the top banner. +- **#8** `online/+page.svelte`: the seconds counter moved out of the `role="status"` paragraph into a sibling `aria-hidden` one; `quickMatchWaiting` copy dropped its embedded `{n}`. `quickMatchNudge`/`quickMatchNudgeLink` reworded to say the nudge leaves the queue. The nudge's `/play` link now reads `settings.state.lastDifficulty` (new store field, persisted to `localStorage`, set from the landing `DifficultyPicker`'s `onselect`), falling back to plain `/play` when unset. Added `quickMatchHint`/`createRoomHint` sub-labels under the two entry buttons. +- **#9** `ChainHistory.svelte`: `.parts` is now a `