Some checks failed
Test and deploy staging / staging (push) Has been cancelled
65 lines
1.7 KiB
Svelte
65 lines
1.7 KiB
Svelte
<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>
|