Skip to content

feat(settings): adds navigation TOC and section grouping#106

Merged
wgordon17 merged 11 commits into
gordon-code:mainfrom
wgordon17:feat/settings-nav-toc
May 5, 2026
Merged

feat(settings): adds navigation TOC and section grouping#106
wgordon17 merged 11 commits into
gordon-code:mainfrom
wgordon17:feat/settings-nav-toc

Conversation

@wgordon17
Copy link
Copy Markdown
Member

@wgordon17 wgordon17 commented May 4, 2026

Summary

  • Adds sticky shrinking header, IntersectionObserver scroll-spy TOC sidebar (desktop) and dropdown (mobile)
  • Reorganizes 12 settings sections into 4 logical groups: Data Sources, Display, Integrations, Account
  • Uses JS-driven smooth scroll (rAF) for browser compatibility (Vivaldi, Chromium forks)
  • Hysteresis on header threshold prevents layout feedback oscillation

Closes #105

wgordon17 added 11 commits May 5, 2026 14:31
- Add optional id prop to Section component for scroll-spy targeting
- Assign stable IDs to all 12 Section usages in SettingsPage
- Reorder sections into 4 logical groups: Data Sources, Display,
  Integrations, Account
- Add group heading dividers between groups
- Export SETTINGS_PAGE_SECTION_IDS constant for test sync
- Fix existing tests to use getByRole('heading') for disambiguation
- Replaces Map.groupBy (ES2024) with manual reduce for browser compat
- Promotes displayedActiveId to createMemo
- Adds scrollend listener cleanup on unmount
- Adds aria-current='location' to active TOC items
- Adds aria-label to mobile toggle button
- Increases mobile touch target (btn-sm → btn, full width)
- Bumps mobile dropdown z-index from z-30 to z-40
- Removes redundant 'relative' class on mobile container
- Scopes mobile toggle test query with within()
When prefers-reduced-motion is active, scrollIntoView uses behavior
'instant' which completes synchronously. The scrollend event may not
fire in all browsers for instant scrolls, leaving scrollingTo stuck.
Uses requestAnimationFrame to clear in the next frame instead.
- Fixes closing tag indentation in two-column layout wrapper
- Adds animate-pulse to prefers-reduced-motion override
- Adds test verifying requestAnimationFrame is used for instant scroll
Object.defineProperty on window.innerHeight, scrollY, and
scrollHeight leaked between tests. Captures original values
and restores in afterEach to prevent cross-test contamination.
Native scrollIntoView({behavior: 'smooth'}) can be overridden by
browser settings (Vivaldi, some Chromium forks disable smooth scroll
at the engine level). Replaces with requestAnimationFrame-driven
eased scroll that works regardless of browser scroll settings.
Still uses scrollIntoView for instant scroll (reduced-motion).
The scroll listener that shrinks/expands the header was firing during
programmatic TOC scrolling, causing a feedback loop: scroll crosses
50px threshold → header resizes → content shifts → scroll position
changes → header resizes again. Uses a data-scrollLock attribute to
suppress header state updates during TOC-driven scroll animations.
Dispatches a synthetic scroll event on completion to sync final state.
Shrink at scrollY > 50, expand only at scrollY < 10. The 40px dead
zone absorbs the ~32px content shift from header padding change,
preventing the layout feedback loop where header resize triggers
scroll position change which re-triggers header resize.
Adds 'dependencies' to SETTINGS_SECTIONS (13 entries) to match
upstream's new Dependencies section in SettingsPage.
@wgordon17 wgordon17 force-pushed the feat/settings-nav-toc branch from b48e641 to 96a6c93 Compare May 5, 2026 18:34
@wgordon17 wgordon17 marked this pull request as ready for review May 5, 2026 18:44
@wgordon17 wgordon17 merged commit a08fa1d into gordon-code:main May 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Settings page needs sticky navigation and section TOC

1 participant