Teal.fm frontend powered by slices.network tealfm-slices.wisp.place
tealfm slices
at main 3.0 kB view raw
1import { graphql, useFragment } from "react-relay"; 2import type { TrackItem_play$key } from "./__generated__/TrackItem_play.graphql"; 3import AlbumArt from "./AlbumArt"; 4import MusicBrainzLink from "./MusicBrainzLink"; 5 6interface TrackItemProps { 7 play: TrackItem_play$key; 8} 9 10export default function TrackItem({ play }: TrackItemProps) { 11 const data = useFragment( 12 graphql` 13 fragment TrackItem_play on FmTealAlphaFeedPlay { 14 trackName 15 playedTime 16 artists { 17 artistName 18 artistMbId 19 } 20 releaseName 21 releaseMbId 22 actorHandle 23 musicServiceBaseDomain 24 appBskyActorProfile { 25 displayName 26 } 27 } 28 `, 29 play 30 ); 31 32 return ( 33 <div className="group py-3 px-4 hover:bg-zinc-900/50 transition-colors"> 34 <div className="flex items-center gap-4"> 35 <div className="flex-shrink-0"> 36 <AlbumArt releaseMbId={data.releaseMbId} alt={`${data.trackName} album art`} /> 37 </div> 38 39 <div className="flex-1 min-w-0 grid grid-cols-2 gap-4"> 40 <div className="min-w-0"> 41 <h3 className="text-sm font-medium text-zinc-100 truncate flex items-center gap-2"> 42 <span className="truncate">{data.trackName}</span> 43 {data.musicServiceBaseDomain === "nts.live" && ( 44 <a 45 href={`https://${data.musicServiceBaseDomain}`} 46 target="_blank" 47 rel="noopener noreferrer" 48 className="text-[10px] px-1.5 py-0.5 bg-violet-500/20 text-violet-400 rounded flex-shrink-0 hover:bg-violet-500/30 transition-colors" 49 > 50 NTS 51 </a> 52 )} 53 </h3> 54 <p className="text-xs text-zinc-500 truncate"> 55 {Array.isArray(data.artists) 56 ? data.artists.map((a) => a.artistName).join(", ") 57 : data.artists} 58 </p> 59 </div> 60 61 <div className="text-right min-w-0"> 62 <p className="text-xs text-zinc-400 truncate"> 63 <MusicBrainzLink releaseMbId={data.releaseMbId}> 64 {data.releaseName} 65 </MusicBrainzLink> 66 </p> 67 <div className="flex items-center justify-end gap-2 mt-0.5 min-w-0 overflow-hidden"> 68 {data.playedTime && ( 69 <p className="text-xs text-zinc-600 flex-shrink-0"> 70 {new Date(data.playedTime).toLocaleTimeString("en-US", { 71 hour: "numeric", 72 minute: "2-digit", 73 })} 74 </p> 75 )} 76 <a 77 href={`/profile/${data.actorHandle}`} 78 className="text-xs text-violet-500 hover:text-violet-400 transition-colors truncate block max-w-[120px]" 79 > 80 @{data.actorHandle} 81 </a> 82 </div> 83 </div> 84 </div> 85 </div> 86 </div> 87 ); 88}