diff --git a/apps/web/src/components/full-player.tsx b/apps/web/src/components/full-player.tsx
index c7c1715..3cb1734 100644
--- a/apps/web/src/components/full-player.tsx
+++ b/apps/web/src/components/full-player.tsx
@@ -1,7 +1,8 @@
import { useQuery } from '@tanstack/react-query'
-import { ChevronDown, Heart, ListMusic, Pause, Play, Repeat2, Rewind, Shuffle, SkipForward, Volume2 } from 'lucide-react'
+import { ChevronDown, ListMusic, Pause, Play, Repeat2, Rewind, Shuffle, SkipForward, Trash2, Volume2 } from 'lucide-react'
import { useMemo, useState } from 'react'
-import { coverArtUrl } from '@/lib/api'
+import { FavoriteToggle } from '@/components/favorite-toggle'
+import { coverArtUrl, fetchFavorites } from '@/lib/api'
import { usePlayerStore } from '@/stores/player-store'
type LyricsLine = {
@@ -16,12 +17,24 @@ export function FullPlayer() {
const currentTime = usePlayerStore((state) => state.currentTime)
const duration = usePlayerStore((state) => state.duration)
const volume = usePlayerStore((state) => state.volume)
+ const shuffle = usePlayerStore((state) => state.shuffle)
+ const repeatMode = usePlayerStore((state) => state.repeatMode)
const togglePlayback = usePlayerStore((state) => state.togglePlayback)
const playNext = usePlayerStore((state) => state.playNext)
const playPrevious = usePlayerStore((state) => state.playPrevious)
+ const playAtIndex = usePlayerStore((state) => state.playAtIndex)
+ const removeFromQueue = usePlayerStore((state) => state.removeFromQueue)
+ const toggleShuffle = usePlayerStore((state) => state.toggleShuffle)
+ const cycleRepeatMode = usePlayerStore((state) => state.cycleRepeatMode)
const setVolume = usePlayerStore((state) => state.setVolume)
+ const seekTo = usePlayerStore((state) => state.seekTo)
const setFullPlayerOpen = usePlayerStore((state) => state.setFullPlayerOpen)
const [tab, setTab] = useState<'queue' | 'now' | 'lyrics'>('now')
+ const favoritesQuery = useQuery({
+ queryKey: ['favorites'],
+ queryFn: fetchFavorites,
+ enabled: !!currentTrack,
+ })
const lyricsQuery = useQuery({
queryKey: ['lrclib', currentTrack?.id],
@@ -40,6 +53,7 @@ export function FullPlayer() {
})
const parsedLyrics = useMemo(() => parseLyrics(lyricsQuery.data?.syncedLyrics ?? lyricsQuery.data?.plainLyrics ?? ''), [lyricsQuery.data])
+ const favoriteTrackIds = useMemo(() => new Set((favoritesQuery.data?.tracks ?? []).map((item) => item.id)), [favoritesQuery.data])
const activeLine = useMemo(() => {
if (parsedLyrics.length === 0) {
return -1
@@ -113,22 +127,35 @@ export function FullPlayer() {
{tab === 'queue' ? (
{queue.map((track, index) => (
-
playAtIndex(index)}
+ type="button"
>
{index + 1}
{track.coverArtId ?
})
: null}
-
+
{track.title}
{track.artistName}
-
+
+
))}
) : null}
@@ -137,9 +164,15 @@ export function FullPlayer() {
{formatClock(currentTime)}
-
+
seekTo(Number(event.target.value))}
+ step={0.1}
+ type="range"
+ value={Math.min(currentTime, duration || 0)}
+ />
{formatClock(duration)}
@@ -154,17 +187,17 @@ export function FullPlayer() {
-
} />
+
} onClick={toggleShuffle} />
} onClick={playPrevious} />
} onClick={playNext} />
-
} />
+
} label={repeatMode === 'one' ? '1' : undefined} onClick={cycleRepeatMode} />
-
} />
+
void
}) {
return (
-