Add drag-to-reorder within playlists

Cards in playlist view are draggable. Visual feedback: opacity on
source card, accent border on drop target. Reorder persists to store.

Files:
- frontend/app.js: dragSource state, drag/drop handlers on cards,
  container-level dragover guard in wireUI
- frontend/styles.css: .card.dragging, .card.drag-over styles
This commit is contained in:
Jonathan Sykes
2026-06-14 14:41:05 +08:00
parent a4d6b825d5
commit 0ba0f56a54
6 changed files with 44 additions and 1 deletions

View File

@@ -51,6 +51,7 @@ let searchResults = [];
let queue = []; // list of video objects for autoplay
let queueIndex = -1;
let current = null; // { meta, qualities, audioUrl, localUrl? }
let dragSource = -1; // index of card being dragged
let saveTimer = null;
const cachedIds = new Set(); // video ids that exist in the offline cache
const downloading = new Set(); // video ids with an in-flight download
@@ -889,6 +890,39 @@ function renderCard(v, index, list) {
e.stopPropagation();
openCardMenu(v);
});
// Drag-to-reorder in playlist view
if (view.type === 'playlist') {
card.draggable = true;
card.addEventListener('dragstart', () => {
card.classList.add('dragging');
dragSource = index;
});
card.addEventListener('dragend', () => {
card.classList.remove('dragging');
});
card.addEventListener('dragover', (e) => {
e.preventDefault();
card.classList.add('drag-over');
});
card.addEventListener('dragleave', () => {
card.classList.remove('drag-over');
});
card.addEventListener('drop', (e) => {
e.preventDefault();
card.classList.remove('drag-over');
const from = dragSource;
const to = index;
if (from === to || from < 0) return;
const pl = data.playlists.find((p) => p.id === view.id);
if (!pl) return;
const [moved] = pl.videos.splice(from, 1);
pl.videos.splice(to, 0, moved);
persist();
renderList();
});
}
return card;
}
@@ -1173,6 +1207,11 @@ function wireUI() {
});
$('modal').addEventListener('click', (e) => { if (e.target.id === 'modal') closeModal(); });
// Drag-to-reorder: prevent default on cards container
els.cards.addEventListener('dragover', (e) => {
if (view.type === 'playlist') e.preventDefault();
});
}
// ============================================================================