Import source: src/components/TrendingTracks/TrackRow
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { useState } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
export default function TrackRow({ track, index, isActive, onPlay }) {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onClick={() => onPlay(track)}
|
||||
animate={{ x: hovered ? 6 : 0, backgroundColor: hovered ? 'rgba(201,168,76,0.035)' : 'transparent' }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="flex items-center gap-4 px-4 py-3.5 rounded-xl cursor-pointer"
|
||||
style={isActive ? { background: 'rgba(201,168,76,0.06)', border: '1px solid rgba(201,168,76,0.18)' }
|
||||
: { border: '1px solid transparent' }}
|
||||
>
|
||||
{/* Rank / eq bars */}
|
||||
<div className="w-5 flex items-center justify-center flex-shrink-0">
|
||||
{isActive ? (
|
||||
<div className="flex items-end gap-px h-3.5">
|
||||
{[1,2,3].map(i => (
|
||||
<motion.span key={i}
|
||||
animate={{ scaleY: [1, 0.25, 1] }}
|
||||
transition={{ repeat: Infinity, duration: 0.65, delay: i * 0.18, ease: 'easeInOut' }}
|
||||
className="block w-0.5 rounded-full origin-bottom"
|
||||
style={{ height: '100%', background: 'var(--gold)' }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-xs font-mono text-muted">{index + 1}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Cover */}
|
||||
<div className="relative w-11 h-11 rounded-lg overflow-hidden flex-shrink-0 shadow-card">
|
||||
<img src={track.cover} alt={track.title}
|
||||
className="w-full h-full object-cover transition-transform duration-300"
|
||||
style={{ transform: hovered ? 'scale(1.12)' : 'scale(1)' }} />
|
||||
{hovered && !isActive && (
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}
|
||||
className="absolute inset-0 flex items-center justify-center"
|
||||
style={{ background: 'rgba(7,7,9,0.55)' }}>
|
||||
<svg className="w-3.5 h-3.5 ml-0.5" fill="var(--gold)" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Title & artist */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className={`text-sm font-medium truncate transition-colors duration-200 ${
|
||||
isActive ? 'gold-text' : hovered ? 'text-white' : 'text-white'
|
||||
}`}>{track.title}</p>
|
||||
<p className="text-xs text-secondary truncate mt-0.5">{track.artist} · {track.album}</p>
|
||||
</div>
|
||||
|
||||
{/* Plays */}
|
||||
<span className="hidden sm:block text-xs text-muted font-mono w-14 text-right">{track.plays}</span>
|
||||
|
||||
{/* Duration */}
|
||||
<span className="text-xs text-secondary font-mono w-9 text-right">{track.duration}</span>
|
||||
|
||||
{/* Action button */}
|
||||
<motion.button
|
||||
animate={{ opacity: hovered ? 1 : 0, scale: hovered ? 1 : 0.75 }}
|
||||
transition={{ duration: 0.18 }}
|
||||
className="w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0"
|
||||
style={{ background: 'rgba(201,168,76,0.12)', border: '1px solid rgba(201,168,76,0.25)' }}
|
||||
>
|
||||
<svg className="w-3 h-3" fill="none" stroke="var(--gold)" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 12h14M12 5l7 7-7 7" />
|
||||
</svg>
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user