diff --git a/web/src/lib/components/DropOverlay.svelte b/web/src/lib/components/DropOverlay.svelte new file mode 100644 index 0000000..c146ec5 --- /dev/null +++ b/web/src/lib/components/DropOverlay.svelte @@ -0,0 +1,96 @@ + + +
+ {@render children()} + {#if dragging} + + {/if} +
+ + diff --git a/web/src/lib/components/DropZone.svelte b/web/src/lib/components/DropZone.svelte index b11a757..6ba835d 100644 --- a/web/src/lib/components/DropZone.svelte +++ b/web/src/lib/components/DropZone.svelte @@ -11,7 +11,24 @@ $props(); let input = $state(); - let dragging = $state(false); + let depth = $state(0); + const dragging = $derived(depth > 0); + + function enter() { + depth += 1; + } + + function leave() { + depth = Math.max(0, depth - 1); + } + + function over(event: DragEvent) { + event.preventDefault(); + } + + function end() { + depth = 0; + } function accept(file: File | undefined | null) { if (!file) return; @@ -40,14 +57,13 @@ openPicker(); } }} - ondragover={(e) => { - e.preventDefault(); - dragging = true; - }} - ondragleave={() => (dragging = false)} + ondragenter={enter} + ondragleave={leave} + ondragover={over} + ondragend={end} ondrop={(e) => { e.preventDefault(); - dragging = false; + depth = 0; accept(e.dataTransfer?.files[0]); }} > diff --git a/web/src/lib/components/ToolPage.svelte b/web/src/lib/components/ToolPage.svelte index ae65c93..63757d3 100644 --- a/web/src/lib/components/ToolPage.svelte +++ b/web/src/lib/components/ToolPage.svelte @@ -5,6 +5,7 @@ import { defaultParams, outputOf, sanitizeParams, type ToolEntry } from '$lib/registry'; import Button from './ui/Button.svelte'; import DownloadButton from './DownloadButton.svelte'; + import DropOverlay from './DropOverlay.svelte'; import DropZone from './DropZone.svelte'; import EmptyState from './ui/EmptyState.svelte'; import InfoPanel from './InfoPanel.svelte'; @@ -109,10 +110,12 @@ {#if !source} (errorText = message)} /> {:else} -
- -
- + (errorText = message)}> +
+ +
+ +
{/if}