drag drop

This commit is contained in:
2026-02-06 05:23:07 -08:00
parent f8b5f12812
commit 03be6760cc
2 changed files with 174 additions and 23 deletions

View File

@@ -25,6 +25,7 @@
nowPlayingLabel,
prev,
removeTrack,
reorderTrackById,
schedulePersistNow,
setUiOpen,
setVolume,
@@ -274,6 +275,87 @@
let clearQueueDialogOpen = $state(false);
// --- Drag & drop reorder (works for both linear and shuffle) ---
// We reorder by track.id (annSongId). The player module adjusts traversal state.
let dragId = $state<number | null>(null);
let dragOverId = $state<number | null>(null);
function onDragStart(trackId: number, e: DragEvent) {
dragId = trackId;
dragOverId = null;
// Best-effort: set payload (useful for some browsers)
try {
e.dataTransfer?.setData("text/plain", String(trackId));
e.dataTransfer!.effectAllowed = "move";
} catch {
// ignore
}
}
function onDragOver(trackId: number, e: DragEvent) {
// Required to allow dropping
e.preventDefault();
dragOverId = trackId;
try {
e.dataTransfer!.dropEffect = "move";
} catch {
// ignore
}
}
function onDrop(targetTrackId: number, e: DragEvent) {
e.preventDefault();
// Prefer our internal dragId; fall back to transfer data
let sourceId = dragId;
if (sourceId == null) {
const raw = e.dataTransfer?.getData("text/plain");
const parsed = raw ? Number(raw) : NaN;
if (Number.isFinite(parsed)) sourceId = parsed;
}
if (sourceId == null) {
dragId = null;
dragOverId = null;
return;
}
if (sourceId === targetTrackId) {
dragId = null;
dragOverId = null;
return;
}
// Reorder by queue indices
const fromIndex = snap.queue.findIndex((t) => t.id === sourceId);
const toIndex = snap.queue.findIndex((t) => t.id === targetTrackId);
if (fromIndex === -1 || toIndex === -1) {
dragId = null;
dragOverId = null;
return;
}
reorderTrackById(sourceId, toIndex);
dragId = null;
dragOverId = null;
}
function onDragEnd() {
dragId = null;
dragOverId = null;
}
function draggableHint(trackId: number) {
if (dragId == null) return "";
if (dragId === trackId) return "opacity-70";
if (dragOverId === trackId) return "ring-2 ring-primary/40";
return "";
}
function formatTime(seconds: number) {
if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
const s = Math.floor(seconds);
@@ -699,7 +781,17 @@
<ul class="rounded border">
{#each queueDisplay as item (item.track.id)}
<li
class="flex items-center gap-2 border-b px-2 py-2 last:border-b-0"
class={[
"flex items-center gap-2 border-b px-2 py-2 last:border-b-0",
draggableHint(item.track.id),
]
.filter(Boolean)
.join(" ")}
draggable="true"
ondragstart={(e) => onDragStart(item.track.id, e)}
ondragover={(e) => onDragOver(item.track.id, e)}
ondrop={(e) => onDrop(item.track.id, e)}
ondragend={onDragEnd}
>
<button
class="min-w-0 flex-1 truncate text-left text-sm hover:underline"
@@ -976,7 +1068,17 @@
<ul class="rounded border">
{#each queueDisplay as item (item.track.id)}
<li
class="flex items-center gap-2 border-b px-2 py-2 last:border-b-0"
class={[
"flex items-center gap-2 border-b px-2 py-2 last:border-b-0",
draggableHint(item.track.id),
]
.filter(Boolean)
.join(" ")}
draggable="true"
ondragstart={(e) => onDragStart(item.track.id, e)}
ondragover={(e) => onDragOver(item.track.id, e)}
ondrop={(e) => onDrop(item.track.id, e)}
ondragend={onDragEnd}
>
<button
class="min-w-0 flex-1 truncate text-left text-sm hover:underline"