diff --git a/src/components/track/TrackRow.tsx b/src/components/track/TrackRow.tsx index df1dbdd..9b58fff 100644 --- a/src/components/track/TrackRow.tsx +++ b/src/components/track/TrackRow.tsx @@ -1,10 +1,12 @@ import { Row } from '@olly/modern-sk'; +import { useTranslation } from 'react-i18next'; import { TrackContextMenu } from './TrackContextMenu'; import { AvailabilityBadge } from './AvailabilityBadge'; import { MetadataStatusBadge } from './MetadataStatusBadge'; +import { Icon } from '../common/Icon'; import { formatDuration } from '../../lib/format'; import { useAppDispatch, useAppSelector } from '../../hooks/useAppDispatch'; -import { play } from '../../store/slices/player'; +import { playNow } from '../../store/slices/queue'; import type { Track } from '../../api/types'; import { getCoverUrl, getTrackCoverUrl } from '../../api/endpoints/streaming'; @@ -25,6 +27,7 @@ export function TrackRow({ onEditMetadata, onDelete, }: Props) { + const { t } = useTranslation(); const dispatch = useAppDispatch(); const currentTrackId = useAppSelector((s) => s.player.currentTrackId); const isPlaying = useAppSelector((s) => s.player.isPlaying); @@ -36,10 +39,22 @@ export function TrackRow({ getCoverUrl(track.albumArtUrl) ?? (token ? getTrackCoverUrl(track.id, token, track.hasCover) : undefined); + const handlePlayNow = () => { + dispatch( + playNow({ + trackId: track.id, + title: track.title, + artistName: track.artistName, + albumTitle: track.albumTitle, + durationMs: track.durationMs, + albumArtUrl: track.albumArtUrl, + }), + ); + }; + return ( dispatch(play(track.id))} style={{ display: 'grid', gridTemplateColumns: '2rem 2.5rem 1fr auto auto', @@ -58,24 +73,38 @@ export function TrackRow({ > {isActive && isPlaying ? '▶' : index !== undefined ? index + 1 : ''} - {artUrl ? ( - - ) : ( -
- )} +
+ {artUrl ? ( + + ) : ( +
+ )} + +
) { state.entries.splice(state.currentIndex + 1, 0, action.payload); }, + playNow(state, action: PayloadAction) { + const insertAt = state.currentIndex + 1; + state.entries.splice(insertAt, 0, action.payload); + state.currentIndex = insertAt; + }, removeFromQueue(state, action: PayloadAction) { state.entries.splice(action.payload, 1); if (action.payload < state.currentIndex) state.currentIndex--; @@ -93,6 +98,7 @@ export const { setQueue, addToQueue, addNextInQueue, + playNow, removeFromQueue, moveInQueue, goToIndex, diff --git a/src/styles/shell.css b/src/styles/shell.css index f55e3bb..551ea63 100644 --- a/src/styles/shell.css +++ b/src/styles/shell.css @@ -951,3 +951,28 @@ .sb-sec-link.active { color: var(--fg-1); } + +/* ============================================================ + TRACK ROW — cover art play overlay + ============================================================ */ +.track-art-play { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + border: none; + border-radius: 4px; + background: rgba(0, 0, 0, 0.5); + color: var(--fg-1); + font-size: 16px; + cursor: pointer; + opacity: 0; + transition: opacity var(--dur-quick); +} +.track-art:hover .track-art-play { + opacity: 1; +} +.track-art-play:hover { + color: var(--lime); +}