export function moveId(order, dragId, beforeId) { if (dragId === beforeId) return [...order]; const out = order.filter(id => id !== dragId); if (beforeId == null) { out.push(dragId); return out; } const i = out.indexOf(beforeId); if (i < 0) { out.push(dragId); return out; } out.splice(i, 0, dragId); return out; } // Wires HTML5 drag on .sv-card elements in `grid`. onReorder(newOrderIds) fires // after a drop. Drag handle = the whole card (cursor:grab on the title via CSS). export function attachReorder(grid, onReorder) { let dragId = null; grid.querySelectorAll('.sv-card').forEach(card => { card.draggable = true; card.addEventListener('dragstart', () => { dragId = card.dataset.cardId; card.classList.add('dragging'); }); card.addEventListener('dragend', () => { card.classList.remove('dragging'); dragId = null; }); 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'); if (!dragId || dragId === card.dataset.cardId) return; const ids = [...grid.querySelectorAll('.sv-card')].map(c => c.dataset.cardId); onReorder(moveId(ids, dragId, card.dataset.cardId)); }); }); }