Add OverlayScrollArea with shared thumb metrics and drag handling; size the
thumb against the rail track height so panel insets cannot push it past the
visible rail. Route scroll uses a stable viewport id; Genres restores scroll
and infinite-scroll observation against that viewport (merged with upstream
virtualized genres list and lazy routes behind Suspense).
Suppress queue resizer activation when the pointer targets the main-route
overlay scrollbar; disable the resizer while dragging the thumb and use a
grabbing cursor on the body.
Apply WebKitGTK smooth wheel to the mini webview as well as main; the mini
window reapplies the persisted setting after auth store hydration.
Reported: opening the Genres page after a cold start froze the UI for
up to 30 seconds with a 500-genre Subsonic library. The page itself
was structurally trivial (one getGenres() call, sort, render) but each
card mounted a Lucide watermark SVG at size=80 — 500 complex SVGs
reconciled in one batch was the actual blocker, especially when other
cold-start useEffects were still draining the main thread.
Two changes:
- Pagination via IntersectionObserver, PAGE_SIZE 60. First paint mounts
~88% fewer cards; the observer pulls the next batch in 1500px ahead
so the user never sees the end. Same pattern Albums.tsx uses.
- useMemo for the sort. Without it, every unrelated re-render
(theme change, sidebar toggle) re-sorted all 500 entries.
Scroll-restore extended to also persist visibleCount in sessionStorage
so coming back from a GenreDetail page lands the user on a grid that
still contains the row they scrolled to.
Confirmed locally on a 500-genre library: page now renders instantly
on cold start.
Co-authored-by: Psychotoxical <dev@psysonic.app>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Sidebar.tsx: title={} → data-tooltip + data-tooltip-pos="right" on
scope subtitle (CLAUDE.md rule: never use native title= for tooltips)
- authStore.ts: merge two set() calls in setMusicFolders into one atomic
update — avoids double render on folder list arrival
- locales (all 7): remove dead libraryScopeHint key (defined but never
rendered in any component)
- Genres.tsx: remove musicLibraryFilterVersion from effect deps —
getGenres is intentionally not folder-scoped, re-fetching on filter
change was a no-op waste
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Apply musicFolderId across Subsonic requests, bump a filter version so library views reload, and add a fixed-position sidebar dropdown (with capped height when there are many folders).