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:
@@ -37,14 +37,28 @@
|
||||
<div class="table-hex-border">
|
||||
<div class="table-hex">
|
||||
<div class="table-center">
|
||||
<button id="id_draw_sea_btn" type="button" class="btn btn-primary">DRAW<br>SEA</button>
|
||||
{# Sprint 5 iter 1 — FREE DRAW = the 1/24hr free-quota draw. #}
|
||||
{# Future sprint will conditionally swap this for a DRAW SEA #}
|
||||
{# .btn-primary that calls the gatekeeper partial once the #}
|
||||
{# free daily has been used; until then the btn renders FREE #}
|
||||
{# DRAW. ID retained as `id_draw_sea_btn` (intent: the draw #}
|
||||
{# entry point) so the swap is label-only when iter 6+ lands. #}
|
||||
<button id="id_draw_sea_btn" type="button" class="btn btn-primary">FREE<br>DRAW</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% for n in "123456" %}
|
||||
{# Chair-position labels (1C-6C). No roles in #}
|
||||
{# my-sea (this is the solo draw flow); using #}
|
||||
{# `.seat-position-label` instead of the room's #}
|
||||
{# `.seat-role-label` to keep the no-role #}
|
||||
{# semantics clean. `.position-status-icon` + #}
|
||||
{# `.fa-ban` are unchanged — already role- #}
|
||||
{# agnostic in _room.scss. #}
|
||||
<div class="table-seat" data-slot="{{ n }}">
|
||||
<i class="fa-solid fa-chair"></i>
|
||||
<span class="seat-label">{{ n }}C</span>
|
||||
<span class="seat-position-label">{{ n }}C</span>
|
||||
<i class="position-status-icon fa-solid fa-ban"></i>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -68,11 +82,35 @@
|
||||
var landing = page.querySelector('.my-sea-landing');
|
||||
var picker = page.querySelector('.my-sea-picker');
|
||||
var drawBtn = document.getElementById('id_draw_sea_btn');
|
||||
// FREE DRAW click flow:
|
||||
// 1) seat 1C transitions to .seated (chair --terUser +
|
||||
// drop-shadow glow + .fa-ban → .fa-circle-check —
|
||||
// _room.scss line 596 makes the colour change a
|
||||
// 0.6s ease transition);
|
||||
// 2) after a brief delay (so the user sees the seat
|
||||
// animation), data-phase swaps to 'picker' + the
|
||||
// landing hides. Picker content lands in iter 2.
|
||||
// The seat-take logic is solo-coded for now: 1C is the
|
||||
// lowest-numeral chair, and my-sea is 1-user-per-page
|
||||
// until the friend-invite feature (per [[project-my-
|
||||
// sea-roadmap]]) — so 1C is always the user's seat.
|
||||
var SEAT_ANIM_MS = 800;
|
||||
if (drawBtn) {
|
||||
drawBtn.addEventListener('click', function () {
|
||||
page.setAttribute('data-phase', 'picker');
|
||||
if (landing) landing.style.display = 'none';
|
||||
if (picker) picker.style.display = '';
|
||||
var seat1 = page.querySelector('.table-seat[data-slot="1"]');
|
||||
if (seat1) {
|
||||
seat1.classList.add('seated');
|
||||
var statusIcon = seat1.querySelector('.position-status-icon');
|
||||
if (statusIcon) {
|
||||
statusIcon.classList.remove('fa-ban');
|
||||
statusIcon.classList.add('fa-circle-check');
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
page.setAttribute('data-phase', 'picker');
|
||||
if (landing) landing.style.display = 'none';
|
||||
if (picker) picker.style.display = '';
|
||||
}, SEAT_ANIM_MS);
|
||||
});
|
||||
}
|
||||
// Mirror my-sign's scaleTable() init timing fix — the
|
||||
|
||||
Reference in New Issue
Block a user