This commit is contained in:
64
src/lib/components/ListPictureDropzone.svelte
Normal file
64
src/lib/components/ListPictureDropzone.svelte
Normal file
@@ -0,0 +1,64 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let { label = 'Picture (optional)' }: { label?: string } = $props();
|
||||
let input: HTMLInputElement;
|
||||
let fileName = $state('');
|
||||
let dragging = $state(false);
|
||||
|
||||
function selected() {
|
||||
fileName = input.files?.[0]?.name ?? '';
|
||||
}
|
||||
|
||||
function drop(event: DragEvent) {
|
||||
event.preventDefault();
|
||||
dragging = false;
|
||||
const file = event.dataTransfer?.files?.[0];
|
||||
if (!file) return;
|
||||
const transfer = new DataTransfer();
|
||||
transfer.items.add(file);
|
||||
input.files = transfer.files;
|
||||
selected();
|
||||
}
|
||||
|
||||
function clear() {
|
||||
input.value = '';
|
||||
fileName = '';
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const form = input.form;
|
||||
form?.addEventListener('reset', clear);
|
||||
return () => form?.removeEventListener('reset', clear);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<span class="block font-medium">{label}</span>
|
||||
<input
|
||||
bind:this={input}
|
||||
name="picture"
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/webp"
|
||||
onchange={selected}
|
||||
class="sr-only"
|
||||
aria-label={label}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => input.click()}
|
||||
ondragover={(event) => {
|
||||
event.preventDefault();
|
||||
dragging = true;
|
||||
if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';
|
||||
}}
|
||||
ondragleave={() => (dragging = false)}
|
||||
ondrop={drop}
|
||||
class={`mt-2 block w-full rounded border border-dashed p-5 text-center transition-colors ${dragging ? 'border-[var(--site-text)] bg-[var(--site-hover)]' : 'border-[var(--site-border)] hover:border-[var(--site-muted)]'}`}
|
||||
>
|
||||
{fileName ? `Selected: ${fileName}` : 'Drop an image here or click to browse'}
|
||||
</button>
|
||||
<p class="mt-2 text-base text-[var(--site-muted)]">JPEG, PNG, or WebP · up to 5 MB</p>
|
||||
{#if fileName}<button type="button" onclick={clear} class="mt-2 underline">Clear selection</button
|
||||
>{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user