feat(slint): discover home loading skeleton + paginated slim carousels
Three of the four Discover > Home quick-wins. Loading skeleton (#1): - New HomeSkeleton replaces the spinner + "Loading your music…" text shown while the first fetch is in flight. Grey placeholder blocks shaped like two real carousels (title bar + a row of square art with two text lines), gently pulsing via a shared 900ms Timer phase + animate opacity — no more artifact titles during load. Recently Played Tracks + Popular albums (#3, #4): - New SlimCarousel: a paginated 4x3 slim-card grid (12 per page), capped at two pages, sliding one viewport width per page. The prev/next controls only appear when there is a second page (>12 items); 12 or fewer renders as a single static page with no arrows. Replaces the old non-paginated GridSection that grew into a tall wall of rows. - home.rs caps `recent` and `popular` to 24 items (two pages) so the carousel never has hidden overflow; the Popular/Recent artwork-job indices are unchanged. GridSection is retained — the artist ReleaseGrid still uses it. Note on #2 (Recently Played Albums "spurious AlbumCard"): there is only one AlbumCard component (discover/AlbumCard.slint, used by 5 call sites incl. this carousel via Carousel) — no duplicate to delete. The cards look bare because the local play-history store keeps only id/title/artist/artwork (no quality/year/ribbon), not because of a different component. cc
This commit is contained in:
4 files changed
+218
-22
No files matched your search
@@ -0,0 +1,70 @@
|
||||
// Loading skeleton for the Discover home — grey placeholder blocks
|
||||
// shaped like the real carousels, gently pulsing (fade in/out) while
|
||||
// the first fetch is in flight. Replaces the spinner + "Loading…"
|
||||
// text so the first paint reads as the page filling in rather than a
|
||||
// generic loader.
|
||||
|
||||
import { Theme } from "../foundation/semantic-colors.slint";
|
||||
import { Radius } from "../foundation/radius.slint";
|
||||
|
||||
// A single shimmering block. Opacity breathes between two values on a
|
||||
// shared phase so the whole skeleton pulses in unison.
|
||||
component Shimmer inherits Rectangle {
|
||||
in property <bool> phase;
|
||||
background: Theme.surface-elevated;
|
||||
border-radius: Radius.sm;
|
||||
opacity: root.phase ? 0.85 : 0.4;
|
||||
animate opacity { duration: 900ms; easing: ease-in-out; }
|
||||
}
|
||||
|
||||
// One placeholder carousel: a short title bar over a row of card
|
||||
// blocks (square art + two text lines).
|
||||
component SkeletonRow inherits VerticalLayout {
|
||||
in property <bool> phase;
|
||||
in property <length> card-size: 220px;
|
||||
spacing: 12px;
|
||||
|
||||
Shimmer {
|
||||
phase: root.phase;
|
||||
width: 180px;
|
||||
height: 22px;
|
||||
}
|
||||
HorizontalLayout {
|
||||
spacing: 32px;
|
||||
for _ in [0, 1, 2, 3, 4]: VerticalLayout {
|
||||
spacing: 8px;
|
||||
Shimmer {
|
||||
phase: root.phase;
|
||||
width: root.card-size;
|
||||
height: root.card-size;
|
||||
}
|
||||
Shimmer {
|
||||
phase: root.phase;
|
||||
width: root.card-size * 0.7;
|
||||
height: 14px;
|
||||
}
|
||||
Shimmer {
|
||||
phase: root.phase;
|
||||
width: root.card-size * 0.45;
|
||||
height: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export component HomeSkeleton inherits VerticalLayout {
|
||||
property <bool> phase: false;
|
||||
spacing: 40px;
|
||||
|
||||
// Drives the shared breathing phase.
|
||||
Timer {
|
||||
interval: 900ms;
|
||||
running: true;
|
||||
triggered => {
|
||||
root.phase = !root.phase;
|
||||
}
|
||||
}
|
||||
|
||||
SkeletonRow { phase: root.phase; }
|
||||
SkeletonRow { phase: root.phase; }
|
||||
}
|
||||
Reference in new issue
Block a user