From 4322e1fc1777c8f2fda5174ca2e9c707f67c56e9 Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Sun, 7 Jun 2026 19:37:50 -0400 Subject: [PATCH] table-hex: DRY-lift the shared hex skeleton into core/_partials/_table_hex.html MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .room-table-scene → .table-hex-border → .table-hex → .table-center + seats ring was byte-identical across room.html, my_sea.html, my_sea_visit.html & billboard/my_sign.html. Lift the skeleton into one cross-app partial so every surface — and the upcoming Sea Select felt rebuild — shares a single source. - core/_partials/_table_hex.html: the 4-div skeleton. The varying center + seats are passed as partial NAMES (`hex_center` / `hex_seats`) since Django {% include %} has no slot; `{% include hex_center %}` resolves the string var + inherits the full page context (no `only`), so each fragment sees its page's vars unchanged → identical render. - Per-surface center fragments (verbatim moves): _room_hex_center, _my_sea_hex_center, _my_sea_visit_hex_center (gameboard/_partials), _my_sign_hex_center (billboard/_partials). - Seats fragments: _room_hex_seats (gate_positions); _table_seats — SHARED by my_sea + my_sea_visit (`seats` loop; the `--self` modifier is inert on my_sea); _my_sign_hex_seats (single chair). - The page-specific outer wrappers stay put (room's .room-shell + ROLE_SELECT SCAN SIGS form; .my-sea-landing / .my-sign-landing; my_sign's {% if not current_significator %} gate). The "felt" is deliberately NOT extracted — it's a --duoUser bg toggled by phase/stage classes (CSS), already DRY; each phase's felt content is bespoke. Markup-only, no behaviour change. Verified: 1170 epic+gameboard+billboard render ITs green (the table-hex / table-seat / center-btn assertions are the gate) + MySeaDrawSeaLandingTest FTs green (live hex render + FREE DRAW seats .table-seat[data-slot="1"] through the shared seats partial). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../_partials/_my_sign_hex_center.html | 7 ++ .../_partials/_my_sign_hex_seats.html | 8 +++ src/templates/apps/billboard/my_sign.html | 15 +---- .../_partials/_my_sea_hex_center.html | 34 ++++++++++ .../_partials/_my_sea_visit_hex_center.html | 16 +++++ .../gameboard/_partials/_room_hex_center.html | 47 +++++++++++++ .../gameboard/_partials/_room_hex_seats.html | 18 +++++ .../gameboard/_partials/_table_seats.html | 22 ++++++ src/templates/apps/gameboard/my_sea.html | 65 ++---------------- .../apps/gameboard/my_sea_visit.html | 43 ++---------- src/templates/apps/gameboard/room.html | 67 +------------------ src/templates/core/_partials/_table_hex.html | 26 +++++++ 12 files changed, 190 insertions(+), 178 deletions(-) create mode 100644 src/templates/apps/billboard/_partials/_my_sign_hex_center.html create mode 100644 src/templates/apps/billboard/_partials/_my_sign_hex_seats.html create mode 100644 src/templates/apps/gameboard/_partials/_my_sea_hex_center.html create mode 100644 src/templates/apps/gameboard/_partials/_my_sea_visit_hex_center.html create mode 100644 src/templates/apps/gameboard/_partials/_room_hex_center.html create mode 100644 src/templates/apps/gameboard/_partials/_room_hex_seats.html create mode 100644 src/templates/apps/gameboard/_partials/_table_seats.html create mode 100644 src/templates/core/_partials/_table_hex.html diff --git a/src/templates/apps/billboard/_partials/_my_sign_hex_center.html b/src/templates/apps/billboard/_partials/_my_sign_hex_center.html new file mode 100644 index 0000000..eef2d75 --- /dev/null +++ b/src/templates/apps/billboard/_partials/_my_sign_hex_center.html @@ -0,0 +1,7 @@ +{% comment %} +my_sign.html table-hex center — included via core/_partials/_table_hex.html +(hex_center). The lone SCAN SIGN button (the my_sign hex renders only when the +user has no saved significator; that {% if not current_significator %} gate +stays in my_sign.html). +{% endcomment %} + diff --git a/src/templates/apps/billboard/_partials/_my_sign_hex_seats.html b/src/templates/apps/billboard/_partials/_my_sign_hex_seats.html new file mode 100644 index 0000000..c7b3936 --- /dev/null +++ b/src/templates/apps/billboard/_partials/_my_sign_hex_seats.html @@ -0,0 +1,8 @@ +{% comment %} +my_sign.html table-hex seats — included via core/_partials/_table_hex.html +(hex_seats). Single founder chair — solo-coded but extensible to the 6-chair +friend-invite plan in [[project-my-sea-roadmap]]. +{% endcomment %} +
+ +
diff --git a/src/templates/apps/billboard/my_sign.html b/src/templates/apps/billboard/my_sign.html index 00fd452..fe01278 100644 --- a/src/templates/apps/billboard/my_sign.html +++ b/src/templates/apps/billboard/my_sign.html @@ -128,20 +128,7 @@ this billboard surface re-brands to "Sign". {% if not current_significator %}
-
-
-
-
- -
-
-
- {# Single founder chair — solo-coded but extensible to the #} - {# 6-chair friend-invite plan in [[project-my-sea-roadmap]]. #} -
- -
-
+ {% include "core/_partials/_table_hex.html" with hex_center="apps/billboard/_partials/_my_sign_hex_center.html" hex_seats="apps/billboard/_partials/_my_sign_hex_seats.html" %}
{% endif %} diff --git a/src/templates/apps/gameboard/_partials/_my_sea_hex_center.html b/src/templates/apps/gameboard/_partials/_my_sea_hex_center.html new file mode 100644 index 0000000..6b59326 --- /dev/null +++ b/src/templates/apps/gameboard/_partials/_my_sea_hex_center.html @@ -0,0 +1,34 @@ +{% comment %} +my_sea.html table-hex center — included via core/_partials/_table_hex.html +(hex_center). Verbatim move of the old inline .table-center body; inherits +my_sea.html's context (show_cont_draw, show_paid_draw, show_gate_view). +{% endcomment %} +{% if show_cont_draw %} + {# CONT DRAW — user came to the landing via the gear-menu NVM mid-draw #} + {# (?phase=landing). The picker hand is non-empty + incomplete; CONT DRAW #} + {# re-enters the picker (a fresh GET w.o. ?phase=landing falls through to #} + {# show_picker=True via the hand_non_empty branch). #} + CONT
DRAW
+{% elif show_paid_draw %} + {# PAID DRAW — two underlying states collapse into one button (user-spec #} + {# 2026-05-23): #} + {# • `deposit_reserved` → POST commits the deposited token via #} + {# `my_sea_paid_draw` + redirects to picker. #} + {# • `paid_through` (token already spent this cycle, hand still empty) → #} + {# POST is a no-op commit branch in the view; redirects to picker anyway.#} +
+ {% csrf_token %} + +
+{% elif show_gate_view %} + +{% else %} + +{% endif %} diff --git a/src/templates/apps/gameboard/_partials/_my_sea_visit_hex_center.html b/src/templates/apps/gameboard/_partials/_my_sea_visit_hex_center.html new file mode 100644 index 0000000..105dbaa --- /dev/null +++ b/src/templates/apps/gameboard/_partials/_my_sea_visit_hex_center.html @@ -0,0 +1,16 @@ +{% comment %} +my_sea_visit.html table-hex center — included via core/_partials/_table_hex.html +(hex_center). Verbatim move of the old inline .table-center body; inherits the +visit page context (seat2_present, owner). +{% endcomment %} +{% if seat2_present %} + {# Visitor is present — VIEW DRAW reveals the owner's read-only draw #} + {# (client-side toggle below). #} + +{% else %} + {# Not yet present — GATE VIEW → visitor token gate. #} + +{% endif %} diff --git a/src/templates/apps/gameboard/_partials/_room_hex_center.html b/src/templates/apps/gameboard/_partials/_room_hex_center.html new file mode 100644 index 0000000..86a1f7f --- /dev/null +++ b/src/templates/apps/gameboard/_partials/_room_hex_center.html @@ -0,0 +1,47 @@ +{% comment %} +room.html table-hex center — included via core/_partials/_table_hex.html +(hex_center). Verbatim move of the old inline .table-center body; inherits +room.html's context (table_status, card_stack_state, viewer_cost_current, +sky_confirmed, polarity_done, user_polarity, current_slot, …). +{% endcomment %} +{# ROLE card-stack — the gamer's own role pick stays available even when their #} +{# token cost has lapsed (deposit-privilege grace, 7d), so it renders OUTSIDE #} +{# the cost gate below. #} +{% if room.table_status == "ROLE_SELECT" and card_stack_state %} +
+ {% if card_stack_state == "ineligible" %} + + {% endif %} +
+{% endif %} +{% if not viewer_cost_current %} + {# Token cost lapsed → GATE VIEW supersedes SCAN SIGS / CAST SKY / DRAW SEA #} + {# / the sig waiting msg. The gamer keeps their seat through the renewal #} + {# grace; GATE VIEW routes to the renewal gate-view. Only the ROLE pick #} + {# (above) survives. ` +{% else %} + {% if room.table_status == "SKY_SELECT" %} + {# Both phase btns render so the post-save cascade can cross-fade CAST #} + {# SKY → DRAW SEA in place (no reload). The server sets --out on the #} + {# inactive one; sky-select.js's cascade swaps them. On a confirmed #} + {# reload the server lands DRAW SEA visible + CAST SKY out, same as the #} + {# cascade end. #} +
+ + +
+ {% elif room.table_status == "SIG_SELECT" %} + + {% if polarity_done %} +

{% if user_polarity == "levity" %}Gravity settling . . .{% else %}Levity appraising . . .{% endif %}

+ {% endif %} + {% endif %} +{% endif %} diff --git a/src/templates/apps/gameboard/_partials/_room_hex_seats.html b/src/templates/apps/gameboard/_partials/_room_hex_seats.html new file mode 100644 index 0000000..2911a28 --- /dev/null +++ b/src/templates/apps/gameboard/_partials/_room_hex_seats.html @@ -0,0 +1,18 @@ +{% comment %} +room.html table-hex seats — included via core/_partials/_table_hex.html +(hex_seats). Verbatim move of the gate_positions seat ring; inherits room.html's +context (gate_positions, starter_roles). +{% endcomment %} +{# Seats — fa-chair layout persists from ROLE_SELECT through SIG_SELECT #} +{% for pos in gate_positions %} +
+ + {{ pos.role_label }} + {% if pos.role_label in starter_roles %} + + {% else %} + + {% endif %} +
+{% endfor %} diff --git a/src/templates/apps/gameboard/_partials/_table_seats.html b/src/templates/apps/gameboard/_partials/_table_seats.html new file mode 100644 index 0000000..ba88855 --- /dev/null +++ b/src/templates/apps/gameboard/_partials/_table_seats.html @@ -0,0 +1,22 @@ +{% comment %} +Shared table-hex seats ring for my_sea.html + my_sea_visit.html — included via +core/_partials/_table_hex.html (hex_seats). Iterates the `seats` context +(seat.present / .n / .label / .token). The `.table-seat--self` modifier marks +the visitor's own seat on my_sea_visit; it is inert on my_sea (seat.is_self is +undefined → falsy). +{% endcomment %} +{% for seat in seats %} + {% if seat.present %} +
+ + {{ seat.label }} + +
+ {% else %} +
+ + {{ seat.label }} + +
+ {% endif %} +{% endfor %} diff --git a/src/templates/apps/gameboard/my_sea.html b/src/templates/apps/gameboard/my_sea.html index 5fa9424..b46e711 100644 --- a/src/templates/apps/gameboard/my_sea.html +++ b/src/templates/apps/gameboard/my_sea.html @@ -48,66 +48,11 @@
-
-
-
-
- {% if show_cont_draw %} - {# CONT DRAW — user came to the landing via the gear- #} - {# menu NVM mid-draw (?phase=landing). The picker hand #} - {# is non-empty + incomplete; CONT DRAW re-enters the #} - {# picker (a fresh GET w.o. ?phase=landing falls through #} - {# to show_picker=True via the hand_non_empty branch). #} - CONT
DRAW
- {% elif show_paid_draw %} - {# PAID DRAW — two underlying states collapse into one #} - {# button (user-spec 2026-05-23): #} - {# • `deposit_reserved` → POST commits the deposited #} - {# token via `my_sea_paid_draw` + redirects to picker. #} - {# • `paid_through` (token already spent this cycle, #} - {# hand still empty) → POST is a no-op commit branch #} - {# in the view; the view redirects to picker anyway. #} -
- {% csrf_token %} - -
- {% elif show_gate_view %} - - {% else %} - - {% endif %} -
-
-
- {# Owner 1C + present visitors 2C-6C — the shared #} - {# `_my_sea_seats` ring, so the owner sees who's #} - {# seated at her table, not just herself. The FREE #} - {# DRAW client-side transition still targets #} - {# `.table-seat[data-slot="1"]`. `.position-status- #} - {# icon` / `.fa-ban` are role-agnostic in _room.scss. #} - {% for seat in seats %} - {% if seat.present %} -
- - {{ seat.label }} - -
- {% else %} -
- - {{ seat.label }} - -
- {% endif %} - {% endfor %} -
+ {# Owner 1C + present visitors 2C-6C — the shared seats ring #} + {# (_table_seats.html), so the owner sees who's seated at her #} + {# table, not just herself. The FREE DRAW client-side #} + {# transition still targets `.table-seat[data-slot="1"]`. #} + {% include "core/_partials/_table_hex.html" with hex_center="apps/gameboard/_partials/_my_sea_hex_center.html" hex_seats="apps/gameboard/_partials/_table_seats.html" %}
diff --git a/src/templates/apps/gameboard/my_sea_visit.html b/src/templates/apps/gameboard/my_sea_visit.html index 89ecebf..00c75a2 100644 --- a/src/templates/apps/gameboard/my_sea_visit.html +++ b/src/templates/apps/gameboard/my_sea_visit.html @@ -20,44 +20,11 @@
-
-
-
-
- {% if seat2_present %} - {# Visitor is present — VIEW DRAW reveals the owner's #} - {# read-only draw (client-side toggle below). #} - - {% else %} - {# Not yet present — GATE VIEW → visitor token gate. #} - - {% endif %} -
-
-
- {# Every present member shows on the ring — owner 1C + #} - {# present invitees 2C–6C by deposit order (the viewer's #} - {# own seat carries `--self`). Built server-side as #} - {# `seats` so all viewers see identical absolute seating. #} - {% for seat in seats %} - {% if seat.present %} -
- - {{ seat.label }} - -
- {% else %} -
- - {{ seat.label }} - -
- {% endif %} - {% endfor %} -
+ {# Every present member shows on the ring (the shared #} + {# _table_seats.html) — owner 1C + present invitees 2C–6C by #} + {# deposit order; the viewer's own seat carries `--self`. Built #} + {# server-side as `seats` so all viewers see identical seating. #} + {% include "core/_partials/_table_hex.html" with hex_center="apps/gameboard/_partials/_my_sea_visit_hex_center.html" hex_seats="apps/gameboard/_partials/_table_seats.html" %}
diff --git a/src/templates/apps/gameboard/room.html b/src/templates/apps/gameboard/room.html index f2fa759..1fc12d0 100644 --- a/src/templates/apps/gameboard/room.html +++ b/src/templates/apps/gameboard/room.html @@ -50,72 +50,7 @@ {% endif %} -
-
-
-
- {# ROLE card-stack — the gamer's own role pick stays #} - {# available even when their token cost has lapsed #} - {# (deposit-privilege grace, 7d), so it renders OUTSIDE #} - {# the cost gate below. #} - {% if room.table_status == "ROLE_SELECT" and card_stack_state %} -
- {% if card_stack_state == "ineligible" %} - - {% endif %} -
- {% endif %} - {% if not viewer_cost_current %} - {# Token cost lapsed → GATE VIEW supersedes SCAN SIGS #} - {# / CAST SKY / DRAW SEA / the sig waiting msg. The #} - {# gamer keeps their seat through the renewal grace; #} - {# GATE VIEW routes to the renewal gate-view. Only #} - {# the ROLE pick (above) survives. ` - {% else %} - {% if room.table_status == "SKY_SELECT" %} - {# Both phase btns render so the post-save cascade can #} - {# cross-fade CAST SKY → DRAW SEA in place (no reload). The #} - {# server sets --out on the inactive one; sky-select.js's #} - {# cascade swaps them. On a confirmed reload the server lands #} - {# DRAW SEA visible + CAST SKY out, same as the cascade end. #} -
- - -
- {% elif room.table_status == "SIG_SELECT" %} - - {% if polarity_done %} -

{% if user_polarity == "levity" %}Gravity settling . . .{% else %}Levity appraising . . .{% endif %}

- {% endif %} - {% endif %} - {% endif %} -
-
-
- {# Seats — fa-chair layout persists from ROLE_SELECT through SIG_SELECT #} - {% for pos in gate_positions %} -
- - {{ pos.role_label }} - {% if pos.role_label in starter_roles %} - - {% else %} - - {% endif %} -
- {% endfor %} -
+ {% include "core/_partials/_table_hex.html" with hex_center="apps/gameboard/_partials/_room_hex_center.html" hex_seats="apps/gameboard/_partials/_room_hex_seats.html" %} {# /.room-shell #} {# Sig Select stage — green-felt card stage + thumbnail grid, rendered #} diff --git a/src/templates/core/_partials/_table_hex.html b/src/templates/core/_partials/_table_hex.html new file mode 100644 index 0000000..4439405 --- /dev/null +++ b/src/templates/core/_partials/_table_hex.html @@ -0,0 +1,26 @@ +{% comment %} +Shared hexagonal game table — the .room-table-scene skeleton (border / hex / +center) + the seats ring. This 4-div nesting is byte-identical across room.html, +my_sea.html, my_sea_visit.html and billboard/my_sign.html, so it lives here once. + +The CENTER content and the SEATS loop vary per surface, and Django {% include %} +has no block/slot, so each caller passes them as partial NAMES: + + {% include "core/_partials/_table_hex.html" + with hex_center="apps/gameboard/_partials/_room_hex_center.html" + hex_seats="apps/gameboard/_partials/_room_hex_seats.html" %} + +`{% include hex_center %}` resolves the string var to a template and inherits the +full page context (no `only`), so each center/seats partial sees its page's vars +unchanged — the markup is identical to the pre-extraction inline blocks. +{% endcomment %} +
+
+
+
+ {% include hex_center %} +
+
+
+ {% include hex_seats %} +