Compare commits

2 Commits

Author SHA1 Message Date
d4564ca973 scope ul font-size rule to prevent global CSS pollution
All checks were successful
CI / update (push) Successful in 9s
The global 'ul' selector was affecting all unordered lists across the app after visiting /glaube/rosenkranz. This caused layout issues with action buttons on recipe pages where the internal symbols would shift to the top instead of being centered.

Fixed by scoping the rule to only apply to ul elements within .gebet containers.
2025-12-27 13:31:40 +01:00
f161d8a15d 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
2025-12-27 12:24:30 +01:00
8 changed files with 112 additions and 60 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,7 +2,7 @@ div.gebet{
text-align: center;
font-size: 1.25em;
}
ul {
.gebet ul {
font-size: 120%;
}
.gebet v{

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>