feat(web): multi-select + bulk actions on track lists (Tier A3)
test-web / test (push) Successful in 31s
test-web / test (push) Successful in 31s
Add a global selection store backing a checkbox per track row and a floating SelectionBar above PlayerBar with Play next / Add to queue / Add to playlist / Like all / Clear. - selection/store.svelte.ts: id Set + TrackRef Map + anchor index; toggleOne, selectRange (shift+click), clearSelection. Singleton — layout effect clears on pathname change. - TrackRow: checkbox slot replaces the track number on hover; row click toggles selection once any row is picked; shift+click extends the range. Esc clears (takes priority over closing the queue drawer). - SelectionBar: floating pill above PlayerBar, mounted inside the QueryClientProvider so the Like-all action can resolve. - player.playNextMany: bulk variant of playNext for "Play next" on a multi-track selection. Covered by selection-store unit tests and three new TrackRow tests (checkbox toggle, sticky select-mode row click, shift+click range).
This commit is contained in:
@@ -288,6 +288,21 @@ export function enqueueTracks(ts: TrackRef[]): void {
|
||||
if (_state === 'idle') _index = 0;
|
||||
}
|
||||
|
||||
// Bulk variant of playNext: inserts every track immediately after the
|
||||
// currently-playing one, preserving order. Empty queue seeds the queue
|
||||
// with the batch at index 0 (mirrors playNext's single-track shape).
|
||||
export function playNextMany(ts: TrackRef[]): void {
|
||||
_radioSeedId = null;
|
||||
if (ts.length === 0) return;
|
||||
if (_queue.length === 0) {
|
||||
_queue = [...ts];
|
||||
_index = 0;
|
||||
return;
|
||||
}
|
||||
const next = _index + 1;
|
||||
_queue = [..._queue.slice(0, next), ...ts, ..._queue.slice(next)];
|
||||
}
|
||||
|
||||
export async function playRadio(seedTrackId: string): Promise<void> {
|
||||
const resp = await api.get<RadioResponse>(
|
||||
`/api/radio?seed_track=${encodeURIComponent(seedTrackId)}`
|
||||
|
||||
Reference in New Issue
Block a user