diff --git a/src/App.svelte b/src/App.svelte
index 2d454e7..1c78e9a 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -8,8 +8,10 @@
import { createStorage } from './lib/storage.js';
import { rollover, msUntilNextMidnight } from './lib/rollover.js';
import * as taskOps from './lib/tasks.js';
+ import { createUndoStack, applyUndo } from './lib/undo.js';
const storage = createStorage();
+ const undoStack = createUndoStack();
let tasks = $state([]);
let newTask = $state('');
@@ -43,27 +45,55 @@
}
function deleteTask(id) {
+ const index = tasks.findIndex(task => task.id === id);
+ if (index === -1) return;
+ undoStack.push({ type: 'delete', task: tasks[index], index });
setTasks(taskOps.deleteTask(tasks, id));
}
function clearCompleted() {
+ // Built in ascending index order, which applyUndo relies on to put each
+ // task back where it was.
+ const removed = tasks
+ .map((task, index) => ({ task, index }))
+ .filter(({ task }) => task.completed);
+
+ if (removed.length === 0) return;
+ undoStack.push({ type: 'clearCompleted', removed });
setTasks(taskOps.clearCompleted(tasks));
}
+ function undo() {
+ const entry = undoStack.pop();
+ if (entry) setTasks(applyUndo(tasks, entry));
+ }
+
function toggleTheme() {
darkMode = !darkMode;
}
- function handleKeydown(event) {
+ /** Scoped to the input. Previously this also sat on window, so Enter while a
+ * task was focused would toggle that task *and* add whatever was in the
+ * input. */
+ function handleInputKeydown(event) {
if (event.key === 'Enter') addTask();
else if (event.key === 'Escape') newTask = '';
}
+ function handleGlobalKeydown(event) {
+ if (!(event.metaKey || event.ctrlKey) || event.key.toLowerCase() !== 'z') return;
+ // Leave the text field its own native undo.
+ if (event.target instanceof HTMLInputElement) return;
+ event.preventDefault();
+ undo();
+ }
+
+ /** Backspace no longer deletes: it is the key people press meaning "go back",
+ * and a task destroyed that way used to be unrecoverable. Delete still does,
+ * and Cmd/Ctrl+Z now reverses it. */
function handleTaskKeydown(event, taskId) {
- if (event.key === ' ' || event.key === 'Enter') {
+ if (event.key === 'Delete') {
event.preventDefault();
- toggleTask(taskId);
- } else if (event.key === 'Delete' || event.key === 'Backspace') {
deleteTask(taskId);
}
}
@@ -170,7 +200,7 @@
});
-
No tasks yet. Add one above to get started!
{:else} +