feat(slint): labels and similar artists sections in the sidebar
Extracts the two Qobuz-driven sidebar sections from /artist/page data
the artist controller already receives and wires them into the
NetworkSidebar.
Controller (`crates/qbz-slint/src/artist.rs`):
- Labels collected during the existing release-bucketing loop,
matching Tauri's extractLabelsFromPageReleases: only the "album"
release group, only releases attributed to this artist, dedupe by
label id, sorted by name. Each label exposes {id, name}.
- Similar artists pulled from page.similar_artists.items as
{id, name}. No artwork on the sidebar rows (Tauri only renders a
User icon + name there).
- ArtistData / ArtistState gained `labels` and `similar_artists`;
reset_artist clears them on artist change.
Slint (`ui/state.slint`, `ui/artist/ArtistPageView.slint`):
- New LabelEntry and SimilarEntry structs alongside ArtistState.
- New SidebarLink local component — small leading icon (12px) +
elided name, surface-elevated hover, mirrors Tauri's
`.sidebar-artist-link`. Used by Labels (Disc), Similar (User),
and the upcoming Relationships rows.
- Labels section: title + items or "No label info" placeholder.
- Similar Artists section: title + items, with "Loading…" while
the artist page itself is loading and "No similar artists found"
once loaded with an empty list.
main.rs:
- on_artist_clicked now navigates: records nav history and calls
navigate_artist, same flow as the top-level on_open_artist. The
target view exists in Slint already (unlike LabelReleases /
ArtistsByLocation / MusicianPage, which stay logged-only).
cc
This commit is contained in:
4 files changed
+244
-8
No files matched your search
@@ -211,6 +211,55 @@ component SectionTitle inherits Text {
|
||||
font-weight: Typography.semibold;
|
||||
}
|
||||
|
||||
// One row in the network sidebar — small leading icon + name. Used by
|
||||
// Labels (Disc icon), Similar Artists / Members / Discovery (User
|
||||
// icon), and Member-Of groups (Music icon). Mirrors Tauri's
|
||||
// `.sidebar-artist-link` rendering.
|
||||
component SidebarLink inherits Rectangle {
|
||||
in property <string> label;
|
||||
in property <image> icon;
|
||||
in property <string> tooltip;
|
||||
callback clicked();
|
||||
|
||||
height: 28px;
|
||||
border-radius: 4px;
|
||||
background: link-ta.has-hover ? Theme.surface-elevated : transparent;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
spacing: 8px;
|
||||
alignment: stretch;
|
||||
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
horizontal-stretch: 0;
|
||||
QbzIcon {
|
||||
source: root.icon;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
tint: link-ta.has-hover ? Theme.text-primary : Theme.text-muted;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.label;
|
||||
color: link-ta.has-hover ? Theme.text-primary : Theme.text-secondary;
|
||||
font-size: 13px;
|
||||
overflow: elide;
|
||||
vertical-alignment: center;
|
||||
horizontal-stretch: 1;
|
||||
}
|
||||
}
|
||||
|
||||
link-ta := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export component ArtistPageView inherits Rectangle {
|
||||
callback open-album(string);
|
||||
callback media-action(string, string, string);
|
||||
@@ -768,6 +817,76 @@ export component ArtistPageView inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Labels (Qobuz, deduped from own albums) ---
|
||||
VerticalLayout {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 6px;
|
||||
spacing: 4px;
|
||||
|
||||
Text {
|
||||
text: @tr("LABELS");
|
||||
color: Theme.text-muted;
|
||||
font-size: 11px;
|
||||
font-weight: Typography.semibold;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
if ArtistState.labels.length == 0: Text {
|
||||
text: @tr("No label info");
|
||||
color: Theme.text-muted;
|
||||
font-size: 12px;
|
||||
}
|
||||
for label in ArtistState.labels: SidebarLink {
|
||||
label: label.name;
|
||||
icon: @image-url("../assets/icons/disc.svg");
|
||||
tooltip: label.name;
|
||||
clicked => {
|
||||
NetworkSidebarActions.label-clicked(
|
||||
label.id, label.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Similar Artists (Qobuz) ---
|
||||
VerticalLayout {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 6px;
|
||||
spacing: 4px;
|
||||
|
||||
Text {
|
||||
text: @tr("SIMILAR ARTISTS");
|
||||
color: Theme.text-muted;
|
||||
font-size: 11px;
|
||||
font-weight: Typography.semibold;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
if ArtistState.similar-artists.length == 0
|
||||
&& !ArtistState.loading: Text {
|
||||
text: @tr("No similar artists found");
|
||||
color: Theme.text-muted;
|
||||
font-size: 12px;
|
||||
}
|
||||
if ArtistState.similar-artists.length == 0
|
||||
&& ArtistState.loading: Text {
|
||||
text: @tr("Loading…");
|
||||
color: Theme.text-muted;
|
||||
font-size: 12px;
|
||||
}
|
||||
for similar in ArtistState.similar-artists: SidebarLink {
|
||||
label: similar.name;
|
||||
icon: @image-url("../assets/icons/user.svg");
|
||||
tooltip: similar.name;
|
||||
clicked => {
|
||||
NetworkSidebarActions.artist-clicked(similar.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user