Files
flotilla/src/app/components/InputProfilePicture.svelte
T
2025-09-18 13:43:43 -07:00

111 lines
2.9 KiB
Svelte

<script lang="ts">
import {randomId, call} from "@welshman/lib"
import {preventDefault, stopPropagation, compressFile} from "@lib/html"
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
import GallerySend from "@assets/icons/gallery-send.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import {uploadFile} from "@app/core/commands"
interface Props {
file?: File | undefined
url?: string | undefined
}
let {file = $bindable(), url = $bindable()}: Props = $props()
const id = randomId()
const onDragEnter = () => {
active = true
}
const onDragOver = () => {
active = true
}
const onDragLeave = () => {
active = false
}
const onDrop = async (e: any) => {
active = false
file = await compressFile(e.dataTransfer.files[0])
}
const onChange = async (e: any) => {
file = await compressFile(e.target.files[0])
}
const onClear = () => {
initialUrl = undefined
file = undefined
url = undefined
}
let active = $state(false)
let initialUrl = $state(url)
$effect(() => {
call(async () => {
if (file) {
const {result} = await uploadFile(file)
if (result?.url) {
url = result.url
} else {
const reader = new FileReader()
reader.addEventListener(
"load",
() => {
url = reader.result as string
},
false,
)
reader.readAsDataURL(file)
}
} else {
url = initialUrl
}
})
})
</script>
<form>
<input {id} type="file" accept="image/*" onchange={onChange} class="hidden" />
<label
for={id}
aria-label="Drag and drop files here."
style="background-image: url({url});"
class="relative flex h-24 w-24 shrink-0 cursor-pointer items-center justify-center rounded-full border-2 border-solid border-base-content bg-base-300 bg-cover bg-center transition-all"
class:transparent={!url}
class:border-primary={active}
ondragenter={stopPropagation(preventDefault(onDragEnter))}
ondragover={stopPropagation(preventDefault(onDragOver))}
ondragleave={stopPropagation(preventDefault(onDragLeave))}
ondrop={stopPropagation(preventDefault(onDrop))}>
<div
class="absolute right-0 top-0 h-5 w-5 overflow-hidden rounded-full bg-primary"
class:bg-error={url}
class:bg-primary={!url}>
{#if url}
<span
role="button"
tabindex="-1"
onmousedown={stopPropagation(onClear)}
ontouchstart={stopPropagation(onClear)}>
<Icon icon={CloseCircle} class="scale-150 !bg-base-300" />
</span>
{:else}
<Icon icon={AddCircle} class="scale-150 !bg-base-300" />
{/if}
</div>
{#if !url}
<Icon icon={GallerySend} size={7} />
{/if}
</label>
</form>