web-player: cards and grids (MediaCard)

MediaCard now builds its own art (src/trackIds via Artwork
size="fill", or a custom art snippet) and its own play button
(onPlay, with a scrim and a glass PlayButton on hover) instead of
relying on each wrapper passing it a snippet. Replaces AlbumCard,
PlaylistCard and MixTile, which are removed along with
MediaGrid.svelte (their grids move to the
grid-cards/grid-cards-lg/grid-tiles/grid-wide @utility recipes).

format.ts gains albumMeta() and playlistMeta() (previously ad-hoc
calculations inside each card). Explore's genre tile moves from an
inline style= gradient to the genre-tile @utility recipe +
--tile-hue. Along the way, fixes the "follower/s" pluralization on
the user profile that had been missed.

Delta documented: the art's hover-zoom and the scrim+PlayButton
(previously exclusive to MixTile) become MediaCard behavior gated on
the onPlay prop — they'll apply to any future card that uses it, for
consistency.

Verified with npm run check/build; no authenticated visual QA (Docker
unavailable this session).
This commit is contained in:
2026-09-21 00:30:30 +02:00
parent 8cea298b2a
commit 964dfc809f
13 changed files with 126 additions and 221 deletions
@@ -378,13 +378,12 @@
{#if !data.query}
<!-- GÉNEROS -->
<div class="mt-7 grid grid-cols-[repeat(auto-fill,minmax(268px,1fr))] gap-3.5">
<div class="mt-7 grid-wide">
{#each genreTiles as genre, i (genre.query)}
<a
href={searchHref(genre.query)}
class="animate-enter group relative flex h-28 flex-col gap-1 overflow-hidden rounded-2xl p-4.25 transition-[filter] hover:brightness-110"
style="animation-delay:{Math.min(i, 10) *
40}ms; background:linear-gradient(140deg, oklch(var(--mf-tile-l) var(--mf-tile-c) {genre.hue}), oklch(var(--mf-tile-shade-l) var(--mf-tile-shade-c) {genre.hue}))"
class="animate-enter group relative flex h-28 flex-col gap-1 overflow-hidden rounded-panel p-4.25 transition-[filter] genre-tile hover:brightness-110"
style="--i:{i}; --tile-hue:{genre.hue}"
>
<div class="text-on-art">
{genre.label}