Add an alphabet index to the library page #15

Merged
kyuno merged 1 commit from feature/library-alphabet-index into master 2026-09-16 21:24:33 +02:00
Owner

Summary

  • After a mockup round (two variants proposed, "with section headings" picked), the library page now groups its already-alphabetical items into per-letter sections with a sticky heading, plus a right-edge A-Z rail to jump straight to one — tap or drag it, iOS Contacts-style, with a big letter bubble while dragging.
  • First-letter bucketing folds accents to their base letter (Écho → E), and rendering stays chunked (renderGroupedTilesInChunks, mirroring tiles.ts's own renderTilesInChunks) so a 1000+-item library doesn't block the main thread just because it's sectioned now too.
  • The rail and every section heading's sticky offset are measured live off .libraryHeader and the shell's .bottomStack (ResizeObserver, not a guessed constant) so neither the header wrapping to two lines nor a listen party's music bar floating at the bottom (desktop included) ever sits under/behind them.
  • renderLibrary changed shape to the synchronous-wrapper-returning-a-CleanupFn pattern views/player/Player.ts already uses, since the rail's ResizeObservers and window scroll/resize listeners need real teardown when navigating away — otherwise the exact leak class this app already fixed once elsewhere.
  • Empty letters (no items) render dimmed and inert. Searching hides a section's heading too once every tile under it is filtered out.

Base branch note: this stacks on feature/library-sticky-header (uses its .libraryHeader/Library.css), not master — that PR (#14) is still open. Per CLAUDE.md's sequential-PRs rule, this avoids two branches independently touching the same new files.

Test plan

  • npm run typecheck (client) — clean
  • npm run build (client) — clean
  • No Emby session available here, so verified against a synthetic harness instead: a throwaway esbuild bundle of alphaIndex.ts alone (deleted after) driven inside a page reproducing the real Shell/Library DOM + real compiled CSS.
    • A genuine browser click (not a script-dispatched event — those never register as an active pointer, so setPointerCapture only proves out under real input) on a rail letter jumped and highlighted correctly, zero console errors.
    • Dragging across several letters updated the active letter + bubble live at each step.
    • Tapping an empty letter highlighted it but left scroll position untouched.
    • Typing into the search box hid exactly the section headings left with no visible tiles, restored on clearing it.
    • Growing the (simulated) music bar's height live moved the rail's bottom edge with it, and back down again.
    • Calling the returned cleanup function stopped that last reaction cold, confirming the ResizeObservers were actually disconnected.
  • Not verified against a real Emby session/real touch device — flagged the same way in docs/architecture.md.

🤖 Generated with Claude Code

## Summary - After a mockup round (two variants proposed, "with section headings" picked), the library page now groups its already-alphabetical items into per-letter sections with a sticky heading, plus a right-edge A-Z rail to jump straight to one — tap or drag it, iOS Contacts-style, with a big letter bubble while dragging. - First-letter bucketing folds accents to their base letter (`Écho` → `E`), and rendering stays chunked (`renderGroupedTilesInChunks`, mirroring `tiles.ts`'s own `renderTilesInChunks`) so a 1000+-item library doesn't block the main thread just because it's sectioned now too. - The rail and every section heading's sticky offset are measured live off `.libraryHeader` and the shell's `.bottomStack` (`ResizeObserver`, not a guessed constant) so neither the header wrapping to two lines nor a listen party's music bar floating at the bottom (desktop included) ever sits under/behind them. - `renderLibrary` changed shape to the synchronous-wrapper-returning-a-`CleanupFn` pattern `views/player/Player.ts` already uses, since the rail's `ResizeObserver`s and `window` scroll/resize listeners need real teardown when navigating away — otherwise the exact leak class this app already fixed once elsewhere. - Empty letters (no items) render dimmed and inert. Searching hides a section's heading too once every tile under it is filtered out. **Base branch note**: this stacks on `feature/library-sticky-header` (uses its `.libraryHeader`/`Library.css`), not `master` — that PR (#14) is still open. Per CLAUDE.md's sequential-PRs rule, this avoids two branches independently touching the same new files. ## Test plan - [x] `npm run typecheck` (client) — clean - [x] `npm run build` (client) — clean - [x] No Emby session available here, so verified against a synthetic harness instead: a throwaway esbuild bundle of `alphaIndex.ts` alone (deleted after) driven inside a page reproducing the real Shell/Library DOM + real compiled CSS. - A genuine browser click (not a script-dispatched event — those never register as an active pointer, so `setPointerCapture` only proves out under real input) on a rail letter jumped and highlighted correctly, zero console errors. - Dragging across several letters updated the active letter + bubble live at each step. - Tapping an empty letter highlighted it but left scroll position untouched. - Typing into the search box hid exactly the section headings left with no visible tiles, restored on clearing it. - Growing the (simulated) music bar's height live moved the rail's bottom edge with it, and back down again. - Calling the returned cleanup function stopped that last reaction cold, confirming the `ResizeObserver`s were actually disconnected. - Not verified against a real Emby session/real touch device — flagged the same way in docs/architecture.md. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kyuno added 1 commit 2026-09-16 20:31:40 +02:00
Groups an already-alphabetical library into per-letter sections (accents
folded, so an item is bucketed under its base letter) with a sticky
heading before each - still one chunked-rendered grid, not a big
synchronous write, so a 1000+-item library stays smooth. The right-edge
rail jumps to a letter on tap or drag (pointer-capture, same shape as
the mobile nav sheet's own drag handle), dims letters with nothing in
them, and tracks the header/music-bar's real height instead of a
guessed offset so it never sits under either.

Stacked on feature/library-sticky-header (Library.css's .libraryHeader,
not yet merged) rather than master, per CLAUDE.md's sequential-PRs rule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
kyuno changed target branch from feature/library-sticky-header to master 2026-09-16 21:24:16 +02:00
kyuno merged commit b34e1ce8ff into master 2026-09-16 21:24:33 +02:00
kyuno deleted branch feature/library-alphabet-index 2026-09-16 21:24:33 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: kyuno/watchparty#15
No description provided.