Coves frontend - a photon fork
1<script lang="ts">
2 import { Button, Label } from 'mono-svelte'
3 import { generateID } from './helper'
4
5 interface Props {
6 accept?: string
7 id?: string
8 files?: FileList | null
9 multiple?: boolean
10 preview?: boolean
11 label?: string | undefined
12 class?: string
13 customLabel?: import('svelte').Snippet
14 button?: import('svelte').Snippet
15 choose?: import('svelte').Snippet
16 }
17
18 let {
19 accept = '*',
20 id = generateID(),
21 files = $bindable(),
22 multiple = false,
23 preview = true,
24 label = undefined,
25 class: clazz = '',
26 customLabel,
27 button,
28 choose,
29 }: Props = $props()
30
31 let previewURLs = $derived(
32 preview && files ? Array.from(files).map(URL.createObjectURL) : undefined,
33 )
34</script>
35
36<div class="flex flex-col gap-1 {clazz}">
37 {#if customLabel || label}
38 <Label for={id} text={label}>
39 {@render customLabel?.()}
40 </Label>
41 {/if}
42 <label
43 class="w-max relative cursor-pointer space-x-2 flex flex-row items-center"
44 >
45 {#if button}{@render button()}{:else}
46 <Button>Browse</Button>
47 {/if}
48 {#if previewURLs}
49 <div
50 class="flex flex-row items-center -space-x-1 hover:space-x-1 z-20 h-8"
51 >
52 {#each previewURLs as file (file)}
53 <img
54 src={file}
55 onload={() => URL.revokeObjectURL(file)}
56 alt=""
57 class="w-8 h-8 object-cover rounded-full hover:w-16
58 hover:h-16 transition-all border border-slate-200 ring-1
59 ring-slate-50 dark:ring-zinc-950 bg-white dark:bg-zinc-950"
60 />
61 {/each}
62 </div>
63 {/if}
64 <span class="flex flex-row items-center text-slate-600 dark:text-zinc-400">
65 {#if choose}{@render choose()}{:else if (files ?? []).length == 0}
66 No file selected.
67 {:else}
68 {(files ?? []).length} files selected
69 {/if}
70 </span>
71 <input
72 type="file"
73 bind:files
74 {accept}
75 {multiple}
76 class="w-full h-full inset-0 opacity-0 absolute cursor-pointer"
77 />
78 </label>
79</div>