diff --git a/src/renderer-queue.ts b/src/renderer-queue.ts index 6567960..71d9f9a 100644 --- a/src/renderer-queue.ts +++ b/src/renderer-queue.ts @@ -198,6 +198,49 @@ function updateQueueItemProgress(progress: DownloadProgress): void { if (meta) meta.textContent = getQueueMetaText(queue[idx]); } +function toggleQueueDetails(id: string): void { + const el = document.getElementById(`details-${id}`); + if (el) el.style.display = el.style.display === 'none' ? 'block' : 'none'; +} + +function initQueueDragDrop(): void { + const list = byId('queueList'); + + list.addEventListener('dragstart', (e: DragEvent) => { + const el = (e.target as HTMLElement).closest('.queue-item') as HTMLElement; + if (!el) return; + draggedQueueItemId = el.dataset.id || null; + el.classList.add('dragging'); + if (e.dataTransfer) e.dataTransfer.effectAllowed = 'move'; + }); + + list.addEventListener('dragover', (e: DragEvent) => { + e.preventDefault(); + if (e.dataTransfer) e.dataTransfer.dropEffect = 'move'; + }); + + list.addEventListener('drop', (e: DragEvent) => { + e.preventDefault(); + const target = (e.target as HTMLElement).closest('.queue-item') as HTMLElement; + if (!target || !draggedQueueItemId) return; + const targetId = target.dataset.id; + if (!targetId || targetId === draggedQueueItemId) return; + + const fromIdx = queue.findIndex(i => i.id === draggedQueueItemId); + const toIdx = queue.findIndex(i => i.id === targetId); + if (fromIdx < 0 || toIdx < 0) return; + const [moved] = queue.splice(fromIdx, 1); + queue.splice(toIdx, 0, moved); + window.api.reorderQueue(queue.map(i => i.id)); + renderQueue(); + }); + + list.addEventListener('dragend', () => { + draggedQueueItemId = null; + document.querySelectorAll('.queue-item.dragging').forEach(el => el.classList.remove('dragging')); + }); +} + function renderQueue(): void { if (!Array.isArray(queue)) { queue = []; @@ -244,7 +287,7 @@ function renderQueue(): void { : ''; return ` -
+
${showSelector ? `
${isSelected ? selectionIndex + 1 : ''}
` : '' @@ -252,7 +295,7 @@ function renderQueue(): void {
-
${mergeIcon}${isClip}${safeTitle}
+
${mergeIcon}${isClip}${safeTitle}
${safeStatusLabel}
${safeMeta}${mergeMetaExtra}
@@ -260,6 +303,12 @@ function renderQueue(): void {
${safeProgressText}
+
x
diff --git a/src/renderer.ts b/src/renderer.ts index 73302fa..8abdf8c 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -42,6 +42,7 @@ async function init(): Promise { changeTheme(config.theme ?? 'twitch'); renderStreamers(); renderQueue(); + initQueueDragDrop(); updateDownloadButtonState(); window.api.onQueueUpdated((q: QueueItem[]) => { diff --git a/src/styles.css b/src/styles.css index 7587dd9..2736870 100644 --- a/src/styles.css +++ b/src/styles.css @@ -334,6 +334,29 @@ body { opacity: 1; } +.queue-item[draggable="true"] { + cursor: grab; +} + +.queue-item[draggable="true"]:active { + cursor: grabbing; +} + +.queue-item.dragging { + opacity: 0.4; +} + +.queue-details { + font-size: 10px; + color: var(--text-secondary); + padding: 4px 0; + word-break: break-all; +} + +.queue-details div { + margin-bottom: 2px; +} + .queue-selector { width: 22px; height: 22px;