game room title: GAME ROOM ⇄ GAME SCROLL reel on the scroll aperture — TDD
The h2's second slot becomes a two-word vertical reel: GAME stays put, ROOM rests in view, SCROLL is parked one notch below in the slot's bottom fade. room-scroll.js toggles `.is-scroll` on the h2 from the SAME IntersectionObserver that already watches the table-hex aperture's scroll pane — ROOM slides up & out under the navbar line while SCROLL rises out of the page-aperture gradient (reverses on scroll-up). Table-phase only; the gate phase stays a plain GAME ROOM. One translateY drives both orientations. Portrait: the word is a short horizontal row in a short slot. Landscape: writing-mode: vertical-rl (inherited from the rotated gutter wordmark) makes the word a tall letter-column, so the same translateY slides it ALONG the wordmark — the user-chosen landscape behaviour for free. Landscape uses a shallower --gr-fade + a letter inset so the space-between end-letters parked at the slot edges aren't dimmed by the dissolve. Motion is deliberately old & rusty: a single cubic-bezier can overshoot at most once and can't oscillate, so the easing is a CSS linear() curve — stall against the grime, jerk free, clunk PAST the mark, then a damped end-wobble into place. Exposed as --gr-ease / --gr-dur / --gr-fade knobs on .gr-swap. base.html's letter-splitter now also splits the two .gr-word words; the .gr-swap window ships data-letters-split="1" so the splitter skips it (no 'roomscroll' run). Reel SCSS is scoped to .gr-swap/.gr-word; `> span.gr-swap` ties `> span:last-child` at (0,4,3) and wins on later source order [[feedback-scss-import-order-specificity]]. TRAP: libsass does NOT strip `//` comments INSIDE a CSS custom-property value — they leak into the compiled output, making the linear() (hence the whole `transition` shorthand) invalid-at-computed-value-time, which silently resets to 0s/ease (no animation). Keep every annotation OUTSIDE the linear(). [[feedback-libsass-comment-in-custom-property]] Reusable .gr-swap seam: my_sea gets GAME SEA → GAME SCROLL via a one-line header swap once its sea-scroll pane is built (deferred — the sea scroll doesn't exist yet). Tests: 2 ITs (RoomScrollOfEventsTest) — reel markup renders in the table phase, stays plain in the gate phase; 1 FT (test_scroll_swaps_room_title_to_scroll) — scrolling the aperture toggles GAME ROOM ⇄ GAME SCROLL both ways. collectstatic'd room-scroll.js for the FT [[feedback-collectstatic-before-ft]]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -128,6 +128,39 @@ class RoomScrollOfEventsTest(FunctionalTest):
|
||||
By.CSS_SELECTOR, "#id_room_menu .room-menu-default a.btn-cancel"
|
||||
).is_displayed())
|
||||
|
||||
def test_scroll_swaps_room_title_to_scroll(self):
|
||||
"""Scrolling the aperture to the feed advances the page-title reel
|
||||
GAME ROOM → GAME SCROLL (the <h2> gains `.is-scroll`, which the reel
|
||||
CSS uses to slide the words); scrolling back to the hex reverses it."""
|
||||
self._open()
|
||||
# Both reel words ship in the header; the window starts at the hex.
|
||||
self.assertTrue(
|
||||
self.browser.find_elements(By.CSS_SELECTOR, ".gr-word--base"))
|
||||
self.assertTrue(
|
||||
self.browser.find_elements(By.CSS_SELECTOR, ".gr-word--scroll"))
|
||||
h2 = self.browser.find_element(By.CSS_SELECTOR, ".row .col-lg-6 h2")
|
||||
self.assertNotIn("is-scroll", h2.get_attribute("class") or "")
|
||||
|
||||
# Scroll down to the feed → the reel advances to GAME SCROLL.
|
||||
self.browser.execute_script(
|
||||
"document.querySelector('.room-aperture').scrollTop = 99999;")
|
||||
self.wait_for(lambda: self.assertIn(
|
||||
"is-scroll",
|
||||
self.browser.find_element(
|
||||
By.CSS_SELECTOR, ".row .col-lg-6 h2"
|
||||
).get_attribute("class") or "",
|
||||
))
|
||||
|
||||
# Scroll back up to the hex → the reel reverses to GAME ROOM.
|
||||
self.browser.execute_script(
|
||||
"document.querySelector('.room-aperture').scrollTop = 0;")
|
||||
self.wait_for(lambda: self.assertNotIn(
|
||||
"is-scroll",
|
||||
self.browser.find_element(
|
||||
By.CSS_SELECTOR, ".row .col-lg-6 h2"
|
||||
).get_attribute("class") or "",
|
||||
))
|
||||
|
||||
def test_redact_filter_hides_struck_rows(self):
|
||||
"""Unchecking Redact + OK in the scroll-view gear hides the struck
|
||||
(retracted) rows while the framed ones stay."""
|
||||
|
||||
Reference in New Issue
Block a user