feat(playlists): remove tracks
This commit is contained in:
@@ -7,16 +7,16 @@
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import { getCoverUrl } from '$lib/covers';
|
||||
import Play from 'virtual:icons/lucide/play';
|
||||
import Trash2 from 'virtual:icons/lucide/trash-2';
|
||||
import { getPlayerState } from '$lib/player.svelte';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { deserialize } from '$app/forms';
|
||||
import type { TrackList } from '$lib/proto/library';
|
||||
import * as ContextMenu from '$lib/components/ui/context-menu';
|
||||
dayjs.extend(duration);
|
||||
|
||||
const library = getLibraryState();
|
||||
const player = getPlayerState();
|
||||
|
||||
let playlist = $derived(library.playlists.find((p) => p.id === Number($page.params.id)));
|
||||
let playlist = $derived(library.playlists.get(Number($page.params.id)));
|
||||
|
||||
let totalDuration = $derived<number>(
|
||||
playlist?.tracks.reduce((acc, track) => acc + Number(track.duration), 0) ?? 0
|
||||
@@ -29,39 +29,14 @@
|
||||
}
|
||||
|
||||
async function onDrop(e: DragEvent) {
|
||||
const aIndex = e.dataTransfer?.getData('text/plain')!;
|
||||
const bIndex = (e.currentTarget as HTMLElement).getAttribute('data-playlist-index')!;
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
formData.set('a', aIndex);
|
||||
formData.set('b', bIndex);
|
||||
|
||||
const response = await fetch(`/playlists/${playlist!.id}?/swap-tracks`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'x-sveltekit-action': 'true'
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (!playlist) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = deserialize(await response.text());
|
||||
const aIndex = e.dataTransfer?.getData('text/plain')!;
|
||||
const bIndex = (e.currentTarget as HTMLElement).getAttribute('data-playlist-index')!;
|
||||
|
||||
if (result.type === 'success' && result.data && 'tracks' in result.data) {
|
||||
const _playlist = library.playlists.find((p) => p.id === playlist?.id);
|
||||
|
||||
if (playlist) {
|
||||
playlist.tracks = (result.data as unknown as TrackList).tracks;
|
||||
}
|
||||
|
||||
if (_playlist) {
|
||||
_playlist.tracks = (result.data as unknown as TrackList).tracks;
|
||||
}
|
||||
}
|
||||
library.swapPlaylistTracks(playlist.id, Number(aIndex), Number(bIndex));
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -99,27 +74,46 @@
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each playlist.tracks as track, i}
|
||||
<Table.Row
|
||||
class="select-none"
|
||||
ondblclick={() => player.playTrack(track.hash, fetch)}
|
||||
data-playlist-index={i}
|
||||
ondragstart={onDragStart}
|
||||
ondrop={onDrop}
|
||||
ondragover={(e) => e.preventDefault()}
|
||||
draggable
|
||||
>
|
||||
<Table.Cell class="text-center">{i + 1}</Table.Cell>
|
||||
<Table.Cell class="w-0">
|
||||
<img class="overflow-hidden rounded-md" src={getCoverUrl(track.hash)} alt="" />
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-nowrap">{track.name}</Table.Cell>
|
||||
<Table.Cell class="w-fit text-nowrap">{track.artistName}</Table.Cell>
|
||||
<Table.Cell class="text-right"
|
||||
>{dayjs
|
||||
.duration(Number(track.duration), 'milliseconds')
|
||||
.format('mm:ss')}</Table.Cell
|
||||
>
|
||||
</Table.Row>
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Table.Row
|
||||
{...props}
|
||||
class="select-none"
|
||||
ondblclick={() => player.playTrack(track.hash, fetch)}
|
||||
data-playlist-index={i}
|
||||
ondragstart={onDragStart}
|
||||
ondrop={onDrop}
|
||||
ondragover={(e) => e.preventDefault()}
|
||||
draggable
|
||||
>
|
||||
<Table.Cell class="text-center">{i + 1}</Table.Cell>
|
||||
<Table.Cell class="w-0">
|
||||
<img
|
||||
class="overflow-hidden rounded-md"
|
||||
src={getCoverUrl(track.hash)}
|
||||
alt=""
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-nowrap">{track.name}</Table.Cell>
|
||||
<Table.Cell class="w-fit text-nowrap">{track.artistName}</Table.Cell>
|
||||
<Table.Cell class="text-right"
|
||||
>{dayjs
|
||||
.duration(Number(track.duration), 'milliseconds')
|
||||
.format('mm:ss')}</Table.Cell
|
||||
>
|
||||
</Table.Row>
|
||||
{/snippet}
|
||||
</ContextMenu.Trigger>
|
||||
<ContextMenu.Content>
|
||||
<ContextMenu.Item
|
||||
onclick={() => library.removeTrackFromPlaylist(playlist.id, i, fetch)}
|
||||
>
|
||||
<Trash2 class="mr-1 size-4" />
|
||||
Remove from Playlist
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Root>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
|
||||
Reference in New Issue
Block a user