|
<script lang="ts"> |
|
import { onDestroy } from "svelte"; |
|
import CarbonImage from "~icons/carbon/image"; |
|
|
|
|
|
export let files: File[]; |
|
|
|
let file_error_message = ""; |
|
let errorTimeout: ReturnType<typeof setTimeout>; |
|
|
|
export let onDrag = false; |
|
|
|
async function dropHandle(event: DragEvent) { |
|
event.preventDefault(); |
|
if (event.dataTransfer && event.dataTransfer.items) { |
|
|
|
if (files.length > 0) { |
|
files = []; |
|
} |
|
|
|
|
|
|
|
if (event.dataTransfer.items[0].kind === "file") { |
|
const file = event.dataTransfer.items[0].getAsFile(); |
|
if (file) { |
|
if (!event.dataTransfer.items[0].type.startsWith("image")) { |
|
setErrorMsg("Only images are supported"); |
|
files = []; |
|
return; |
|
} |
|
|
|
if (file.size > 2 * 1024 * 1024) { |
|
setErrorMsg("Image is too big. (2MB max)"); |
|
files = []; |
|
return; |
|
} |
|
files = [file]; |
|
onDrag = false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
function setErrorMsg(errorMsg: string) { |
|
if (errorTimeout) { |
|
clearTimeout(errorTimeout); |
|
} |
|
file_error_message = errorMsg; |
|
errorTimeout = setTimeout(() => { |
|
file_error_message = ""; |
|
onDrag = false; |
|
}, 2000); |
|
} |
|
|
|
onDestroy(() => { |
|
if (errorTimeout) { |
|
clearTimeout(errorTimeout); |
|
} |
|
}); |
|
</script> |
|
|
|
<div |
|
id="dropzone" |
|
role="form" |
|
on:drop={dropHandle} |
|
class="relative flex w-full max-w-4xl flex-col items-center rounded-xl border border-dashed bg-gray-100 focus-within:border-gray-300 dark:border-gray-500 dark:bg-gray-700 dark:focus-within:border-gray-500" |
|
> |
|
<div class="object-center"> |
|
{#if file_error_message} |
|
<div |
|
class="absolute bottom-0 left-0 right-0 top-0 flex flex-col items-center justify-center gap-2 rounded-xl bg-gray-100 bg-opacity-50 dark:bg-gray-700 dark:bg-opacity-50" |
|
> |
|
<p class="text-red-500 dark:text-red-400">{file_error_message}</p> |
|
<div class="h-2.5 w-1/2 rounded-full bg-gray-200 dark:bg-gray-700"> |
|
<div |
|
class="animate-progress-bar h-2.5 |
|
rounded-full bg-red-500 |
|
dark:text-red-400 |
|
" |
|
/> |
|
</div> |
|
</div> |
|
{/if} |
|
<div class="mt-3 flex justify-center" class:opacity-0={file_error_message}> |
|
<CarbonImage class="text-xl text-gray-500 dark:text-gray-400" /> |
|
</div> |
|
<p |
|
class="mb-3 mt-1.5 text-sm text-gray-500 dark:text-gray-400" |
|
class:opacity-0={file_error_message} |
|
> |
|
Drag and drop <span class="font-semibold">one image</span> here |
|
</p> |
|
</div> |
|
</div> |
|
|
|
<style> |
|
@keyframes slideInFromLeft { |
|
0% { |
|
width: 0; |
|
} |
|
100% { |
|
width: 100%; |
|
} |
|
} |
|
|
|
.animate-progress-bar { |
|
|
|
animation: 2s linear 0s 1 slideInFromLeft; |
|
} |
|
</style> |
|
|