room scroll-of-events: applet-box card styling + scroll-driven gear menu (Frame/Redact filter) — TDD
The room scroll pane now matches scroll.html: the feed sits in a .applet-scroll %applet-box card with the rotated room-name title; dropped the special --duoUser pane bg (the dark card sits on the room-page bg). Gear menu is now view-aware. #id_room_menu carries two panes: .room-menu-default (the existing NVM/DEL/BYE) + .room-menu-scroll (a Frame/Redact #id_scroll_filter_form, rendered only when the gear include gets scroll_filter — room.html passes scroll_filter=room.table_status). room-scroll.js (NEW) runs an IntersectionObserver on .room-scroll-pane (root=#id_room_aperture): scrolled to the feed -> show the filter pane; back on the hex -> show the default. The filter mirrors scroll.html (per-room localStorage, toggles .drama-event[data-label] display). Buffer-dots animation moved from the inline partial script into room-scroll.js. Other views keep their own menus, as asked: GATE VIEW (room_gate.html) includes _room_gear.html with nvm_url only (no scroll_filter, no room-scroll.js) -> NVM(->hex)/DEL/BYE; the cross/spread phase is a modal over the hex (scrollTop 0) -> default pane. Traps: applets.js caches gear.dataset.menuTarget at bind time, so you can't swap a gear's target to a 2nd menu — both panes live in ONE #id_room_menu and JS toggles visibility. .room-menu-default is display:contents so wrapping the existing controls doesn't change their layout (JS toggles none<->contents, not ''). Tests: +3 ITs (RoomScrollOfEventsTest — .applet-scroll card + room-name title, filter pane renders in table phase, filter absent in gate phase); +2 FTs (test_game_room_scroll — gear swaps to filter when scrolled to feed, unchecking Redact+OK hides struck rows). 8 scroll ITs + 4 scroll FTs green; 554 epic ITs/UTs green; gatekeeper DEL+BYE gear FTs green (the .room-menu-default wrap is layout-neutral). [[project-room-scroll-of-events]] Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3354,3 +3354,32 @@ class RoomScrollOfEventsTest(TestCase):
|
||||
).content.decode()
|
||||
self.assertNotIn("room-scroll-pane", content)
|
||||
self.assertNotIn("is-scrollable", content)
|
||||
|
||||
def test_scroll_pane_uses_applet_box_card_with_room_name(self):
|
||||
"""The feed sits in an `.applet-scroll` card (same %applet-box chrome as
|
||||
the Billscroll page), with the room name as its rotated title."""
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn("applet-scroll", content)
|
||||
# The rotated <h2> title inside the card carries the room name.
|
||||
self.assertIn("<h2>Whataburgher</h2>", content)
|
||||
|
||||
def test_scroll_gear_filter_renders_in_table_phase(self):
|
||||
"""From Role Select onwards the gear menu carries BOTH panes: the
|
||||
default NVM/DEL/BYE (`.room-menu-default`) and the Frame/Redact log
|
||||
filter (`.room-menu-scroll`), swapped by scroll position client-side."""
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn("room-menu-default", content)
|
||||
self.assertIn("room-menu-scroll", content)
|
||||
self.assertIn("id_scroll_filter_form", content)
|
||||
self.assertIn('value="frame"', content)
|
||||
self.assertIn('value="redact"', content)
|
||||
|
||||
def test_scroll_gear_filter_absent_in_gate_phase(self):
|
||||
"""The gate phase has no scroll, so no Frame/Redact filter pane — the
|
||||
gear keeps only its NVM/DEL/BYE menu."""
|
||||
gate_room = Room.objects.create(name="Gatehouse", owner=self.user)
|
||||
content = self.client.get(
|
||||
reverse("epic:gatekeeper", args=[gate_room.id])
|
||||
).content.decode()
|
||||
self.assertNotIn("room-menu-scroll", content)
|
||||
self.assertNotIn("id_scroll_filter_form", content)
|
||||
|
||||
Reference in New Issue
Block a user