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