The wiki editor's Save row stays on screen, Back returns to where you were, and the frame stops scrolling under itself (#1023, #1017) #1028

Merged
claude-bot merged 5 commits from fix/1023-editor-save-row-back-scroll into main 2026-10-02 04:03:22 +00:00
Collaborator

Closes #1023. Closes #1017. Six layout faults seen while checking the footer change (#1024), all older than it, and one flaky test.

The wiki editor's Save row left the screen

.ed-actions is position: sticky; bottom: 0, but it sat in the middle of the form, after the text and before Facts, Timeline, Stat block, Picture and Relationships. A sticky row pins only while its natural place is still below the window, so it scrolled away once you passed it. It is now the last thing in the editor: pinned at the bottom of the window throughout, and settling above the footer at the end. (It saves the text, fields, facts and timeline; Picture, Relationships and Owners write through their own buttons, as before.)

Back returned short

useScrollRestoration set scrollTop once on the POP, before the page had loaded its content, so the browser clamped it; and the scroll listener then remembered the clamped value over the real one. It now keeps re-applying the saved position as the page grows, until it is reachable, the reader scrolls (wheel, touch, pointer on the scroller, a key), the route changes, or ten seconds pass; and it does not record positions while it is restoring.

The window scrolled under the frame

A visually hidden element is position: absolute. Its nearest positioned ancestor was .app, not the scroller, so the scroller did not clip it and it added to the document's height. .book__scroll is now position: relative, and .app.qb-frame is overflow: clip.

The bell's panel scrolled inside itself

The same cause, one level in: each row's hidden " — unread" was positioned against .menu, which made the panel taller than its box, and an overflow: hidden box can still be scrolled by focus, as "Show older" does. .menu__scroll and .menu__panel are position: relative, and .menu is overflow: clip.

Smaller

  • The bell and Contents buttons are 44×44 on a coarse pointer and at the phone width (the bell was 36 wide).
  • A footer line never ends in a "·": each separator stays with the link after it.

