feat: Live-Vorschau beim Kalender-Sortieren
Beim Ziehen wandert die Zeile jetzt live zwischen die anderen, die Liste macht sichtbar Platz an der Zielposition. Container-dragover wird nur einmal gebunden (kein Listener-Stacking pro Render). Version v30. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -575,34 +575,50 @@ function saveCalOrder(keys) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Drag & drop reordering of the flat calendar list (persisted per device).
|
// Drag & drop reordering of the flat calendar list (persisted per device).
|
||||||
|
// The dragged row is moved live among its siblings during dragover, so the
|
||||||
|
// list visibly "makes space" and you can see where it will land.
|
||||||
function bindCalDragReorder(container) {
|
function bindCalDragReorder(container) {
|
||||||
let dragKey = null;
|
// Find the row the cursor is currently above (by vertical midpoint), so we
|
||||||
|
// know before which sibling to insert the dragged row.
|
||||||
|
const rowAfter = (y) => {
|
||||||
|
const rows = [...container.querySelectorAll('.cal-item:not(.cal-dragging)')];
|
||||||
|
return rows.reduce((closest, row) => {
|
||||||
|
const box = row.getBoundingClientRect();
|
||||||
|
const offset = y - box.top - box.height / 2;
|
||||||
|
if (offset < 0 && offset > closest.offset) return { offset, el: row };
|
||||||
|
return closest;
|
||||||
|
}, { offset: Number.NEGATIVE_INFINITY, el: null }).el;
|
||||||
|
};
|
||||||
|
|
||||||
container.querySelectorAll('.cal-item').forEach(item => {
|
container.querySelectorAll('.cal-item').forEach(item => {
|
||||||
item.addEventListener('dragstart', e => {
|
item.addEventListener('dragstart', e => {
|
||||||
// Don't start a drag from interactive children (checkbox, color dot, buttons).
|
// Don't start a drag from interactive children (checkbox, color dot, buttons).
|
||||||
if (e.target.closest('input, button, .cal-item-dot')) { e.preventDefault(); return; }
|
if (e.target.closest('input, button, .cal-item-dot')) { e.preventDefault(); return; }
|
||||||
dragKey = item.dataset.key;
|
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
item.classList.add('cal-dragging');
|
// Defer the class so the drag image is the full opaque row, then dim it.
|
||||||
|
requestAnimationFrame(() => item.classList.add('cal-dragging'));
|
||||||
});
|
});
|
||||||
item.addEventListener('dragend', () => {
|
item.addEventListener('dragend', () => {
|
||||||
dragKey = null;
|
|
||||||
item.classList.remove('cal-dragging');
|
item.classList.remove('cal-dragging');
|
||||||
|
// Persist the final DOM order; no full re-render needed.
|
||||||
|
saveCalOrder([...container.querySelectorAll('.cal-item')].map(el => el.dataset.key));
|
||||||
});
|
});
|
||||||
item.addEventListener('dragover', e => { e.preventDefault(); });
|
});
|
||||||
item.addEventListener('drop', e => {
|
|
||||||
|
// Live reorder: move the dragged row to the hovered position as the cursor
|
||||||
|
// moves. Bound once on the (stable) container to avoid stacking listeners on
|
||||||
|
// every re-render.
|
||||||
|
if (!container.__dragBound) {
|
||||||
|
container.__dragBound = true;
|
||||||
|
container.addEventListener('dragover', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const targetKey = item.dataset.key;
|
const dragging = container.querySelector('.cal-dragging');
|
||||||
if (!dragKey || dragKey === targetKey) return;
|
if (!dragging) return;
|
||||||
const keys = [...container.querySelectorAll('.cal-item')].map(el => el.dataset.key);
|
const after = rowAfter(e.clientY);
|
||||||
const from = keys.indexOf(dragKey);
|
if (after == null) container.appendChild(dragging);
|
||||||
const to = keys.indexOf(targetKey);
|
else if (after !== dragging) container.insertBefore(dragging, after);
|
||||||
if (from === -1 || to === -1) return;
|
|
||||||
keys.splice(to, 0, keys.splice(from, 1)[0]);
|
|
||||||
saveCalOrder(keys);
|
|
||||||
renderCalendarList();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCalendarList() {
|
function renderCalendarList() {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// Increment APP_VERSION with every code change
|
// Increment APP_VERSION with every code change
|
||||||
export const APP_VERSION = 'v29';
|
export const APP_VERSION = 'v30';
|
||||||
|
|||||||
Reference in New Issue
Block a user