307 Commits

Author SHA1 Message Date
Peter Meier 9d58c92e94 ui: card-surface utility, rounded corners, calendar polish, banner layout
Deploy / verify (push) Successful in 1m1s
Deploy / deploy (push) Successful in 1m9s
- Add .card-surface utility (@layer components): rounded-sm border shadow-sm
- Card.svelte, CalendarBlock, SearchableTextBlock, BlogOverview use card-surface
- OrganisationsBlock: logo h-12 rounded-sm, description style cleanup, pt-1 for hover clip fix
- DeadlineBanner: container-custom width constraint, text left-aligned
- WindAreaPanel stats: card-surface
- CalendarBlock: rounded-sm day headers, past days opacity-20 + diagonal strike
- Add .day-past pseudo-element utility for diagonal line

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 14:32:42 +02:00
Peter Meier f08e3bb790 windkarte: scroll map into view when URL hash selects an area
Deploy / verify (push) Successful in 54s
Deploy / deploy (push) Successful in 1m4s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:45:46 +02:00
Peter Meier cd362fb811 windkarte: Rechtskräftig default hidden, remove Entwurf-2-voraussichtlich, 2km/5km rings on by default
Deploy / verify (push) Successful in 58s
Deploy / deploy (push) Successful in 1m6s
- Hide status badge for rechtskraeftig in WindAreaPanel
- Default hiddenStatuses=["rechtskraeftig"] so polygons start hidden
- Fix: call restyleAll after geojsonLayer init so initial hidden state applies
- Default hiddenRings=[] so 2km+5km buffer rings show on selection
- Remove entwurf_2_voraussichtlich from legend
- Lower maxZoom 12→11 for more context on feature select

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:26:19 +02:00
Peter Meier 4a72142555 WindAreaPanel: compact key-value rows instead of cards
Label left, value right, divided rows. No more padded bg cards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:18:38 +02:00
Peter Meier 823adde1fa WindAreaPanel: stats single column layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:18:06 +02:00
Peter Meier f55f409158 WindAreaPanel: render notizen as HTML with prose styles
Was output as escaped plain text. Field contains HTML from the CMS editor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:16:46 +02:00
Peter Meier 250865893e FilesBlock: icon size-4 → size-5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:46:52 +02:00
Peter Meier 07b6317b94 FilesBlock: mt-0.5 on icon for top alignment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:46:38 +02:00
Peter Meier 07f17e880e FilesBlock: top-align icon with text
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:45:48 +02:00
Peter Meier baa4b9aae4 FilesBlock: allow description to wrap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:45:17 +02:00
Peter Meier 61e01c127f FilesBlock: size as inline badge after filename
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:44:46 +02:00
Peter Meier 887a6bda3e FilesBlock: remove default link underline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:43:57 +02:00
Peter Meier 774ac893ec FilesBlock: description on second line below filename
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:43:10 +02:00
Peter Meier 1284be9c42 FilesBlock: size label smaller + no-wrap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:42:32 +02:00
Peter Meier 325f95487f FilesBlock: move size under icon, drop redundant ext label
Icon already communicates file type. Size now sits below the icon
in a fixed-width left column. Ext text removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:41:40 +02:00
Peter Meier 1825b7d9fe FilesBlock: compact single-row layout
Reduce padding, smaller icon, filename + ext/size on one line.
Description hidden on mobile, truncated on desktop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:39:09 +02:00
Peter Meier 4b9214dbaf Fix FilesBlock: external URLs bypass /cms-files proxy
getCmsFileUrl() returned /cms-files?src=... for all URLs including
external ones. resolveCmsSource() rejects foreign hosts (SSRF guard),
so external file links 404'd. External http(s) URLs now returned directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:36:43 +02:00
Peter Meier 44b991f7c1 Improve social media OG/Twitter meta for posts
Deploy / verify (push) Successful in 51s
Deploy / deploy (push) Successful in 1m2s
- Fix bug: post page was overriding og:image with 150x200 thumbnail
- og:type = "article" for posts (was always "website")
- article:published_time, article:modified_time, article:author, article:tag
- og:image:alt + twitter:image:alt (post headline)
- twitter:label1/data1 with reading time
- Remove thumbnail fallback from socialImage (falls back to site logo instead)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:35:32 +02:00
Peter Meier d7a84aff0d SearchableTextBlock: animated accordion, tag counts, empty state, focus-visible
- Replace <details> with Svelte-controlled accordion + slide transition (180ms)
- Close all items on search/tag filter change
- Live tag counts per filter showing matches for current search query
- Visual empty state with reset button when no results
- focus-visible ring on all interactive elements (was focus: — shows on click too)
- Tag.svelte: remove ring-0, add focus-visible:ring-2
- Card.svelte: add focus-visible ring to linked cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:31:38 +02:00
Peter Meier fa50617d3c Fix Tooltip overflow-hidden clipping via portal action
Portal the tooltip into document.body so overflow:hidden ancestors
can't clip it. Fixed positioning + getBoundingClientRect() for placement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:25:18 +02:00
Peter Meier cbf0e4aa51 Fix Tooltip clipping in overflow-hidden containers — use fixed positioning
Switches from absolute (clipped by ancestor overflow:hidden) to fixed
with viewport-relative coords from getBoundingClientRect().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:22:27 +02:00
Peter Meier 35a34eb300 Fix SearchableTextBlock h2 color — override global heading CSS with \!text-white
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:21:03 +02:00
Peter Meier 1f430f01a5 Fix SearchableTextBlock header text contrast — white/80 on dark green
Deploy / verify (push) Successful in 53s
Deploy / deploy (push) Successful in 1m1s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:19:08 +02:00
Peter Meier 5b4d59175b Redesign SearchableTextBlock UI — stronger visual hierarchy
Deploy / verify (push) Successful in 56s
Deploy / deploy (push) Successful in 1m6s
Green gradient header, white card with shadow, left-border accent on open
accordion items, hover-visible copy button in summary row, lighter dividers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:18:07 +02:00
Peter Meier 4fc541acf9 perf: parallel block resolution, immutable asset caching, fewer favicons
Deploy / verify (push) Successful in 57s
Deploy / deploy (push) Successful in 59s
- +page.server.ts: resolveContentImages/Calendar/Deadline/SearchableText
  now run in parallel via Promise.all (after resolvePostOverviewBlocks)
