feat(slint): jump-nav scroll-to-section + hide empty tabs + UX fixes

Brings the JUMP TO bar from a visual placeholder to a working nav,
plus two interaction fixes the user flagged on the previous build.

JUMP TO bar — functional scroll-to:
  - JumpNavTab gains an `anchor-y: length` field. JumpNavBar's
    tab-clicked callback now emits (id, anchor-y); the parent
    (ArtistPageView) scrolls page-flickable to land the section
    just below the sticky bar.
  - Tab list is built in Rust (`build_jump_tabs` in artist.rs)
    from the artist's actual data and pushed to a new
    `ArtistState.jump-tabs` model. Tabs are emitted only for
    sections that exist (top tracks present, "Discography" /
    "EPs & Singles" / "Live Albums" / "Compilations" / "Others"
    only when the corresponding release_sections entry is there);
    the Playlists tab — not implemented yet — never appears.
  - anchor-y estimates use layout-derived constants per section
    type (popular-tracks header + visible row count, release grid
    headers + ceil(album_count / 5) rows). Not pixel-perfect for
    long bios or grids that wrap differently, but lands the
    viewport inside the right section.
  - Removed the hardcoded ArtistPageView property — tabs and
    visibility are now data-driven.

Sticky positioning — dynamic:
  - jump-nav.natural-top now binds to
    `body-row.absolute-position.y - page-flickable.absolute-y -
    self.height`, so the bar always sits flush in the gap above
    the body row regardless of artist-header height (long-bio
    artists stop pushing the row out from under the bar).
  - Sidebar natural-top follows the same body-row anchor, so it
    too tracks where the body actually starts.

Search input UX:
  - The outer search-icon slot is now removed from layout (via
    `if !search-open`, not `visible:`) when the input opens, so
    the expanded input runs all the way to the bar's right
    padding — right under the user's cursor where the lupa just
    was, no leftover gap on the right.
  - `changed search-open` auto-focuses the inline TextInput, so
    typing starts immediately after clicking the lupa with no
    second click in the input.

cc
This commit is contained in:
vicrodh committed 2026-05-20 14:20:47 -06:00
1 parent 3429fe4ee2
commit 06a763443a
4 files changed
+146 -38

No files matched your search

+8
View File
@@ -3,6 +3,9 @@
// The Rust side builds these models on a worker thread, then sets them
// on the global from the Slint event loop (see src/home.rs, src/main.rs).
import { JumpNavTab } from "primitives/JumpNavBar.slint";
export { JumpNavTab }
export struct AlbumCardItem {
id: string,
title: string,
@@ -231,6 +234,11 @@ export global ArtistState {
// Similar artists from the /artist/page response — feed the Similar
// Artists section of the network sidebar.
in property <[SimilarEntry]> similar-artists: [];
// Filtered JUMP TO tabs for this artist — only the sections
// that actually have content. Built in artist::apply_artist
// from the page response. anchor-y is the page-local y the
// ArtistPageView will scroll to when the tab is clicked.
in property <[JumpNavTab]> jump-tabs: [];
in property <bool> loading: false;
}