fix(todo): improve drag-and-drop handles and fix reorder persistence

- Replace hamburger icon with standard 6-dot grip icon for drag handles
- Increase drag handle icon size (1rem → 1.25rem) and hit area
- Fix reorder bug: handleDndFinalize was not calling reorderTasks(),
  so reordered items were never persisted and would revert on refresh
- Add optimistic update with rollback on error in reorderTasks store

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-24 19:43:30 +01:00
parent 233a3c0732
commit c96447981f
3 changed files with 22 additions and 9 deletions

View file

@ -301,8 +301,13 @@
>
<!-- Drag handle -->
<div class="drag-handle">
<svg class="drag-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16" />
<svg class="drag-icon" viewBox="0 0 24 24" fill="currentColor">
<circle cx="9" cy="6" r="1.5" />
<circle cx="15" cy="6" r="1.5" />
<circle cx="9" cy="12" r="1.5" />
<circle cx="15" cy="12" r="1.5" />
<circle cx="9" cy="18" r="1.5" />
<circle cx="15" cy="18" r="1.5" />
</svg>
</div>
@ -706,9 +711,11 @@
flex-shrink: 0;
display: flex;
align-items: center;
padding: 0.25rem;
margin-left: -0.125rem;
justify-content: center;
padding: 0.5rem 0.375rem;
margin-left: -0.25rem;
border-radius: 0.25rem;
min-height: 2rem;
}
.task-item:hover .drag-handle {
@ -730,8 +737,8 @@
}
.drag-icon {
width: 1rem;
height: 1rem;
width: 1.25rem;
height: 1.25rem;
color: currentColor;
}

View file

@ -197,6 +197,10 @@
// Task moved FROM another section TO this section
onTaskDrop(movedTaskId, dropTargetDate);
}
} else if (wasInThisList) {
// Task reordered within this list - persist the new order
const taskIds = newItems.map((t) => t.id);
tasksStore.reorderTasks(taskIds);
}
// Update local state and sync lastTaskKey to prevent $effect from reverting

View file

@ -452,17 +452,19 @@ export const tasksStore = {
*/
async reorderTasks(taskIds: string[]) {
error = null;
const previousTasks = [...tasks];
try {
await tasksApi.reorderTasks(taskIds);
// Update local order
// Optimistic update - set new order values
tasks = tasks.map((t) => {
const newOrder = taskIds.indexOf(t.id);
return newOrder !== -1 ? { ...t, order: newOrder } : t;
});
await tasksApi.reorderTasks(taskIds);
} catch (e) {
// Rollback on error
tasks = previousTasks;
error = e instanceof Error ? e.message : 'Failed to reorder tasks';
console.error('Failed to reorder tasks:', e);
throw e;
}
},