// Artist card — ported 1:1 from the Tauri SearchView `.artist-card`: // 160x220 tile inside a surface-card container, with a 120px circular // avatar (gradient placeholder), centered name, and an optional Follow // chip (rectangular per ADR-008) shown only when the user does not yet // follow the artist. import { Theme } from "../foundation/semantic-colors.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; import { SlimItem } from "../state.slint"; import { QbzIcon } from "../primitives/QbzIcon.slint"; export component ArtistCard inherits Rectangle { in property artist; // Follow-chip behavior: // "auto" show only when NOT following (artist search default); // "toggle" always show, reflecting Follow/Following (label more-labels); // "none" never show (label artists carousel — no follow there). in property follow-mode: "auto"; // kind passed in the follow media-action ("artist" | "label"). in property follow-kind: "artist"; callback clicked(string); // kind ("artist" | "label"), id, action ("follow"). callback media-action(string, string, string); width: 160px; height: 220px; border-radius: 12px; background: ta.has-hover ? Theme.surface-elevated : Theme.surface-card; animate background { duration: 150ms; } ta := TouchArea { mouse-cursor: pointer; clicked => { root.clicked(root.artist.id); } } VerticalLayout { padding: 16px; spacing: 12px; alignment: start; // 120px circular avatar with a soft gradient placeholder. HorizontalLayout { alignment: center; Rectangle { width: 120px; height: 120px; border-radius: 60px; clip: true; background: @linear-gradient( 135deg, Theme.surface-elevated 0%, Theme.surface-card 100%); QbzIcon { source: @image-url("../assets/icons/user.svg"); width: 38px; height: 38px; x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; tint: Theme.text-muted; } Image { width: 100%; height: 100%; source: root.artist.artwork; image-fit: cover; } } } Text { text: root.artist.title; width: 128px; color: Theme.text-primary; font-size: 14px; font-weight: Typography.medium; horizontal-alignment: center; overflow: elide; } // Rectangular Follow / Following chip (ADR-008 — no pills). See // `follow-mode`: "auto" shows it only when not yet following, // "toggle" always shows it (and reflects the state), "none" hides it. if (root.follow-mode == "auto" && !root.artist.following) || root.follow-mode == "toggle": HorizontalLayout { alignment: center; spacing: 0px; Rectangle { width: chip-row.preferred-width; height: 28px; border-radius: Radius.sm; background: follow-ta.has-hover ? Theme.surface-hover : Theme.surface-elevated; animate background { duration: 150ms; } chip-row := HorizontalLayout { padding-left: 12px; padding-right: 12px; spacing: 6px; VerticalLayout { alignment: center; QbzIcon { source: root.artist.following ? @image-url("../assets/icons/check.svg") : @image-url("../assets/icons/user-plus.svg"); width: 13px; height: 13px; tint: Theme.text-primary; } } Text { text: root.artist.following ? @tr("Following") : @tr("Follow"); color: Theme.text-primary; font-size: 12px; font-weight: Typography.medium; vertical-alignment: center; } } follow-ta := TouchArea { mouse-cursor: pointer; clicked => { root.media-action(root.follow-kind, root.artist.id, "follow"); } } } } } }