66 lines
2.5 KiB
TypeScript
66 lines
2.5 KiB
TypeScript
import { createSignal, createEffect, onCleanup, untrack } from "solid-js";
|
|
import type { Task } from "@/store";
|
|
|
|
export function useDelayedSort(
|
|
sourceTasks: () => Task[],
|
|
sortFn: (a: Task, b: Task) => number,
|
|
delayMs = 300
|
|
) {
|
|
const initialTasks = untrack(() => [...sourceTasks()].sort(sortFn));
|
|
const [displayedTasks, setDisplayedTasks] = createSignal<Task[]>(initialTasks);
|
|
const [shakingTaskIds, setShakingTaskIds] = createSignal<string[]>([]);
|
|
|
|
let timer: number | undefined;
|
|
|
|
createEffect(() => {
|
|
const sorted = [...sourceTasks()].sort(sortFn);
|
|
const currentDisplayed = untrack(() => displayedTasks());
|
|
|
|
// Initial load (though now handled by initial state, kept for safety if it resets)
|
|
if (currentDisplayed.length === 0 && sorted.length > 0) {
|
|
setDisplayedTasks(sorted);
|
|
return;
|
|
}
|
|
|
|
// Check if anything fundamentally changed order
|
|
const newIds = sorted.map(t => t.id).join(',');
|
|
const oldIds = currentDisplayed.map(t => t.id).join(',');
|
|
|
|
if (newIds !== oldIds) {
|
|
// Find which IDs have moved or changed their presence
|
|
// To be safe, let's just shake all currently visible ones, or maybe just the ones moving.
|
|
// A simple "shake everything" works perfectly for a brief warning: "Items are shifting!"
|
|
// The user wanted "tasks an animation when they rearange where they shake"
|
|
const changedSet = new Set<string>();
|
|
sorted.forEach((t: Task, i: number) => {
|
|
if (currentDisplayed[i]?.id !== t.id) {
|
|
changedSet.add(t.id);
|
|
if (currentDisplayed[i]) changedSet.add(currentDisplayed[i].id);
|
|
}
|
|
});
|
|
|
|
if (changedSet.size > 0) {
|
|
setShakingTaskIds(Array.from(changedSet));
|
|
|
|
if (timer) clearTimeout(timer);
|
|
timer = window.setTimeout(() => {
|
|
setShakingTaskIds([]);
|
|
setDisplayedTasks(sorted);
|
|
}, delayMs);
|
|
} else {
|
|
setDisplayedTasks(sorted);
|
|
}
|
|
} else {
|
|
// Identical order, just data updates (e.g. title changes)
|
|
// We want these to pass through instantly without rearranging
|
|
setDisplayedTasks(sorted);
|
|
}
|
|
});
|
|
|
|
onCleanup(() => {
|
|
if (timer) clearTimeout(timer);
|
|
});
|
|
|
|
return { displayedTasks, shakingTaskIds };
|
|
}
|