import type { SubsonicSong } from '../api/subsonicTypes'; import { songToTrack } from '../utils/playback/songToTrack'; import React, { memo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Play, ListPlus, Star } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { usePlayerStore } from '../store/playerStore'; import { CoverArtImage } from '../cover/CoverArtImage'; import { useCoverArt } from '../cover/useCoverArt'; import { COVER_DENSE_RAIL_CELL_CSS_PX } from '../cover/layoutSizes'; import { enqueueAndPlay } from '../utils/playback/playSong'; import { useDragDrop } from '../contexts/DragDropContext'; import { useOrbitSongRowBehavior } from '../hooks/useOrbitSongRowBehavior'; interface SongCardProps { song: SubsonicSong; disableArtwork?: boolean; /** Layout-native cover square width in CSS px (rail cell). */ displayCssPx?: number; /** @deprecated Use displayCssPx */ artworkSize?: number; } function SongCard({ song, disableArtwork = false, displayCssPx = COVER_DENSE_RAIL_CELL_CSS_PX, artworkSize, }: SongCardProps) { const layoutPx = artworkSize ?? displayCssPx; const { t } = useTranslation(); const navigate = useNavigate(); const openContextMenu = usePlayerStore(s => s.openContextMenu); const enqueue = usePlayerStore(s => s.enqueue); const coverHandle = useCoverArt(song.coverArt, layoutPx, { surface: 'dense', ensurePriority: 'middle', }); const coverUrl = coverHandle.src; const psyDrag = useDragDrop(); const { orbitActive, addTrackToOrbit } = useOrbitSongRowBehavior(); const handlePlay = () => { if (orbitActive) { addTrackToOrbit(song.id); return; } enqueueAndPlay(song); }; const handleEnqueue = () => { if (orbitActive) { addTrackToOrbit(song.id); return; } enqueue([songToTrack(song)]); }; const handleClick = handlePlay; const handleArtistClick = (e: React.MouseEvent) => { if (!song.artistId) return; e.stopPropagation(); navigate(`/artist/${song.artistId}`); }; return (
{song.title}
{song.artist}
{(song.userRating ?? 0) > 0 && (