| <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> |
|
|