feat(header): icon nav redesign + migrate icons mdi→lucide
Deploy / verify (push) Successful in 1m26s
Deploy / deploy (push) Successful in 2m26s

- Header desktop nav: social icons grouped in a wald-tinted pill with
  labels, active-state (aria-current + bold), opacity hover (no per-item bg)
- Mobile overlay: social links as icon+label rows with active-state
- Search button: lucide:search, icon-only
- Migrate all icons mdi→lucide app-wide (234 refs); brand/language logos
  (google, whatsapp, mastodon, telegram, language-*) stay on mdi
- generate-icons: emit mdi + lucide subsets; add @iconify-json/lucide
- iconify-offline: register lucide collection
- scripts/icon-map|validate|apply: reusable migration tooling

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-06-24 10:44:56 +02:00
parent e434ee3620
commit 0ab2c58eb4
46 changed files with 823 additions and 598 deletions
+1 -1
View File
@@ -34,7 +34,7 @@
<details {id} {open} ontoggle={onToggle} class="pt-4 border-t border-stein-200 group {cls}">
<summary class="flex cursor-pointer list-none items-center gap-2 text-sm font-medium select-none">
<Icon icon="mdi:chevron-right" class="size-4 shrink-0 transition-transform group-open:rotate-90" />
<Icon icon="lucide:chevron-right" class="size-4 shrink-0 transition-transform group-open:rotate-90" />
{label}
</summary>
<div class="mt-4">
+6 -6
View File
@@ -133,7 +133,7 @@
<span
class="pointer-events-none absolute top-1/2 left-2 -translate-y-1/2 text-stein-500"
>
<Icon icon="mdi:magnify" class="h-4 w-4" />
<Icon icon="lucide:search" class="h-4 w-4" />
</span>
<input
type="search"
@@ -148,7 +148,7 @@
class="absolute top-1/2 right-1.5 -translate-y-1/2 rounded-xs p-1 text-stein-500 hover:bg-stein-100 hover:text-stein-900"
aria-label={t(T.blog_search_clear)}
>
<Icon icon="mdi:close" class="h-4 w-4" />
<Icon icon="lucide:x" class="h-4 w-4" />
</button>
{/if}
</label>
@@ -158,7 +158,7 @@
<span
class="pointer-events-none absolute top-1/2 left-2 -translate-y-1/2 text-stein-500"
>
<Icon icon="mdi:calendar" class="h-4 w-4" />
<Icon icon="lucide:calendar" class="h-4 w-4" />
</span>
<select
bind:value={year}
@@ -172,7 +172,7 @@
<span
class="pointer-events-none absolute top-1/2 right-1.5 -translate-y-1/2 text-stein-500"
>
<Icon icon="mdi:chevron-down" class="h-4 w-4" />
<Icon icon="lucide:chevron-down" class="h-4 w-4" />
</span>
</label>
{/if}
@@ -186,7 +186,7 @@
<h2
class="mb-3 flex items-center gap-2 text-sm font-semibold tracking-wide text-stein-700"
>
<Icon icon="mdi:calendar-clock" class="size-7 shrink-0" />
<Icon icon="lucide:calendar-clock" class="size-7 shrink-0" />
{t(T.blog_upcoming_events)}
</h2>
<ul class="not-prose list-none space-y-2 pl-0">
@@ -343,7 +343,7 @@
href="/posts/rss.xml"
class="inline-flex items-center gap-1 hover:underline"
>
<Icon icon="mdi:rss" class="h-3.5 w-3.5" />
<Icon icon="lucide:rss" class="h-3.5 w-3.5" />
{t(T.blog_rss_subscribe)}
</a>
</div>
+2 -2
View File
@@ -73,7 +73,7 @@
aria-label="Vorheriger Eintrag"
class="shrink-0 inline-flex items-center justify-center size-7 rounded-full bg-white/90 border border-stein-200 shadow-sm hover:bg-white hover:border-wald-700 transition"
>
<Icon icon="mdi:chevron-left" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="size-4" aria-hidden="true" />
</button>
{/if}
@@ -97,7 +97,7 @@
aria-label="Nächster Eintrag"
class="shrink-0 inline-flex items-center justify-center size-7 rounded-full bg-white/90 border border-stein-200 shadow-sm hover:bg-white hover:border-wald-700 transition"
>
<Icon icon="mdi:chevron-right" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="size-4" aria-hidden="true" />
</button>
{/if}
</div>
+7 -7
View File
@@ -332,7 +332,7 @@
onclick={() => startEdit(c)}
class="text-xs text-stein-600 hover:text-stein-900 inline-flex items-center gap-1"
>
<Icon icon="mdi:pencil-outline" class="size-3" />
<Icon icon="lucide:pencil" class="size-3" />
{t(T.comments_edit)}
</button>
<button
@@ -340,7 +340,7 @@
onclick={() => deleteComment(c.id)}
class="text-xs text-stein-600 hover:text-fire-700 inline-flex items-center gap-1"
>
<Icon icon="mdi:trash-can-outline" class="size-3" />
<Icon icon="lucide:trash-2" class="size-3" />
{t(T.comments_delete)}
</button>
</div>
@@ -364,7 +364,7 @@
{/if}
{#if c.status === "pending"}
<span class="ml-auto inline-flex items-center gap-1 rounded-full bg-erde-100 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-erde-800">
<Icon icon="mdi:clock-outline" class="size-3" />
<Icon icon="lucide:clock" class="size-3" />
{t(T.comments_pending_short)}
</span>
{/if}
@@ -387,7 +387,7 @@
</ul>
{:else if loadError}
<div class="flex items-start gap-2 rounded-xs border border-fire-200 bg-fire-50 p-3 text-sm text-fire-800">
<Icon icon="mdi:alert-circle-outline" class="size-5 shrink-0 mt-0.5" />
<Icon icon="lucide:circle-alert" class="size-5 shrink-0 mt-0.5" />
<div class="flex-1">
<p class="font-medium">{t(T.comments_load_error_title)}</p>
<p class="mt-1 text-xs text-fire-700">{loadError}</p>
@@ -401,7 +401,7 @@
{:else}
{#if topLevel.length === 0}
<div class="flex flex-col items-center gap-1 py-8 text-center sm:flex-row sm:items-center sm:text-left sm:py-4 sm:gap-1.5">
<Icon icon="mdi:comment-text-outline" class="size-5 text-stein-300 shrink-0" />
<Icon icon="lucide:message-square-text" class="size-5 text-stein-300 shrink-0" />
<p class="text-sm font-semibold text-stein-300">{t(T.comments_empty)}</p>
</div>
{:else}
@@ -424,7 +424,7 @@
onclick={() => (replyTo = replyTo === c.id ? null : c.id)}
class="text-xs text-stein-600 hover:text-stein-900 inline-flex items-center gap-1"
>
<Icon icon="mdi:reply" class="size-3" />
<Icon icon="lucide:reply" class="size-3" />
{replyTo === c.id
? t(T.comments_cancel)
: replies.length === 0
@@ -531,7 +531,7 @@
</button>
{#if requireApproval}
<span class="text-stein-500 inline-flex items-center gap-1">
<Icon icon="mdi:shield-check-outline" class="size-3.5" />
<Icon icon="lucide:shield-check" class="size-3.5" />
{t(T.comments_approval_hint)}
</span>
{/if}
+3 -3
View File
@@ -43,20 +43,20 @@
onclick={() => downloadVCard(contact)}
class="absolute top-3 right-3 text-stein-300 transition-colors hover:text-wald-600"
>
<Icon icon="mdi:card-account-details-outline" class="size-4" />
<Icon icon="lucide:id-card" class="size-4" />
</button>
{#if contact.phone || contact.email}
<div class="flex flex-col gap-1">
{#if contact.phone}
<a href="tel:{contact.phone.replace(/\s/g, '')}" class="inline-flex items-center gap-1.5 text-xs text-stein-600 no-underline hover:text-wald-700">
<Icon icon="mdi:phone-outline" class="size-3.5 shrink-0 text-stein-400" />
<Icon icon="lucide:phone" class="size-3.5 shrink-0 text-stein-400" />
<span class="truncate">{contact.phone}</span>
</a>
{/if}
{#if contact.email}
<a href="mailto:{contact.email}" class="inline-flex items-center gap-1.5 text-xs text-stein-600 no-underline hover:text-wald-700">
<Icon icon="mdi:email-outline" class="size-3.5 shrink-0 text-stein-400" />
<Icon icon="lucide:mail" class="size-3.5 shrink-0 text-stein-400" />
<span class="truncate">{contact.email}</span>
</a>
{/if}
+3 -3
View File
@@ -28,19 +28,19 @@
<div class="flex flex-wrap gap-2">
{#if dateLabel}
<span class="inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-wald-500 px-3 py-1 text-[.65rem] font-semibold text-white shadow-sm no-underline! [text-decoration:none]">
<Icon icon="mdi:calendar" class="size-3.5 shrink-0 opacity-90" aria-hidden="true" />
<Icon icon="lucide:calendar" class="size-3.5 shrink-0 opacity-90" aria-hidden="true" />
{dateLabel}
</span>
{/if}
{#if locationText}
{#if locationHref}
<a href={locationHref} target={locationHref.startsWith('#') ? undefined : '_blank'} rel={locationHref.startsWith('#') ? undefined : 'noopener noreferrer'} title={locationText} class="inline-flex min-w-0 items-center gap-1.5 rounded-full bg-stein-800 text-stein-50! px-3 py-1 text-[.65rem] shadow-sm hover:bg-stein-700 transition-colors no-underline!">
<Icon icon="mdi:map-marker" class="size-3.5 shrink-0 opacity-90" aria-hidden="true" />
<Icon icon="lucide:map-pin" class="size-3.5 shrink-0 opacity-90" aria-hidden="true" />
<span class="truncate max-w-[16rem]">{locationText}</span>
</a>
{:else}
<span title={locationText} class="inline-flex min-w-0 items-center gap-1.5 rounded-full bg-stein-800 text-stein-50 px-3 py-1 text-[.65rem] font-medium shadow-sm no-underline! [text-decoration:none]">
<Icon icon="mdi:map-marker" class="size-3.5 shrink-0 opacity-90" aria-hidden="true" />
<Icon icon="lucide:map-pin" class="size-3.5 shrink-0 opacity-90" aria-hidden="true" />
<span class="truncate max-w-[16rem]">{locationText}</span>
</span>
{/if}
+3 -3
View File
@@ -45,7 +45,7 @@
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') overlayVisible = false; }}
>
<div class="flex items-center gap-2 rounded-full bg-white/90 px-4 py-2 text-xs font-medium text-stein-700 shadow">
<Icon icon="mdi:cursor-default-click" class="size-4 shrink-0" aria-hidden="true" />
<Icon icon="lucide:mouse-pointer-click" class="size-4 shrink-0" aria-hidden="true" />
{t(translations, T.post_map_activate)}
</div>
</div>
@@ -58,7 +58,7 @@
rel="noopener noreferrer"
class="flex items-center gap-1.5 px-3 py-1.5 bg-wald-50 text-wald-700 text-[.65rem] font-medium hover:bg-wald-100 transition-colors border-t border-wald-200"
>
<Icon icon="mdi:open-in-new" class="size-3.5 shrink-0" aria-hidden="true" />
<Icon icon="lucide:external-link" class="size-3.5 shrink-0" aria-hidden="true" />
{t(translations, T.post_map_open_osm)}
</a>
{/if}
@@ -70,7 +70,7 @@
rel="noopener noreferrer"
class="flex items-center gap-2 px-3 py-2 bg-wald-50 text-wald-700 text-xs font-medium hover:bg-wald-100 transition-colors"
>
<Icon icon="mdi:map-marker" class="size-4 shrink-0" aria-hidden="true" />
<Icon icon="lucide:map-pin" class="size-4 shrink-0" aria-hidden="true" />
{locationText ?? t(translations, T.post_map_open_osm)}
</a>
{/if}
+63 -48
View File
@@ -149,7 +149,7 @@
aria-expanded="false"
>
{link.label}
<Icon icon="mdi:chevron-down" class="size-3" aria-hidden="true" />
<Icon icon="lucide:chevron-down" class="size-3" aria-hidden="true" />
</a>
{:else}
<button
@@ -159,7 +159,7 @@
aria-expanded="false"
>
{link.label}
<Icon icon="mdi:chevron-down" class="size-3" aria-hidden="true" />
<Icon icon="lucide:chevron-down" class="size-3" aria-hidden="true" />
</button>
{/if}
<div
@@ -193,43 +193,51 @@
</a>
{/if}
{/each}
<div class="w-1 h-4"></div>
{#each socialLinks as social}
{@const isInternal = social.href.startsWith("/")}
<a
href={social.href}
target={isInternal ? undefined : "_blank"}
rel={isInternal ? undefined : "noopener noreferrer"}
class="p-1.5 -m-1.5 rounded-xs transition-colors flex items-center justify-center"
aria-label={social.label || t(T.header_social_aria)}
title={social.label || t(T.header_social_aria)}
>
<Icon icon={social.icon} aria-hidden="true" />
</a>
{/each}
<button
type="button"
class="p-2 -mr-2 rounded-xs transition-colors flex items-center justify-center"
aria-label={searchOpen
? t(T.header_search_close)
: t(T.header_search_open)}
title={searchOpen
? t(T.header_search_close)
: t(T.header_search_open)}
aria-expanded={searchOpen}
aria-controls="search-panel"
onclick={() => (searchOpen = !searchOpen)}
<div
class="ml-2 flex items-center gap-0.5 rounded-full border border-wald-700/15 bg-wald-700/8 px-2 py-1"
>
{#if searchOpen}
<Icon
icon="mdi:close"
class="text-error!"
aria-hidden="true"
/>
{:else}
<Icon icon="mdi:magnify" aria-hidden="true" />
{/if}
</button>
{#each socialLinks as social}
{@const isInternal = social.href.startsWith("/")}
{@const sActive = isInternal && isActiveLink(social.href, $page.url.pathname)}
<a
href={social.href}
target={isInternal ? undefined : "_blank"}
rel={isInternal ? undefined : "noopener noreferrer"}
class="px-1.5 py-0.5 rounded-full transition-opacity hover:opacity-70 inline-flex items-center gap-1.5 {sActive ? 'font-bold' : ''}"
aria-current={sActive ? "page" : undefined}
aria-label={social.label || t(T.header_social_aria)}
title={social.label || t(T.header_social_aria)}
>
<Icon icon={social.icon} class="text-sm" aria-hidden="true" />
{#if social.label}
<span class="text-[.7rem] leading-none">{social.label}</span>
{/if}
</a>
{/each}
<button
type="button"
class="px-1.5 py-0.5 rounded-full transition-opacity hover:opacity-70 inline-flex items-center justify-center"
aria-label={searchOpen
? t(T.header_search_close)
: t(T.header_search_open)}
title={searchOpen
? t(T.header_search_close)
: t(T.header_search_open)}
aria-expanded={searchOpen}
aria-controls="search-panel"
onclick={() => (searchOpen = !searchOpen)}
>
{#if searchOpen}
<Icon
icon="lucide:x"
class="text-sm text-error!"
aria-hidden="true"
/>
{:else}
<Icon icon="lucide:search" class="text-sm" aria-hidden="true" />
{/if}
</button>
</div>
</nav>
<!-- Mobile: Such- und Burger-Buttons (unter lg) -->
@@ -246,13 +254,13 @@
>
{#if searchOpen}
<Icon
icon="mdi:close"
icon="lucide:x"
class="text-2xl text-error!"
aria-hidden="true"
/>
{:else}
<Icon
icon="mdi:magnify"
icon="lucide:search"
class="text-2xl"
aria-hidden="true"
/>
@@ -275,12 +283,12 @@
>
{#if menuOpen}
<Icon
icon="mdi:close"
icon="lucide:x"
class="text-2xl"
aria-hidden="true"
/>
{:else}
<Icon icon="mdi:menu" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:menu" class="text-2xl" aria-hidden="true" />
{/if}
</button>
</div>
@@ -314,7 +322,7 @@
onclick={() => toggleSubmenu(link.label)}
>
<span>{link.label}</span>
<Icon icon={expanded ? "mdi:chevron-up" : "mdi:chevron-down"} class="size-4" aria-hidden="true" />
<Icon icon={expanded ? "lucide:chevron-up" : "lucide:chevron-down"} class="size-4" aria-hidden="true" />
</button>
{#if expanded}
<div class="ml-6 border-l border-stein-0/10" in:slide={{ duration: 150 }} out:slide={{ duration: 100 }}>
@@ -357,27 +365,34 @@
{/if}
{/each}
{#if socialLinks.length > 0}
<div
class="flex flex-wrap gap-2 pt-2 mt-2 border-t border-stein-0/10"
>
<div class="flex flex-col gap-1 pt-2 mt-2 border-t border-stein-0/10">
{#each socialLinks as social}
{@const isInternal = social.href.startsWith("/")}
{@const sActive =
isInternal &&
isActiveLink(social.href, $page.url.pathname)}
<a
href={social.href}
target={isInternal ? undefined : "_blank"}
rel={isInternal
? undefined
: "noopener noreferrer"}
class="inline-flex p-2 text-stein-100 hover:text-stein-0 hover:bg-stein-0/10 rounded-xs transition-colors"
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'
: 'text-stein-100 hover:text-stein-0 hover:bg-stein-0/10 border-transparent'}"
aria-current={sActive ? "page" : undefined}
aria-label={social.label ||
t(T.header_social_aria)}
onclick={closeMenu}
>
<Icon
icon={social.icon}
class="text-[1.5rem]"
class="text-base"
aria-hidden="true"
/>
{#if social.label}
<span>{social.label}</span>
{/if}
</a>
{/each}
</div>
+1 -1
View File
@@ -39,6 +39,6 @@
class="absolute top-4 right-4 p-2 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
aria-label="Schließen"
>
<Icon icon="mdi:close" class="size-5" aria-hidden="true" />
<Icon icon="lucide:x" class="size-5" aria-hidden="true" />
</button>
</div>
+2 -2
View File
@@ -17,7 +17,7 @@
body = "",
variant = "stein",
open = false,
iconName = "mdi:information-outline",
iconName = "lucide:info",
}: {
title: string;
body?: string;
@@ -48,7 +48,7 @@
<summary class="flex cursor-pointer items-center gap-1.5 px-3 py-1.5 font-medium leading-snug list-none {p.summary}">
<Icon icon={iconName} class="size-3.5 shrink-0 {p.icon}" />
<span class="flex-1">{title}</span>
<Icon icon="mdi:chevron-down" class="info-accordion-chevron size-3.5 shrink-0 transition-transform {p.icon}" />
<Icon icon="lucide:chevron-down" class="info-accordion-chevron size-3.5 shrink-0 transition-transform {p.icon}" />
</summary>
<div class="markdown prose prose-sm prose-zinc max-w-none border-t px-3 py-2 leading-relaxed {p.body}">{@html body}</div>
</details>
+2 -2
View File
@@ -60,7 +60,7 @@
<div class="flex items-center">
{#if hasPrev}
<a href={pageHref(prevPage)} class="{baseShape} {navShape} {inactiveColors}" aria-label={t(T.pagination_prev)}>
<Icon icon="mdi:chevron-left" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="size-4" aria-hidden="true" />
<span class="hidden sm:inline">{t(T.pagination_prev)}</span>
</a>
{/if}
@@ -76,7 +76,7 @@
{#if hasNext}
<a href={pageHref(nextPage)} class="{baseShape} {navShape} {inactiveColors}" aria-label={t(T.pagination_next)}>
<span class="hidden sm:inline">{t(T.pagination_next)}</span>
<Icon icon="mdi:chevron-right" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="size-4" aria-hidden="true" />
</a>
{/if}
</div>
+6 -6
View File
@@ -174,7 +174,7 @@
title={t(T.comments_jump_to)}
class="no-underline! inline-flex items-center gap-1 rounded-full border border-stein-200 bg-white px-2.5 py-1 text-xs font-medium text-stein-700! hover:bg-stein-50 hover:border-stein-300 transition-colors"
>
<Icon icon="mdi:comment-outline" class="size-3.5" />
<Icon icon="lucide:message-circle" class="size-3.5" />
<span class="tabular-nums">{commentCount ?? "…"}</span>
</a>
{/if}
@@ -189,7 +189,7 @@
title={t(T.post_action_share)}
>
<Icon
icon={shared ? "mdi:check" : "mdi:share-variant-outline"}
icon={shared ? "lucide:check" : "lucide:share-2"}
class="size-3.5"
/>
</button>
@@ -201,7 +201,7 @@
aria-label={copied ? t(T.post_action_copied) : t(T.post_action_copy)}
title={copied ? t(T.post_action_copied) : t(T.post_action_copy)}
>
<Icon icon={copied ? "mdi:check" : "mdi:link-variant"} class="size-3.5" />
<Icon icon={copied ? "lucide:check" : "lucide:link"} class="size-3.5" />
</button>
<button
type="button"
@@ -210,7 +210,7 @@
aria-label={t(T.post_action_print)}
title={t(T.post_action_print)}
>
<Icon icon="mdi:printer-outline" class="size-3.5" />
<Icon icon="lucide:printer" class="size-3.5" />
</button>
{#if socialSlug}
<button
@@ -220,7 +220,7 @@
aria-label="Social-Bild Vorschau"
title="Social-Bild Vorschau (für Instagram, Facebook, WhatsApp)"
>
<Icon icon="mdi:image-outline" class="size-3.5" />
<Icon icon="lucide:image" class="size-3.5" />
</button>
{/if}
<QrButton
@@ -247,7 +247,7 @@
class="inline-flex items-center gap-1 rounded-full border border-stein-200 bg-white px-2.5 py-1 text-xs text-stein-500"
title={t(T.post_action_reading_time, { minutes: readingTimeMinutes })}
>
<Icon icon="mdi:clock-outline" class="size-3.5" />
<Icon icon="lucide:clock" class="size-3.5" />
<span class="tabular-nums"
>{t(T.post_action_reading_time, { minutes: readingTimeMinutes })}</span
>
+1 -1
View File
@@ -102,7 +102,7 @@
aria-label={t(T.comments_count_aria, { count: commentCount })}
title={t(T.comments_count_aria, { count: commentCount })}
>
<Icon icon="mdi:comment-outline" class="size-3" />
<Icon icon="lucide:message-circle" class="size-3" />
{commentCount}
</span>
</div>
+1 -1
View File
@@ -24,7 +24,7 @@
onclick={() => (open = true)}
class={cls}
>
<Icon icon="mdi:qrcode" class="size-[1em]" />
<Icon icon="lucide:qr-code" class="size-[1em]" />
</button>
<QrModal value={open ? value : null} {label} {sublabel} onclose={() => (open = false)} />
+2 -2
View File
@@ -71,7 +71,7 @@
class="absolute right-3 top-3 text-stein-400 hover:text-stein-700"
aria-label="Schließen"
>
<Icon icon="mdi:close" class="size-5" />
<Icon icon="lucide:x" class="size-5" />
</button>
{#if label}
<p class="mb-1 text-sm font-medium text-stein-900">{label}</p>
@@ -93,7 +93,7 @@
disabled={!qrPngUrl}
class="btn-outline btn-sm mt-3 w-full justify-center"
>
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Als PNG herunterladen
</button>
</div>
+3 -3
View File
@@ -90,7 +90,7 @@
<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">
<Icon icon="mdi:magnify" class="h-5 w-5" />
<Icon icon="lucide:search" class="h-5 w-5" />
</span>
<input
bind:this={inputEl}
@@ -106,7 +106,7 @@
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"
>
<Icon icon="mdi:close" class="h-4 w-4" />
<Icon icon="lucide:x" class="h-4 w-4" />
</button>
{/if}
</label>
@@ -138,7 +138,7 @@
/>
{: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">
<Icon icon={hit.type === "post" ? "mdi:file-document-outline" : "mdi:file-outline"} class="h-5 w-5" />
<Icon icon={hit.type === "post" ? "lucide:file-text" : "lucide:file"} class="h-5 w-5" />
</span>
{/if}
<div class="min-w-0 flex-1">
+5 -5
View File
@@ -100,7 +100,7 @@
title="Direktlink zu dieser Vorschau kopieren"
aria-label="Direktlink kopieren"
>
<Icon icon={linkCopied ? "mdi:check" : "mdi:link-variant"} class="size-3.5" />
<Icon icon={linkCopied ? "lucide:check" : "lucide:link"} class="size-3.5" />
{linkCopied ? "Kopiert" : "Direktlink"}
</button>
<button
@@ -109,7 +109,7 @@
class="text-stein-400 hover:text-stein-700"
aria-label="Schließen"
>
<Icon icon="mdi:close" class="size-5" />
<Icon icon="lucide:x" class="size-5" />
</button>
</div>
</div>
@@ -170,7 +170,7 @@
/>
</div>
<a href={ogUrl} download={`${downloadPrefix}-${slug}-og-${theme}.png`} class="btn-outline btn-sm justify-center no-underline!">
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Quer herunterladen
</a>
</div>
@@ -189,7 +189,7 @@
/>
</div>
<a href={sqUrl} download={`${downloadPrefix}-${slug}-square-${theme}.png`} class="btn-outline btn-sm justify-center no-underline!">
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Quadrat herunterladen
</a>
</div>
@@ -208,7 +208,7 @@
/>
</div>
<a href={storyUrl} download={`${downloadPrefix}-${slug}-story-${theme}.png`} class="btn-outline btn-sm justify-center no-underline!">
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Story herunterladen
</a>
</div>
+14 -14
View File
@@ -110,7 +110,7 @@
class="shrink-0 rounded-md p-1.5 text-stein-400 hover:bg-stein-100 hover:text-stein-700 transition-colors"
aria-label={t(T.windkarte_panel_close)}
>
<Icon icon="mdi:close" class="size-5" />
<Icon icon="lucide:x" class="size-5" />
</button>
</div>
@@ -121,7 +121,7 @@
{#if area.flaeche_ha != null}
<div class="flex items-center justify-between px-3 py-1.5">
<span class="flex items-center gap-1.5 text-xs text-stein-500">
<Icon icon="mdi:ruler-square" class="size-3.5 text-stein-400" />
<Icon icon="lucide:ruler" class="size-3.5 text-stein-400" />
{t(T.windkarte_label_flaeche)}
</span>
<span class="font-semibold text-stein-800">{area.flaeche_ha.toFixed(1)} ha</span>
@@ -130,13 +130,13 @@
{#if area.anlagen_geplant != null}
<div class="flex items-center justify-between px-3 py-1.5">
<span class="flex items-center gap-1.5 text-xs text-stein-500">
<Icon icon="mdi:wind-turbine" class="size-3.5 text-stein-400" />
<Icon icon="lucide:fan" class="size-3.5 text-stein-400" />
{t(T.windkarte_label_anlagen_geplant)}
</span>
<span class="flex items-center gap-1.5 font-semibold text-stein-800">
{area.anlagen_geplant}
{#if area.anlagen_geplant_hinweis}
<Icon icon="mdi:information-outline" class="size-3.5 text-amber-700" />
<Icon icon="lucide:info" class="size-3.5 text-amber-700" />
{/if}
</span>
</div>
@@ -144,7 +144,7 @@
{#if area.investor}
<div class="flex items-center justify-between px-3 py-1.5">
<span class="flex items-center gap-1.5 text-xs text-stein-500">
<Icon icon="mdi:domain" class="size-3.5 text-stein-400" />
<Icon icon="lucide:building-2" class="size-3.5 text-stein-400" />
{t(T.windkarte_label_investor)}
</span>
<span class="font-semibold text-stein-800">{area.investor}</span>
@@ -164,7 +164,7 @@
{#if area.gemeinden && area.gemeinden.length > 0}
<div>
<p class="mb-2 flex items-center gap-1.5 text-xs font-medium uppercase tracking-wide text-stein-500">
<Icon icon="mdi:map-marker" class="size-3.5 text-stein-400" />
<Icon icon="lucide:map-pin" class="size-3.5 text-stein-400" />
{t(T.windkarte_label_gemeinden)}
</p>
<div class="flex flex-wrap gap-1.5">
@@ -186,7 +186,7 @@
<!-- Stellungnahme-Kriterien -->
{#if loadingKriterien}
<div class="flex items-center gap-2 text-xs text-stein-400">
<Icon icon="mdi:loading" class="size-3.5 animate-spin" />
<Icon icon="lucide:loader-circle" class="size-3.5 animate-spin" />
<span>{t(T.windkarte_kriterien_loading)}</span>
</div>
{:else if kriterien.length > 0}
@@ -201,7 +201,7 @@
>
<span class="min-w-0 line-clamp-2">{k.title ?? k._slug}</span>
<Icon
icon={expandedSlug === k._slug ? "mdi:chevron-up" : "mdi:chevron-down"}
icon={expandedSlug === k._slug ? "lucide:chevron-up" : "lucide:chevron-down"}
class="size-3.5 shrink-0 mt-0.5 text-stein-400"
/>
</button>
@@ -222,7 +222,7 @@
href={area.stellungnahmeUrl}
class="flex items-center gap-2 rounded-lg bg-wald-700 px-4 py-3 text-sm font-semibold text-white no-underline hover:bg-wald-800 transition-colors"
>
<Icon icon="mdi:file-document-edit-outline" class="size-4 shrink-0" />
<Icon icon="lucide:file-pen" class="size-4 shrink-0" />
Einwendung erstellen
</a>
{/if}
@@ -233,7 +233,7 @@
href={stellungnahmeHref(area.stellungnahme)}
class="flex items-center gap-2 rounded-lg border border-wald-300 bg-wald-50 px-4 py-3 text-sm font-medium text-wald-700 hover:bg-wald-100 transition-colors"
>
<Icon icon="mdi:file-document-edit-outline" class="size-4 shrink-0" />
<Icon icon="lucide:file-pen" class="size-4 shrink-0" />
{t(T.windkarte_stellungnahme_link)}
</a>
{/if}
@@ -244,7 +244,7 @@
onclick={copyLink}
class="flex flex-1 items-center justify-center gap-1.5 rounded-lg border border-stein-200 px-2 py-2 text-xs font-medium text-stein-600 hover:bg-stein-50 transition-colors whitespace-nowrap"
>
<Icon icon={copied ? "mdi:check" : "mdi:link-variant"} class="size-3.5 shrink-0" />
<Icon icon={copied ? "lucide:check" : "lucide:link"} class="size-3.5 shrink-0" />
{copied ? t(T.windkarte_action_copied) : t(T.windkarte_action_copy_link)}
</button>
{#if osmHref(center)}
@@ -254,7 +254,7 @@
rel="noopener noreferrer"
class="flex flex-1 items-center justify-center gap-1.5 rounded-lg border border-stein-200 px-2 py-2 text-xs font-medium text-stein-600 hover:bg-stein-50 transition-colors whitespace-nowrap"
>
<Icon icon="mdi:map-outline" class="size-3.5 shrink-0" />
<Icon icon="lucide:map" class="size-3.5 shrink-0" />
{t(T.windkarte_action_osm)}
</a>
{/if}
@@ -270,7 +270,7 @@
title={`${t(T.windkarte_action_download_geojson)}\n${exportInfo}`}
class="flex flex-1 items-center justify-center gap-1.5 rounded-lg border border-stein-200 px-2 py-2 text-xs font-medium text-stein-600 no-underline hover:bg-stein-50 transition-colors whitespace-nowrap"
>
<Icon icon="mdi:download" class="size-3.5 shrink-0" />
<Icon icon="lucide:download" class="size-3.5 shrink-0" />
GeoJSON
</a>
<a
@@ -279,7 +279,7 @@
title={`${t(T.windkarte_action_download_kml)}\n${exportInfo}`}
class="flex flex-1 items-center justify-center gap-1.5 rounded-lg border border-stein-200 px-2 py-2 text-xs font-medium text-stein-600 no-underline hover:bg-stein-50 transition-colors whitespace-nowrap"
>
<Icon icon="mdi:download" class="size-3.5 shrink-0" />
<Icon icon="lucide:download" class="size-3.5 shrink-0" />
KML
</a>
</div>
@@ -122,7 +122,7 @@
<div class="no-print mb-4 flex flex-col gap-2">
<div class="flex gap-2">
<div class="relative max-w-sm flex-1">
<Icon icon="mdi:magnify" class="absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-stein-400" />
<Icon icon="lucide:search" class="absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-stein-400" />
<input
type="search"
placeholder="Suchen…"
@@ -138,7 +138,7 @@
class="px-2 py-1 transition-colors {viewMode === 'alpha' ? 'bg-wald-500 text-white' : 'bg-white text-stein-600 hover:bg-stein-50'}"
title="Alphabetisch"
>
<Icon icon="mdi:sort-alphabetical-ascending" class="size-4" />
<Icon icon="lucide:arrow-down-a-z" class="size-4" />
</button>
<button
type="button"
@@ -146,7 +146,7 @@
class="px-2 py-1 transition-colors {viewMode === 'org' ? 'bg-wald-500 text-white' : 'bg-white text-stein-600 hover:bg-stein-50'}"
title="Nach Organisation"
>
<Icon icon="mdi:account-group-outline" class="size-4" />
<Icon icon="lucide:users" class="size-4" />
</button>
</div>
</div>
@@ -224,7 +224,7 @@
onclick={() => downloadVCardAll(filtered())}
class="no-print btn-outline btn-sm"
>
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Alle exportieren (.vcf)
</button>
<p class="text-xs text-stein-400">{filtered().length} Kontakt{filtered().length !== 1 ? "e" : ""}</p>
@@ -266,13 +266,13 @@
onclick={() => downloadVCard(contact)}
class="text-stein-300 transition-colors hover:text-wald-600"
>
<Icon icon="mdi:card-account-details-outline" class="size-4" />
<Icon icon="lucide:id-card" class="size-4" />
</button>
</div>
{#if contact.note}
<div class="flex items-center gap-1.5 text-xs text-stein-400">
<Icon icon="mdi:map-marker-outline" class="size-3.5 shrink-0" />
<Icon icon="lucide:map-pin" class="size-3.5 shrink-0" />
<span class="min-w-0 truncate">{contact.note}</span>
</div>
{/if}
@@ -281,7 +281,7 @@
<div class="flex flex-col gap-1">
{#if contact.phone}
<div class="flex items-center gap-1.5">
<Icon icon="mdi:phone-outline" class="size-3.5 shrink-0 text-stein-400" />
<Icon icon="lucide:phone" class="size-3.5 shrink-0 text-stein-400" />
<span class="min-w-0 truncate text-xs text-stein-600">{contact.phone}</span>
<button
type="button"
@@ -289,20 +289,20 @@
onclick={() => navigator.clipboard.writeText(contact.phone ?? "")}
class="no-print shrink-0 text-stein-300 transition-colors hover:text-wald-600"
>
<Icon icon="mdi:content-copy" class="size-3.5" />
<Icon icon="lucide:copy" class="size-3.5" />
</button>
<a
href="tel:{contact.phone.replace(/\s/g, '')}"
title="Anrufen"
class="no-print shrink-0 text-stein-300 no-underline transition-colors hover:text-wald-600"
>
<Icon icon="mdi:arrow-top-right" class="size-3.5" />
<Icon icon="lucide:arrow-up-right" class="size-3.5" />
</a>
</div>
{/if}
{#if contact.email}
<div class="flex items-center gap-1.5">
<Icon icon="mdi:email-outline" class="size-3.5 shrink-0 text-stein-400" />
<Icon icon="lucide:mail" class="size-3.5 shrink-0 text-stein-400" />
<span class="min-w-0 truncate text-xs text-stein-600">{contact.email}</span>
<button
type="button"
@@ -310,14 +310,14 @@
onclick={() => navigator.clipboard.writeText(contact.email ?? "")}
class="no-print shrink-0 text-stein-300 transition-colors hover:text-wald-600"
>
<Icon icon="mdi:content-copy" class="size-3.5" />
<Icon icon="lucide:copy" class="size-3.5" />
</button>
<a
href="mailto:{contact.email}"
title="E-Mail schreiben"
class="no-print shrink-0 text-stein-300 no-underline transition-colors hover:text-wald-600"
>
<Icon icon="mdi:arrow-top-right" class="size-3.5" />
<Icon icon="lucide:arrow-up-right" class="size-3.5" />
</a>
</div>
{/if}
+22 -22
View File
@@ -635,7 +635,7 @@
class="inline-flex items-center gap-1 tabular-nums"
>
<Icon
icon="mdi:clock-outline"
icon="lucide:clock"
class="size-3"
aria-hidden="true"
/>
@@ -647,7 +647,7 @@
class="inline-flex items-center gap-1 min-w-0"
>
<Icon
icon="mdi:map-marker-outline"
icon="lucide:map-pin"
class="size-3 shrink-0"
aria-hidden="true"
/>
@@ -671,7 +671,7 @@
</div>
</div>
<Icon
icon="mdi:chevron-down"
icon="lucide:chevron-down"
class="size-4 text-stein-400 shrink-0 mt-1 transition-transform group-open/event:rotate-180"
aria-hidden="true"
/>
@@ -738,7 +738,7 @@
class="absolute inset-0 flex items-center justify-center bg-black/0 group-hover:bg-black/20 transition-colors"
>
<Icon
icon="mdi:magnify-plus"
icon="lucide:zoom-in"
class="size-5 text-white opacity-0 group-hover:opacity-100 transition-opacity drop-shadow"
aria-hidden="true"
/>
@@ -758,7 +758,7 @@
>
Details
<Icon
icon="mdi:arrow-right"
icon="lucide:arrow-right"
class="size-3.5"
aria-hidden="true"
/>
@@ -773,7 +773,7 @@
>
{t(T.calendar_more_info)}
<Icon
icon="mdi:open-in-new"
icon="lucide:external-link"
class="size-3.5"
aria-hidden="true"
/>
@@ -788,7 +788,7 @@
aria-label={t(T.calendar_open_maps)}
>
<Icon
icon="mdi:map-marker"
icon="lucide:map-pin"
class="size-3.5 shrink-0"
aria-hidden="true"
/>
@@ -803,7 +803,7 @@
aria-label={item.attachment.label || "Anhang herunterladen"}
>
<Icon
icon="mdi:file-download"
icon="lucide:file-down"
class="size-3.5 shrink-0"
aria-hidden="true"
/>
@@ -827,7 +827,7 @@
title={t(T.calendar_download_ics)}
aria-label={t(T.calendar_download_ics)}
>
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
ICS
</button>
<a
@@ -858,7 +858,7 @@
title={t(T.post_action_copy)}
aria-label={t(T.post_action_copy)}
>
<Icon icon={copied ? "mdi:check" : "mdi:link-variant"} class="size-3.5" />
<Icon icon={copied ? "lucide:check" : "lucide:link"} class="size-3.5" />
{copied ? t(T.post_action_copied) : "Link"}
</button>
<button
@@ -868,7 +868,7 @@
title={t(T.calendar_share_aria)}
aria-label={t(T.calendar_share_aria)}
>
<Icon icon={shared ? "mdi:check" : "mdi:share-variant"} class="size-3.5" />
<Icon icon={shared ? "lucide:check" : "lucide:share-2"} class="size-3.5" />
{shared ? t(T.calendar_share_copied) : t(T.calendar_share)}
</button>
{#if item._slug}
@@ -879,7 +879,7 @@
title="Social-Bild Vorschau"
aria-label="Social-Bild Vorschau"
>
<Icon icon="mdi:image-outline" class="size-3.5" />
<Icon icon="lucide:image" class="size-3.5" />
Bild
</button>
{/if}
@@ -890,7 +890,7 @@
title="QR-Code anzeigen & herunterladen"
aria-label="QR-Code anzeigen & herunterladen"
>
<Icon icon="mdi:qrcode" class="size-3.5" />
<Icon icon="lucide:qr-code" class="size-3.5" />
QR
</button>
</div>
@@ -905,7 +905,7 @@
title={t(T.calendar_jump_to_month)}
aria-label={t(T.calendar_jump_to_month)}
>
<Icon icon="mdi:calendar-search" class="size-3.5" />
<Icon icon="lucide:calendar-search" class="size-3.5" />
Im Grid
</button>
</div>
@@ -970,7 +970,7 @@
class="btn-primary btn-sm inline-flex items-center gap-1.5 min-h-[36px]"
>
<Icon
icon="mdi:calendar-plus"
icon="lucide:calendar-plus"
class="size-3.5 shrink-0"
aria-hidden="true"
/>
@@ -984,7 +984,7 @@
class="btn-primary btn-sm inline-flex items-center gap-1.5 min-h-[36px]"
>
<Icon
icon="mdi:calendar-plus"
icon="lucide:calendar-plus"
class="size-3.5 shrink-0"
aria-hidden="true"
/>
@@ -998,7 +998,7 @@
class="btn-outline btn-sm inline-flex items-center gap-1.5 min-h-[36px]"
>
<Icon
icon="mdi:download"
icon="lucide:download"
class="size-3.5 shrink-0"
aria-hidden="true"
/>
@@ -1029,7 +1029,7 @@
onclick={prevMonth}
>
<Icon
icon="mdi:chevron-left"
icon="lucide:chevron-left"
class="size-5"
aria-hidden="true"
/>
@@ -1041,7 +1041,7 @@
onclick={nextMonth}
>
<Icon
icon="mdi:chevron-right"
icon="lucide:chevron-right"
class="size-5"
aria-hidden="true"
/>
@@ -1191,7 +1191,7 @@
class="inline-flex items-center gap-1 text-[11px] text-himmel-700 hover:text-himmel-900 hover:underline shrink-0"
>
<Icon
icon="mdi:close"
icon="lucide:x"
class="size-3.5"
aria-hidden="true"
/>
@@ -1246,7 +1246,7 @@
class="cursor-pointer list-none px-3 py-2 text-xs text-stein-600 hover:bg-stein-100 inline-flex items-center gap-1.5"
>
<Icon
icon="mdi:chevron-right"
icon="lucide:chevron-right"
class="size-3.5 transition-transform group-open/past:rotate-90"
aria-hidden="true"
/>
@@ -1272,7 +1272,7 @@
class="cursor-pointer list-none px-3 py-2 text-xs text-stein-600 hover:bg-stein-100 inline-flex items-center gap-1.5 border-b border-stein-200"
>
<Icon
icon="mdi:chevron-right"
icon="lucide:chevron-right"
class="size-3.5 transition-transform group-open/past:rotate-90"
aria-hidden="true"
/>
@@ -69,7 +69,7 @@
data-block-slug={block._slug}
>
<header class="flex items-center gap-2 border-b border-stein-100 px-3 py-2">
<Icon icon="mdi:calendar-month-outline" class="size-8 shrink-0 text-stein-900" aria-hidden="true" />
<Icon icon="lucide:calendar" class="size-8 shrink-0 text-stein-900" aria-hidden="true" />
<h2 class="text-sm font-semibold leading-none text-stein-800">
{block.title ?? t(T.calendar_next_events)}
</h2>
@@ -120,7 +120,7 @@
class="flex items-center justify-center gap-1 border-t border-stein-100 bg-stein-50 px-3 py-1.5 text-xs font-medium text-wald-700 hover:bg-wald-50"
>
{t(T.calendar_all_upcoming)}
<Icon icon="mdi:arrow-right" class="size-3.5" aria-hidden="true" />
<Icon icon="lucide:arrow-right" class="size-3.5" aria-hidden="true" />
</a>
{/if}
</div>
@@ -130,7 +130,7 @@
class="font-semibold whitespace-nowrap text-gray-900 hover:text-gray-700"
>
{ctaLabel}&nbsp;<Icon
icon="mdi:arrow-right"
icon="lucide:arrow-right"
class="inline-block size-4 align-[-0.15em]"
aria-hidden="true"
/>
@@ -145,7 +145,7 @@
>
<span class="sr-only">Schließen</span>
<Icon
icon="mdi:close"
icon="lucide:x"
class="size-5 text-gray-900"
aria-hidden="true"
/>
+11 -11
View File
@@ -28,42 +28,42 @@
function iconForExt(ext: string | null): string {
switch (ext) {
case "pdf":
return "mdi:file-pdf-box";
return "lucide:file-text";
case "doc":
case "docx":
case "rtf":
case "odt":
return "mdi:file-word-box";
return "lucide:file-text";
case "xls":
case "xlsx":
case "ods":
case "csv":
case "tsv":
return "mdi:file-excel-box";
return "lucide:file-spreadsheet";
case "ppt":
case "pptx":
return "mdi:file-powerpoint-box";
return "lucide:presentation";
case "zip":
case "tar":
case "gz":
case "7z":
return "mdi:folder-zip";
return "lucide:folder-archive";
case "jpg":
case "jpeg":
case "png":
case "webp":
case "gif":
case "svg":
return "mdi:file-image";
return "lucide:file-image";
case "txt":
case "md":
return "mdi:file-document-outline";
return "lucide:file-text";
case "json":
return "mdi:code-json";
return "lucide:braces";
case "xml":
case "html":
case "htm":
return "mdi:xml";
return "lucide:code";
case "py":
return "mdi:language-python";
case "js":
@@ -75,9 +75,9 @@
return "mdi:language-rust";
case "sh":
case "bash":
return "mdi:console";
return "lucide:terminal";
default:
return "mdi:file-outline";
return "lucide:file";
}
}
+1 -1
View File
@@ -52,7 +52,7 @@
onkeydown={(e) => e.key === "Enter" && activateMap()}
>
<Icon
icon="mdi:cursor-default-click"
icon="lucide:mouse-pointer-click"
width="2rem"
height="2rem"
class="block text-white"
@@ -239,7 +239,7 @@
title={t(T.image_gallery_download)}
aria-label={t(T.image_gallery_download)}
>
<Icon icon="mdi:download-outline" class="text-xl" aria-hidden="true" />
<Icon icon="lucide:download" class="text-xl" aria-hidden="true" />
</a>
</div>
{#if withUrl.length > 1}
@@ -249,7 +249,7 @@
onclick={modalPrev}
aria-label={t(T.image_gallery_prev_aria)}
>
<Icon icon="mdi:chevron-left" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="text-2xl" aria-hidden="true" />
</button>
<button
type="button"
@@ -257,7 +257,7 @@
onclick={modalNext}
aria-label={t(T.image_gallery_next_aria)}
>
<Icon icon="mdi:chevron-right" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="text-2xl" aria-hidden="true" />
</button>
{/if}
<button
@@ -266,7 +266,7 @@
onclick={closeModal}
aria-label={t(T.image_gallery_close)}
>
<Icon icon="mdi:close" class="text-lg" aria-hidden="true" />
<Icon icon="lucide:x" class="text-lg" aria-hidden="true" />
</button>
</div>
</div>
@@ -337,7 +337,7 @@
aria-label={t(T.image_gallery_prev_aria)}
onclick={prev}
>
<Icon icon="mdi:chevron-left" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="text-2xl" aria-hidden="true" />
</button>
<button
type="button"
@@ -345,7 +345,7 @@
aria-label={t(T.image_gallery_next_aria)}
onclick={next}
>
<Icon icon="mdi:chevron-right" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="text-2xl" aria-hidden="true" />
</button>
<div class="flex justify-center gap-1.5 mt-2" role="tablist" aria-label={t(T.image_gallery_position_aria)}>
@@ -126,7 +126,7 @@
onclick={(e) => e.stopPropagation()}
class="inline-flex items-center gap-1 rounded-sm border border-stein-200 bg-stein-50 px-2 py-0.5 text-[0.6rem] text-stein-600 no-underline transition-colors hover:border-red-300 hover:bg-red-50 hover:text-red-700"
>
<Icon icon="mdi:youtube" class="size-3 shrink-0" />
<Icon icon="lucide:youtube" class="size-3 shrink-0" />
<span>YouTube</span>
</a>
{/if}
@@ -198,7 +198,7 @@
aria-label="Vorherige Organisationen"
class="hidden md:flex absolute -left-3 top-1/2 -translate-y-1/2 -translate-x-1/2 size-7 items-center justify-center rounded-full bg-white border border-stein-200 shadow-md hover:bg-stein-50 transition"
>
<Icon icon="mdi:chevron-left" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="size-4" aria-hidden="true" />
</button>
<button
type="button"
@@ -206,7 +206,7 @@
aria-label="Weitere Organisationen"
class="hidden md:flex absolute -right-3 top-1/2 -translate-y-1/2 translate-x-1/2 size-7 items-center justify-center rounded-full bg-white border border-stein-200 shadow-md hover:bg-stein-50 transition"
>
<Icon icon="mdi:chevron-right" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="size-4" aria-hidden="true" />
</button>
{/if}
</div>
@@ -144,7 +144,7 @@
aria-label="Karte aktivieren"
>
<span class="flex items-center gap-2 rounded-md bg-white/95 px-3 py-1.5 text-sm font-medium text-stein-800 shadow-md">
<Icon icon="mdi:cursor-default-click-outline" class="size-4" />
<Icon icon="lucide:mouse-pointer-click" class="size-4" />
Karte aktivieren
</span>
</button>
@@ -167,13 +167,13 @@
class="shrink-0 text-stein-400 transition-colors hover:text-stein-700"
aria-label="Schließen"
>
<Icon icon="mdi:close" class="size-4" />
<Icon icon="lucide:x" class="size-4" />
</button>
</div>
{#if selectedOrg.location?.text}
<p class="mb-3 flex items-center gap-1 text-xs text-stein-500">
<Icon icon="mdi:map-marker-outline" class="size-3.5 shrink-0" />
<Icon icon="lucide:map-pin" class="size-3.5 shrink-0" />
{selectedOrg.location.text}
</p>
{/if}
@@ -203,13 +203,13 @@
{/if}
{#if c.email}
<a href="mailto:{c.email}" class="mt-0.5 flex items-center gap-1 text-wald-700 hover:underline">
<Icon icon="mdi:email-outline" class="size-3 shrink-0" />
<Icon icon="lucide:mail" class="size-3 shrink-0" />
<span class="truncate">{c.email}</span>
</a>
{/if}
{#if c.phone}
<a href="tel:{c.phone.replace(/\s+/g, '')}" class="mt-0.5 flex items-center gap-1 text-wald-700 hover:underline">
<Icon icon="mdi:phone" class="size-3 shrink-0" />
<Icon icon="lucide:phone" class="size-3 shrink-0" />
{c.phone}
</a>
{/if}
@@ -228,7 +228,7 @@
rel="noopener noreferrer"
class="btn-outline btn-sm w-full justify-center no-underline!"
>
<Icon icon="mdi:open-in-new" class="size-3.5" />
<Icon icon="lucide:external-link" class="size-3.5" />
{getLinkLabel(selectedOrg)}
</a>
{/if}
@@ -106,7 +106,7 @@
aria-label="Zurück"
class="hidden md:flex absolute -left-3 top-1/2 -translate-y-1/2 -translate-x-1/2 size-7 items-center justify-center rounded-full bg-white/90 border border-stein-200 shadow-sm hover:bg-white hover:border-wald-700 transition"
>
<Icon icon="mdi:chevron-left" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="size-4" aria-hidden="true" />
</button>
<button
type="button"
@@ -114,7 +114,7 @@
aria-label="Weiter"
class="hidden md:flex absolute -right-3 top-1/2 -translate-y-1/2 translate-x-1/2 size-7 items-center justify-center rounded-full bg-white/90 border border-stein-200 shadow-sm hover:bg-white hover:border-wald-700 transition"
>
<Icon icon="mdi:chevron-right" class="size-4" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="size-4" aria-hidden="true" />
</button>
{/if}
</div>
@@ -211,7 +211,7 @@
>
<div class="flex flex-col gap-2">
<div class="relative max-w-sm flex-1">
<Icon icon="mdi:magnify" class="absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-stein-400 pointer-events-none" aria-hidden="true" />
<Icon icon="lucide:search" class="absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-stein-400 pointer-events-none" aria-hidden="true" />
<input
type="search"
placeholder={t(T.searchable_text_placeholder)}
@@ -226,7 +226,7 @@
onclick={() => (searchQuery = "")}
aria-label={t(T.searchable_text_clear_search)}
>
<Icon icon="mdi:close" class="size-4" aria-hidden="true" />
<Icon icon="lucide:x" class="size-4" aria-hidden="true" />
</button>
{/if}
</div>
@@ -269,7 +269,7 @@
{#if visibleFragments.length === 0}
<div class="flex flex-col items-center justify-center gap-3 py-12 px-6 text-center">
<div class="size-12 rounded-full bg-stein-100 flex items-center justify-center">
<Icon icon="mdi:magnify" class="size-6 text-stein-400" aria-hidden="true" />
<Icon icon="lucide:search" class="size-6 text-stein-400" aria-hidden="true" />
</div>
<div>
<div class="text-sm font-medium text-stein-600">{t(T.searchable_text_no_results)}</div>
@@ -317,10 +317,10 @@
}}
aria-label={t(T.searchable_text_copy_aria)}
>
<Icon icon={copiedIndex === i ? "mdi:check" : "mdi:content-copy"} class="size-3.5 {copiedIndex === i ? 'text-wald-600' : ''}" aria-hidden="true" />
<Icon icon={copiedIndex === i ? "lucide:check" : "lucide:copy"} class="size-3.5 {copiedIndex === i ? 'text-wald-600' : ''}" aria-hidden="true" />
</button>
<Icon
icon="mdi:chevron-down"
icon="lucide:chevron-down"
class="text-stein-400 transition-transform size-5 {isOpen ? 'rotate-180' : ''}"
aria-hidden="true"
/>
@@ -349,7 +349,7 @@
}}
aria-label={t(T.searchable_text_copy_aria)}
>
<Icon icon={copiedIndex === i ? "mdi:check" : "mdi:content-copy"} class="size-4 {copiedIndex === i ? 'text-wald-600' : ''}" aria-hidden="true" />
<Icon icon={copiedIndex === i ? "lucide:check" : "lucide:copy"} class="size-4 {copiedIndex === i ? 'text-wald-600' : ''}" aria-hidden="true" />
</button>
</div>
{@html highlightInHtml(fragment.textHtml, searchQuery.trim())}
@@ -713,7 +713,7 @@ ${outputText}
{@const soon = deadlineDays <= 7}
<div class="mb-4 flex items-center gap-3 rounded-lg border px-4 py-3 text-sm font-medium
{urgent ? 'border-red-300 bg-red-50 text-red-800' : soon ? 'border-orange-300 bg-orange-50 text-orange-800' : 'border-gelb-300 bg-gelb-50 text-gelb-800'}">
<Icon icon="mdi:clock-alert-outline" class="size-5 shrink-0" />
<Icon icon="lucide:alarm-clock" class="size-5 shrink-0" />
<span>
Einwendungsfrist: <strong>{deadlineFormatted}</strong>
{#if deadlineDays === 0}, <strong>heute letzter Tag!</strong>
@@ -724,7 +724,7 @@ ${outputText}
</div>
{:else if deadlineDays !== null && deadlineDays < 0}
<div class="mb-4 flex items-center gap-3 rounded-lg border border-stein-300 bg-stein-100 px-4 py-3 text-sm font-medium text-stein-600">
<Icon icon="mdi:clock-remove-outline" class="size-5 shrink-0" />
<Icon icon="lucide:clock-fading" class="size-5 shrink-0" />
<span>Einwendungsfrist abgelaufen ({deadlineFormatted}). Eine Einreichung ist möglicherweise nicht mehr möglich.</span>
</div>
{/if}
@@ -740,7 +740,7 @@ ${outputText}
<!-- Fortsetzen-Banner -->
{#if hadSavedState && step === 0}
<div class="mb-6 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-wald-300 bg-wald-50 px-4 py-3 text-sm">
<span class="text-wald-800"><Icon icon="mdi:content-save-outline" class="mr-1 inline size-4" />Letzte Sitzung wiederhergestellt.</span>
<span class="text-wald-800"><Icon icon="lucide:save" class="mr-1 inline size-4" />Letzte Sitzung wiederhergestellt.</span>
<div class="flex gap-2">
{#if outputHistory.length > 0}
<button class="rounded-md bg-wald-700 px-3 py-1.5 text-xs font-semibold text-white hover:bg-wald-800" onclick={() => goTo(4)}>Zur Ausgabe →</button>
@@ -778,7 +778,7 @@ ${outputText}
title={STEP_LABELS[s]}
>
{#if s !== step && s <= maxStepReached && stepFilled[s]}
<Icon icon="mdi:check" class="size-4" />
<Icon icon="lucide:check" class="size-4" />
{:else}
{s + 1}
{/if}
@@ -792,7 +792,7 @@ ${outputText}
<span class="font-semibold text-wald-800">Schritt {step + 1} / {TOTAL_STEPS}, {STEP_LABELS[step]}</span>
{#if saveStatus === "saved"}
<span class="flex items-center gap-1 text-wald-600" aria-live="polite">
<Icon icon="mdi:check-circle" class="size-3.5" aria-hidden="true" />
<Icon icon="lucide:circle-check" class="size-3.5" aria-hidden="true" />
Gespeichert
</span>
{/if}
@@ -814,28 +814,28 @@ ${outputText}
<dl class="mt-4 grid grid-cols-2 gap-3 text-sm sm:grid-cols-3">
{#if windArea.gemeinden?.length}
<div class="col-span-full rounded-lg border border-wald-200 bg-white/70 p-3 shadow-sm">
<Icon icon="mdi:home-group" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<Icon icon="lucide:house" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<dt class="whitespace-nowrap text-sm font-semibold text-wald-800 sm:text-base">Gemeinden</dt>
<dd class="mt-1 text-stein-600">{windArea.gemeinden.join(", ")}</dd>
</div>
{/if}
{#if windArea.flaeche_ha}
<div class="rounded-lg border border-wald-200 bg-white/70 p-3 shadow-sm">
<Icon icon="mdi:vector-square" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<Icon icon="lucide:square-dashed" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<dt class="whitespace-nowrap text-sm font-semibold text-wald-800 sm:text-base">Fläche</dt>
<dd class="mt-1 text-stein-600">{windArea.flaeche_ha.toLocaleString("de-DE")} ha</dd>
</div>
{/if}
{#if windArea.investor}
<div class="rounded-lg border border-wald-200 bg-white/70 p-3 shadow-sm">
<Icon icon="mdi:domain" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<Icon icon="lucide:building-2" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<dt class="whitespace-nowrap text-sm font-semibold text-wald-800 sm:text-base">Investor</dt>
<dd class="mt-1 text-stein-600">{windArea.investor}</dd>
</div>
{/if}
{#if windArea.status}
<div class="rounded-lg border border-wald-200 bg-white/70 p-3 shadow-sm">
<Icon icon="mdi:flag-outline" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<Icon icon="lucide:flag" class="mb-1 size-5 text-wald-600" aria-hidden="true" />
<dt class="whitespace-nowrap text-sm font-semibold text-wald-800 sm:text-base">Status</dt>
<dd class="mt-1 text-stein-600 capitalize">{windArea.status.replace(/_/g, " ")}</dd>
</div>
@@ -844,7 +844,7 @@ ${outputText}
{#if windArea.notizen}
<details class="mt-4 border-t border-wald-200 pt-3" open>
<summary class="flex cursor-pointer items-center gap-1 text-sm font-medium text-wald-700 list-none">
<Icon icon="mdi:chevron-down" class="det-chevron size-4" />
<Icon icon="lucide:chevron-down" class="det-chevron size-4" />
Steckbrief des Gebiets
</summary>
<div class="prose prose-sm prose-stein mt-2 max-h-72 max-w-none overflow-y-auto rounded-lg bg-white/60 p-3 text-sm text-stein-700">{@html md(windArea.notizen.replace(/\n/g, " \n"))}</div>
@@ -939,7 +939,7 @@ ${outputText}
class="shrink-0 text-wald-500 hover:text-wald-800"
onclick={() => toggleItem(k._slug)}
aria-label={expandedItems.has(k._slug) ? "Einklappen" : "Ausklappen"}
><Icon icon={expandedItems.has(k._slug) ? "mdi:chevron-up" : "mdi:chevron-down"} class="size-4" /></button>
><Icon icon={expandedItems.has(k._slug) ? "lucide:chevron-up" : "lucide:chevron-down"} class="size-4" /></button>
{/if}
</div>
</div>
@@ -996,7 +996,7 @@ ${outputText}
{#if allgemeineGruppen.length > 0}
<div class="relative mb-3">
<Icon icon="mdi:magnify" class="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-stein-400" />
<Icon icon="lucide:search" class="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-stein-400" />
<input
type="search"
class="w-full rounded-lg border border-stein-300 py-2 pl-9 pr-3 text-sm text-stein-800 focus:border-wald-500 focus:outline-none focus:ring-2 focus:ring-wald-200"
@@ -1076,7 +1076,7 @@ ${outputText}
class="shrink-0 text-wald-500 hover:text-wald-800"
onclick={() => toggleItem(f._slug)}
aria-label={expandedItems.has(f._slug) ? "Einklappen" : "Ausklappen"}
><Icon icon={expandedItems.has(f._slug) ? "mdi:chevron-up" : "mdi:chevron-down"} class="size-4" /></button>
><Icon icon={expandedItems.has(f._slug) ? "lucide:chevron-up" : "lucide:chevron-down"} class="size-4" /></button>
{/if}
</div>
</div>
@@ -1166,7 +1166,7 @@ ${outputText}
}}
title="Felder mit Platzhaltern füllen, später im fertigen Text in eckigen Klammern suchen und ersetzen."
>
<Icon icon="mdi:format-text-variant-outline" class="size-3.5 text-stein-500" />
<Icon icon="lucide:type" class="size-3.5 text-stein-500" />
Mit Platzhaltern füllen
</button>
<span class="text-[11px] text-stein-400">Erzeugt z.B. <code class="rounded bg-stein-100 px-1">[Vor- und Nachname]</code>, später ersetzen.</span>
@@ -1203,7 +1203,7 @@ ${outputText}
<div class="my-6 flex items-center gap-3">
<div class="h-px flex-1 bg-wald-200"></div>
<span class="flex items-center gap-1.5 rounded-full bg-wald-100 px-3 py-1 text-[11px] font-semibold uppercase tracking-wider text-wald-800">
<Icon icon="mdi:check-decagram" class="size-3.5" />
<Icon icon="lucide:badge-check" class="size-3.5" />
Ergebnis
</span>
<div class="h-px flex-1 bg-wald-200"></div>
@@ -1212,7 +1212,7 @@ ${outputText}
<!-- Block 1: Schreibvorlage -->
<div class="mb-4 rounded-xl border border-wald-200 bg-white p-4 shadow-sm">
<div class="mb-2 flex items-start gap-2">
<Icon icon="mdi:file-document-edit-outline" class="mt-0.5 size-5 shrink-0 text-wald-700" />
<Icon icon="lucide:file-pen" class="mt-0.5 size-5 shrink-0 text-wald-700" />
<div class="flex-1">
<h4 class="text-sm font-semibold text-wald-800">Schreibvorlage verwenden</h4>
<p class="mt-0.5 text-xs text-stein-500">Text direkt übernehmen, kopieren, herunterladen oder drucken.</p>
@@ -1223,21 +1223,21 @@ ${outputText}
class="inline-flex items-center gap-1.5 rounded-md border border-wald-300 bg-wald-50 px-3 py-1.5 text-xs font-medium text-wald-800 hover:bg-wald-100"
onclick={copyText}
>
<Icon icon="mdi:content-copy" class="size-3.5" />
<Icon icon="lucide:copy" class="size-3.5" />
{copyFeedback || "Kopieren"}
</button>
<button
class="inline-flex items-center gap-1.5 rounded-md border border-stein-300 bg-white px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50"
onclick={downloadText}
>
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Herunterladen
</button>
<button
class="inline-flex items-center gap-1.5 rounded-md border border-stein-300 bg-white px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50"
onclick={printText}
>
<Icon icon="mdi:printer" class="size-3.5" />
<Icon icon="lucide:printer" class="size-3.5" />
Drucken
</button>
{#if mailtoLink && !mailTooLong}
@@ -1245,7 +1245,7 @@ ${outputText}
href={mailtoLink}
class="inline-flex items-center gap-1.5 rounded-md border border-wald-400 bg-wald-50 px-3 py-1.5 text-xs font-medium text-wald-700 no-underline hover:bg-wald-100"
>
<Icon icon="mdi:email-outline" class="size-3.5" />
<Icon icon="lucide:mail" class="size-3.5" />
{block.recipientEmail ? "Per E-Mail senden" : "Per E-Mail (an mich)"}
</a>
{/if}
@@ -1255,7 +1255,7 @@ ${outputText}
<!-- Block 2: KI-Variante -->
<div class="mb-4 rounded-xl border border-himmel-200 bg-himmel-50/40 p-4 shadow-sm">
<div class="mb-3 flex items-start gap-2">
<Icon icon="mdi:robot-outline" class="mt-0.5 size-5 shrink-0 text-himmel-700" />
<Icon icon="lucide:bot" class="mt-0.5 size-5 shrink-0 text-himmel-700" />
<div class="flex-1">
<h4 class="text-sm font-semibold text-himmel-800">Mit KI eine individuelle Version erstellen</h4>
<p class="mt-0.5 text-xs text-stein-500">
@@ -1305,13 +1305,13 @@ ${outputText}
<details class="mb-3 rounded-lg border border-himmel-200 bg-white/70 overflow-hidden">
<summary class="flex cursor-pointer items-center justify-between bg-himmel-50 px-3 py-2 text-[11px] font-medium text-himmel-800 hover:bg-himmel-100 list-none">
<span class="flex items-center gap-1.5">
<Icon icon="mdi:tune-variant" class="size-3.5" />
<Icon icon="lucide:sliders-horizontal" class="size-3.5" />
Inhaltliche Regeln für die KI feinjustieren
{#if aiRules.trim() !== DEFAULT_AI_RULES.trim()}
<span class="rounded-full bg-himmel-200 px-1.5 py-0.5 text-[9px] text-himmel-800">angepasst</span>
{/if}
</span>
<Icon icon="mdi:chevron-down" class="det-chevron size-4 text-himmel-600" />
<Icon icon="lucide:chevron-down" class="det-chevron size-4 text-himmel-600" />
</summary>
<div class="border-t border-himmel-100 p-3">
<p class="mb-2 text-[10px] text-stein-500">
@@ -1339,7 +1339,7 @@ ${outputText}
class="inline-flex items-center gap-1.5 rounded-md border border-himmel-500 bg-himmel-600 px-3.5 py-2 text-xs font-semibold text-white shadow-sm hover:bg-himmel-700"
onclick={copyAiPrompt}
>
<Icon icon="mdi:content-copy" class="size-3.5" />
<Icon icon="lucide:copy" class="size-3.5" />
{copyAiPromptFeedback || "In Zwischenablage kopieren"}
</button>
<button
@@ -1347,7 +1347,7 @@ ${outputText}
onclick={downloadAiPrompt}
title="Prompt als Textdatei speichern, alternativ zur Zwischenablage."
>
<Icon icon="mdi:download" class="size-3.5" />
<Icon icon="lucide:download" class="size-3.5" />
Als .txt herunterladen
</button>
</div>
@@ -1357,20 +1357,20 @@ ${outputText}
<details class="mb-4 rounded-xl border border-stein-200 bg-white overflow-hidden">
<summary class="flex cursor-pointer items-center justify-between bg-stein-50 px-4 py-3 text-sm font-medium text-stein-700 hover:bg-stein-100 list-none">
<span class="flex items-center gap-2">
<Icon icon="mdi:tune" class="size-4 text-stein-500" />
<Icon icon="lucide:sliders-horizontal" class="size-4 text-stein-500" />
Brief im Detail anpassen
{#if tweakBadges.length > 0}
<span class="text-[10px] text-stein-400">({tweakBadges.join(" · ")})</span>
{/if}
</span>
<Icon icon="mdi:chevron-down" class="det-chevron size-4 text-stein-400" />
<Icon icon="lucide:chevron-down" class="det-chevron size-4 text-stein-400" />
</summary>
<div class="border-t border-stein-200 p-4 space-y-4">
<!-- Vorschau -->
<div>
<p class="mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-stein-500">
<Icon icon="mdi:file-document-outline" class="size-3.5" />
<Icon icon="lucide:file-text" class="size-3.5" />
Vorschau
{#if hasManualEdit}
<span class="rounded-full bg-himmel-100 px-2 py-0.5 text-[9px] font-normal text-himmel-700">bearbeitet</span>
@@ -1400,7 +1400,7 @@ ${outputText}
{#if selectedFragments.length > 1}
<div>
<p class="mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-stein-500">
<Icon icon="mdi:drag-vertical" class="size-3.5" />
<Icon icon="lucide:grip-vertical" class="size-3.5" />
Reihenfolge der Argumente ({selectedFragments.length})
</p>
<div class="divide-y divide-stein-100 rounded-lg border border-stein-200">
@@ -1414,7 +1414,7 @@ ${outputText}
class="flex cursor-grab items-center gap-3 px-3 py-2 text-sm transition-colors active:cursor-grabbing
{dragOverIdx === i && dragIdx !== i ? 'bg-wald-50 border-t-2 border-wald-400' : 'bg-white hover:bg-stein-50'}"
>
<Icon icon="mdi:drag-vertical" class="size-4 shrink-0 text-stein-400" />
<Icon icon="lucide:grip-vertical" class="size-4 shrink-0 text-stein-400" />
<span class="flex-1 truncate text-stein-700">{frag.title ?? frag._slug.replace(/_/g, " ")}</span>
<span class="shrink-0 text-[10px] text-stein-400">{i + 1}</span>
</div>
@@ -1478,7 +1478,7 @@ ${outputText}
onclick={() => (historyExpanded = !historyExpanded)}
>
<span>Frühere Versionen ({outputHistory.length})</span>
<Icon icon={historyExpanded ? "mdi:chevron-up" : "mdi:chevron-down"} class="size-4" />
<Icon icon={historyExpanded ? "lucide:chevron-up" : "lucide:chevron-down"} class="size-4" />
</button>
{#if historyExpanded}
@@ -403,7 +403,7 @@
</span>
{#if explanationHref}
<span class="text-xs text-stein-500 inline-flex items-center gap-1">
<Icon icon="mdi:chevron-right" class="size-3.5" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="size-3.5" aria-hidden="true" />
{t(T.strommix_compact_more)}
</span>
{/if}
@@ -433,7 +433,7 @@
>
<span class="inline-flex items-center gap-1.5 uppercase tracking-wide">
<Icon
icon="mdi:transmission-tower"
icon="lucide:radio-tower"
class="size-4"
aria-hidden="true"
/>
@@ -443,12 +443,12 @@
<span class="inline-flex items-center gap-2 normal-case font-normal">
{#if isStale}
<span class="inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] uppercase tracking-wide bg-fire-700 text-fire-50">
<Icon icon="mdi:cloud-off-outline" class="size-3" aria-hidden="true" />
<Icon icon="lucide:cloud-off" class="size-3" aria-hidden="true" />
{t(T.strommix_stale_badge)}
</span>
{:else}
<span class="inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] uppercase tracking-wide {accentClasses.badge}">
<Icon icon="mdi:database-outline" class="size-3" aria-hidden="true" />
<Icon icon="lucide:database" class="size-3" aria-hidden="true" />
{#if live.dataSource === "smard"}
SMARD
{:else if live.dataSource === "smard+energy-charts"}
@@ -473,7 +473,7 @@
<!-- Main: percentage + status -->
{#if loadError && !live}
<div class="p-6 text-sm text-fire-700 flex flex-wrap items-center gap-3">
<Icon icon="mdi:alert-circle-outline" class="size-5 shrink-0" aria-hidden="true" />
<Icon icon="lucide:circle-alert" class="size-5 shrink-0" aria-hidden="true" />
<span class="flex-1 min-w-0">
{t(T.strommix_load_error, { error: loadError })}
</span>
@@ -483,7 +483,7 @@
onclick={() => loadLive()}
disabled={isLoading}
>
<Icon icon="mdi:refresh" class="size-3.5 {isLoading ? 'animate-spin' : ''}" aria-hidden="true" />
<Icon icon="lucide:refresh-cw" class="size-3.5 {isLoading ? 'animate-spin' : ''}" aria-hidden="true" />
{t(T.strommix_retry)}
</button>
</div>
@@ -615,7 +615,7 @@
derselbe Preis sonst zweimal genannt würde. -->
<div class="mt-2 flex items-start gap-3 rounded-xs border-2 border-fire-500 bg-fire-50 px-4 py-2.5 text-sm shadow-sm">
<Icon
icon="mdi:alert-circle"
icon="lucide:circle-alert"
class="size-6 shrink-0 text-fire-700"
aria-hidden="true"
/>
@@ -679,7 +679,7 @@
{#if live && hasHistoryPanels}
<details class="strommix-history mt-3 group">
<summary class="cursor-pointer rounded-xs border border-stein-200 bg-white px-4 py-2 text-sm font-semibold text-stein-700 shadow-sm hover:bg-stein-50 inline-flex items-center gap-2">
<Icon icon="mdi:chevron-right" class="size-4 transition-transform group-open:rotate-90" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="size-4 transition-transform group-open:rotate-90" aria-hidden="true" />
{t(T.strommix_history_summary)}
</summary>
@@ -833,7 +833,7 @@
{#if isStale}
<span class="inline-flex items-center gap-1 text-fire-700">
<Icon
icon="mdi:cloud-off-outline"
icon="lucide:cloud-off"
class="size-3.5"
aria-hidden="true"
/>
@@ -191,7 +191,7 @@
<span
class="inline-flex h-12 w-12 items-center justify-center rounded-full bg-white/90 text-stein-900 shadow-md group-hover:bg-white"
>
<Icon icon="mdi:play" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:play" class="text-2xl" aria-hidden="true" />
</span>
</span>
{#if label}
@@ -251,7 +251,7 @@
onclick={modalPrev}
aria-label={t(T.image_gallery_prev_aria)}
>
<Icon icon="mdi:chevron-left" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="text-2xl" aria-hidden="true" />
</button>
<button
type="button"
@@ -259,7 +259,7 @@
onclick={modalNext}
aria-label={t(T.image_gallery_next_aria)}
>
<Icon icon="mdi:chevron-right" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="text-2xl" aria-hidden="true" />
</button>
{/if}
<button
@@ -268,7 +268,7 @@
onclick={closeModal}
aria-label={t(T.image_gallery_close)}
>
<Icon icon="mdi:close" class="text-lg" aria-hidden="true" />
<Icon icon="lucide:x" class="text-lg" aria-hidden="true" />
</button>
</div>
</div>
@@ -312,7 +312,7 @@
aria-label={t(T.image_gallery_prev_aria)}
onclick={prev}
>
<Icon icon="mdi:chevron-left" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-left" class="text-2xl" aria-hidden="true" />
</button>
<button
type="button"
@@ -320,7 +320,7 @@
aria-label={t(T.image_gallery_next_aria)}
onclick={next}
>
<Icon icon="mdi:chevron-right" class="text-2xl" aria-hidden="true" />
<Icon icon="lucide:chevron-right" class="text-2xl" aria-hidden="true" />
</button>
{/if}
</div>