feat(slint): sticky JUMP TO bar, search toggle, View less
Three follow-on refinements after the layout restructure.
JUMP TO bar (`ui/primitives/JumpNavBar.slint`):
- New reusable component — same shape Tauri ships above
section-rich pages (artist, library, future label / musician
views): "JUMP TO" label, horizontal list of tabs with an accent
underline on the active one, search icon on the right.
- Presentation-only — sticky positioning is the parent's
responsibility. Tabs and search icon emit callbacks; reuse by
passing a fresh tab list and routing the callbacks.
Artist page wiring:
- JumpNavBar mounted as an overlay sibling of the page Flickable
with the same sticky math as the sidebar: y =
`max(290px + page-flickable.viewport-y, 0px)`. At rest the bar
sits below the artist header; once the user scrolls past the
header, it pins to the top of the page. (This is the reusable
sticky recipe the user asked for — it's wired here for artist
and lifts straight into the next section that needs it.)
- jump-tabs hardcoded with About / Popular Tracks / Discography /
EPs & Singles / Compilations / Playlists — same labels as
Tauri. tab-clicked updates the active-tab visual state; actual
scroll-to-section wiring is a follow-up (needs anchor positions
that depend on per-artist data).
- search-visible flag flips on the bar's search-clicked. The
existing in-page search input is now gated by it, so the search
is closed by default (matches Tauri's `.page-search.open`
behaviour) and opens on click of the JUMP TO bar's search icon.
Popular Tracks "View less":
- The Load more affordance now flips its label to "View less" once
expanded so users can collapse back to the 5-track preview
without scrolling. A small improvement over the Tauri flow
(which only shows Load more).
cc
This commit is contained in:
2 files changed
+204
-9
No files matched your search
@@ -25,6 +25,7 @@ import { TrackContextMenu } from "../primitives/TrackContextMenu.slint";
|
||||
import { LoadingSpinner } from "../primitives/LoadingSpinner.slint";
|
||||
import { ReleaseGrid } from "ReleaseGrid.slint";
|
||||
import { NavButtons } from "../shell/NavButtons.slint";
|
||||
import { JumpNavBar, JumpNavTab } from "../primitives/JumpNavBar.slint";
|
||||
|
||||
component CircleAction inherits Rectangle {
|
||||
in property <image> icon;
|
||||
@@ -268,6 +269,24 @@ export component ArtistPageView inherits Rectangle {
|
||||
// Whether the full-biography modal is open. Mirrors the album
|
||||
// description Read-more pattern in AlbumPageView.
|
||||
property <bool> show-bio: false;
|
||||
// Whether the in-page search input is currently visible.
|
||||
// Closed by default; the JUMP TO bar's search icon toggles it.
|
||||
property <bool> search-visible: false;
|
||||
// Active JUMP TO tab. Currently set by tab-clicked only — a
|
||||
// future pass will compute it from scroll position so the bar
|
||||
// self-tracks the visible section.
|
||||
property <string> active-jump-tab: "popular-tracks";
|
||||
// Static tab list — same labels Tauri uses. The Slint tabs trigger
|
||||
// scroll-to-section via tab-clicked; until the section anchors are
|
||||
// wired, the click just updates the active state.
|
||||
property <[JumpNavTab]> jump-tabs: [
|
||||
{ id: "about", label: "About" },
|
||||
{ id: "popular-tracks", label: "Popular Tracks" },
|
||||
{ id: "discography", label: "Discography" },
|
||||
{ id: "eps-singles", label: "EPs & Singles" },
|
||||
{ id: "compilations", label: "Compilations" },
|
||||
{ id: "playlists", label: "Playlists" },
|
||||
];
|
||||
// Width handed down to the bio paragraph. The artist header sits
|
||||
// above the body row where the sidebar lives, so the bio never
|
||||
// needs to shrink for the sidebar — it always uses the full
|
||||
@@ -484,10 +503,11 @@ export component ArtistPageView inherits Rectangle {
|
||||
// --- In-page search ---------------------------------------------
|
||||
// Single client-side substring filter — applied to Popular
|
||||
// Tracks (title + artist) and to every release-section
|
||||
// album title. Same pattern as Tauri's `.page-search` plus
|
||||
// the AlbumActions.search wiring AlbumPageView uses for
|
||||
// its track list.
|
||||
if !ArtistState.loading || ArtistState.top-tracks.length > 0:
|
||||
// album title. Hidden by default; the JUMP TO bar's search
|
||||
// icon toggles `search-visible` (mirrors Tauri's search
|
||||
// toggle inside `.jump-nav`).
|
||||
if root.search-visible
|
||||
&& (!ArtistState.loading || ArtistState.top-tracks.length > 0):
|
||||
Rectangle {
|
||||
height: 36px;
|
||||
border-radius: Radius.sm;
|
||||
@@ -605,9 +625,11 @@ export component ArtistPageView inherits Rectangle {
|
||||
root.media-action(kind, id, action);
|
||||
}
|
||||
}
|
||||
// Load more — visible when there are more than the preview cap.
|
||||
if !root.top-tracks-expanded
|
||||
&& ArtistState.top-tracks.length > root.top-tracks-preview: HorizontalLayout {
|
||||
// Load more / View less — same affordance, label flips
|
||||
// with the expanded state. Tauri only shows Load more;
|
||||
// View less is a Slint-side improvement so users can
|
||||
// collapse back to the 5-track preview without scrolling.
|
||||
if ArtistState.top-tracks.length > root.top-tracks-preview: HorizontalLayout {
|
||||
alignment: start;
|
||||
Rectangle {
|
||||
width: load-more-text.preferred-width + 32px;
|
||||
@@ -619,7 +641,9 @@ export component ArtistPageView inherits Rectangle {
|
||||
? Theme.surface-elevated
|
||||
: Theme.surface-card;
|
||||
load-more-text := Text {
|
||||
text: @tr("Load more");
|
||||
text: root.top-tracks-expanded
|
||||
? @tr("View less")
|
||||
: @tr("Load more");
|
||||
color: Theme.text-secondary;
|
||||
font-size: 13px;
|
||||
x: (parent.width - self.width) / 2;
|
||||
@@ -628,7 +652,7 @@ export component ArtistPageView inherits Rectangle {
|
||||
load-more-ta := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
root.top-tracks-expanded = true;
|
||||
root.top-tracks-expanded = !root.top-tracks-expanded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -660,6 +684,30 @@ export component ArtistPageView inherits Rectangle {
|
||||
} // close page VerticalLayout
|
||||
} // close Flickable
|
||||
|
||||
// --- Sticky JUMP TO bar -------------------------------------------------
|
||||
// Overlay anchored to the top of ArtistPageView with the same
|
||||
// sticky math as the sidebar: tracks the page scroll until the
|
||||
// user scrolls past the header, then pins to y = 0. The natural
|
||||
// y is the row just below the artist header in the page layout
|
||||
// (NavButtons + spacer + artist header + small gap, ~290px).
|
||||
jump-nav := JumpNavBar {
|
||||
property <length> natural-top: 290px;
|
||||
property <length> sticky-top: 0px;
|
||||
|
||||
x: 0;
|
||||
y: max(self.natural-top + page-flickable.viewport-y, self.sticky-top);
|
||||
width: root.width;
|
||||
tabs: root.jump-tabs;
|
||||
active-tab-id: root.active-jump-tab;
|
||||
search-open: root.search-visible;
|
||||
tab-clicked(id) => {
|
||||
root.active-jump-tab = id;
|
||||
}
|
||||
search-clicked => {
|
||||
root.search-visible = !root.search-visible;
|
||||
}
|
||||
}
|
||||
|
||||
// Network sidebar — overlay anchored to the right edge of the
|
||||
// ArtistPageView, with sticky-style y positioning so it tracks
|
||||
// the page scroll while the header is visible and then pins
|
||||
|
||||
Reference in new issue
Block a user