Replace the early prototype UI with a darker Aonsoku-inspired shell featuring a compact top bar, library sidebar, command palette, settings overlay, dense track list, artists table, albums grid, and a bottom player bar. Add a supporting albums browse endpoint so the frontend can render the same navigation shape without faking data.
61 lines
1.7 KiB
TypeScript
61 lines
1.7 KiB
TypeScript
import { create } from 'zustand'
|
|
import type { Track } from '@/lib/api'
|
|
|
|
type PlayerState = {
|
|
currentTrack: Track | null
|
|
queue: Track[]
|
|
isPlaying: boolean
|
|
volume: number
|
|
setQueue: (tracks: Track[], startIndex?: number) => void
|
|
playTrack: (track: Track, queue?: Track[]) => void
|
|
togglePlayback: () => void
|
|
playNext: () => void
|
|
playPrevious: () => void
|
|
setVolume: (volume: number) => void
|
|
}
|
|
|
|
export const usePlayerStore = create<PlayerState>((set, get) => ({
|
|
currentTrack: null,
|
|
queue: [],
|
|
isPlaying: false,
|
|
volume: 0.7,
|
|
setQueue: (queue, startIndex = 0) =>
|
|
set({
|
|
queue,
|
|
currentTrack: queue[startIndex] ?? null,
|
|
isPlaying: queue.length > 0,
|
|
}),
|
|
playTrack: (currentTrack, queue) =>
|
|
set((state) => ({
|
|
currentTrack,
|
|
queue: queue ?? state.queue,
|
|
isPlaying: true,
|
|
})),
|
|
togglePlayback: () => set((state) => ({ isPlaying: !state.isPlaying })),
|
|
playNext: () =>
|
|
set((state) => {
|
|
if (!state.currentTrack || state.queue.length === 0) {
|
|
return state
|
|
}
|
|
const index = state.queue.findIndex((track) => track.id === state.currentTrack?.id)
|
|
const nextTrack = state.queue[index + 1] ?? state.queue[0] ?? null
|
|
return {
|
|
currentTrack: nextTrack,
|
|
isPlaying: !!nextTrack,
|
|
}
|
|
}),
|
|
playPrevious: () =>
|
|
set((state) => {
|
|
if (!state.currentTrack || state.queue.length === 0) {
|
|
return state
|
|
}
|
|
const index = state.queue.findIndex((track) => track.id === state.currentTrack?.id)
|
|
const previousTrack = state.queue[index - 1] ?? state.queue[state.queue.length - 1] ?? null
|
|
return {
|
|
currentTrack: previousTrack,
|
|
isPlaying: !!previousTrack,
|
|
}
|
|
}),
|
|
setVolume: (volume) => set({ volume }),
|
|
}))
|