style(header mobile): Menü kompakter + Such-Overlay an Menü-Look angeglichen
Deploy / verify (push) Successful in 1m18s
Deploy / deploy (push) Successful in 1m42s

- Menü: Hauptpunkte text-sm + py-2.5 (kein Größensprung zu Subpunkten),
  Active nur per Farbe (kein font-bold), CTA-Buttons Ghost + Icons
- Search.svelte: dunkel-frosted Overlay (bg-stein-900/90 + blur), absolute
  statt in-flow, dunkler Input, helle Ergebnisse — konsistent mit dem Menü

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-06-30 16:04:50 +02:00
parent 7f67f59c8c
commit 85d6314ab4
2 changed files with 34 additions and 28 deletions
+16 -10
View File
@@ -311,8 +311,14 @@
aria-label={t(T.header_nav_aria)}
>
<div class="grid grid-cols-2 gap-2.5 pb-4 mb-2 border-b border-stein-0/10">
<a href="/mitmachen/" class="btn-primary btn-sm justify-center rounded-full py-2 shadow-sm" onclick={closeMenu}>Mitmachen</a>
<a href="/termin-melden" class="btn-warning btn-sm justify-center rounded-full py-2 shadow-sm" onclick={closeMenu}>Termin melden</a>
<a href="/mitmachen/" class="inline-flex items-center justify-center gap-1.5 rounded-full border border-wald-400/40 px-3 py-2 text-sm font-medium text-wald-200 transition-colors hover:bg-stein-0/10" onclick={closeMenu}>
<Icon icon="lucide:heart-handshake" class="size-4 shrink-0" aria-hidden="true" />
Mitmachen
</a>
<a href="/termin-melden" class="inline-flex items-center justify-center gap-1.5 rounded-full border border-gelb-400/40 px-3 py-2 text-sm font-medium text-gelb-300 transition-colors hover:bg-stein-0/10" onclick={closeMenu}>
<Icon icon="lucide:calendar-plus" class="size-4 shrink-0" aria-hidden="true" />
Termin melden
</a>
</div>
{#each links as link}
{@const active = isActiveTree(link, $page.url.pathname)}
@@ -321,7 +327,7 @@
<div>
<button
type="button"
class="flex w-full items-center justify-between py-4 px-3 rounded-xs transition-colors text-base text-stein-100 hover:bg-stein-0/10 border-l-4 {active ? 'border-wald-400 font-bold text-wald-300' : 'border-transparent'}"
class="flex w-full items-center justify-between py-2.5 px-3 rounded-xs transition-colors text-sm text-stein-100 hover:bg-stein-0/10 border-l-4 {active ? 'border-wald-400 text-wald-300' : 'border-transparent'}"
aria-expanded={expanded}
onclick={() => toggleSubmenu(link.label)}
>
@@ -334,7 +340,7 @@
{@const pActive = isActiveLink(link.href, $page.url.pathname)}
<a
href={link.href}
class="block py-3 px-3 text-sm {pActive ? 'font-bold text-wald-300' : 'text-stein-200 hover:text-stein-0'}"
class="block py-2 px-3 text-sm {pActive ? 'text-wald-300' : 'text-stein-200 hover:text-stein-0'}"
aria-current={pActive ? "page" : undefined}
onclick={closeMenu}
>
@@ -345,7 +351,7 @@
{@const cActive = isActiveLink(child.href, $page.url.pathname)}
<a
href={child.href}
class="block py-3 px-3 text-sm {cActive ? 'font-bold text-wald-300' : 'text-stein-200 hover:text-stein-0'}"
class="block py-2 px-3 text-sm {cActive ? 'text-wald-300' : 'text-stein-200 hover:text-stein-0'}"
aria-current={cActive ? "page" : undefined}
onclick={closeMenu}
>
@@ -358,8 +364,8 @@
{:else}
<a
href={link.href}
class="block py-4 px-3 rounded-xs transition-colors text-base {active
? 'font-bold text-wald-300 bg-wald-700/20 border-l-4 border-wald-400'
class="block py-2.5 px-3 rounded-xs transition-colors text-sm {active
? 'text-wald-300 bg-wald-700/20 border-l-4 border-wald-400'
: 'text-stein-100 hover:text-stein-0 hover:bg-stein-0/10 border-l-4 border-transparent'}"
aria-current={active ? "page" : undefined}
onclick={closeMenu}
@@ -381,8 +387,8 @@
rel={isInternal
? undefined
: "noopener noreferrer"}
class="flex items-center gap-3 py-4 px-3 rounded-xs transition-colors text-base border-l-4 {sActive
? 'font-bold text-wald-300 bg-wald-700/20 border-wald-400'
class="flex items-center gap-3 py-2.5 px-3 rounded-xs transition-colors text-sm border-l-4 {sActive
? 'text-wald-300 bg-wald-700/20 border-wald-400'
: 'text-stein-100 hover:text-stein-0 hover:bg-stein-0/10 border-transparent'}"
aria-current={sActive ? "page" : undefined}
aria-label={social.label ||
@@ -391,7 +397,7 @@
>
<Icon
icon={social.icon}
class="text-base"
class="text-sm"
aria-hidden="true"
/>
{#if social.label}
+18 -18
View File
@@ -88,7 +88,7 @@
.join("|");
return safe.replace(
new RegExp(`(${pattern})`, "gi"),
'<mark class="bg-wald-100 text-inherit rounded-xs px-0.5">$1</mark>',
'<mark class="bg-wald-400/30 text-wald-100 rounded-xs px-0.5">$1</mark>',
);
}
@@ -154,16 +154,16 @@
{#if open}
<div
id="search-panel"
class="border-t border-white/30 bg-white/95 backdrop-blur overflow-hidden"
class="absolute left-0 right-0 top-full z-30 shadow-2xl border-t border-stein-0/10 bg-stein-900/90 backdrop-blur-lg max-h-[calc(100dvh-3.5rem)] overflow-y-auto overscroll-contain"
role="region"
aria-label="Suche"
in:slide={{ duration: 200 }}
out:slide={{ duration: 150 }}
>
<div class="container-custom py-4 overflow-auto max-h-[calc(100vh-120px)]">
<div class="container-custom pt-4 pb-[calc(2rem+env(safe-area-inset-bottom))]">
<label class="relative block max-w-xl mx-auto">
<span class="sr-only">Suche</span>
<span class="pointer-events-none absolute top-1/2 left-3 -translate-y-1/2 text-stein-500">
<span class="pointer-events-none absolute top-1/2 left-3 -translate-y-1/2 text-stein-300">
<Icon icon="lucide:search" class="h-5 w-5" />
</span>
<input
@@ -171,14 +171,14 @@
type="search"
bind:value={query}
placeholder="Seiten und Beiträge durchsuchen…"
class="w-full rounded-xs border border-stein-300 bg-white py-3 pl-10 pr-10 text-sm focus:border-stein-500 focus:outline-none"
class="w-full rounded-xs border border-stein-0/20 bg-stein-800/70 py-3 pl-10 pr-10 text-sm text-stein-0 placeholder:text-stein-400 focus:border-wald-400 focus:outline-none"
/>
{#if query}
<button
type="button"
onclick={() => (query = "")}
aria-label="Eingabe leeren"
class="absolute top-1/2 right-2 -translate-y-1/2 rounded-xs p-1 text-stein-500 hover:bg-stein-100 hover:text-stein-900"
class="absolute top-1/2 right-2 -translate-y-1/2 rounded-xs p-1 text-stein-300 hover:bg-stein-0/10 hover:text-stein-0"
>
<Icon icon="lucide:x" class="h-4 w-4" />
</button>
@@ -192,18 +192,18 @@
{/if}
</p>
{#if loading}
<p class="text-stein-500 text-center py-2">Lade Suchindex…</p>
<p class="text-stein-300 text-center py-2">Lade Suchindex…</p>
{:else if loadError}
<p class="text-fire-600 text-center py-2">Suche nicht verfügbar: {loadError}</p>
<p class="text-fire-400 text-center py-2">Suche nicht verfügbar: {loadError}</p>
{:else if normalizedQuery.length < 2}
<p class="text-stein-500 text-center py-2">Mindestens 2 Zeichen eingeben.</p>
<p class="text-stein-300 text-center py-2">Mindestens 2 Zeichen eingeben.</p>
{:else if results.length === 0}
<p class="text-stein-500 text-center py-2">Keine Treffer.</p>
<p class="text-stein-300 text-center py-2">Keine Treffer.</p>
{:else}
<p class="text-stein-400 text-xs mb-2">
{results.length === MAX_RESULTS ? `${MAX_RESULTS}+ Treffer` : `${results.length} Treffer`} · ↑↓ zum Wählen, ⏎ zum Öffnen
</p>
<ul class="divide-y divide-stein-200">
<ul class="divide-y divide-stein-0/10">
{#each results as hit, i}
<li>
<a
@@ -212,32 +212,32 @@
onclick={closeSearch}
onmouseenter={() => (activeIndex = i)}
aria-current={i === activeIndex ? "true" : undefined}
class="flex items-start gap-3 py-3 rounded-xs px-2 -mx-2 no-underline {i === activeIndex ? 'bg-stein-100' : 'hover:bg-stein-50'}"
class="flex items-start gap-3 py-3 rounded-xs px-2 -mx-2 no-underline {i === activeIndex ? 'bg-stein-0/10' : 'hover:bg-stein-0/10'}"
>
{#if hit.image}
<img
src={hit.image}
alt=""
class="w-20 h-12 object-cover shrink-0 rounded-xs border border-stein-200"
class="w-20 h-12 object-cover shrink-0 rounded-xs border border-stein-0/10"
loading="lazy"
/>
{:else}
<span class="w-20 h-12 shrink-0 bg-stein-100 rounded-xs border border-stein-200 flex items-center justify-center text-stein-400">
<span class="w-20 h-12 shrink-0 bg-stein-0/10 rounded-xs border border-stein-0/10 flex items-center justify-center text-stein-400">
<Icon icon={hit.type === "post" ? "lucide:file-text" : "lucide:file"} class="h-5 w-5" />
</span>
{/if}
<div class="min-w-0 flex-1">
<div class="flex items-center gap-2 text-[.65rem] uppercase tracking-wide text-stein-500">
<div class="flex items-center gap-2 text-[.65rem] uppercase tracking-wide text-stein-300">
<span>{hit.type === "post" ? "Beitrag" : "Seite"}</span>
{#if hit.isEvent && hit.eventDate}
<span class="text-wald-700">{formatDate(hit.eventDate)}</span>
<span class="text-wald-300">{formatDate(hit.eventDate)}</span>
{:else if hit.created}
<span>{formatDate(hit.created)}</span>
{/if}
</div>
<div class="font-medium text-stein-900 truncate">{@html highlight(hit.title)}</div>
<div class="font-medium text-stein-0 truncate">{@html highlight(hit.title)}</div>
{#if hit.excerpt}
<div class="text-xs text-stein-600 line-clamp-2">{@html highlight(hit.excerpt)}</div>
<div class="text-xs text-stein-300 line-clamp-2">{@html highlight(hit.excerpt)}</div>
{/if}
</div>
</a>