Migrates to svelte 5

This commit is contained in:
Christian Beutel
2025-01-24 17:46:13 +01:00
parent 7571f6e9b9
commit 3721b7f537
106 changed files with 5524 additions and 4232 deletions

View File

@@ -1,13 +1,12 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { type Snippet } from "svelte";
import {
SummitLogCreateSchema,
} from "$lib/models/api/summit_log_schema";
import { SummitLogCreateSchema } from "$lib/models/api/summit_log_schema";
import GPX from "$lib/models/gpx/gpx";
import { summitLog } from "$lib/stores/summit_log_store";
import { createForm } from "felte";
import { cloneDeep } from "$lib/util/deep_util";
import { validator } from "@felte/validator-zod";
import { createForm } from "felte";
import { _ } from "svelte-i18n";
import { z } from "zod";
import Datepicker from "../base/datepicker.svelte";
@@ -15,11 +14,19 @@
import Textarea from "../base/textarea.svelte";
import PhotoPicker from "../trail/photo_picker.svelte";
import TrailPicker from "../trail/trail_picker.svelte";
import { cloneDeep } from "$lib/util/deep_util";
export let openModal: (() => void) | undefined = undefined;
export let closeModal: (() => void) | undefined = undefined;
import type { SummitLog } from "$lib/models/summit_log";
interface Props {
children?: Snippet<[any]>;
onsave?: (summitLog: SummitLog) => void;
}
const dispatch = createEventDispatcher();
let { children, onsave }: Props = $props();
let modal: Modal;
export function openModal() {
modal.openModal();
}
const ClientSummitLogCreateSchema = SummitLogCreateSchema.extend({
_photos: z.array(z.instanceof(File)).optional(),
@@ -36,7 +43,7 @@
>({
initialValues: $summitLog,
extend: validator({ schema: ClientSummitLogCreateSchema }),
onSubmit: async (form) => {
onSubmit: async (form) => {
if (!form.expand?.gpx_data) {
form.gpx = "";
}
@@ -56,15 +63,22 @@
form._photos = [new File([blob], "route")];
}
dispatch("save", form);
closeModal!();
onsave?.(form);
modal.closeModal!();
},
});
$: setFields(cloneDeep($summitLog));
$: if ($summitLog._gpx) {
$data._gpx = $summitLog._gpx;
}
let trailData = $derived($data.expand?.gpx_data);
$effect(() => {
setFields(cloneDeep($summitLog));
});
$effect(() => {
if ($summitLog._gpx) {
$data._gpx = $summitLog._gpx;
}
});
async function handleTrailSelection(trailData: string | null) {
if (!trailData) {
@@ -85,63 +99,69 @@
$data.elevation_gain = totals.elevationGain;
$data.elevation_loss = totals.elevationLoss;
$data.distance = totals.distance;
$data.expand!.gpx_data = trailData;
}
const children_render = $derived(children);
</script>
<Modal
id="summit-log-modal"
title={$data.id ? $_("edit-entry") : $_("add-entry")}
let:openModal
bind:openModal
bind:closeModal
bind:this={modal}
>
<slot {openModal} />
<form
id="summit-log-form"
slot="content"
class="modal-content space-y-4"
use:form
>
<div class="flex">
<Datepicker name="date" label={$_("date")} error={$errors.date}
></Datepicker>
</div>
<div>
<label for="summitlog-photo-input" class="text-sm font-medium pb-1">
{$_("photos")}
</label>
<PhotoPicker
id="summitlog-photo-input"
parent={$data}
bind:photos={$data.photos}
bind:photoFiles={$data._photos}
showThumbnailControls={false}
></PhotoPicker>
</div>
<div class="flex gap-4">
{#if $data.expand}
<TrailPicker
bind:trailFile={$data._gpx}
bind:trailData={$data.expand.gpx_data}
label={$_("trail", { values: { n: 1 } })}
on:change={(e) => handleTrailSelection(e.detail)}
></TrailPicker>
{/if}
<div class="basis-full">
<Textarea
name="text"
extraClasses="h-28"
label={$_("text")}
error={$errors.text}
></Textarea>
{#snippet children({ openModal })}
{@render children_render?.({ openModal })}
{/snippet}
{#snippet content()}
<form id="summit-log-form" class="modal-content space-y-4" use:form>
<div class="flex">
<Datepicker name="date" label={$_("date")} error={$errors.date}
></Datepicker>
</div>
<div>
<label
for="summitlog-photo-input"
class="text-sm font-medium pb-1"
>
{$_("photos")}
</label>
<PhotoPicker
id="summitlog-photo-input"
parent={$data}
bind:photos={$data.photos}
bind:photoFiles={$data._photos}
showThumbnailControls={false}
></PhotoPicker>
</div>
<div class="flex gap-4">
{#if $data.expand}
<TrailPicker
bind:trailFile={$data._gpx}
{trailData}
label={$_("trail", { values: { n: 1 } })}
onchange={(trail) => handleTrailSelection(trail)}
></TrailPicker>
{/if}
<div class="basis-full">
<Textarea
name="text"
extraClasses="h-28"
label={$_("text")}
error={$errors.text}
></Textarea>
</div>
</div>
</form>
{/snippet}
{#snippet footer()}
<div class="flex items-center gap-4">
<button class="btn-secondary" onclick={() => modal.closeModal()}
>{$_("cancel")}</button
>
<button class="btn-primary" type="submit" form="summit-log-form"
>{$_("save")}</button
>
</div>
</form>
<div slot="footer" class="flex items-center gap-4">
<button class="btn-secondary" on:click={closeModal}
>{$_("cancel")}</button
>
<button class="btn-primary" type="submit" form="summit-log-form"
>{$_("save")}</button
>
</div>
{/snippet}
</Modal>