From aa20e70671d1153dbc1a3f6a31408b0dc19d4ea9 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Sun, 20 Sep 2026 22:48:08 +0200 Subject: [PATCH] web-player: buttons (Button, IconButton, PlayButton) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Button: subtle variants (primary/secondary, left unchanged per the user's call), glass (formerly secondaryOnGlow, with its own font-normal), accent, strong (cta-strong/ink, replacing the `!` overrides on the Home hero), danger. Uses the --color-btn* tokens instead of bg-[var(--mf-btn-...)]. Radius unified to rounded-control. IconButton: adds shape (square/round), size (xs/sm/md/lg), tone (muted/subtle/plain), pressed (aria-pressed + text-accent), href/reload (links), surface (permanent background + hover to surface-hover instead of the generic `hover` alias, which matched surface-2 and gave no contrast). New PlayButton: a single place for the play/pause SVGs, strong/glass variants, as="span" for non-interactive overlays. Replaces TransportControls' main button, the MixTile overlay, and the "Top result" circle in Explore. Migrated to IconButton: close queue, "Create playlist" (Sidebar), Like (TrackInfo, with pressed), queue (PlayerExtras), back (TopBar), login (MobileHeader), and the row actions in tables (remove/add, size xs). BackLink uses size-icon-sm and drops a duplicate hover. Decision (not blocking): remove TopBar's decorative "forward" button and PlayerExtras' decorative AlignJustify icon (visually dead code). TransportControls' buttons (shuffle/prev/next/repeat) are deliberately left unmigrated: they currently have no background or hit-box of their own, and IconButton always applies a fixed-size box — migrating them would have added a visible hover pill that couldn't be verified without Docker this session. Verified with npm run check/build. --- web-player/docs/frontend-refactor-plan.md | 2 +- .../src/lib/components/MobileHeader.svelte | 12 ++-- web-player/src/lib/components/Sidebar.svelte | 13 ++-- web-player/src/lib/components/TopBar.svelte | 39 +++++------ .../lib/components/player/PlayerExtras.svelte | 21 +++--- .../src/lib/components/player/Queue.svelte | 12 ++-- .../lib/components/player/TrackInfo.svelte | 15 +++-- .../player/TransportControls.svelte | 21 ++---- .../src/lib/components/ui/BackLink.svelte | 6 +- .../src/lib/components/ui/Button.svelte | 17 +++-- .../src/lib/components/ui/IconButton.svelte | 67 ++++++++++++++----- .../src/lib/components/ui/MixTile.svelte | 15 ++--- .../src/lib/components/ui/PlayButton.svelte | 59 ++++++++++++++++ .../[id]/components/AlbumTrackTable.svelte | 2 +- .../[id]/components/LibraryPicker.svelte | 2 +- .../src/routes/(app)/explore/+page.svelte | 8 +-- .../src/routes/(app)/library/+page.svelte | 2 +- .../src/routes/(app)/liked/+page.svelte | 2 +- .../[id]/components/PlaylistTrackTable.svelte | 2 +- web-player/src/routes/+page.svelte | 12 +--- 20 files changed, 191 insertions(+), 138 deletions(-) create mode 100644 web-player/src/lib/components/ui/PlayButton.svelte diff --git a/web-player/docs/frontend-refactor-plan.md b/web-player/docs/frontend-refactor-plan.md index 502a994..ec32700 100644 --- a/web-player/docs/frontend-refactor-plan.md +++ b/web-player/docs/frontend-refactor-plan.md @@ -776,7 +776,7 @@ Tareas: | 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 | ✅ | (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 | ⬜ | | | +| P4 | ✅ | (pendiente) | Decisión tomada sin bloquear: se elimina el botón "adelante" decorativo (TopBar) y el icono `AlignJustify` decorativo (PlayerExtras) por ser código muerto visual. `TransportControls` (shuffle/prev/next/repeat) se deja sin migrar a IconButton a propósito: son iconos sin chrome (sin fondo/hit-box), migrarlos habría añadido una píldora de hover no presente hoy — riesgo visual no verificable sin Docker | | P5 | ⬜ | | | | P6 | ⬜ | | | | P7 | ⬜ | | | diff --git a/web-player/src/lib/components/MobileHeader.svelte b/web-player/src/lib/components/MobileHeader.svelte index ae1c0c5..d232195 100644 --- a/web-player/src/lib/components/MobileHeader.svelte +++ b/web-player/src/lib/components/MobileHeader.svelte @@ -6,6 +6,7 @@ import MenuItem from './ui/MenuItem.svelte'; import AccountMenu from './ui/AccountMenu.svelte'; import Avatar from './ui/Avatar.svelte'; + import IconButton from './ui/IconButton.svelte'; interface Props { user: SessionUser | null; @@ -50,14 +51,9 @@ {/snippet} {:else} - - - + + + {/if} diff --git a/web-player/src/lib/components/Sidebar.svelte b/web-player/src/lib/components/Sidebar.svelte index 8824a7b..223f487 100644 --- a/web-player/src/lib/components/Sidebar.svelte +++ b/web-player/src/lib/components/Sidebar.svelte @@ -5,6 +5,7 @@ import { createPlaylistModal } from '$lib/playlists.svelte'; import type { SessionUser } from '$lib/types'; import Artwork from './ui/Artwork.svelte'; + import IconButton from './ui/IconButton.svelte'; import Home from '@lucide/svelte/icons/house'; import Compass from '@lucide/svelte/icons/compass'; import ListMusic from '@lucide/svelte/icons/list-music'; @@ -77,14 +78,14 @@
Tus playlists {#if playlists.length > 0} - + + {/if}
diff --git a/web-player/src/lib/components/TopBar.svelte b/web-player/src/lib/components/TopBar.svelte index 12566e6..b5241e7 100644 --- a/web-player/src/lib/components/TopBar.svelte +++ b/web-player/src/lib/components/TopBar.svelte @@ -6,9 +6,10 @@ import Search from '@lucide/svelte/icons/search'; import X from '@lucide/svelte/icons/x'; 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'; + import IconButton from './ui/IconButton.svelte'; + import Button from './ui/Button.svelte'; interface Props { user: SessionUser | null; @@ -56,24 +57,18 @@ diff --git a/web-player/src/lib/components/player/PlayerExtras.svelte b/web-player/src/lib/components/player/PlayerExtras.svelte index 800d3cb..e0d3731 100644 --- a/web-player/src/lib/components/player/PlayerExtras.svelte +++ b/web-player/src/lib/components/player/PlayerExtras.svelte @@ -1,22 +1,19 @@ - {#if !compact} - + + {/if} diff --git a/web-player/src/lib/components/player/TransportControls.svelte b/web-player/src/lib/components/player/TransportControls.svelte index 326078e..7d00594 100644 --- a/web-player/src/lib/components/player/TransportControls.svelte +++ b/web-player/src/lib/components/player/TransportControls.svelte @@ -1,5 +1,6 @@ diff --git a/web-player/src/lib/components/ui/IconButton.svelte b/web-player/src/lib/components/ui/IconButton.svelte index 8cc0555..ee60492 100644 --- a/web-player/src/lib/components/ui/IconButton.svelte +++ b/web-player/src/lib/components/ui/IconButton.svelte @@ -4,8 +4,14 @@ interface Props { label: string; type?: 'button' | 'submit'; - size?: 'sm' | 'md'; + size?: 'xs' | 'sm' | 'md' | 'lg'; + shape?: 'square' | 'round'; + tone?: 'muted' | 'subtle' | 'plain'; + pressed?: boolean; + surface?: boolean; revealOnHover?: boolean; + href?: string; + reload?: boolean; onclick?: (event: MouseEvent) => void; class?: string; children: Snippet; @@ -14,26 +20,55 @@ let { label, type = 'button', - size = 'md', + size = 'sm', + shape = 'square', + tone = 'muted', + pressed, + surface = false, revealOnHover = false, + href, + reload = false, onclick, class: klass = '', children }: Props = $props(); - const sizes = { sm: 'h-7 w-7', md: 'h-8 w-8' }; + const SIZE: Record<'xs' | 'sm' | 'md' | 'lg', string> = { + xs: 'size-7', + sm: 'size-8', + md: 'size-9', + lg: 'size-10' + }; + + const TEXT: Record<'muted' | 'subtle' | 'plain', string> = { + muted: 'text-muted hover:text-fg', + subtle: 'text-fg-2 hover:text-fg', + plain: 'text-fg-2 hover:text-fg' + }; + + const background = $derived( + surface ? 'bg-surface-2 hover:bg-surface-hover' : tone === 'plain' ? '' : 'hover:bg-hover' + ); + + const classes = $derived( + `grid place-items-center transition focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none ${SIZE[size]} ${shape === 'round' ? 'rounded-full' : 'rounded-control'} ${pressed ? 'text-accent' : TEXT[tone]} ${background} ${ + revealOnHover ? 'sm:opacity-0 sm:group-hover:opacity-100 sm:focus-visible:opacity-100' : '' + } ${klass}` + ); - +{#if href} + + {@render children()} + +{:else} + +{/if} diff --git a/web-player/src/lib/components/ui/MixTile.svelte b/web-player/src/lib/components/ui/MixTile.svelte index 591d6b7..e2c586d 100644 --- a/web-player/src/lib/components/ui/MixTile.svelte +++ b/web-player/src/lib/components/ui/MixTile.svelte @@ -1,6 +1,6 @@ + +{#snippet icon()} + {#if playing} + + + + + {:else} + + + + {/if} +{/snippet} + +{#if as === 'span'} + +{:else} + +{/if} diff --git a/web-player/src/routes/(app)/albums/[id]/components/AlbumTrackTable.svelte b/web-player/src/routes/(app)/albums/[id]/components/AlbumTrackTable.svelte index 12bc291..e9e5e4b 100644 --- a/web-player/src/routes/(app)/albums/[id]/components/AlbumTrackTable.svelte +++ b/web-player/src/routes/(app)/albums/[id]/components/AlbumTrackTable.svelte @@ -54,7 +54,7 @@ update()} > - + diff --git a/web-player/src/routes/(app)/albums/[id]/components/LibraryPicker.svelte b/web-player/src/routes/(app)/albums/[id]/components/LibraryPicker.svelte index 12994da..5281c8e 100644 --- a/web-player/src/routes/(app)/albums/[id]/components/LibraryPicker.svelte +++ b/web-player/src/routes/(app)/albums/[id]/components/LibraryPicker.svelte @@ -55,7 +55,7 @@ update()} > - + diff --git a/web-player/src/routes/(app)/explore/+page.svelte b/web-player/src/routes/(app)/explore/+page.svelte index 599a1e4..5329697 100644 --- a/web-player/src/routes/(app)/explore/+page.svelte +++ b/web-player/src/routes/(app)/explore/+page.svelte @@ -1,6 +1,5 @@