feat(ui): F8-09 — turn report sticky icon-popup section menu #67
Reference in New Issue
Block a user
Delete Branch "feature/issue-52-report-toc-popup"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Закрываю F8-09 (#52, зонтичный #43). Переписала меню разделов turn report
в sticky icon-popup паттерне: в правом верхнем углу колонки отчёта
висит липкая кнопка
≡ <название активного раздела>, по клику —anchored popover на десктопе и bottom-sheet ниже 768.98px (стиль
повторяет
lib/active-view/map-toggles.svelte). Колонка-сайдбар на14rem ушла, отчёт теперь занимает всю ширину контейнера; кнопка
«Back to map» удалена из отчёта (она уже есть в главном выпадающем
меню, тест на это живёт в
tests/e2e/game-shell.spec.ts).Highlights
report-toc.svelte— sticky-триггер с CSS-ellipsis на лейбле +restoreFocus+ Escape/outside-click; scrollIntoView отложен на rAF,иначе focus-restore на sticky-триггер прерывает только что начатый
scroll в Chromium/WebKit.
report.svelte— grid → flex-column.game.report.back_to_mapиgame.report.toc.mobile_label;добавлены
game.report.toc.open/close(зеркалятgame.map.toggles.*).десктоп и оба mobile-проекта зелёные локально.
ui/docs/report-view.md,docs/FUNCTIONAL.md(+ru) —заодно вычистила устаревшее упоминание SvelteKit
SnapshotAPI.Test plan
pnpm checkзелёно (1567 файлов, 0 ошибок)pnpm testзелёно (821/821)pnpm buildчистоpnpm test:e2e report-sections— 4 проекта зелёныеpnpm test:e2e game-shell— 39 passed (Back-to-map через view-menu)go-unit+ui-test+integration)Refs: #52 (#43 umbrella).
- Replace the 14 rem sticky sidebar (and its mobile <select> twin) with a single sticky icon-popup trigger pinned to the top-right corner of the report column. Trigger shows `≡` followed by the currently active section title (CSS-clamped with text-overflow: ellipsis so long RU titles cannot bloat the button). Click opens an anchored popover on desktop and a fixed bottom-sheet on <768.98 px (mirrors lib/active-view/map-toggles.svelte). - Each menuitem closes the popover and scrolls the matching `<section id="report-<slug>">` into view. The scroll is deferred one animation frame so the surface unmount + restoreFocus's focus restoration on the (sticky) trigger commit first; otherwise the focus call could cancel the just-started smooth/instant scroll under desktop Chromium and WebKit. - Drop the in-report "Back to map" button — the same affordance lives in the app-shell view menu (tests/e2e/game-shell.spec.ts covers it). - Tighten the report grid to a single flex column so the section body now occupies the full container width. - i18n: remove game.report.back_to_map and game.report.toc.mobile_label; add game.report.toc.open and game.report.toc.close (mirrors game.map.toggles.open/close). - Tests: Vitest report-toc.test.ts rewritten for the new icon-popup contract; Playwright report-sections.spec.ts switches the anchor loop to trigger → menuitem and adds a mobile bottom-sheet assertion; game-shell-stubs.test.ts no longer asserts the back-to-map button on the report orchestrator. - Docs: ui/docs/report-view.md (TOC + i18n + test seams) and docs/FUNCTIONAL{,_ru}.md §6.4 updated. The stale SvelteKit Snapshot reference (the route file was removed by the single-URL app-shell) is dropped at the same time. Refs: #52 (#43 umbrella). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Owner-reported regressions in Firefox + Safari on desktop after the initial F8-09 patch landed: 1. The TOC trigger rode up with the page during scroll instead of staying pinned to the viewport (mobile worked, desktop did not). 2. Clicking a popover item scrolled the matching section so its heading went up under the chrome — only the table body was visible. Root cause for (1): the in-game shell declares `overflow-y: auto` on `.active-view-host` so mobile (where `.game-shell` is fixed at `inset: 0`) has an internal scroll region. On desktop the host grows with content, no overflow ever engages, and the document body becomes the actual scroll container. Per CSS spec the host remains the "scrollport" for any `position: sticky` descendant, so the trigger inside the report column never sees the scroll event and rides up with the body content. Fix: - Swap the trigger from `position: sticky` to `position: fixed`. The component is mounted only while the report active view is on screen, so the fixed element is naturally tied to the view's lifetime. Anchor at `top: 4rem` (below the in-game header), and on `min-width: 1024px` shift `right` by 18 rem to clear the always-on sidebar; below 1024 px the sidebar is an overlay so the default `right: 1.25rem` matches the report's right padding. - Add `padding-top: 4.5rem` to `.report-view` (4rem mobile) so the first section heading does not land under the trigger at scroll position 0. - Add `scroll-margin-top: 7.5rem` to every `<section id="report-…">` so `scrollIntoView({ block: "start" })` lands the heading below the trigger after a popover-driven jump. - Sync `ui/docs/report-view.md` §"Table of contents and active highlight" with the new positioning rationale. Tests: `pnpm check`, `pnpm test` (821), `pnpm test:e2e report-sections` (4 projects) all green. Refs: #52 (#43 umbrella). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>