// Radio / Top-Tracks card — port of Tauri's RadioCardLite. A 180px // tile: a square "display" with the seed artwork centered and a // wordmark label ("RADIO" / "TOP TRACKS") over it, then a title + // subtitle below. Hover reveals a play button. // // The Tauri version derives the panel colour from the artwork's // dominant palette; that palette extraction is omitted here (a // neutral elevated panel stands in), the rest matches. import { Theme } from "../foundation/semantic-colors.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; import { QbzIcon } from "../primitives/QbzIcon.slint"; export component RadioCard inherits Rectangle { in property seed-title; in property seed-subtitle; in property label: "RADIO"; in property artwork; callback clicked(); callback play(); // Matches AlbumCard / PlaylistCard (200 x 246): panel 200 + 8 + meta. width: 200px; height: 246px; VerticalLayout { spacing: 8px; // Display panel. panel := Rectangle { width: 200px; height: 200px; border-radius: Radius.sm; background: Theme.surface-elevated; clip: true; // Centered artwork "display". Rectangle { width: 126px; height: 126px; x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px - 8px; border-radius: 4px; background: Theme.surface-card; clip: true; Image { width: 100%; height: 100%; source: root.artwork; image-fit: cover; } } // Wordmark over the display, bottom. Text { text: root.label; color: #ffffffe6; font-size: 15px; font-weight: Typography.bold; letter-spacing: 2px; x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: parent.height - self.height - 16px; } // Hover overlay + play. Rectangle { width: 100%; height: 100%; background: #000000; opacity: ta.has-hover || play-ta.has-hover ? 0.45 : 0.0; animate opacity { duration: 150ms; } } play-circle := Rectangle { width: 44px; height: 44px; border-radius: 22px; background: #ffffff; x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; opacity: ta.has-hover || play-ta.has-hover ? 1.0 : 0.0; animate opacity { duration: 150ms; } QbzIcon { source: @image-url("../assets/icons/play-fill.svg"); width: 18px; height: 18px; x: Math.round((parent.width - self.width) / 2 / 1px) * 1px; y: Math.round((parent.height - self.height) / 2 / 1px) * 1px; tint: #000000; } play-ta := TouchArea { mouse-cursor: pointer; clicked => { root.play(); } } } ta := TouchArea { mouse-cursor: pointer; clicked => { root.clicked(); } } } // Meta. Text { text: root.seed-title; color: Theme.text-primary; font-size: Typography.body; font-weight: Typography.medium; overflow: elide; width: 200px; } if root.seed-subtitle != "": Text { text: root.seed-subtitle; color: Theme.text-muted; font-size: Typography.legal; overflow: elide; width: 200px; } } }