From 58eb670fed851d8ec885fe9669e7781a24fef729 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Sun, 20 Sep 2026 22:39:05 +0200 Subject: [PATCH] web-player: unify Artwork and Avatar Add src/lib/components/ui/Artwork.svelte and Avatar.svelte (B.3) and migrate every use of Cover, PlaylistArt, MixArt and ArtistAvatar (Sidebar, Queue, TrackInfo, TrackContextMenu, AlbumContextMenu, TrackTitleCell, AlbumCard, PlaylistCard, MixTile, AlbumHeader, PlaylistHeader, Home, Explore, mix, user profile, TopBar, MobileHeader). Remove the 4 old components. Artwork: size decides both dimension and radius automatically (cover-*/radius tokens from the earlier token pass); fallback chain is src -> mosaic (>=4 trackIds) -> first cover -> placeholder, cascading if each step fails (previously split across 3 components with slightly different logic each). Adds a 'fill' size (aspect-square w-full), not in the spec, needed for fluid grid cards until MediaCard lands later. TrackTitleCell's `coverSize` prop (free-form Tailwind classes) becomes `size: 'sm'|'lg'`, delegating to Artwork. SearchResultRow loses its `kind` prop and the per-type radius (now decided by Artwork/Avatar). Product decision (not blocking): remove the name under the profile avatar on /u/[id] since it duplicated the CollectionHeader title. Small radius/size deltas are documented in the plan's README (auto-radius by size replaces ad-hoc classes; see table B.1.1/B.1.2). Verified with npm run check/build; no authenticated visual QA (Docker unavailable this session). --- web-player/docs/frontend-refactor-plan.md | 2 +- .../lib/components/AlbumContextMenu.svelte | 11 +- .../src/lib/components/MobileHeader.svelte | 11 +- web-player/src/lib/components/Sidebar.svelte | 13 +- web-player/src/lib/components/TopBar.svelte | 18 ++- .../lib/components/TrackContextMenu.svelte | 11 +- .../src/lib/components/player/Queue.svelte | 21 +-- .../lib/components/player/TrackInfo.svelte | 12 +- .../src/lib/components/ui/AlbumCard.svelte | 9 +- .../src/lib/components/ui/ArtistAvatar.svelte | 36 ----- .../src/lib/components/ui/Artwork.svelte | 133 ++++++++++++++++++ .../src/lib/components/ui/Avatar.svelte | 60 ++++++++ web-player/src/lib/components/ui/Cover.svelte | 47 ------- .../src/lib/components/ui/MixArt.svelte | 25 ---- .../src/lib/components/ui/MixTile.svelte | 23 +-- .../src/lib/components/ui/PlaylistArt.svelte | 61 -------- .../src/lib/components/ui/PlaylistCard.svelte | 10 +- .../lib/components/ui/SearchResultRow.svelte | 15 +- .../lib/components/ui/TrackTitleCell.svelte | 16 +-- .../albums/[id]/components/AlbumHeader.svelte | 9 +- .../src/routes/(app)/explore/+page.svelte | 76 ++++------ .../src/routes/(app)/mixes/[id]/+page.svelte | 9 +- .../[id]/components/PlaylistHeader.svelte | 12 +- .../src/routes/(app)/u/[id]/+page.svelte | 4 +- web-player/src/routes/+page.svelte | 41 +++--- 25 files changed, 326 insertions(+), 359 deletions(-) delete mode 100644 web-player/src/lib/components/ui/ArtistAvatar.svelte create mode 100644 web-player/src/lib/components/ui/Artwork.svelte create mode 100644 web-player/src/lib/components/ui/Avatar.svelte delete mode 100644 web-player/src/lib/components/ui/Cover.svelte delete mode 100644 web-player/src/lib/components/ui/MixArt.svelte delete mode 100644 web-player/src/lib/components/ui/PlaylistArt.svelte diff --git a/web-player/docs/frontend-refactor-plan.md b/web-player/docs/frontend-refactor-plan.md index 8dc5a0c..502a994 100644 --- a/web-player/docs/frontend-refactor-plan.md +++ b/web-player/docs/frontend-refactor-plan.md @@ -775,7 +775,7 @@ Tareas: | P0 | ✅ | (pendiente) | Button primary/secondary se mantienen iguales (decisión del usuario) | | P1 | ✅ | (pendiente) | Verificado con `build` (Tailwind compila `@apply sm:` dentro de `@utility`); sin QA visual autenticada (Docker no disponible en esta sesión) | | P2 | ✅ | (pendiente) | `` no interpola en Svelte (se trata como CSS del componente); solución: `{@html \`\`}` | -| P3 | ⬜ | | | +| P3 | ✅ | (pendiente) | Se quitó el nombre bajo el avatar de perfil (decisión tomada: redundante con el título de CollectionHeader). Se añadió `size="fill"` a Artwork (no está en la spec) para las tarjetas de grid fluidas (AlbumCard/PlaylistCard/MixTile), ya que P9 (MediaCard) aún no existe. SearchResultRow perdió su prop `kind`/radio-por-tipo (ahora el radio lo decide Artwork/Avatar). Sin QA visual autenticada (Docker no disponible) | | P4 | ⬜ | | | | P5 | ⬜ | | | | P6 | ⬜ | | | diff --git a/web-player/src/lib/components/AlbumContextMenu.svelte b/web-player/src/lib/components/AlbumContextMenu.svelte index d55609e..d0a8bd1 100644 --- a/web-player/src/lib/components/AlbumContextMenu.svelte +++ b/web-player/src/lib/components/AlbumContextMenu.svelte @@ -20,7 +20,7 @@ import ChevronRight from '@lucide/svelte/icons/chevron-right'; import ListPlus from '@lucide/svelte/icons/list-plus'; import ListEnd from '@lucide/svelte/icons/list-end'; - import PlaylistArt from '$lib/components/ui/PlaylistArt.svelte'; + import Artwork from '$lib/components/ui/Artwork.svelte'; import GlassMenu from '$lib/components/ui/GlassMenu.svelte'; interface Props { @@ -99,11 +99,10 @@ type="submit" class="flex w-full items-center gap-3 rounded-control px-2 py-2.5 text-left text-sm font-medium text-fg transition hover:bg-hover" > - {playlist.name} diff --git a/web-player/src/lib/components/MobileHeader.svelte b/web-player/src/lib/components/MobileHeader.svelte index 24aef1d..ae1c0c5 100644 --- a/web-player/src/lib/components/MobileHeader.svelte +++ b/web-player/src/lib/components/MobileHeader.svelte @@ -5,6 +5,7 @@ import LogIn from '@lucide/svelte/icons/log-in'; import MenuItem from './ui/MenuItem.svelte'; import AccountMenu from './ui/AccountMenu.svelte'; + import Avatar from './ui/Avatar.svelte'; interface Props { user: SessionUser | null; @@ -40,15 +41,7 @@ aria-expanded={open} class="flex items-center rounded-full" > - {#if user.picture} - - {:else} - - {user.name.charAt(0)} - - {/if} + {/snippet} {#snippet extraItems({ close })} diff --git a/web-player/src/lib/components/Sidebar.svelte b/web-player/src/lib/components/Sidebar.svelte index 1e2a797..8824a7b 100644 --- a/web-player/src/lib/components/Sidebar.svelte +++ b/web-player/src/lib/components/Sidebar.svelte @@ -4,7 +4,7 @@ import { liked } from '$lib/player/liked.svelte'; import { createPlaylistModal } from '$lib/playlists.svelte'; import type { SessionUser } from '$lib/types'; - import PlaylistArt from './ui/PlaylistArt.svelte'; + import Artwork from './ui/Artwork.svelte'; import Home from '@lucide/svelte/icons/house'; import Compass from '@lucide/svelte/icons/compass'; import ListMusic from '@lucide/svelte/icons/list-music'; @@ -97,12 +97,13 @@ ? 'bg-surface-hover' : 'hover:bg-hover'}" > -
diff --git a/web-player/src/lib/components/TopBar.svelte b/web-player/src/lib/components/TopBar.svelte index b8bc201..12566e6 100644 --- a/web-player/src/lib/components/TopBar.svelte +++ b/web-player/src/lib/components/TopBar.svelte @@ -8,6 +8,7 @@ import ChevronLeft from '@lucide/svelte/icons/chevron-left'; import ChevronRight from '@lucide/svelte/icons/chevron-right'; import AccountMenu from './ui/AccountMenu.svelte'; + import Avatar from './ui/Avatar.svelte'; interface Props { user: SessionUser | null; @@ -113,17 +114,14 @@ onclick={toggle} aria-label="Tu cuenta" aria-expanded={open} - class="block h-8.25 w-8.25 shrink-0 overflow-hidden rounded-full border border-line-strong transition active:scale-95" + class="block shrink-0 rounded-full transition active:scale-95" > - {#if user.picture} - - {:else} - - {user.name.charAt(0)} - - {/if} + {/snippet} diff --git a/web-player/src/lib/components/TrackContextMenu.svelte b/web-player/src/lib/components/TrackContextMenu.svelte index f8a03e5..b793914 100644 --- a/web-player/src/lib/components/TrackContextMenu.svelte +++ b/web-player/src/lib/components/TrackContextMenu.svelte @@ -21,7 +21,7 @@ import { enhance } from '$app/forms'; import ListPlus from '@lucide/svelte/icons/list-plus'; import ChevronRight from '@lucide/svelte/icons/chevron-right'; - import PlaylistArt from '$lib/components/ui/PlaylistArt.svelte'; + import Artwork from '$lib/components/ui/Artwork.svelte'; import GlassMenu from '$lib/components/ui/GlassMenu.svelte'; interface Props { @@ -91,11 +91,10 @@ type="submit" class="flex w-full items-center gap-3 rounded-control px-2 py-2.5 text-left text-sm font-medium text-fg transition hover:bg-hover" > - {playlist.name} diff --git a/web-player/src/lib/components/player/Queue.svelte b/web-player/src/lib/components/player/Queue.svelte index da41e33..9194270 100644 --- a/web-player/src/lib/components/player/Queue.svelte +++ b/web-player/src/lib/components/player/Queue.svelte @@ -1,7 +1,7 @@ - -
-
- {#if imageUrl} - - {:else} -
- {initials} - {/if} -
-
{name}
-
diff --git a/web-player/src/lib/components/ui/Artwork.svelte b/web-player/src/lib/components/ui/Artwork.svelte new file mode 100644 index 0000000..471b578 --- /dev/null +++ b/web-player/src/lib/components/ui/Artwork.svelte @@ -0,0 +1,133 @@ + + +
+ {#if showSrc} + (srcFailed = true)} + class="h-full w-full object-cover" + /> + {:else if showMosaic} +
+ {#each trackIds.slice(0, 4) as id (id)} + ((e.currentTarget as HTMLImageElement).style.visibility = 'hidden')} + class="h-full w-full object-cover" + /> + {/each} +
+ {:else if showSingle} + (singleFailed = true)} + class="h-full w-full object-cover" + /> + {:else if fallback === 'music'} +
+ + + +
+ {:else if fallback === 'gradient'} +
+ {:else} +
+ {/if} + {@render children?.()} +
diff --git a/web-player/src/lib/components/ui/Avatar.svelte b/web-player/src/lib/components/ui/Avatar.svelte new file mode 100644 index 0000000..d26b0b5 --- /dev/null +++ b/web-player/src/lib/components/ui/Avatar.svelte @@ -0,0 +1,60 @@ + + +
+ {#if src && !failed} + (failed = true)} + class="absolute inset-0 h-full w-full object-cover" + /> + {:else} + {initials} + {/if} +
diff --git a/web-player/src/lib/components/ui/Cover.svelte b/web-player/src/lib/components/ui/Cover.svelte deleted file mode 100644 index 8c97aa9..0000000 --- a/web-player/src/lib/components/ui/Cover.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - - diff --git a/web-player/src/lib/components/ui/MixArt.svelte b/web-player/src/lib/components/ui/MixArt.svelte deleted file mode 100644 index f931d93..0000000 --- a/web-player/src/lib/components/ui/MixArt.svelte +++ /dev/null @@ -1,25 +0,0 @@ - - -{#if tiles.length >= 4} -
- {#each tiles as item (mixItemKey(item))} - - {/each} -
-{:else if tiles.length > 0} - -{:else} -
-{/if} diff --git a/web-player/src/lib/components/ui/MixTile.svelte b/web-player/src/lib/components/ui/MixTile.svelte index 5f7c540..591d6b7 100644 --- a/web-player/src/lib/components/ui/MixTile.svelte +++ b/web-player/src/lib/components/ui/MixTile.svelte @@ -1,6 +1,6 @@ - -{#if src && !coverFailed} -
- (coverFailed = true)} - class="h-full w-full object-cover" - /> -
-{:else if mosaic} -
- {#each trackIds.slice(0, 4) as id (id)} - - {/each} -
-{:else if single !== null} - -{:else} -
- - - -
-{/if} diff --git a/web-player/src/lib/components/ui/PlaylistCard.svelte b/web-player/src/lib/components/ui/PlaylistCard.svelte index bf00bf7..6950690 100644 --- a/web-player/src/lib/components/ui/PlaylistCard.svelte +++ b/web-player/src/lib/components/ui/PlaylistCard.svelte @@ -1,6 +1,6 @@ - {#snippet content()} diff --git a/web-player/src/lib/components/ui/TrackTitleCell.svelte b/web-player/src/lib/components/ui/TrackTitleCell.svelte index 8c6f0f8..14dd3d8 100644 --- a/web-player/src/lib/components/ui/TrackTitleCell.svelte +++ b/web-player/src/lib/components/ui/TrackTitleCell.svelte @@ -1,6 +1,6 @@