Demo using Slices Network GraphQL Relay API to make a teal.fm client
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 } 19 releaseName 20 releaseMbId 21 actorHandle 22 musicServiceBaseDomain 23 appBskyActorProfileByDid { 24 displayName 25 } 26 } 27 `, 28 play, 29 ); 30 31 return ( 32 <div className="group py-3 px-4 hover:bg-zinc-900/50 transition-colors"> 33 <div className="flex items-center gap-4"> 34 <div className="flex-shrink-0"> 35 <AlbumArt 36 releaseMbId={data.releaseMbId} 37 alt={`${data.trackName} album art`} 38 /> 39 </div> 40 41 <div className="flex-1 min-w-0 grid grid-cols-2 gap-4"> 42 <div className="min-w-0"> 43 <h3 className="text-sm font-medium text-zinc-100 truncate flex items-center gap-2"> 44 <span className="truncate">{data.trackName}</span> 45 {data.musicServiceBaseDomain === "nts.live" && ( 46 <a 47 href={`https://${data.musicServiceBaseDomain}`} 48 target="_blank" 49 rel="noopener noreferrer" 50 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" 51 > 52 NTS 53 </a> 54 )} 55 </h3> 56 <p className="text-xs text-zinc-500 truncate"> 57 {Array.isArray(data.artists) 58 ? data.artists.map((a) => a.artistName).join(", ") 59 : "Unknown Artist"} 60 </p> 61 </div> 62 63 <div className="text-right min-w-0"> 64 <p className="text-xs text-zinc-400 truncate"> 65 <MusicBrainzLink releaseMbId={data.releaseMbId}> 66 {data.releaseName} 67 </MusicBrainzLink> 68 </p> 69 <div className="flex items-center justify-end gap-2 mt-0.5 min-w-0 overflow-hidden"> 70 {data.playedTime && ( 71 <p className="text-xs text-zinc-600 flex-shrink-0"> 72 {new Date(data.playedTime).toLocaleTimeString("en-US", { 73 hour: "numeric", 74 minute: "2-digit", 75 })} 76 </p> 77 )} 78 <a 79 href={`/profile/${data.actorHandle}`} 80 className="text-xs text-violet-500 hover:text-violet-400 transition-colors truncate block max-w-[120px]" 81 > 82 @{data.actorHandle} 83 </a> 84 </div> 85 </div> 86 </div> 87 </div> 88 </div> 89 ); 90}