feat(web): redesign PlayerBar — Lucide icons, focal play button, taller bar

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) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 23:28:10 -04:00
parent 564e0bf7ca
commit 8c62f0089e
2 changed files with 90 additions and 47 deletions
+10 -2
View File
@@ -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}
<div
role="menu"
class="absolute right-0 z-20 mt-1 w-48 rounded-md border border-border bg-surface p-1 shadow-lg"
class="absolute right-0 z-20 w-48 rounded-md border border-border bg-surface p-1 shadow-lg {direction === 'up' ? 'bottom-full mb-1' : 'top-full mt-1'}"
onclick={(e) => e.stopPropagation()}
>
<button