migrate from deprecated slots to snippets and fix event handlers

- Replace deprecated <slot> syntax with modern {#snippet} and {@render} patterns
- Add TypeScript types for snippet props in Header component
- Convert on:click event handlers to onclick attribute throughout
- Update all layout files to use new snippet-based composition pattern
This commit is contained in:
2025-12-27 12:24:30 +01:00
parent abc0d03e01
commit f161d8a15d
7 changed files with 111 additions and 59 deletions

View File

@@ -1,8 +1,23 @@
<script>
<script lang="ts">
import "$lib/css/nordtheme.css"
import { onMount } from "svelte";
import { page } from '$app/stores';
import Symbol from "./Symbol.svelte"
import type { Snippet } from 'svelte';
let {
links,
language_selector_mobile,
language_selector_desktop,
right_side,
children
}: {
links?: Snippet;
language_selector_mobile?: Snippet;
language_selector_desktop?: Snippet;
right_side?: Snippet;
children?: Snippet;
} = $props();
let underlineLeft = $state(0);
let underlineWidth = $state(0);
@@ -297,25 +312,25 @@ footer{
<div class=button_wrapper>
<a href="/"><Symbol></Symbol></a>
<div class="right-buttons">
<slot name=language_selector_mobile></slot>
<button class=nav_button on:click={() => {toggle_sidebar()}}><svg xmlns="http://www.w3.org/2000/svg" height="0.5em" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></button>
{@render language_selector_mobile?.()}
<button class=nav_button onclick={() => {toggle_sidebar()}}><svg xmlns="http://www.w3.org/2000/svg" height="0.5em" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></button>
</div>
</div>
<nav hidden class=nav_site>
<a class=entry href="/"><Symbol></Symbol></a>
<div class="links-wrapper">
<slot name=links></slot>
{@render links?.()}
<div class="active-underline" class:no-transition={disableTransition} style="left: {underlineLeft}px; width: {underlineWidth}px;"></div>
</div>
<div class="header-right">
<div class="language-selector-desktop">
<slot name=language_selector_desktop></slot>
{@render language_selector_desktop?.()}
</div>
<slot name=right_side></slot>
{@render right_side?.()}
</div>
</nav>
<slot></slot>
{@render children?.()}
</div>
<footer>

View File

@@ -136,7 +136,7 @@ h2 + p{
</style>
{#if user}
<button on:click={toggle_options} style="background-image: url(https://bocken.org/static/user/thumb/{user.nickname}.webp)" id=button>
<button onclick={toggle_options} style="background-image: url(https://bocken.org/static/user/thumb/{user.nickname}.webp)" id=button>
<div id=options class="speech top" hidden>
<h2>{user.name}</h2>
<p>({user.nickname})</p>

View File

@@ -2,16 +2,28 @@
import Header from '$lib/components/Header.svelte'
import UserHeader from '$lib/components/UserHeader.svelte';
import LanguageSelector from '$lib/components/LanguageSelector.svelte';
let { data } = $props();
let { data, children } = $props();
let user = $derived(data.session?.user);
</script>
<Header>
<ul class=site_header slot=links>
{#snippet links()}
<ul class=site_header>
</ul>
<LanguageSelector slot=language_selector_mobile />
<LanguageSelector slot=language_selector_desktop />
<UserHeader {user} slot=right_side></UserHeader>
<slot></slot>
{/snippet}
{#snippet language_selector_mobile()}
<LanguageSelector />
{/snippet}
{#snippet language_selector_desktop()}
<LanguageSelector />
{/snippet}
{#snippet right_side()}
<UserHeader {user}></UserHeader>
{/snippet}
{@render children()}
</Header>

View File

@@ -80,8 +80,10 @@
</svelte:head>
<Header>
<ul class="site_header" slot="links">
{#snippet links()}
<ul class="site_header">
</ul>
{/snippet}
<main class="error-page">
<div class="error-container">
@@ -109,38 +111,38 @@
<div class="error-actions">
{#if status === 401}
<button class="btn btn-primary" on:click={login}>
<button class="btn btn-primary" onclick={login}>
Anmelden
</button>
<button class="btn btn-secondary" on:click={goHome}>
<button class="btn btn-secondary" onclick={goHome}>
Zur Startseite
</button>
{:else if status === 403}
<button class="btn btn-primary" on:click={goHome}>
<button class="btn btn-primary" onclick={goHome}>
Zur Startseite
</button>
<button class="btn btn-secondary" on:click={goBack}>
<button class="btn btn-secondary" onclick={goBack}>
Zurück
</button>
{:else if status === 404}
<button class="btn btn-primary" on:click={goHome}>
<button class="btn btn-primary" onclick={goHome}>
Zur Startseite
</button>
<button class="btn btn-secondary" on:click={goBack}>
<button class="btn btn-secondary" onclick={goBack}>
Zurück
</button>
{:else if status === 500}
<button class="btn btn-primary" on:click={goHome}>
<button class="btn btn-primary" onclick={goHome}>
Zur Startseite
</button>
<button class="btn btn-secondary" on:click={goBack}>
<button class="btn btn-secondary" onclick={goBack}>
Erneut versuchen
</button>
{:else}
<button class="btn btn-primary" on:click={goHome}>
<button class="btn btn-primary" onclick={goHome}>
Zur Startseite
</button>
<button class="btn btn-secondary" on:click={goBack}>
<button class="btn btn-secondary" onclick={goBack}>
Zurück
</button>
{/if}

View File

@@ -3,7 +3,7 @@ import { page } from '$app/stores';
import Header from '$lib/components/Header.svelte'
import UserHeader from '$lib/components/UserHeader.svelte';
import LanguageSelector from '$lib/components/LanguageSelector.svelte';
let { data } = $props();
let { data, children } = $props();
let user = $derived(data.session?.user);
@@ -29,7 +29,8 @@ function isActive(path) {
</script>
<Header>
<ul class=site_header slot=links>
{#snippet links()}
<ul class=site_header>
<li><a href="/{data.recipeLang}" class:active={isActive(`/${data.recipeLang}`)}>{labels.allRecipes}</a></li>
{#if user}
<li><a href="/{data.recipeLang}/favorites" class:active={isActive(`/${data.recipeLang}/favorites`)}>{labels.favorites}</a></li>
@@ -39,8 +40,19 @@ function isActive(path) {
<li><a href="/{data.recipeLang}/icon" class:active={isActive(`/${data.recipeLang}/icon`)}>{labels.icon}</a></li>
<li><a href="/{data.recipeLang}/tag" class:active={isActive(`/${data.recipeLang}/tag`)}>{labels.keywords}</a></li>
</ul>
<LanguageSelector slot=language_selector_mobile />
<LanguageSelector slot=language_selector_desktop />
<UserHeader slot=right_side {user}></UserHeader>
<slot></slot>
{/snippet}
{#snippet language_selector_mobile()}
<LanguageSelector />
{/snippet}
{#snippet language_selector_desktop()}
<LanguageSelector />
{/snippet}
{#snippet right_side()}
<UserHeader {user}></UserHeader>
{/snippet}
{@render children()}
</Header>

View File

@@ -8,7 +8,7 @@
import Header from '$lib/components/Header.svelte';
import UserHeader from '$lib/components/UserHeader.svelte';
export let data;
let { data, children } = $props();
let showModal = false;
let paymentId = null;
@@ -57,16 +57,21 @@
</script>
<Header>
<ul class="site_header" slot="links">
{#snippet links()}
<ul class="site_header">
<li><a href="/cospend" class:active={isActive('/cospend')}>Dashboard</a></li>
<li><a href="/cospend/payments" class:active={isActive('/cospend/payments')}>All Payments</a></li>
<li><a href="/cospend/recurring" class:active={isActive('/cospend/recurring')}>Recurring Payments</a></li>
</ul>
<UserHeader slot="right_side" {user}></UserHeader>
{/snippet}
{#snippet right_side()}
<UserHeader {user}></UserHeader>
{/snippet}
<div class="layout-container" class:has-modal={showModal}>
<div class="main-content">
<slot />
{@render children()}
</div>
<div class="side-panel">

View File

@@ -2,7 +2,7 @@
import { page } from '$app/stores';
import Header from '$lib/components/Header.svelte'
import UserHeader from '$lib/components/UserHeader.svelte';
export let data
let { data, children } = $props();
function isActive(path) {
const currentPath = $page.url.pathname;
@@ -11,11 +11,17 @@ function isActive(path) {
}
</script>
<Header>
<ul class=site_header slot=links>
{#snippet links()}
<ul class=site_header>
<li><a href="/glaube/gebete" class:active={isActive('/glaube/gebete')}>Gebete</a></li>
<li><a href="/glaube/rosenkranz" class:active={isActive('/glaube/rosenkranz')}>Rosenkranz</a></li>
<li><a href="/glaube/predigten" class:active={isActive('/glaube/predigten')}>Predigten</a></li>
</ul>
<UserHeader user={data.session?.user} slot=right_side></UserHeader>
<slot></slot>
{/snippet}
{#snippet right_side()}
<UserHeader user={data.session?.user}></UserHeader>
{/snippet}
{@render children()}
</Header>