My Sea iter-4a follow-up batch: modal port + draw polish + label positioning + Major Arcana fix — TDD
User-driven bug-squash + UX-polish cycle on top of iter 4a (ca2a62f). All 14 fixes ship behind the same iter-4a banner since they close the substage's UX gaps without expanding scope to iter 4b's persistence layer.
SeaDeal modal port — extracted apps/gameboard/_partials/_sea_stage.html shared by gameroom + my-sea; aliased .my-sea-picker w. id=id_sea_overlay so SeaDeal.init() finds it; FLIP click → SeaDeal.openStage delegation instead of bare _fillSlot. Fixes the user-reported 'thumbnail disappears' bug — slot was landing at opacity 0 (.--filled w.o .--visible) because SeaDeal's _hideStage (which adds --visible on modal dismiss) was never running. 3 new FTs cover the modal flow.
Spread lock + DEL reshuffle — _lockSpread/_unlockSpread toggle .sea-select--locked class on the combobox; first deposit locks, _resetHand unlocks. _reshuffleDeck Fisher-Yates over combined piles + re-rolls 25% reversal axis on DEL so successive DELs don't re-deal the same hand. Verified Claudezilla: 3 DEL cycles produced distinct lay cards (150 → 114 → 155).
Cover/cross empty slots — subtle dotted outline (transparent bg + 0.25 alpha border) w. --duoUser mask reveal on hover/touch. Per the user spec; rule lives in _card-deck.scss (shared between gameroom + my-sea). Plus matching label-opacity (0.25 idle → 0.6 hover) via CSS :hover ancestor propagation.
DOS spec — Solution moved from cover → crown per user correction. DRAW_ORDER ['loom', 'cross', 'crown']; POSITION_LABELS {loom: Desire, cross: Obstacle, crown: Solution}; SCSS hide list flipped from [leave, crown, lay] → [leave, cover, lay]; FT/IT assertions updated.
SAO → DOS soft-reload bug — Firefox autofill on hidden input restored the previous-session DOS value, tripping combobox.js's change-event guard. Fix: autocomplete=off + force-sync hidden.value from server-rendered aria-selected option in init. Captured as feedback_firefox_autofill_hidden_inputs (generalizable trap).
.sea-pos-label outside .sea-card-slot — moved label to be a sibling of the slot in the cell, so SeaDeal innerHTML clobber on draw doesn't erase it. Per-position absolute positioning touching slot borders: crown/cover above (translate -50%, 0.1rem, scaleY 1.2); lay/cross below (translate -50%, -0.1rem, scaleY 1.2); leave left, CCW (writing-mode vertical-rl + rotate 180deg + scaleX 1.2); loom right, CW (writing-mode vertical-rl + scaleX 1.2). scaleX for rotated labels (not scaleY) — perpendicular to text-flow is the visible-width direction after rotation. .my-sea-cross gap bumped to 1.75rem for label clearance.
Escape Velocity label swaps — POSITION_LABELS for escape-velocity: {crown: Crown, leave: Lay, cover: Cover, cross: Cross, loom: Loom, lay: Leave}. Replaces the Waite-Smith Behind/Beneath/Before per user spec.
SPREAD dropdown portal — .my-sea-form-col .sea-form-main { overflow: visible } + .sea-select-list { z-index: 1000 } so the dropdown extends past the form-main scroll area + sits above the picker stacking ints. Gameroom .sea-form-main still scrolls (only my-sea opts out).
Major Arcana polarity-split rendering — added 9 missing _card_dict keys to my-sea's _my_sea_deck_data to match gameroom epic.views.sea_deck's contract: levity_emanation, gravity_emanation, levity_reversal, gravity_reversal, italic_word, keywords_upright, keywords_reversed, energies, operations. Without these StageCard.populateCard falls through to plain name_title for trumps 19-21 + cards 48-49. Iter 4b cleanup candidate: extract apps.epic.utils.card_dict() to DRY the now-identical helpers.
Tests deferred — user explicitly belayed FT runs during the bug-fix substage. Iter 4b will re-establish a green sweep before its commit lands.
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:
@@ -139,50 +139,9 @@
|
||||
</div>{# /.sea-modal-wrap #}
|
||||
|
||||
{# ── Sea stage — big card viewer ─────────────────────────────────────────── #}
|
||||
<div class="sea-stage" id="id_sea_stage" style="display:none">
|
||||
<div class="sea-stage-backdrop"></div>
|
||||
<div class="sea-stage-content">
|
||||
<div class="sig-stage-card sea-stage-card">
|
||||
<div class="fan-card-corner fan-card-corner--tl">
|
||||
<span class="fan-corner-rank"></span>
|
||||
<i class="fa-solid stage-suit-icon" style="display:none"></i>
|
||||
</div>
|
||||
<div class="fan-card-face">
|
||||
<div class="fan-card-face-upright">
|
||||
<p class="fan-card-name-group"></p>
|
||||
<p class="sig-qualifier-above"></p>
|
||||
<p class="fan-card-name"></p>
|
||||
<p class="sig-qualifier-below"></p>
|
||||
</div>
|
||||
<p class="fan-card-arcana"></p>
|
||||
<div class="fan-card-face-reversal">
|
||||
{# Default DOM order — matches non-major arcana layout. stage-card.js #}
|
||||
{# swaps the class names on these <p>s for Major arcana so each #}
|
||||
{# element's class still matches its semantic content. #}
|
||||
<p class="fan-card-reversal-name"></p>
|
||||
<p class="fan-card-reversal-qualifier"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fan-card-corner fan-card-corner--br">
|
||||
<span class="fan-corner-rank"></span>
|
||||
<i class="fa-solid stage-suit-icon" style="display:none"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sig-stat-block sea-stat-block">
|
||||
<button class="btn btn-reverse spin-btn" type="button">SPIN</button>
|
||||
<button class="btn btn-info fyi-btn" type="button">FYI</button>
|
||||
<div class="stat-face stat-face--upright">
|
||||
<p class="stat-face-label">Emanation</p>
|
||||
<ul class="stat-keywords" id="id_sea_stat_upright"></ul>
|
||||
</div>
|
||||
<div class="stat-face stat-face--reversed">
|
||||
<p class="stat-face-label">Reversal</p>
|
||||
<ul class="stat-keywords" id="id_sea_stat_reversed"></ul>
|
||||
</div>
|
||||
{% include "apps/gameboard/_partials/_sig_fyi_panel.html" with panel_id="id_sea_fyi_panel" panel_extra_attrs='style="display:none"' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# Extracted to a shared partial so the my-sea picker (Sprint 5 iter 4-bugs) #}
|
||||
{# reuses the same DOM contract that SeaDeal binds to. #}
|
||||
{% include "apps/gameboard/_partials/_sea_stage.html" %}
|
||||
|
||||
</div>{# /.sea-overlay #}
|
||||
|
||||
|
||||
52
src/templates/apps/gameboard/_partials/_sea_stage.html
Normal file
52
src/templates/apps/gameboard/_partials/_sea_stage.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{# Sea stage — full-viewport portaled modal (`position: fixed; inset: 0` #}
|
||||
{# per _card-deck.scss:1615) that opens above the picker / overlay when #}
|
||||
{# `SeaDeal.openStage(card, posSelector, isLevity)` fires. Hosts the #}
|
||||
{# full card face + stat block + SPIN / FYI controls; click backdrop to #}
|
||||
{# dismiss + reveal the deposited card thumbnail in its slot. #}
|
||||
{# #}
|
||||
{# Shared by the gameroom SEA SELECT phase and the my-sea picker — same #}
|
||||
{# HTML, same SeaDeal module bindings; only the parent overlay differs. #}
|
||||
<div class="sea-stage" id="id_sea_stage" style="display:none">
|
||||
<div class="sea-stage-backdrop"></div>
|
||||
<div class="sea-stage-content">
|
||||
<div class="sig-stage-card sea-stage-card">
|
||||
<div class="fan-card-corner fan-card-corner--tl">
|
||||
<span class="fan-corner-rank"></span>
|
||||
<i class="fa-solid stage-suit-icon" style="display:none"></i>
|
||||
</div>
|
||||
<div class="fan-card-face">
|
||||
<div class="fan-card-face-upright">
|
||||
<p class="fan-card-name-group"></p>
|
||||
<p class="sig-qualifier-above"></p>
|
||||
<p class="fan-card-name"></p>
|
||||
<p class="sig-qualifier-below"></p>
|
||||
</div>
|
||||
<p class="fan-card-arcana"></p>
|
||||
<div class="fan-card-face-reversal">
|
||||
{# Default DOM order — matches non-major arcana layout. stage-card.js #}
|
||||
{# swaps the class names on these <p>s for Major arcana so each #}
|
||||
{# element's class still matches its semantic content. #}
|
||||
<p class="fan-card-reversal-name"></p>
|
||||
<p class="fan-card-reversal-qualifier"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fan-card-corner fan-card-corner--br">
|
||||
<span class="fan-corner-rank"></span>
|
||||
<i class="fa-solid stage-suit-icon" style="display:none"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sig-stat-block sea-stat-block">
|
||||
<button class="btn btn-reverse spin-btn" type="button">SPIN</button>
|
||||
<button class="btn btn-info fyi-btn" type="button">FYI</button>
|
||||
<div class="stat-face stat-face--upright">
|
||||
<p class="stat-face-label">Emanation</p>
|
||||
<ul class="stat-keywords" id="id_sea_stat_upright"></ul>
|
||||
</div>
|
||||
<div class="stat-face stat-face--reversed">
|
||||
<p class="stat-face-label">Reversal</p>
|
||||
<ul class="stat-keywords" id="id_sea_stat_reversed"></ul>
|
||||
</div>
|
||||
{% include "apps/gameboard/_partials/_sig_fyi_panel.html" with panel_id="id_sea_fyi_panel" panel_extra_attrs='style="display:none"' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user