diff --git a/README.md b/README.md index f984626..903c04b 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ The date, storage, rollover, task and undo logic lives in `src/lib/` as plain mo ### Managing Tasks - **Add a task**: Type in the input field and press Enter - **Complete a task**: Click the checkbox next to the task -- **Delete a task**: Hover over a task and click the delete icon, or press `Delete` with the task focused +- **Delete a task**: Click the delete icon on the task (it shows on hover, and is always visible on touch), or press `Delete` with the task focused - **Undo a delete**: Press `Cmd/Ctrl+Z`. The task returns to where it was - **Reorder tasks**: Drag with a mouse, long-press then drag on touch, or focus a task and press `Alt+↑`/`Alt+↓` - **Clear input**: Press Escape while the input is focused diff --git a/src/App.svelte b/src/App.svelte index 5cda81d..6fbd9c7 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -84,6 +84,19 @@ darkMode = !darkMode; } + // Svelte's transitions are driven in JavaScript, so the CSS media query in + // style.css cannot reach them. Read the same preference here and collapse the + // durations. The lift on a dragged card stays: it tracks the pointer rather + // than playing at you, and losing it would make dragging harder to follow. + const motionQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); + let reduceMotion = $state(motionQuery.matches); + + const flyIn = (index) => + reduceMotion ? { duration: 0 } : { y: -10, duration: 300, delay: index * 30, easing: cubicOut }; + + const flyOut = (index) => + reduceMotion ? { duration: 0 } : { x: 30, opacity: 0, duration: 250, delay: index * 20, easing: cubicOut }; + let fileInput; let status = $state(''); let statusIsError = $state(false); @@ -399,6 +412,10 @@ }, msUntilNextMidnight(new Date())); } + function handleMotionPreference(event) { + reduceMotion = event.matches; + } + function handleVisibility() { if (document.visibilityState === 'visible') runRollover(); } @@ -426,11 +443,13 @@ scheduleMidnight(); document.addEventListener('visibilitychange', handleVisibility); window.addEventListener('focus', runRollover); + motionQuery.addEventListener('change', handleMotionPreference); return () => { clearTimeout(midnightTimer); document.removeEventListener('visibilitychange', handleVisibility); window.removeEventListener('focus', runRollover); + motionQuery.removeEventListener('change', handleMotionPreference); }; }); @@ -518,7 +537,7 @@
{#key selectedKey} {#if tasks.length === 0} -
+