From df8c67b368ad3b31612308e96810db0291fb5783 Mon Sep 17 00:00:00 2001 From: Senko-san Date: Sat, 13 Jun 2026 17:51:55 +0300 Subject: [PATCH] feat(album): single cover on album detail, track-number rows Album detail header falls back to a track's cover when the album record itself has none, and each track row hides its per-track art in favour of a large album-position number, since the header already shows the album's cover once. --- src/components/track/TrackRow.tsx | 46 ++++++++++++++----- src/features/album-detail/AlbumDetailPage.tsx | 15 ++++-- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/components/track/TrackRow.tsx b/src/components/track/TrackRow.tsx index fe5b154..dd92fb2 100644 --- a/src/components/track/TrackRow.tsx +++ b/src/components/track/TrackRow.tsx @@ -15,6 +15,10 @@ interface Props { track: Track; index?: number; showAlbum?: boolean; + /** Hide cover art and show the track's album position instead — used on + * the album detail page, where the album cover is already shown once in + * the header and per-track art would be redundant. */ + hideArt?: boolean; onAddToPlaylist?: (track: Track) => void; onEditMetadata?: (track: Track) => void; onDelete?: (track: Track) => void; @@ -24,6 +28,7 @@ export function TrackRow({ track, index, showAlbum = false, + hideArt = false, onAddToPlaylist, onEditMetadata, onDelete, @@ -58,24 +63,43 @@ export function TrackRow({ selected={isActive} style={{ display: 'grid', - gridTemplateColumns: '2rem 2.5rem 1fr auto auto', + gridTemplateColumns: hideArt + ? '2.5rem 1fr auto auto' + : '2rem 2.5rem 1fr auto auto', gap: '0.75rem', alignItems: 'center', padding: '0.375rem 0.75rem', cursor: 'default', }} > - - {isActive && isPlaying ? '▶' : index !== undefined ? index + 1 : ''} - + {!hideArt && ( + + {isActive && isPlaying ? '▶' : index !== undefined ? index + 1 : ''} + + )}
- {artUrl ? ( + {hideArt ? ( +
+ {track.trackNumber ?? (index !== undefined ? index + 1 : '')} +
+ ) : artUrl ? ( (); const navigate = useNavigate(); const dispatch = useAppDispatch(); + const token = useAppSelector((s) => s.auth.accessToken); const albumQuery = useGetAlbumQuery(albumId ?? '', { skip: !albumId }); const tracksQuery = useGetAlbumTracksQuery(albumId ?? '', { skip: !albumId }); @@ -42,7 +43,13 @@ export function AlbumDetailPage() { const album = albumQuery.data; const tracks = tracksQuery.data ?? []; - const artUrl = getCoverUrl(album?.artUrl); + // The album record itself carries no cover; fall back to a track's cover. + const coverTrack = tracks.find((t) => t.hasCover); + const artUrl = + getCoverUrl(album?.artUrl) ?? + (token && coverTrack + ? getTrackCoverUrl(coverTrack.id, token, true) + : undefined); const handlePlayAll = () => { if (!tracks.length || !album) return; @@ -178,7 +185,7 @@ export function AlbumDetailPage() { /> )} {tracks.map((track, i) => ( - + ))}