diff --git a/package-lock.json b/package-lock.json index 1123d1e..65747ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "better-sqlite3": "^12.6.2", "drizzle-orm": "^0.45.1", "nanoid": "^5.1.6", + "svelte-gestures": "^5.2.2", "svelte-persisted-store": "^0.12.0", "tailwindcss": "^4.1.18", "zod": "^4.3.6" @@ -4722,6 +4723,12 @@ } } }, + "node_modules/svelte-gestures": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/svelte-gestures/-/svelte-gestures-5.2.2.tgz", + "integrity": "sha512-Y+chXPaSx8OsPoFppUwPk8PJzgrZ7xoDJKXeiEc7JBqyKKzXer9hlf8F9O34eFuAWB4/WQEvccACvyBplESL7A==", + "license": "MIT" + }, "node_modules/svelte-persisted-store": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/svelte-persisted-store/-/svelte-persisted-store-0.12.0.tgz", diff --git a/package.json b/package.json index a1a10a9..8671ef7 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "better-sqlite3": "^12.6.2", "drizzle-orm": "^0.45.1", "nanoid": "^5.1.6", + "svelte-gestures": "^5.2.2", "svelte-persisted-store": "^0.12.0", "tailwindcss": "^4.1.18", "zod": "^4.3.6" diff --git a/src/lib/components/EntryCard.svelte b/src/lib/components/EntryCard.svelte index 47b2360..7101d12 100644 --- a/src/lib/components/EntryCard.svelte +++ b/src/lib/components/EntryCard.svelte @@ -2,6 +2,7 @@ import type { Entry } from '$lib/server/db/schema'; import { enhance } from '$app/forms'; import { slide } from 'svelte/transition'; + import { useSwipe, type SwipeCustomEvent } from 'svelte-gestures'; interface Props { entry: Entry; @@ -21,6 +22,41 @@ let saveTimeout: ReturnType; let isSaving = $state(false); + // Swipe state + let swipeOffset = $state(0); + let isConfirmingDelete = $state(false); + + function handleSwipe(event: SwipeCustomEvent) { + const { direction } = event.detail; + if (direction === 'left') { + isConfirmingDelete = true; + } + } + + // Create swipe gesture using useSwipe hook + const swipeGesture = useSwipe(handleSwipe, () => ({ + timeframe: 300, + minSwipeDistance: 60, + touchAction: 'pan-y' + })); + + function cancelDelete() { + isConfirmingDelete = false; + swipeOffset = 0; + } + + async function confirmDelete() { + const formData = new FormData(); + formData.append('id', entry.id); + + await fetch('?/delete', { + method: 'POST', + body: formData + }); + + window.location.reload(); + } + async function debouncedSave() { clearTimeout(saveTimeout); saveTimeout = setTimeout(async () => { @@ -64,163 +100,210 @@ } -
- -
- {#if entry.type === 'task'} -
- - -
- {:else} - - T - - {/if} - - -
-

- {entry.title || 'Untitled'} -

- {#if !expanded} -

- {entry.content} -

- {/if} -
- -
- {#if isSaving} - Saving... - {/if} - - {entry.type} - - -
+
+ + - - {#if expanded} -
-
- - -
- -
- - -
- -
-
- - -
- -
+ +
+ +
+ {#if entry.type === 'task'} + + {:else} + + T + + {/if} + + +
+

+ {entry.title || 'Untitled'} +

+ {#if !expanded} +

+ {entry.content} +

+ {/if} +
+ +
+ {#if isSaving} + Saving... + {/if} + + {entry.type} + +
+ + + {#if expanded} +
+
+ + +
+ +
+ + +
+ +
+
+ + +
+ +
+ + +
+
+
+ {/if} +
+ + + {#if isConfirmingDelete} +
+ + +
{/if} -
+