Sea Select options: OK beside the select + --priUser chunk rects — TDD

Restyle the spread-options page (post the scroll-snap refactor):
- OK `.btn-confirm` moves UP beside the `.sea-select` combobox (a new
  `.sea-select-row`), off the AUTO DRAW / DEL action row.
- OK gains `.btn-disabled` + × the moment the first card is drawn — inverse to
  DEL (which loses them then), simultaneous with the combobox locking. So
  `_chooseSpread` (OK) no longer locks; the lock + both btn states flip together
  at the first draw via `_setHasDrawn` + `_lockSpread`. Server-renders OK
  disabled/× when `saved_by_position`.
- The three chunks (spread/select/OK, the mini preview, AUTO DRAW/DEL) each get
  the same --priUser rounded rectangle as the GAME POST lines / composer
  (`_base.scss` `.form-control`): --priUser fill + half-alpha --secUser border +
  rounded + padding. The `.sea-form-col`/`-main` go transparent flex columns so
  the felt shows between the chunks.
- IT: OK enabled / DEL disabled when fresh; flips once a card is drawn.
  953 epic+gameboard ITs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-06-08 00:02:14 -04:00
parent edc9a49f06
commit 1fe257a7a9
3 changed files with 97 additions and 26 deletions

View File

@@ -29,25 +29,31 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs.
{# Two Celtic Cross 6-card spreads only (user-spec 2026-06-07). #}
<input type="hidden" id="id_sea_spread" name="spread" autocomplete="off"
value="{{ sea_default_spread }}">
<div class="sea-select"
data-combobox
data-combobox-target="id_sea_spread"
role="combobox"
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="id_sea_spread_label"
tabindex="0">
<span class="sea-select-current">{% if sea_default_spread == "escape-velocity" %}Celtic Cross, Escape Velocity{% else %}Celtic Cross, Waite-Smith{% endif %}</span>
<span class="sea-select-arrow" aria-hidden="true"></span>
<ul class="sea-select-list" role="listbox">
{% if user_polarity == "levity" %}
<li role="option" data-value="waite-smith" aria-selected="{% if sea_default_spread == 'escape-velocity' %}false{% else %}true{% endif %}">Celtic Cross, Waite-Smith</li>
<li role="option" data-value="escape-velocity" aria-selected="{% if sea_default_spread == 'escape-velocity' %}true{% else %}false{% endif %}">Celtic Cross, Escape Velocity</li>
{% else %}
<li role="option" data-value="escape-velocity" aria-selected="{% if sea_default_spread == 'waite-smith' %}false{% else %}true{% endif %}">Celtic Cross, Escape Velocity</li>
<li role="option" data-value="waite-smith" aria-selected="{% if sea_default_spread == 'waite-smith' %}true{% else %}false{% endif %}">Celtic Cross, Waite-Smith</li>
{% endif %}
</ul>
{# Combobox + OK on one row — OK confirms the spread → shunts. #}
{# OK gains .btn-disabled + × the moment the first card is drawn #}
{# (the spread is then locked, the select disables, DEL enables). #}
<div class="sea-select-row">
<div class="sea-select"
data-combobox
data-combobox-target="id_sea_spread"
role="combobox"
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="id_sea_spread_label"
tabindex="0">
<span class="sea-select-current">{% if sea_default_spread == "escape-velocity" %}Celtic Cross, Escape Velocity{% else %}Celtic Cross, Waite-Smith{% endif %}</span>
<span class="sea-select-arrow" aria-hidden="true"></span>
<ul class="sea-select-list" role="listbox">
{% if user_polarity == "levity" %}
<li role="option" data-value="waite-smith" aria-selected="{% if sea_default_spread == 'escape-velocity' %}false{% else %}true{% endif %}">Celtic Cross, Waite-Smith</li>
<li role="option" data-value="escape-velocity" aria-selected="{% if sea_default_spread == 'escape-velocity' %}true{% else %}false{% endif %}">Celtic Cross, Escape Velocity</li>
{% else %}
<li role="option" data-value="escape-velocity" aria-selected="{% if sea_default_spread == 'waite-smith' %}false{% else %}true{% endif %}">Celtic Cross, Escape Velocity</li>
<li role="option" data-value="waite-smith" aria-selected="{% if sea_default_spread == 'waite-smith' %}true{% else %}false{% endif %}">Celtic Cross, Waite-Smith</li>
{% endif %}
</ul>
</div>
<button type="button" id="id_sea_confirm_spread" class="btn btn-confirm{% if saved_by_position %} btn-disabled{% endif %}">{% if saved_by_position %}&times;{% else %}OK{% endif %}</button>
</div>
</div>
@@ -57,9 +63,6 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs.
</div>
<div class="sea-form-actions">
{# OK confirms the spread → shunts the options down + reveals the #}
{# cross (a regular .btn-confirm, NOT a big .btn-primary). #}
<button type="button" id="id_sea_confirm_spread" class="btn btn-confirm">OK</button>
{# AUTO DRAW commits the remaining hand in one POST + animates onto #}
{# the cross (confirms the spread first if not yet). DEL clears. #}
<button type="button"
@@ -215,7 +218,9 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs.
if (_spreadChosen) return;
_spreadChosen = true;
page.classList.add('sea-spread-chosen');
_lockSpread();
// NB: the combobox is NOT locked here — the spread stays changeable (scroll
// up) until the FIRST card is drawn, when _lockSpread() + _setHasDrawn(true)
// disable the select + OK together (user-spec 2026-06-07).
_scrollToCross();
}
function _scrollToCross() {
@@ -234,10 +239,16 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs.
}
requestAnimationFrame(step);
}
if (okBtn) okBtn.addEventListener('click', _chooseSpread);
if (okBtn) okBtn.addEventListener('click', function () {
if (okBtn.classList.contains('btn-disabled')) return;
_chooseSpread();
});
// First card drawn → DEL un-disables ("DEL") + OK disables ("×"), simultaneous
// with the combobox locking (`_lockSpread`). The two btns are inverse states.
function _setHasDrawn(on) {
if (delBtn) { delBtn.classList.toggle('btn-disabled', !on); delBtn.innerHTML = on ? 'DEL' : '×'; }
if (okBtn) { okBtn.classList.toggle('btn-disabled', on); okBtn.innerHTML = on ? '×' : 'OK'; }
}
function _setComplete(on, live) {
_locked = on;