The flaky test (#1017)

SheetHot › sets the temporary hit points when the number is left failed 3 runs in 30. The box's sync-from-server effect also ran on mount; when the test's change landed before that effect flushed, the effect put "0" back and the blur saw nothing to save. The effect now runs only when the server's value actually changes. 0 failures in 70 runs after. Not reachable by a person: the effect already skips a focused box.

Checked

  • Full vitest on the merged tree: 3710 passed, 1 skipped; eslint 0 errors. No backend change.
  • Rendered in e2e stacks at 390×844 (touch) and 1440×900, light and dark (over 150 shots), and looked at:
    • the editor's row pinned at top, middle and lower sections and settled 72px above the footer at the end; the caret of the lowest field visible above it; the new-page editor likewise;
    • Back: a session's Review tab returned to 1200 and Admin's Audit log to 700 (they were 974 and 0), at both widths; a wheel scroll 300ms after Back was not overridden; Forward goes to the top;
    • document.scrollHeight equals the window on sixteen page and width combinations and window.scrollTo does nothing; the skip link, account menu, bell panel, search results, Contents sheet, Tools sheet and drawers, the shelf's Move menu, a modal and Table mode are all unclipped;
    • the bell: panel scrollHeight = clientHeight, "Show older" moves focus to the first new row by scrolling the list and never the panel, the head and foot stay put, a scripted scroll of the panel reads back 0, every focus ring whole; the other menus the same; arrow keys through a ten-result list keep the row in view;
    • the phone bar's buttons 44×44, desktop unchanged; the footer's lines at 390, 430, 520 and 1440;
    • the temporary hit points box posts once and keeps its value.
  • No journey needed changing.

Seen, not fixed here

A wiki article's "See it as…" menu hangs 30px off the left of a 390px screen (filed separately).

🤖 Generated with Claude Code

Closes #1023. Closes #1017. Six layout faults seen while checking the footer change (#1024), all older than it, and one flaky test. ## The wiki editor's Save row left the screen `.ed-actions` is `position: sticky; bottom: 0`, but it sat in the middle of the form, after the text and before Facts, Timeline, Stat block, Picture and Relationships. A sticky row pins only while its natural place is still below the window, so it scrolled away once you passed it. It is now the last thing in the editor: pinned at the bottom of the window throughout, and settling above the footer at the end. (It saves the text, fields, facts and timeline; Picture, Relationships and Owners write through their own buttons, as before.) ## Back returned short `useScrollRestoration` set `scrollTop` once on the POP, before the page had loaded its content, so the browser clamped it; and the scroll listener then remembered the clamped value over the real one. It now keeps re-applying the saved position as the page grows, until it is reachable, the reader scrolls (wheel, touch, pointer on the scroller, a key), the route changes, or ten seconds pass; and it does not record positions while it is restoring. ## The window scrolled under the frame A visually hidden element is `position: absolute`. Its nearest positioned ancestor was `.app`, not the scroller, so the scroller did not clip it and it added to the document's height. `.book__scroll` is now `position: relative`, and `.app.qb-frame` is `overflow: clip`. ## The bell's panel scrolled inside itself The same cause, one level in: each row's hidden " — unread" was positioned against `.menu`, which made the panel taller than its box, and an `overflow: hidden` box can still be scrolled by focus, as "Show older" does. `.menu__scroll` and `.menu__panel` are `position: relative`, and `.menu` is `overflow: clip`. ## Smaller - The bell and Contents buttons are 44×44 on a coarse pointer and at the phone width (the bell was 36 wide). - A footer line never ends in a "·": each separator stays with the link after it. ## The flaky test (#1017) `SheetHot › sets the temporary hit points when the number is left` failed 3 runs in 30. The box's sync-from-server effect also ran on mount; when the test's change landed before that effect flushed, the effect put "0" back and the blur saw nothing to save. The effect now runs only when the server's value actually changes. 0 failures in 70 runs after. Not reachable by a person: the effect already skips a focused box. ## Checked - Full vitest on the merged tree: **3710 passed, 1 skipped**; eslint 0 errors. No backend change. - Rendered in e2e stacks at 390×844 (touch) and 1440×900, light and dark (over 150 shots), and looked at: - the editor's row pinned at top, middle and lower sections and settled 72px above the footer at the end; the caret of the lowest field visible above it; the new-page editor likewise; - Back: a session's Review tab returned to 1200 and Admin's Audit log to 700 (they were 974 and 0), at both widths; a wheel scroll 300ms after Back was not overridden; Forward goes to the top; - `document.scrollHeight` equals the window on sixteen page and width combinations and `window.scrollTo` does nothing; the skip link, account menu, bell panel, search results, Contents sheet, Tools sheet and drawers, the shelf's Move menu, a modal and Table mode are all unclipped; - the bell: panel `scrollHeight` = `clientHeight`, "Show older" moves focus to the first new row by scrolling the list and never the panel, the head and foot stay put, a scripted scroll of the panel reads back 0, every focus ring whole; the other menus the same; arrow keys through a ten-result list keep the row in view; - the phone bar's buttons 44×44, desktop unchanged; the footer's lines at 390, 430, 520 and 1440; - the temporary hit points box posts once and keeps its value. - No journey needed changing. ## Seen, not fixed here A wiki article's "See it as…" menu hangs 30px off the left of a 390px screen (filed separately). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge remote-tracking branch 'origin/main' into fix/1023-editor-save-row-back-scroll
All checks were successful
CI / Backend lint (ruff) (pull_request) Successful in 42s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m11s
CI / Bot/backend version sync (pull_request) Successful in 36s
CI / Feedback site tests (pull_request) Successful in 49s
CI / Does this change touch the recording path? (pull_request) Successful in 29s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Bot tests and audit (pull_request) Successful in 2m4s
CI / Docker image build (pull_request) Successful in 1m19s
CI / Frontend (shard 2/2) (pull_request) Successful in 8m11s
CI / Frontend (shard 1/2) (pull_request) Successful in 9m50s
CI / End-to-end journeys (phone) (pull_request) Successful in 9m36s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 10m21s
CI / End-to-end journeys (desktop) (pull_request) Successful in 20m45s
CI / Backend migration, tests, and audit (pull_request) Successful in 23m6s
271a05267e
Sign in to join this conversation.
No description provided.