import { useState } from 'react' import { Play, Pause, SkipBack, SkipForward, Shuffle, Repeat, Repeat1, X, ListMusic, Heart, Volume2, VolumeX, ChevronDown, } from '../../lib/icons' import { motion, AnimatePresence } from 'framer-motion' import { useMusicStore } from '../../stores/music-store' import { getBestImage, getStoredServerUrl } from '../../api/jellyfin' interface NowPlayingProps { isOpen: boolean onClose: () => void } export default function NowPlaying({ isOpen, onClose }: NowPlayingProps) { const [showQueue, setShowQueue] = useState(false) const { currentTrack, isPlaying, currentTime, duration, shuffle, repeat, queue, queueIndex, volume, isMuted, pause, resume, nextTrack, prevTrack, toggleShuffle, cycleRepeat, seekTo, toggleMute, setVolume, } = useMusicStore() const serverUrl = getStoredServerUrl() const imageUrl = currentTrack ? getBestImage(serverUrl, currentTrack, 'primary', 800) : '' const bgImageUrl = currentTrack ? getBestImage(serverUrl, currentTrack, 'primary', 320) : '' const title = currentTrack?.Name || 'Unknown track' const artist = currentTrack?.AlbumArtist || currentTrack?.Artists?.[0] || '' const album = currentTrack?.Album || '' const RepeatIcon = repeat === 'one' ? Repeat1 : Repeat const VolIcon = isMuted || volume === 0 ? VolumeX : Volume2 function formatTime(s: number): string { if (!s || !isFinite(s)) return '0:00' const m = Math.floor(s / 60) const sec = Math.floor(s % 60) return `${m}:${sec.toString().padStart(2, '0')}` } const playedPercent = duration > 0 ? (currentTime / duration) * 100 : 0 function handleScrubClick(e: React.MouseEvent) { const rect = e.currentTarget.getBoundingClientRect() const pct = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)) seekTo(pct * duration) } return ( {isOpen && currentTrack && ( {/* ── Cinematic background ────────────────────────────── */}
{bgImageUrl && ( <> {/* Heavy blurred album art as ambient backdrop */} {/* Color wash */}
)}
{/* ── Header ────────────────────────────────────────── */}
Now playing
{/* ── Main content ─────────────────────────────────── */}
{/* Album art */} {/* Glow halo */}
{/* Reflection-like shadow */}
{imageUrl ? ( {title} ) : (
)}
{/* Track info */}

{title}

{artist} {album && ( <> · {album} )}

{/* Scrubber */}
{formatTime(currentTime)} -{formatTime(Math.max(0, duration - currentTime))}
{/* Transport */} {/* Secondary controls */} {/* Volume */}
setVolume(Number(e.target.value))} className="slider w-24" aria-label="Volume" />
{/* ── Queue panel ───────────────────────────────────── */} {showQueue && (

Up next

{queue.length} {queue.length === 1 ? 'track' : 'tracks'}

{queue.map((track, i) => { const isActive = i === queueIndex const thumbUrl = getBestImage(serverUrl, track, 'primary', 100) return (
{thumbUrl ? ( ) : (
)} {isActive && isPlaying && }

{track.Name || 'Unknown'}

{track.AlbumArtist || track.Artists?.[0] || 'Unknown artist'}

{track.RunTimeTicks ? formatTime(Number(track.RunTimeTicks) / 10000000) : ''}
) })}
)}
)} ) } function NPButton({ active, children, ...props }: React.ButtonHTMLAttributes & { active?: boolean }) { return ( ) } function Equalizer() { return (
{[0, 1, 2].map(i => (
))}
) }