- +page.server.ts: banner widths 5→3 [640,1024,1536]
- hooks.server.ts: /_app/immutable/** gets Cache-Control: max-age=31536000
- +layout.svelte: favicon tags 18→4 (ico, 32px png, 192px, apple-180px)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:00:07 +02:00
Peter Meier 19f3948f48 feat(carousel): 2 cols tablet, 3 cols desktop; equal-height cards
Deploy / verify (push) Successful in 54s
Deploy / deploy (push) Successful in 1m4s
- PostOverviewBlock carousel: md:2 cols, lg:3 cols via snap-scroll
- PostCard: add class prop for external styling
- Carousel cards: h-full for equal height

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 14:54:36 +02:00
Peter Meier 41dfbb2930 feat: add carousel design to PostOverview; extract shared Carousel component
Deploy / verify (push) Successful in 57s
Deploy / deploy (push) Successful in 1m5s
- New Carousel.svelte: index-fade, arrows, dots, optional auto-rotate
- QuoteCarouselBlock refactored to use Carousel
- PostOverviewBlock: carousel design variant added
- CMS schema: "carousel" added to post_overview design enum

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 14:27:31 +02:00
Peter Meier a1dcedd855 fix: WindkarteBlock col-span + data-block attrs
Deploy / verify (push) Successful in 52s
Deploy / deploy (push) Successful in 1m24s
Block fehlte layoutClasses (col-span) und data-block/type/slug attrs.
Layout-Feld zu WindMapBlockData ergänzt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 18:14:56 +02:00
Peter Meier 3cb728d677 fix: add wind_map block to ContentRows
Deploy / verify (push) Successful in 1m4s
Deploy / deploy (push) Successful in 1m40s
ContentRows.svelte fehlte wind_map — Block wurde als "Unbekannter Block" gerendert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 17:59:06 +02:00
Peter Meier 0b6174eb53 chore: update iconify subset (map-outline swap)
Deploy / verify (push) Successful in 51s
Deploy / deploy (push) Successful in 59s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 15:31:42 +02:00
Peter Meier b4581e4d4f feat(windkarte): tap-to-activate overlay for mobile scroll fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 15:31:23 +02:00
Peter Meier ad72c44d98 fix(windkarte): 2km/5km-Ringe selektion-basiert statt permanent
Deploy / verify (push) Successful in 54s
Deploy / deploy (push) Successful in 1m1s
Ringe erscheinen nur bei ausgewähltem Gebiet (wie 200m/600m/1km),
Toggle steuert Sichtbarkeit. Permanente Allgebiets-Berechnung entfernt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 15:24:14 +02:00
Peter Meier f9b7057ba4 fix(windkarte): maxZoom bei Selektion von 14 auf 12 reduziert
Deploy / verify (push) Successful in 51s
Deploy / deploy (push) Successful in 1m1s
2026-05-13 15:21:11 +02:00
Peter Meier cd67ff8dc8 feat(windkarte): permanente 2km/5km-Ringe togglebar in Legende
Deploy / verify (push) Successful in 55s
Deploy / deploy (push) Successful in 1m4s
Zeigt 2km (indigo) und 5km (lila) Pufferringe für alle Gebiete gleichzeitig,
unabhängig von Selektion. Default versteckt, Klick auf Legendenitem ein-/ausblenden.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 15:19:44 +02:00
Peter Meier 0f6a58fed4 feat(windkarte): Legend-Toggle — Status ein-/ausblendbar per Klick
Deploy / verify (push) Successful in 54s
Deploy / deploy (push) Successful in 1m1s
Klick auf Legendenitem blendet den Status aus (opacity 0, kein Klick,
kein Hover). Panel schließt sich wenn der Status des gewählten Gebiets
ausgeblendet wird. Visuell: opacity + line-through auf versteckten Items.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 15:09:14 +02:00
Peter Meier 7d4f52ba02 feat(windkarte): neuer Status entwurf_2_voraussichtlich (orange)
Deploy / verify (push) Successful in 56s
Deploy / deploy (push) Successful in 1m3s
Farbe #d4752a. Legende, Typ-Union, Übersetzungen ergänzt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:17:15 +02:00
Peter Meier ca742345f3 feat(windkarte): geometry eingebettet in wind_area CMS-Einträge
Deploy / verify (push) Successful in 49s
Deploy / deploy (push) Successful in 1m8s
GeoJSON-Geometrie direkt in CMS-Einträgen gespeichert — kein separates
GeoJSON-File mehr. WindkarteMap baut FeatureCollection aus areas[].geometry.
WindArea-Typ bekommt geometry-Feld. geojsonUrl-Prop entfernt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:34:59 +02:00
Peter Meier ee56a457d3 feat(windkarte): alle UI-Strings auf t(T.windkarte_*) umgestellt
Deploy / verify (push) Successful in 51s
Deploy / deploy (push) Successful in 59s
Keine hardcodierten Texte mehr — alle Strings über CMS translation_bundle
(app.json5). Keys in translations.ts registriert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:09:09 +02:00
Peter Meier 91a09fd3c4 fix(windkarte): Interne "nicht verknüpft"-Meldung aus Panel entfernt
Deploy / verify (push) Successful in 50s
Deploy / deploy (push) Successful in 59s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:03:59 +02:00
Peter Meier fece9c7cfc fix(windkarte): Mobile — Map höher, Panel kürzer (52% statt 72%)
Deploy / verify (push) Successful in 52s
Deploy / deploy (push) Successful in 59s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 10:28:07 +02:00
Peter Meier 0cbf48f1fb fix(windkarte): Panel z-index über Leaflet-Controls (1001 > 1000)
Deploy / verify (push) Successful in 53s
Deploy / deploy (push) Successful in 1m0s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 10:26:23 +02:00
Peter Meier 0e28a7e334 feat(windkarte): Karten-UX Verbesserungen
Deploy / verify (push) Successful in 54s
Deploy / deploy (push) Successful in 1m7s
- Polygon-Labels ab Zoom 13 mit zoom-proportionaler Schriftgröße
- Hover-Highlight, Deselect per Hintergrundklick
- Mobile Bottom-Sheet / Desktop Side-Panel (CSS-only)
- Share-Link via URL-Hash (#W-10), auto-select on load
- Share-Button + OSM-Link im Panel
- Reset-Button auf Karte
- Buffer-Spinner während Turf-Berechnung
- Leaflet-Attribution nach links (kollidierte mit Panel)
- fitBounds mit asymmetrischem Padding + maxZoom 14

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 10:24:56 +02:00
Peter Meier 6fef86fc6b fix(markdown): use _slug instead of removed name field for data attribute
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 09:41:25 +02:00
Peter Meier c66899fa9b feat(windkarte): slugPrefix enforcement, name→gebiets_nr, name field removed
Deploy / verify (push) Successful in 48s
Deploy / deploy (push) Successful in 59s
- RustyCMS: SchemaDefinition.slug_prefix + auto-prepend in create_entry
- wind_area/wind_map schemas: slugPrefix config, name field removed
- wind_area entries: name→gebiets_nr (faktische Gebietsnummer, GeoJSON-Join-Key)
- WindkarteMap/WindAreaPanel: Join + Anzeige auf gebiets_nr

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 09:35:28 +02:00
Peter Meier 067e847524 feat(windkarte): wind_map referenziert wind_area explizit
Deploy / verify (push) Successful in 49s
Deploy / deploy (push) Successful in 1m1s
areas-Feld im Schema + Block-Logik: referenzierte Slugs werden einzeln
gefetcht. Leer = alle published areas als Fallback. Ermöglicht verschiedene
Karten-Blöcke mit unterschiedlichen Gebiet-Subsets.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 09:25:00 +02:00
Peter Meier 39d7d70c8b feat(windkarte): Leaflet-Block für Windvorranggebiete SWT
Deploy / verify (push) Successful in 58s
Deploy / deploy (push) Successful in 1m18s
Neuer CMS-Block `wind_map` — platzierbar auf jeder Seite per Row-Content.
Fetcht wind_area-Einträge + GeoJSON-Asset client-side, rendert Leaflet-Karte
(CartoDB Light) mit farbcodierten Polygonen nach Planungsstatus. Klick auf
Gebiet öffnet Slide-in-Panel mit Kenndaten, Gemeinden, Stellungnahme-Link
und Puffer-Ringen (200/600/1000 m via Turf). Erweiterbar für 2. Entwurf 2026.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 09:20:32 +02:00
Peter Meier cdc2a79950 refactor(strommix): route EC live snapshot through CMS, keep direct fallback
Deploy / verify (push) Successful in 52s
Deploy / deploy (push) Successful in 54s
Energy-Charts /public_power now fetched via strommix_history_de CMS collection
(which uses ${time:day_start|iso}/${time:now|iso} in its source URL). When the
CMS returns null (old binary without env_subst support), falls back to a direct
EC call so charts keep working during the transition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 08:17:41 +02:00
Peter Meier 81e419aa4d fix(strommix): show sparkline without history backend
Deploy / verify (push) Successful in 55s
Deploy / deploy (push) Successful in 57s
The strommix_history_de collection source URL 404s (Energy-Charts needs
start/end params), so the CMS history backend stays empty and todayHourly
was always null — making the Wind & Solar sparkline never appear.

Extend fetchEnergyChartsPublicPower to start at midnight (was: -2h) and
return the raw series alongside the snapshot values. Build todayHourly
from it when the history backend has no items. No extra API call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 07:58:34 +02:00
Peter Meier 10fb2a3ef6 feat(calendar): markdown descriptions, grid & header polish
Deploy / verify (push) Successful in 49s
Deploy / deploy (push) Successful in 50s
- description field rendered as Markdown (marked.parse + prose)
- month label left/larger, nav arrows grouped right
- weekday headers colored (himmel/stein)
- day cells weekend/weekday coloring
- remove pl-[4.75rem] indent from accordion body

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 20:53:51 +02:00
Peter Meier 7ea23531e9 feat(calendar): grid color polish, month header layout, direct event links
Deploy / verify (push) Successful in 51s
Deploy / deploy (push) Successful in 53s
- month label left + larger, prev/next arrows grouped right
- weekday headers colored (himmel/stein by weekday/weekend)
- day cells colored by weekday/weekend + event state
- event anchor IDs, onDestroy SSR fix, ImageModal component
- copy link button, action buttons always show text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 20:43:21 +02:00