Teal.fm frontend powered by slices.network tealfm-slices.wisp.place
tealfm slices
1import AlbumArt from "./AlbumArt"; 2 3interface Artist { 4 artistName: string; 5} 6 7interface AlbumItemProps { 8 releaseName: string; 9 releaseMbId: string | null | undefined; 10 artists: string | null | undefined; 11 count: number; 12 rank: number; 13 maxCount: number; 14} 15 16export default function AlbumItem({ 17 releaseName, 18 releaseMbId, 19 artists, 20 count, 21 rank, 22 maxCount, 23}: AlbumItemProps) { 24 const barWidth = maxCount > 0 ? (count / maxCount) * 100 : 0; 25 26 // Parse artists JSON 27 let artistNames = "Unknown Artist"; 28 if (artists) { 29 try { 30 const parsed = typeof artists === 'string' ? JSON.parse(artists) : artists; 31 if (Array.isArray(parsed)) { 32 artistNames = parsed.map((a: Artist) => a.artistName).join(", "); 33 } else if (typeof parsed === 'string') { 34 artistNames = parsed; 35 } 36 } catch (e) { 37 console.log('Failed to parse artists:', artists, e); 38 artistNames = String(artists); 39 } 40 } else { 41 console.log('No artists data for:', releaseName); 42 } 43 44 return ( 45 <div className="group py-3 px-4 hover:bg-zinc-900/50 transition-colors relative overflow-hidden"> 46 <div 47 className="absolute inset-y-0 left-0 bg-violet-500/10 transition-all" 48 style={{ width: `${barWidth}%` }} 49 /> 50 <div className="flex items-center gap-4 relative"> 51 <div className="text-xs text-zinc-600 w-8 text-right flex-shrink-0 font-medium"> 52 {rank} 53 </div> 54 55 <div className="flex-shrink-0"> 56 <AlbumArt releaseMbId={releaseMbId} alt={`${releaseName} album art`} /> 57 </div> 58 59 <div className="flex-1 min-w-0"> 60 <h3 className="text-sm font-medium text-zinc-100 truncate"> 61 {releaseName} 62 </h3> 63 <p className="text-xs text-zinc-500 truncate">{artistNames}</p> 64 </div> 65 66 <div className="text-right flex-shrink-0"> 67 <p className="text-xs text-zinc-400 font-medium"> 68 {count.toLocaleString()} 69 </p> 70 </div> 71 </div> 72 </div> 73 ); 74}