diff --git a/src/apps/epic/tests/integrated/test_views.py b/src/apps/epic/tests/integrated/test_views.py index 81adc15..212029a 100644 --- a/src/apps/epic/tests/integrated/test_views.py +++ b/src/apps/epic/tests/integrated/test_views.py @@ -714,6 +714,22 @@ class PositionTooltipRenderTest(TestCase): self.assertNotIn(self.gamers[1].email, content) # g2@test.io self.assertNotIn(self.viewer.email, content) # disco@test.io + def test_gate_view_circles_never_fade_when_roles_assigned(self): + # The gatekeeper's GATE VIEW is the canonical "who holds which + # position" surface: it must ALWAYS show all six circles, even after + # gamers get seated and the main table-hex has faded their circles away + # one-by-one (the role-assigned animation). So when every role is + # assigned — the moment SCAN SIGS appears on the hex — the gate view + # keeps all six circles solid, with NO role-assigned (fade-out) class. + roles = ["PC", "NC", "EC", "SC", "AC", "BC"] + for i, gamer in enumerate(self.gamers, start=1): + TableSeat.objects.create( + room=self.room, gamer=gamer, slot_number=i, role=roles[i - 1], + ) + content = self._gate_content() + self.assertEqual(content.count('class="gate-slot'), 6) + self.assertNotIn("role-assigned", content) + class PositionTooltipCarteRenderTest(TestCase): """CARTE-solo render contract: a single gamer owns all six slots — their diff --git a/src/templates/apps/gameboard/_partials/_table_positions.html b/src/templates/apps/gameboard/_partials/_table_positions.html index 989bd2c..7395d52 100644 --- a/src/templates/apps/gameboard/_partials/_table_positions.html +++ b/src/templates/apps/gameboard/_partials/_table_positions.html @@ -6,9 +6,13 @@ {# appended AFTER `role-assigned` so the `gate-slot filled role-assigned` #} {# substring (RoleSelectRenderingTest) stays intact, and `class` stays first #} {# (before data-slot) for the class-attr regex IT. #} +{# `persist_circles` (passed True by room_gate.html) suppresses the #} +{# role-assigned fade-out so the GATE VIEW always keeps all six circles — #} +{# the disappear-as-seated animation is a table-hex-only cue. Undefined #} +{# (→ falsy) on the room.html include, which keeps the animation. #}
{% for pos in gate_positions %} -
{{ pos.slot.slot_number }} {% if pos.slot.gamer %}{{ pos.slot.gamer|at_handle }}{% else %}empty{% endif %} diff --git a/src/templates/apps/gameboard/room_gate.html b/src/templates/apps/gameboard/room_gate.html index 7640a6b..f74ec58 100644 --- a/src/templates/apps/gameboard/room_gate.html +++ b/src/templates/apps/gameboard/room_gate.html @@ -83,7 +83,11 @@ {# Position circles + their hover tooltips — the gate-view rendered no #} {# circles before this sprint (the headline gap). Reuses the shared #} {# _table_positions partial fed by the merged _gate_context. #} - {% include "apps/gameboard/_partials/_table_positions.html" %} + {# persist_circles=True keeps ALL six circles solid here: the gatekeeper #} + {# is the canonical "who holds which position" surface, so it must never #} + {# fade a circle away as roles get assigned (the role-assigned animation #} + {# is the TABLE-HEX cue only). They stay up to + including SCAN SIGS. #} + {% include "apps/gameboard/_partials/_table_positions.html" with persist_circles=True %} {% include "apps/gameboard/_partials/_position_tooltip.html" %} {# NVM nav-backs one step to the table hex (not out to /gameboard/). #}