From 1fe257a7a9aaaf9695394dd5a96e13e245797907 Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Mon, 8 Jun 2026 00:02:14 -0400 Subject: [PATCH] =?UTF-8?q?Sea=20Select=20options:=20OK=20beside=20the=20s?= =?UTF-8?q?elect=20+=20--priUser=20chunk=20rects=20=E2=80=94=20TDD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/apps/epic/tests/integrated/test_views.py | 20 +++++++ src/static_src/scss/_sky.scss | 44 +++++++++++++- .../gameboard/_partials/_sea_overlay.html | 59 +++++++++++-------- 3 files changed, 97 insertions(+), 26 deletions(-) diff --git a/src/apps/epic/tests/integrated/test_views.py b/src/apps/epic/tests/integrated/test_views.py index ae76c71..6c067db 100644 --- a/src/apps/epic/tests/integrated/test_views.py +++ b/src/apps/epic/tests/integrated/test_views.py @@ -4161,6 +4161,26 @@ class PickSeaUnifiedFeltTest(TestCase): self.assertIn("AUTO", content) self.assertNotIn("id_sea_lock_hand", content) + def test_ok_disabled_and_del_enabled_once_a_card_is_drawn(self): + """Once a card is drawn (saved_by_position), the OK btn gains .btn-disabled + (the spread is locked) while DEL loses it — inverse states, simultaneous + with the select locking (user-spec 2026-06-07). Fresh (no draw): OK is + enabled, DEL disabled.""" + import lxml.html + # Fresh — OK enabled, DEL disabled. + parsed = lxml.html.fromstring(self.client.get(self.url).content) + self.assertNotIn("btn-disabled", parsed.cssselect("#id_sea_confirm_spread")[0].get("class", "")) + self.assertIn("btn-disabled", parsed.cssselect("#id_sea_del")[0].get("class", "")) + # One card drawn — flips. + card_id = TarotCard.objects.filter(deck_variant=self.earthman).first().id + char = Character.objects.get(seat=self.pc_seat, confirmed_at__isnull=False) + char.celtic_cross = {"spread": "waite-smith", "hand": [ + {"position": "cover", "card_id": card_id, "reversed": False, "polarity": "gravity"}]} + char.save(update_fields=["celtic_cross"]) + parsed = lxml.html.fromstring(self.client.get(self.url).content) + self.assertIn("btn-disabled", parsed.cssselect("#id_sea_confirm_spread")[0].get("class", "")) + self.assertNotIn("btn-disabled", parsed.cssselect("#id_sea_del")[0].get("class", "")) + def test_only_two_celtic_cross_spread_options(self): content = self.client.get(self.url).content.decode() self.assertIn('data-value="waite-smith"', content) diff --git a/src/static_src/scss/_sky.scss b/src/static_src/scss/_sky.scss index ac25f15..679e88b 100644 --- a/src/static_src/scss/_sky.scss +++ b/src/static_src/scss/_sky.scss @@ -115,11 +115,51 @@ html.sea-open .sea-page.sea-page--room { } // The options form blends onto the --duoUser felt (transparent, content-sized) — -// "the modal contents on green felt", not the modal's purple --priUser card. +// "the modal contents on green felt". The form-col + form-main are transparent +// flex columns; each of the THREE chunks (spread/select/OK, preview, actions) +// is its own --priUser rounded rectangle (the GAME POST .form-control look). .sea-page--room .sea-options-col .sea-form-col { background: transparent; width: auto; - min-width: 14rem; + min-width: 15rem; + max-width: 22rem; + padding: 0; + gap: 0.6rem; +} +.sea-page--room .sea-options-col .sea-form-main { + flex: 0 0 auto; + overflow: visible; + display: flex; + flex-direction: column; + gap: 0.6rem; +} + +// Combobox + OK on one row (OK to the RIGHT of the select). +.sea-page--room .sea-options-col .sea-select-row { + display: flex; + align-items: center; + gap: 0.5rem; + + .sea-select { flex: 1; min-width: 0; } +} + +// The three chunks — same --priUser rectangle as the GAME POST lines/composer +// (_base.scss .form-control): --priUser fill + a half-alpha --secUser border + +// rounded corners + padding. Resets each chunk's own modal-era margins/padding. +.sea-page--room .sea-options-col .sea-field, +.sea-page--room .sea-options-col .sea-cards-col--preview, +.sea-page--room .sea-options-col .sea-form-actions { + background-color: rgba(var(--priUser), 1); + border: 0.1rem solid rgba(var(--secUser), 0.5); + border-radius: 0.5rem; + padding: 0.6rem 0.75rem; + margin: 0; +} +.sea-page--room .sea-options-col .sea-form-actions { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; } // Pre-confirm: only the options show (the cross is hidden), filling the aperture diff --git a/src/templates/apps/gameboard/_partials/_sea_overlay.html b/src/templates/apps/gameboard/_partials/_sea_overlay.html index f409619..d8a0826 100644 --- a/src/templates/apps/gameboard/_partials/_sea_overlay.html +++ b/src/templates/apps/gameboard/_partials/_sea_overlay.html @@ -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). #} - @@ -57,9 +63,6 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs.
- {# OK confirms the spread → shunts the options down + reveals the #} - {# cross (a regular .btn-confirm, NOT a big .btn-primary). #} - {# AUTO DRAW commits the remaining hand in one POST + animates onto #} {# the cross (confirms the spread first if not yet). DEL clears. #}