feat(slint): release sections render as wrapping grids, not carousels
Tauri's artist page lays Discography / EPs & Singles / Live Albums /
Compilations / Others as grids that wrap into rows — never as
horizontally paginated carousels. The Slint port was reusing the
Discover Carousel here, which paginated horizontally and hid most of
the discography behind chevrons.
New `ui/artist/ReleaseGrid.slint`, modeled on `discover/GridSection`:
- Same DiscoverSection input + album-clicked / media-action
callbacks the Carousel exposed, so swapping is one import + one
component name in ArtistPageView.
- Card grid uses absolute positioning inside a sized Rectangle so a
`for` can render a flow that Slint's layout primitives don't
support directly. Columns recompute on resize:
max(1, floor((width + gap) / (card_width + gap)))
Card sizes match the Carousel for visual continuity (220x266 +
24px gap), so the wider viewport lands ~5 cards per row, the
narrower one ~2.
- Header shows the section title and the count next to it
(mirrors Tauri's `<count>` badge); no sort dropdown yet — per-
section sorting can land in a follow-up.
cc
This commit is contained in:
2 files changed
+75
-2
No files matched your search
@@ -22,7 +22,7 @@ import { ContextMenuItem } from "../primitives/ContextMenuItem.slint";
|
||||
import { TrackPlayCell } from "../primitives/TrackPlayCell.slint";
|
||||
import { TrackContextMenu } from "../primitives/TrackContextMenu.slint";
|
||||
import { LoadingSpinner } from "../primitives/LoadingSpinner.slint";
|
||||
import { Carousel } from "../discover/Carousel.slint";
|
||||
import { ReleaseGrid } from "ReleaseGrid.slint";
|
||||
import { NavButtons } from "../shell/NavButtons.slint";
|
||||
|
||||
component CircleAction inherits Rectangle {
|
||||
@@ -569,7 +569,7 @@ export component ArtistPageView inherits Rectangle {
|
||||
for section in ArtistState.release-sections: VerticalLayout {
|
||||
spacing: 0px;
|
||||
Rectangle { height: 32px; }
|
||||
Carousel {
|
||||
ReleaseGrid {
|
||||
section: section;
|
||||
album-clicked(id) => {
|
||||
root.open-album(id);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Wrapping grid of AlbumCards for the artist page's release sections
|
||||
// (Discography, EPs & Singles, Live Albums, Compilations, Others).
|
||||
//
|
||||
// The Tauri artist view lays these as grids — never as horizontally
|
||||
// paginated carousels — so a long discography wraps into rows and the
|
||||
// whole shape stays scannable. Pattern mirrors `discover/GridSection`:
|
||||
// absolute positioning inside a Rectangle whose height comes from the
|
||||
// row count, computed once per resize.
|
||||
|
||||
import { Theme } from "../foundation/semantic-colors.slint";
|
||||
import { Typography } from "../foundation/typography.slint";
|
||||
import { DiscoverSection } from "../state.slint";
|
||||
import { AlbumCard } from "../discover/AlbumCard.slint";
|
||||
|
||||
export component ReleaseGrid inherits VerticalLayout {
|
||||
in property <DiscoverSection> section;
|
||||
callback album-clicked(string);
|
||||
callback media-action(string, string, string);
|
||||
|
||||
property <length> card-width: 220px;
|
||||
property <length> card-height: 266px;
|
||||
property <length> gap: 24px;
|
||||
property <int> count: root.section.albums.length;
|
||||
|
||||
spacing: 12px;
|
||||
|
||||
// --- Header: title + count -------------------------------------------
|
||||
HorizontalLayout {
|
||||
Text {
|
||||
text: root.section.title;
|
||||
color: Theme.text-primary;
|
||||
font-size: Typography.heading;
|
||||
font-weight: Typography.semibold;
|
||||
vertical-alignment: center;
|
||||
horizontal-stretch: 1;
|
||||
}
|
||||
if root.count > 0: Text {
|
||||
text: " " + root.count;
|
||||
color: Theme.text-muted;
|
||||
font-size: Typography.body;
|
||||
font-weight: Typography.regular;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Grid: absolute-positioned cards inside a sized Rectangle --------
|
||||
grid := Rectangle {
|
||||
// Columns recomputed per resize so the grid flows from 5 wide
|
||||
// at large viewports down to 2 on narrow ones.
|
||||
property <int> columns: Math.max(
|
||||
1,
|
||||
Math.floor((self.width + root.gap) / (root.card-width + root.gap)));
|
||||
property <int> rows: Math.ceil(root.count / self.columns);
|
||||
|
||||
height: self.rows > 0
|
||||
? self.rows * root.card-height + Math.max(0, self.rows - 1) * root.gap
|
||||
: 0px;
|
||||
|
||||
for album[i] in root.section.albums: AlbumCard {
|
||||
x: Math.mod(i, grid.columns) * (root.card-width + root.gap);
|
||||
y: Math.floor(i / grid.columns) * (root.card-height + root.gap);
|
||||
width: root.card-width;
|
||||
height: root.card-height;
|
||||
album: album;
|
||||
clicked(id) => {
|
||||
root.album-clicked(id);
|
||||
}
|
||||
media-action(kind, id, action) => {
|
||||
root.media-action(kind, id, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user