React web app for the self-hosted music streaming project, carved out from the music-app monorepo. Uses @music-app/shared for shared types and utilities.
68 lines
2.8 KiB
TypeScript
68 lines
2.8 KiB
TypeScript
import { Link } from 'react-router-dom'
|
|
import { motion } from 'framer-motion'
|
|
import { usePlayerStore } from '../../store/playerStore'
|
|
|
|
export function NowPlayingMiniBar() {
|
|
const currentSong = usePlayerStore(s => s.currentSong)
|
|
const isPlaying = usePlayerStore(s => s.isPlaying)
|
|
const togglePlay = usePlayerStore(s => s.togglePlay)
|
|
const next = usePlayerStore(s => s.next)
|
|
const previous = usePlayerStore(s => s.previous)
|
|
const progress = usePlayerStore(s => s.progress)
|
|
|
|
const progressPercent = currentSong ? (progress / currentSong.duration) * 100 : 0
|
|
|
|
return (
|
|
<motion.div
|
|
className="fixed bottom-12 left-0 right-0 z-40"
|
|
initial={{ y: 100 }}
|
|
animate={{ y: 0 }}
|
|
exit={{ y: 100 }}
|
|
transition={{ type: 'spring', duration: 0.5, bounce: 0.3 }}
|
|
>
|
|
<div className="h-0.5 bg-music-border relative overflow-hidden">
|
|
<motion.div
|
|
className="h-full bg-music-accent"
|
|
style={{ width: `${progressPercent}%` }}
|
|
transition={{ duration: 0.5 }}
|
|
/>
|
|
<div
|
|
className="absolute top-0 h-full bg-music-accent/30 blur-sm"
|
|
style={{ width: `${progressPercent}%` }}
|
|
/>
|
|
</div>
|
|
<div className="bg-music-card/95 backdrop-blur-lg border-t border-music-border">
|
|
<Link to="/now-playing" className="flex items-center gap-3 px-4 py-2 max-w-6xl mx-auto">
|
|
<motion.div
|
|
className="w-10 h-10 rounded-full vinyl-record flex-shrink-0"
|
|
animate={isPlaying ? { rotate: 360 } : { rotate: 0 }}
|
|
transition={isPlaying ? { duration: 3, repeat: Infinity, ease: 'linear' } : {}}
|
|
/>
|
|
<div className="min-w-0 flex-1">
|
|
<motion.p
|
|
className="text-sm font-medium truncate"
|
|
key={currentSong?.id}
|
|
initial={{ opacity: 0, x: -10 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
>
|
|
{currentSong?.title || 'No song'}
|
|
</motion.p>
|
|
<p className="text-xs text-music-muted truncate">{currentSong?.artist}</p>
|
|
</div>
|
|
<div className="flex items-center gap-2 flex-shrink-0">
|
|
<button onClick={previous} className="material-icons text-music-text hover:text-music-accent transition-colors">skip_previous</button>
|
|
<motion.button
|
|
onClick={togglePlay}
|
|
whileHover={{ scale: 1.1 }}
|
|
whileTap={{ scale: 0.9 }}
|
|
className="material-icons text-xl text-music-accent"
|
|
>
|
|
{isPlaying ? 'pause_circle' : 'play_circle'}
|
|
</motion.button>
|
|
<button onClick={next} className="material-icons text-music-text hover:text-music-accent transition-colors">skip_next</button>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
</motion.div>
|
|
)
|
|
} |