106 lines
2.6 KiB
Svelte
106 lines
2.6 KiB
Svelte
<script lang="ts">
|
|
import { enhance } from '$app/forms';
|
|
import type { ActionData } from './$types';
|
|
// @ts-expect-error: package does not contain type definitions
|
|
import AutoComplete from 'simple-svelte-autocomplete';
|
|
|
|
export let form: ActionData;
|
|
|
|
let selectedName: string;
|
|
|
|
let files: FileList;
|
|
let sending = false;
|
|
|
|
const siPrefixes = new Map([
|
|
[1_000_000, 'M'],
|
|
[1_000, 'k'],
|
|
]);
|
|
const fileSize = (files: FileList) => {
|
|
const size = Array.from(files)
|
|
.map((f) => f.size)
|
|
.reduce((a, b) => a + b, 0);
|
|
return (
|
|
Array.from(siPrefixes)
|
|
.filter(([k]) => size >= k)
|
|
.map(([k, v]) => `${(size / k).toFixed(1)} ${v}B`)[0] ?? `${size} bytes`
|
|
);
|
|
};
|
|
|
|
async function loadNames() {
|
|
const url = './names';
|
|
const response = await fetch(url);
|
|
return await response.json();
|
|
}
|
|
</script>
|
|
|
|
<form
|
|
enctype="multipart/form-data"
|
|
class="box"
|
|
method="POST"
|
|
use:enhance={() => {
|
|
sending = true;
|
|
return ({ update }) => {
|
|
update({ invalidateAll: true }).finally(async () => {
|
|
sending = false;
|
|
});
|
|
};
|
|
}}
|
|
>
|
|
{#if sending}
|
|
<div class="notification is-info">Wird hochgeladen...</div>
|
|
{:else if form?.success}
|
|
<div class="notification is-success">Erfolgreich hochgeladen</div>
|
|
{/if}
|
|
<div class="field">
|
|
<label for="name" class="label">Name</label>
|
|
<div class="control">
|
|
<AutoComplete
|
|
id="name"
|
|
name="name"
|
|
placeholder="Name"
|
|
create={true}
|
|
bind:selectedItem={selectedName}
|
|
bind:text={selectedName}
|
|
createText=""
|
|
searchFunction={loadNames}
|
|
/>
|
|
</div>
|
|
{#if form?.field === 'name'}
|
|
{#if form?.missing}
|
|
<p class="help is-danger">Bitte einen Namen angeben</p>
|
|
{:else if form?.incorrect}
|
|
<p class="help is-danger">Ungültiger Name</p>
|
|
{/if}
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="file is-centered has-name is-boxed">
|
|
<label class="file-label">
|
|
<input class="file-input" type="file" name="files" bind:files multiple required />
|
|
<span class="file-cta">
|
|
<span class="file-label">Fotos auswählen...</span>
|
|
</span>
|
|
{#if files && files?.length !== 0}
|
|
<span class="file-name">
|
|
{files.length} Bild{#if files.length > 1}er{/if} ausgewählt ({fileSize(files)})
|
|
</span>
|
|
{:else}
|
|
<span class="file-name">Keine Bilder ausgewählt</span>
|
|
{/if}
|
|
{#if form?.field === 'files'}
|
|
{#if form?.missing || form?.empty}
|
|
<p class="help is-danger">Bitte mindestens eine Datei auswählen</p>
|
|
{:else if form?.incorrect}
|
|
<p class="help is-danger">Ungültige Dateien</p>
|
|
{/if}
|
|
{/if}
|
|
</label>
|
|
</div>
|
|
|
|
<div class="field is-grouped is-grouped-centered">
|
|
<div class="control">
|
|
<button class="button is-link">Hochladen</button>
|
|
</div>
|
|
</div>
|
|
</form>
|