mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-10 18:59:56 +00:00
feat(v3 library): A–Z fast-scroll jump rail on the Songs grid (#634)
* feat(v3 library): A–Z fast-scroll jump rail on the Songs grid Adds a vertical letter rail (Plex/Radarr/iOS-contacts pattern) pinned to the right edge next to the scrollbar so you can jump the library to a starting letter — tap, drag-to-scrub with a live letter bubble, or arrow-key between letters. The classic (v2) tree already had letter selection; this brings the new v3 grid to parity (it was the gap behind the "alphabetical scroll selection next to the scrollbar" idea). It shows ONLY for the grid view + alphabetical (artist/title) sorts, and only offers letters present in the current sort AND filter set, so a tap always lands on a real card (absent letters are dimmed + non-interactive). The grid is forward-only, server-paged infinite scroll with no virtualization, so a jump pages through to the target card then scrolls to it; a token guards overlapping jumps (drag) so the newest wins. A keyset-seek + virtualized window is the scaling follow-up for very large libraries. Backend: /api/library/stats gains an optional `sort` param and an additive `sort_letters` map — songs-per-first-letter of the ACTIVE sort column (artist or title), filter-synced — so the rail's present-letters match the grid's real order. The legacy `letters` (distinct-artist) field is unchanged, so the dashboard + classic tree are unaffected. `sort` is dropped for providers whose query_stats predates it (existing kwarg-filter), so third-party library providers keep working (rail simply falls back / hides). Frontend: static/v3/songs.js (refreshRail / jumpToLetter / pointer-drag + keyboard, cards tagged data-letter), static/v3/v3.css (.v3-azrail + bubble). Tests: tests/test_library_filters.py (sort_letters artist/title, song-vs- distinct-artist counting), tests/test_library_providers.py (sort forwarded), tests/js/v3_az_rail.test.js (gating, data-letter, load-through, drag/keys). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF * fix(v3 library): harden A–Z jump rail (review P2/P3) Addresses the PR #634 review findings (manual + Codex): P2 correctness - refreshRail prefers the active-sort `sort_letters`; falls back to the artist-based `letters` only on an artist sort, and hides the rail on a title sort when a legacy provider returns none (was mislabeling letters). - reload() bumps `_jumpToken` so an in-flight letter jump can't scroll a grid that's being rebuilt from page 0. - songBucket no longer trims, matching the server SQL + grid ORDER BY raw first-char bucketing (a leading-space title now buckets under '#' on both sides). P3 polish - Paging guard is total-derived (ceil(total/PAGE_SIZE)+2) instead of a magic 4000, keeping large libraries reachable while still bounded. - Roving tabindex: only the first present letter is tabbable; arrow keys move it. Removes up to 27 page tab stops. - `sort_letters` is computed only when the caller opts in (want_sort_letters / route `sort_letters=1`); the dashboard + v2 tree skip the extra GROUP BY. Added sort + want_sort_letters to the optional provider-kwargs so non-introspectable legacy providers drop them. - _railToken supersedes stale refreshRail responses; hide the rail when no letters are present instead of rendering disabled buttons. Tests updated accordingly (v3_az_rail.test.js, test_library_filters.py). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: byrongamatos <xasiklas@gmail.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
byrongamatos
parent
b29bab1884
commit
6a71577e05
@@ -1117,3 +1117,75 @@ html.fb-immersive #v3-main > .screen.active {
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* — A–Z jump rail (v3 Songs grid; static/v3/songs.js) — */
|
||||
/* Fixed to the right edge next to the scroller's scrollbar; vertically
|
||||
centered. Shown only for the grid view + alphabetical (artist/title) sorts. */
|
||||
.v3-azrail {
|
||||
position: fixed;
|
||||
right: 2px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 25;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-height: 84vh;
|
||||
padding: 4px 1px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
touch-action: none; /* let a drag scrub the rail without scrolling the page */
|
||||
}
|
||||
.v3-azrail-letter {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background: none;
|
||||
border: 0;
|
||||
color: #94a3b8; /* fb-textDim */
|
||||
font-size: .62rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.05;
|
||||
padding: 1px 4px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.v3-azrail-letter:hover:not([disabled]),
|
||||
.v3-azrail-letter.is-active {
|
||||
color: #0ea5e9; /* fb-primary */
|
||||
}
|
||||
.v3-azrail-letter:focus-visible {
|
||||
outline: 2px solid #38bdf8; /* fb-primaryHi */
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.v3-azrail-letter[disabled] {
|
||||
color: rgba(148, 163, 184, .28);
|
||||
cursor: default;
|
||||
}
|
||||
/* Drag indicator bubble (Android fast-scroll pattern). */
|
||||
.v3-azbubble {
|
||||
position: fixed;
|
||||
right: 2.6rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 26;
|
||||
width: 2.6rem;
|
||||
height: 2.6rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: .7rem;
|
||||
background: #0ea5e9; /* fb-primary */
|
||||
color: #f8fafc; /* fb-text */
|
||||
font-size: 1.15rem;
|
||||
font-weight: 800;
|
||||
box-shadow: 0 6px 22px rgba(0, 0, 0, .45);
|
||||
pointer-events: none;
|
||||
}
|
||||
.v3-azrail.hidden,
|
||||
.v3-azbubble.hidden { display: none; }
|
||||
/* Coarse-pointer / short viewports: the 27-letter rail can crowd a phone edge.
|
||||
Tighten it; a collapse-to-anchors pass is a follow-up. */
|
||||
@media (max-height: 640px) {
|
||||
.v3-azrail-letter { font-size: .55rem; padding: 0 4px; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user