my_sea_visit: give the visitor a top-left deck stack (owner's deck) with a hover-revealed disabled FLIP — TDD

Mirrors the owner's deck stack onto the spectator hex, DRY:
- new shared _my_sea_deck_stack.html partial (mono DECK / dubbo DECKS by
  is_polarized) rendered by BOTH the owner picker (my_sea.html, flip_disabled=
  hand_complete) AND the visitor cross (flip_disabled=True). Owner markup is
  byte-identical, so its assertions hold.
- the visitor's stack uses the OWNER's deck (everyone at @owner's sea plays the
  owner's deck — the visitor's own equipped deck is irrelevant), pinned
  top-left (--visit) across the table from the owner who deals bottom-right.
- dubbodeck: the Gravity/Levity name flips above the face + upside-down to
  signal someone across the table is dealing.
- the read-only FLIP (disabled ×) is hidden until its stack is hovered/focused,
  then eases in (same opacity 0->1 over 0.3s as the shared flip-btn-base
  reveal; inlined since _gameboard precedes _card-deck in the import order) so a
  permanent × doesn't clutter the stack.

ITs: stack keys on the owner's deck (not the viewer's), dubbo renders 2 named
stacks, FLIP is the disabled state, no stack when the owner has no deck. Owner
deck-stack IT + FT stay green (identical markup).

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-29 23:01:21 -04:00
parent c3594d27ed
commit 260c1c1325
5 changed files with 126 additions and 29 deletions

View File

@@ -0,0 +1,36 @@
{# Deck stack — mono (single DECK) or dubbo (DECKS: Gravity + Levity), per #}
{# `deck.is_polarized`. Shared by the owner picker (my_sea.html) AND the #}
{# read-only visitor cross (_my_sea_visit_cross.html). `deck` = the #}
{# DeckVariant to render; `flip_disabled` forces the FLIP btn to its #}
{# disabled (×) state — owner: hand_complete; visitor: always (a read-only #}
{# spectator can't deal). Markup is byte-identical to the owner's prior #}
{# inline stack so existing assertions hold. #}
{% if deck.is_polarized %}
<div class="sea-stacks">
<span class="sea-stacks-label">DECKS</span>
<div class="sea-deck-stack sea-deck-stack--gravity">
<div class="sea-stack-face">
<button class="btn btn-reveal sea-stack-ok{% if flip_disabled %} btn-disabled{% endif %}" type="button">{% if flip_disabled %}&times;{% else %}FLIP{% endif %}</button>
</div>
<span class="sea-stack-name">Gravity</span>
</div>
<div class="sea-deck-stack sea-deck-stack--levity">
<div class="sea-stack-face">
<button class="btn btn-reveal sea-stack-ok{% if flip_disabled %} btn-disabled{% endif %}" type="button">{% if flip_disabled %}&times;{% else %}FLIP{% endif %}</button>
</div>
<span class="sea-stack-name">Levity</span>
</div>
</div>
{% else %}
<div class="sea-stacks sea-stacks--single">
<span class="sea-stacks-label">DECK</span>
<div class="sea-deck-stack sea-deck-stack--single">
<div class="sea-stack-face">
{% if deck.has_card_images %}
<img class="sea-stack-face-img" src="{{ deck.back_image_url }}" alt="">
{% endif %}
<button class="btn btn-reveal sea-stack-ok{% if flip_disabled %} btn-disabled{% endif %}" type="button">{% if flip_disabled %}&times;{% else %}FLIP{% endif %}</button>
</div>
</div>
</div>
{% endif %}

View File

@@ -49,5 +49,15 @@
</div>
</div>
</div>
{# Deck stack — the OWNER's deck (everyone at @owner's sea plays the #}
{# owner's deck), mirrored to the TOP-LEFT for the visitor sitting across #}
{# from the owner, who deals bottom-right. FLIP is always disabled #}
{# (read-only); a dubbodeck's Gravity/Levity name flips above + upside- #}
{# down via `--visit` to signal someone across the table is dealing. #}
{% if owner.equipped_deck %}
<div class="my-sea-stacks-wrap my-sea-stacks-wrap--visit">
{% include "apps/gameboard/_partials/_my_sea_deck_stack.html" with deck=owner.equipped_deck flip_disabled=True %}
</div>
{% endif %}
{% include "apps/gameboard/_partials/_sea_stage.html" %}
</div>

View File

@@ -186,35 +186,7 @@
{# collapses to a single unnamed stack (DECKS → DECK). #}
{# FLIP btn picks up `.btn-disabled` once hand_complete. #}
<div class="my-sea-stacks-wrap">
{% if request.user.equipped_deck.is_polarized %}
<div class="sea-stacks">
<span class="sea-stacks-label">DECKS</span>
<div class="sea-deck-stack sea-deck-stack--gravity">
<div class="sea-stack-face">
<button class="btn btn-reveal sea-stack-ok{% if hand_complete %} btn-disabled{% endif %}" type="button">{% if hand_complete %}&times;{% else %}FLIP{% endif %}</button>
</div>
<span class="sea-stack-name">Gravity</span>
</div>
<div class="sea-deck-stack sea-deck-stack--levity">
<div class="sea-stack-face">
<button class="btn btn-reveal sea-stack-ok{% if hand_complete %} btn-disabled{% endif %}" type="button">{% if hand_complete %}&times;{% else %}FLIP{% endif %}</button>
</div>
<span class="sea-stack-name">Levity</span>
</div>
</div>
{% else %}
<div class="sea-stacks sea-stacks--single">
<span class="sea-stacks-label">DECK</span>
<div class="sea-deck-stack sea-deck-stack--single">
<div class="sea-stack-face">
{% if request.user.equipped_deck.has_card_images %}
<img class="sea-stack-face-img" src="{{ request.user.equipped_deck.back_image_url }}" alt="">
{% endif %}
<button class="btn btn-reveal sea-stack-ok{% if hand_complete %} btn-disabled{% endif %}" type="button">{% if hand_complete %}&times;{% else %}FLIP{% endif %}</button>
</div>
</div>
</div>
{% endif %}
{% include "apps/gameboard/_partials/_my_sea_deck_stack.html" with deck=request.user.equipped_deck flip_disabled=hand_complete %}
</div>
{# Spread modal — opens on #id_sea_btn click (burger fan). #}