My Sea FREE DRAW + seat-1C seated transition — Sprint 5 iter 1 follow-up — TDD

Iter-1 follow-up after the user re-spec'd the FREE DRAW click behavior:

- **Btn label** DRAW SEA → FREE DRAW (the 1/24h free-quota draw). Element ID `id_draw_sea_btn` retained — describes intent, not label, so a future sprint can conditionally swap the label back to DRAW SEA once the daily free has been used (at which point the btn calls the room gatekeeper partial for token-deposit per [[project-my-sea-roadmap]] Sprint 6).
- **Chair seat markup** — each `.table-seat` now renders w. `.fa-chair` + `.seat-position-label` (1C-6C) + `.position-status-icon.fa-solid.fa-ban` mirroring the room's hex grammar from `_table_positions.html`. **`.seat-position-label`** (not `.seat-role-label`) because my-sea is the solo flow — no roles — and the existing room class carries role-grammar semantics that don't apply here. New class gets its own grid placement in `_gameboard.scss` (col 2 / row 1 default, col 1 for left-side seats 3/4/5 per the room's flip rule).
- **FREE DRAW click flow** — (1) seat 1C immediately gains `.seated` class & its `.fa-ban` icon swaps to `.fa-circle-check`; (2) after 800ms (so the user sees the seat animation against `_room.scss`'s 0.6s `color`/`filter` transition on `.fa-chair`), `data-phase` swaps to `picker` & landing hides. Seat 1C-only because my-sea is single-user-per-page until friend-invite lands — the user always occupies the lowest-numeral seat.
- **`.table-seat.seated` SCSS** in `_gameboard.scss` — `--terUser` chair color + `drop-shadow(--ninUser)` glow. Mirrors `_room.scss:626` `.table-seat.active .fa-chair` styling but uses a stable `.seated` class (semantically distinct: `.active` = current turn in a multi-user room, `.seated` = draw-locked occupant in the solo flow). Status icon green via the existing `_room.scss:616` `.position-status-icon.fa-circle-check` rule — no new color rule needed.
- **FT/IT updates** — renamed `test_landing_renders_hex_with_draw_sea_btn` → `…_free_draw_btn` w. "FREE DRAW" label assertions; T2 extended to assert `.position-status-icon.fa-ban` on each seat at render time; T3 (formerly `…_transitions_to_picker_phase`) rewritten as `test_free_draw_click_seats_user_in_1C_then_swaps_phase` to pin the full click contract: 1C goes `.seated` + `.fa-circle-check`, seats 2-6 unchanged, picker phase swap after the delay. New IT `test_landing_renders_position_status_ban_icon_on_each_seat` asserts initial ban + `.seat-position-label` counts.

**Substring trap caught** (worth a sticky note): bare class-name substrings (`fa-ban`, `position-status-icon`) appear ALSO in the inline JS handler's `classList.remove(…)` / `querySelector(…)` arg strings → `html.count("fa-ban") = 7`, not 6. Tightened IT assertions to match the full class attribute (`class="position-status-icon fa-solid fa-ban"`) — never count bare class names in `assertContains` / `html.count` when the same class is JS-manipulated client-side.

Tests: 25/25 FT green across test_bill_my_sign + test_game_my_sea (165s); 1037/1037 IT/UT green (49s).

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-19 15:48:07 -04:00
parent de48ae226d
commit 285597b467
4 changed files with 148 additions and 38 deletions

View File

@@ -227,23 +227,45 @@ body.page-gameboard {
min-height: 0;
display: flex;
// DRAW SEA btn — centered in the hex, mirrors SCAN SIGN's 2-line
// font sizing so "DRAW/SEA" sits cleanly inside the 4rem circle.
// FREE DRAW btn — centered in the hex, mirrors SCAN SIGN's 2-line
// font sizing so "FREE/DRAW" sits cleanly inside the 4rem circle.
#id_draw_sea_btn {
font-size: 0.75rem;
line-height: 1.1;
white-space: normal;
}
// Chair-seat labels (1C-6C) sit beside the chair icon. The room's
// .table-seat positioning by data-slot (1-6) already places them
// around the hex — this just sizes the label readably + colors it
// to match the gate's --terUser accent.
.table-seat .seat-label {
// Chair-position labels (1C-6C). Mirrors the room's `.seat-role-
// label` grid placement (col 2, row 1 by default; flips to col 1
// for left-side seats 3/4/5 so the label sits closest to the hex)
// but uses a role-free class name — my-sea is the solo draw flow,
// no role-pick phase, so the room's role-grammar doesn't apply.
.table-seat .seat-position-label {
grid-column: 2;
grid-row: 1;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.05em;
color: rgba(var(--secUser), 1);
}
.table-seat[data-slot="3"] .seat-position-label,
.table-seat[data-slot="4"] .seat-position-label,
.table-seat[data-slot="5"] .seat-position-label {
grid-column: 1;
}
// Seated chair (post-FREE DRAW). Visual transition mirrors
// `.table-seat.active .fa-chair` from _room.scss line 626 —
// --terUser color + --ninUser drop-shadow glow — but uses a stable
// `.seated` class (semantically distinct from `.active`: active =
// current turn in a multi-user room; seated = draw-locked occupant
// in this solo-flow). _room.scss line 596 makes the colour change
// a 0.6s ease transition so the chair animates rather than snaps.
// Status icon (.position-status-icon) colour swap fa-ban red →
// fa-circle-check green is handled by _room.scss lines 615-616.
.table-seat.seated .fa-chair {
color: rgba(var(--terUser), 1);
margin-left: 0.25rem;
filter: drop-shadow(0 0 4px rgba(var(--ninUser), 1));
}
}