From 8c62f0089efba01cd52c5057ccb551b0f72076d0 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Fri, 1 May 2026 23:28:10 -0400 Subject: [PATCH] =?UTF-8?q?feat(web):=20redesign=20PlayerBar=20=E2=80=94?= =?UTF-8?q?=20Lucide=20icons,=20focal=20play=20button,=20taller=20bar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three theming/density problems with the old PlayerBar: - Emoji glyphs (โฎ โ–ถ โธ โญ ๐Ÿ”€ ๐Ÿ” โ—Œ) painted at OS-default sizes inside p-1 hit areas, so each button had a 6-8px ring of dead space and the row clashed with the Lucide stroke-icon language used elsewhere. - No focal point on transport โ€” play looked structurally identical to prev/next so the eye had nothing to anchor on. - Cover at 48x48 in a 72px bar left visible vertical breathing room around it that read as accidental empty space. Changes: - All emoji replaced with Lucide icons: SkipBack, Play, Pause, Loader2, SkipForward, Shuffle, Repeat, Repeat1, Volume2/Volume1/VolumeX. - Play button is the brand moment: 48px circular, accent forest-teal background, 24px parchment icon. Prev/next stay minimal at 40px circular with hover-bg. - Cover bumped to 80x80 in a min-h-[108px] bar (~1.5x the previous height) so the player reads as substantial rather than a thin strip. - Shuffle / repeat get consistent 36px circular hit areas with bg-accent-tint + text-accent active state instead of color-only toggling. Repeat1 icon swap on repeat-one mode replaces the old '๐Ÿ”ยน' string concatenation. - Volume slider gets a state-aware Lucide icon to its left (VolumeX / Volume1 / Volume2 by level), giving the right column a visual anchor. - Right column tightens from w-56 to w-48 since icons are denser than emoji + text. TrackMenu gains a 'direction' prop ('up' | 'down', default 'down') so PlayerBar can pass direction='up' โ€” the kebab menu opens upward instead of off the bottom of the page. Co-Authored-By: Claude Opus 4.7 (1M context) --- web/src/lib/components/PlayerBar.svelte | 125 +++++++++++++++--------- web/src/lib/components/TrackMenu.svelte | 12 ++- 2 files changed, 90 insertions(+), 47 deletions(-) diff --git a/web/src/lib/components/PlayerBar.svelte b/web/src/lib/components/PlayerBar.svelte index f6f78e56..47fab8f8 100644 --- a/web/src/lib/components/PlayerBar.svelte +++ b/web/src/lib/components/PlayerBar.svelte @@ -1,4 +1,9 @@ {#if current} -
- -
+
+ +
-
{current.title}
+
{current.title}
{current.artist_name}
- +
@@ -69,7 +80,7 @@ {player.error ?? 'Playback failed.'}
{:else}
+ +
+ + + +
+
{formatDuration(player.position)} @@ -95,56 +147,39 @@ {formatDuration(player.duration)}
-
- - - -
{/if} -
+
+ class="flex h-9 w-9 items-center justify-center rounded-full transition-colors {player.shuffle + ? 'bg-accent-tint text-accent' + : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}" + > + + -
diff --git a/web/src/lib/components/TrackMenu.svelte b/web/src/lib/components/TrackMenu.svelte index a57629bf..258c0c62 100644 --- a/web/src/lib/components/TrackMenu.svelte +++ b/web/src/lib/components/TrackMenu.svelte @@ -3,7 +3,15 @@ import FlagPopover from './FlagPopover.svelte'; import type { TrackRef } from '$lib/api/types'; - let { track }: { track: TrackRef } = $props(); + let { + track, + direction = 'down' + }: { + track: TrackRef; + /** Whether the dropdown opens above the trigger ('up') or below ('down'). + Pass 'up' when used near the bottom of the viewport (e.g. PlayerBar). */ + direction?: 'up' | 'down'; + } = $props(); let menuOpen = $state(false); let popoverOpen = $state(false); @@ -44,7 +52,7 @@ {#if menuOpen}