Commit Graph

37 Commits

Author SHA1 Message Date
Peter Meier 7788e0370e feat(link-list): CMS-Feld columns (auto|single) für Spaltenlayout
Deploy / verify (push) Successful in 1m13s
Deploy / deploy (push) Successful in 1m28s
single = immer untereinander, auto = breitenbasiert mehrspaltig ab >4.
Regionalplan-Generatorenliste (w1-w40) auf single.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 22:40:30 +02:00
Peter Meier 686af53be0 feat(newsletter): slim inline newsletter form for footer
Deploy / verify (push) Successful in 1m12s
Deploy / deploy (push) Successful in 1m54s
Add form-newsletter-inline internal component: compact email + button row
with a consent checkbox, dark-themed for the footer. Turnstile loads lazily
on first email focus (footer is on every page). Reuses /api/newsletter and
the newsletter validation. Wired into footer-main next to Kontakt & Community.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:08:27 +02:00
Peter Meier af90483dc4 feat(newsletter): newsletter signup as internal component
Deploy / verify (push) Successful in 1m18s
Deploy / deploy (push) Successful in 1m34s
Wire a newsletter signup form into the CMS internal-component pattern
(form-newsletter). Posts to /api/newsletter which subscribes to listmonk
(double opt-in) and mirrors a best-effort backup record to the RustyCMS
forms plugin. Reuses the contact-form anti-spam stack: Cloudflare
Turnstile, honeypots, client-age check, origin validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 11:02:48 +02:00
Peter Meier b29dd587b8 feat: Mitmachen-Formular nativ (löst OpnForm ab)
Deploy / verify (push) Successful in 1m8s
Deploy / deploy (push) Successful in 1m17s
- MitmachenFormComponent: Name der BI*, Anliegen*, Ansprechpartner,
  Telefon, E-Mail, Datei-Upload (max 5×5MB, JPG/PNG/WebP/GIF/PDF),
  Consent — Honeypots + Client-Age + Turnstile wie Kontaktformular
- /api/mitmachen: Multipart-Validierung (shared Modul), Forwarding an
  CMS /api/forms/mitmachen/submit-multipart
- internal_component: form-mitmachen registriert
- ~35 neue mitmachen_*-Translation-Keys

Prod braucht BODY_SIZE_LIMIT=30M (adapter-node default 512K) — via
secrets .env.prod deployt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 11:59:31 +02:00
Peter Meier 41597f87b5 feat(windkarte): InfoAccordion, anlagen-Hinweis, Tooltip ohne Icons
Deploy / verify (push) Successful in 1m6s
Deploy / deploy (push) Successful in 1m18s
- Disclaimer aus CMS-Feld (hinweis_text) via InfoAccordion statt Hardcode
- info_text-Feld für Block-Fließtext ergänzt
- anlagen_geplant_hinweis-Feld in WindArea + Panel-Anzeige
- Tooltip-Icons entfernt (square-outline/wind-turbine/map-marker inline SVGs)
- Panel: square-outline → ruler-square für Fläche
- Iconify-Subset neu generiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 12:35:29 +02:00
Peter Meier fc81d973a5 feat: Ansprechpartner im OrganisationsMap Detail-Panel
Deploy / verify (push) Successful in 1m2s
Deploy / deploy (push) Successful in 1m11s
Marker-Klick zeigt jetzt zusätzlich Name, Rolle, Email und Telefon
der Kontaktpersonen pro Organisation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:02:47 +02:00
Peter Meier c9ba88ab80 feat: OrganisationsMapBlock — Karte der Bürgerinitiativen
Deploy / verify (push) Successful in 1m5s
Deploy / deploy (push) Successful in 1m13s
Neuer Block-Typ `organisations_map`: Leaflet-Karte mit CircleMarkern für alle
Organisationen die ein location.lat/lng haben. Klick auf Marker öffnet
Detail-Panel (Desktop: rechte Sidebar / Mobile: Bottom Sheet) mit Name,
Standort, Beschreibung und Website-Link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:03:26 +02:00
Peter Meier 88b2df0c05 feat: location-Feld an Organisation, Header-Tooltips
Deploy / verify (push) Successful in 1m0s
Deploy / deploy (push) Successful in 1m13s
- block-types: OrganisationEntry.location { text, lat, lng }
- Header: title-Attribut auf Social-Icons + Suche-Button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 11:54:13 +02:00
Peter Meier 31f1c8586c feat: WhatsApp/YouTube-Links auf Organisation
Deploy / verify (push) Successful in 1m2s
Deploy / deploy (push) Successful in 1m15s
Neue Felder whatsapp/youtube (string) auf OrganisationEntry.
OrganisationsCard zeigt Icon-Buttons wenn gesetzt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 10:20:41 +02:00
Peter Meier 363d4edb76 feat: Adressbuch-Block mit Suche, Org- und Buchstabenfilter
Deploy / verify (push) Successful in 1m14s
Deploy / deploy (push) Successful in 1m18s
- AdressbuchBlock: listet alle Kontakte alphabetisch mit Suche,
  Org-Filter-Chips und A–Z-Buchstabenfilter; /adressbuch-Seite
- ContactCard: neues Design passend zu OrganisationsCard (Badges, Links)
- ContactsBlock: Karussell mit snap-scroll, volle Breite
- block-types, blog-utils, cms: AdressbuchBlockData, resolveAdressbuchBlocks,
  getContacts; BlockRenderer registriert adressbuch
- Kontakt-Seite: Link auf /adressbuch statt eingebettetem Block

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 10:08:54 +02:00
Peter Meier 7bd62b75b0 feat(contacts): ContactCard + ContactsBlock-Komponente, BlockRenderer registriert
Deploy / verify (push) Successful in 1m8s
Deploy / deploy (push) Successful in 1m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 08:49:23 +02:00
Peter Meier 8194d8639d feat(stellungnahme): Einleitung/Abschluss via CMS-Felder pflegbar
Deploy / verify (push) Failing after 46s
Deploy / deploy (push) Has been skipped
2026-05-28 13:35:31 +02:00
Peter Meier 5f5bd06a78 feat(stellungnahme): E-Mail, Name in Grußformel, Datum-Fix, UX-Polish
Deploy / verify (push) Successful in 57s
Deploy / deploy (push) Successful in 1m9s
- E-Mail-Button: mailto-Link wenn recipientEmail im Block gesetzt
- Name in Grußformel: "Mit freundlichen Grüßen\n\nMax Mustermann"
- Datum-Fix: heute in buildText() berechnet, nicht beim Render
- Disabled-Hint: roter Hinweis wenn Name fehlt
- "Alle ab" klappt Gruppe ein (Symmetrie zu "Alle" öffnet)
- Schritt X von Y unter Step-Indikator
- recipientEmail-Feld in StellingnahmeGeneratorBlockData

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:32:25 +02:00
Peter Meier 96dd88247d feat(stellungnahme): UX-Verbesserungen, localStorage, Mini-Map, Druck
Deploy / verify (push) Successful in 55s
Deploy / deploy (push) Successful in 1m39s
- localStorage: Formularstand + Ausgabe-Historie (max 5) persistieren
- Fortsetzen-Banner: gespeicherte Sitzung erkannt → Sprung zu letztem Schritt
- Neustart-Button: alles inkl. localStorage leeren
- Frist-Banner: deadline-Feld in StellingnahmeGeneratorBlockData, Ampelfarben
- Step 1 überspringen wenn keine ortskonkreten Argumente vorhanden
- Step-Indikator: goTo() statt step= (scrollt jetzt korrekt)
- "Alle wählen" öffnet Gruppe automatisch
- Download als .txt neben Kopieren/Drucken
- <pre> → <div> für konsistentes Schriftbild im Output
- Mini-Map für Vorranggebiet in Step 0 (tap-to-activate, fitBoundsMaxZoom=13)
- WindkarteMap: fitBoundsMaxZoom-Prop ergänzt
- Druckausgabe: 13pt Serif, 2cm Ränder, kein Markdown im Fertigtext

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:57:27 +02:00
Peter Meier 6d0861bb0a feat(stellungnahme): Einwendungs-Assistent für Windvorranggebiete
Deploy / verify (push) Successful in 59s
Deploy / deploy (push) Successful in 2m37s
5-Schritt-Wizard: Gebietskontext → Argumente wählen → Ausgabeform →
persönliche Betroffenheit → Absender + Ausgabe. Alle Eingaben bleiben
lokal im Browser (kein Server-Transfer). Fertigtext- und Leitfaden-Modus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:41:00 +02:00
Peter Meier b7bcdd76ee feat(calendar): compact variant for next-events teaser
Deploy / verify (push) Successful in 1m8s
Deploy / deploy (push) Successful in 1m13s
Calendar block now supports variant: "default" | "compact".
- default = full calendar (unchanged)
- compact = next N events (default 3) + link to a target page

New CalendarCompactBlock.svelte: small card with month/day badge,
title, date/time/location line, "Alle kommenden Termine →" footer
link resolved from the schema's linkTo reference. Filters to future
events (12h tolerance for running ones).

BlockRenderer dispatches by block.variant inside the calendar case.
Schema (cms_content/_types/core/calendar.json5) adds variant + linkTo
+ limit fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 08:49:08 +02:00
Peter Meier 94a8feeb67 feat(contact): full validation, CMS-translated strings, smaller UI
Deploy / verify (push) Failing after 47s
Deploy / deploy (push) Has been skipped
- contact-form-validation.ts: shared client+server validator returning
  {key, params} so messages can be translated via the CMS bundle.
- ContactFormComponent: 3 honeypots, subject field, GDPR consent
  checkbox, character counter, inline per-field errors after submit,
  uses useTranslate() everywhere.
- /api/contact: origin allowlist, multiple honeypot check, client-age
  gate, server-side re-validation, forwards X-Forwarded-For + UA to
  CMS forms plugin with consent timestamp in payload.
- TextInput/Textarea: new size="sm" variant (rounded-sm, shadow-sm,
  h-10, smaller padding/text). Default "md" unchanged.
- translations.ts: 37 new contact_* keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 11:28:23 +02:00
Peter Meier 9e05fbb2ba feat: add internal_component block type with contact form
InternalComponentBlock dispatches on `component` field value.
ContactFormComponent submits via /api/contact (SvelteKit proxy →
CMS /api/forms/kontakt/submit) with honeypot + client_age_ms.
BlockRenderer and block-types.ts updated accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 11:01:47 +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 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 23faef550e feat(calendar): image/attachment per event, direct links, copy link, ImageModal component
Deploy / verify (push) Successful in 58s
Deploy / deploy (push) Successful in 53s
- calendar_item schema: flyer → image (type: image), attachment (assetUrl)
- CalendarItemData: image + attachment fields
- event anchor IDs (#event-{slug}) with onMount hash scroll + auto-open
- share button uses direct calendar anchor URL
- copy link button (mdi:link-variant) copies anchor URL to clipboard
- ImageModal extracted as reusable component
- action buttons always show text (no expand-on-hover)
- onDestroy window guard (SSR fix)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 20:02:30 +02:00
Peter Meier a1c59b549d feat(calendar): future-events accordion, ICS/Google export, multi-day
Right panel now shows all upcoming events as a card-style accordion
(date block + title + location/time chips visible, body collapsed).
Day-grouped with sticky headers + relative countdown.

- ICS download per event (RFC-5545, client-side blob)
- Google Calendar render-template link per event
- Maps link via location field (new schema field)
- Multi-day events via terminEnde (new schema field): grid spans,
  range "Mai / 14–16 / 2026" date block, expanded eventsByDay map
- Tag filter chips (new schema field) above calendar
- Past events <details> at list end, expanded if no future
- Live status badge: "läuft gerade" / "beginnt in 45 min"
  (60s tick interval)
- Today marker on calendar grid (outline + sr-only label)
- Auto-scroll next event into panel viewport on mount
- "Im Kalender anzeigen" jumps grid to event month
- Urgency-colored left border per event: now/today/tomorrow/week/
  later in fire/erde/himmel/stein
- Zebra striping + 4px separator between day-groups
- ARIA: aria-current=date, aria-pressed on day/tag buttons
- Print CSS: details auto-open, day-group break-inside: avoid
- Timezone fix: dayKey uses local Y/M/D not ISO string slice
- Empty-title fallback to "Termin"
- Side-by-side layout from md+ (was always stacked)

Extends CalendarItemData with terminEnde, location, tags
inline until OpenAPI regen catches up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 15:45:16 +02:00
Peter Meier 88514b065a feat(strommix): history-driven panels (residual load, dunkelflaute, neg-price, flow balance)
Aggregator route /api/strommix now reads three RustyCMS history-mode
collections in parallel — strommix_history_de, price_de_history,
crossborder_history_de — and projects derived metrics on top of the raw
upstream snapshots stored there:

- todayHourly: per-slot Last + Wind+Solar for the residual-load chart
- negPriceHoursYtd: count of YTD slots where DE-LU day-ahead < 0
- crossborderTodayGwh / netCrossborderGwhYtd / crossborderByCountryGwhYtd:
  GW × slot-hours integrated into a per-country GWh balance
- lastDunkelflaute / worstDunkelflauten: contiguous runs where
  (wind+solar)/load drops below 10 % for at least 1 h, top 5 by duration

All four are null-graceful — collections that the CMS hasn't backfilled
yet leave the corresponding panel hidden instead of breaking the widget.

Five new components in lib/components/blocks/strommix/:
- ResidualLoadChart.svelte — SVG line chart, no chart-lib dep
- CapacityFactorBars.svelte — live vs installed Wind/Wind-Off/Solar
- DunkelflauteCounter.svelte — last phase card + top-5 list
- NegPriceCounter.svelte — YTD hours + manual EinsMan compensation
- FlowBalanceTodayYtd.svelte — today + YTD saldo with per-country breakdown

Block schema additions (block-types.ts + strommix-default.json5 in
cms_content): installed_*_gw / installed_as_of for the capacity-factor
bars (BNetzA Marktstammdatenregister snapshot, manually maintained), and
einsman_costs_ytd_eur_mio / einsman_costs_as_of for the NegPrice panel
(BNetzA quarterly report figures, no API).
2026-05-07 13:06:30 +02:00
Peter Meier 3ded972642 feat(strommix): variant system + wald palette + UX polish
Deploy / verify (push) Successful in 52s
Deploy / deploy (push) Successful in 52s
Add full/compact variants, prominent share, source badge, big
negative-price banner with conditional disclaimer, cards-style
context row, fade-in animation, and remove em-dashes from
visible strings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 00:43:18 +02:00
Peter Meier 8ddfd026bc feat(blocks): live_strommix widget for energy-charts data
Deploy / verify (push) Successful in 47s
Deploy / deploy (push) Successful in 53s
Editor-controlled live-strommix card that surfaces what share of
electricity demand is currently covered by weather-dependent
renewables (Wind+Solar / Load), plus the conventional generation that
fills the gap, the cross-border saldo, and the day-ahead price (DE/FR
side-by-side). Status bucket + label + argument come from the CMS so
editors can iterate copy without a deploy.

- LiveStrommixBlockData type next to the other block-types.
- New `/api/strommix` aggregator route bundles four CMS external
  collections (strommix_de, crossborder_de, price_de, price_fr) into a
  single payload, computes the renewable + conventional sums and the
  cross-border saldo (Σ flow_xx_gw, sign convention: + = export from
  DE), surfaces stale-on-error flags from the CMS response headers.
  Cache-control 5min so a single node only hits energy-charts once
  per window.
- StrommixBlock.svelte renders the card: percentage, bucket label,
  bucket argument (markdown), context row (conventional + saldo with
  ↑/↓ arrow), price row with optional FR comparison + negative-price
  badge, footer with disclaimer + "Wie wird das berechnet?" link +
  stale-data hint when the CMS served fallback. Re-polls every 5min
  client-side; bucket thresholds + labels + arguments come from the
  block instance so multiple placements can carry different copy.
- ContentRows.svelte dispatcher branch on `_type === "live_strommix"`.

Wired against `cms_content/_types/core/live_strommix.json5` (added in
the rustycms repo today). content_layout.row{1,2,3}Content already
allow the new block-type via the same commit on the CMS side.
2026-05-04 22:57:40 +02:00
Peter Meier 35f7aa8f90 feat(blocks): YoutubeVideoGalleryBlock (carousel + grid)
Deploy / verify (push) Successful in 2m19s
Deploy / deploy (push) Successful in 1m7s
New block for `youtube_video_gallery` CMS type. Carousel renders
2 iframes side-by-side on md+ (1 on mobile) with prev/next/dots; grid
shows YT thumbnails opening modal embeds. Description supports
markdown via marked; long URLs break with overflow-wrap:anywhere.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 08:31:38 +02:00
Peter Meier 354d3f09d3 feat(youtube): playlist support + URL parsing in youtube_video block
Deploy / verify (push) Successful in 42s
Deploy / deploy (push) Successful in 1m5s
YoutubeVideoBlockData gains an optional `playlistId`. The block now
accepts either a video, a playlist, or both, and either field can be
filled with a raw ID *or* a full youtube.com / youtu.be URL — a
helper extracts the ?v= and ?list= parameters automatically.

Embed routing:
- video only           → /embed/<id>?rel=0
- playlist only        → /embed/videoseries?list=<plid>&rel=0
- video + playlist     → /embed/<id>?list=<plid>&rel=0
- block.params merged  via URLSearchParams

Also tweaks ImageGalleryBlock (grid variant): green padding/contain
fit, darker caption gradient, smaller left-aligned label that expands
on hover. Hides post_overview block when no posts and no intro text
(prevents a bare heading on /mediathek).
2026-04-25 13:15:11 +02:00
Peter Meier 6246d7c3a4 feat(gallery): grid variant with hover labels + download modal
Deploy / verify (push) Successful in 40s
Deploy / deploy (push) Successful in 1m1s
ImageGalleryBlock now branches on `block.variant`:

- "standard" (default) → existing carousel.
- "grid" → 2/3/4-column thumbnail grid (1:1 squares, w=400/q=75
  through /cms-images). Each tile scales 5% on hover and surfaces
  the image's title/alt/caption/description as a gradient overlay
  caption that fades in on hover and keyboard focus.

Click any tile → fullscreen lightbox (z-100 overlay + 90vh image).
The lightbox carries:
- A download button using the asset's filename (extracted from the
  src URL).
- Prev/Next arrows when there's more than one image (keyboard:
  ←/→), Esc to close, click on the backdrop closes too.
- Position counter (n/total) when applicable.

Type updates in block-types.ts: ImageGalleryBlockData gains
`variant?: "standard"|"grid"` and `title?`. ImageGalleryImage gains
`alt`/`caption`/`title` so the schema's `image` field shape is
honoured for the hover label.
2026-04-25 10:32:37 +02:00
Peter Meier 5b5ec7c659 feat: add FilesBlock interface and component integration
Deploy / verify (push) Successful in 46s
Deploy / deploy (push) Successful in 1m8s
- Introduced FilesBlockItem and FilesBlockData interfaces to support file handling in the CMS.
- Integrated FilesBlock component into ContentRows.svelte for rendering file blocks.
- Updated block type handling to include support for files, enhancing content versatility.
2026-04-22 10:23:20 +02:00
Peter Meier 2ee451f4ca feat(post-overview): add excludeTag functionality for filtering posts
Deploy / verify (push) Successful in 39s
Deploy / deploy (push) Failing after 1m7s
- Introduced `excludeTag` property in PostOverviewBlockData interface to allow exclusion of specific tag slugs.
- Implemented `excludePostsByTagSlugs` function to filter out posts containing specified tag slugs.
- Updated `resolvePostOverviewBlocks` function to utilize the new exclusion logic, enhancing post filtering capabilities.
2026-04-19 14:18:50 +02:00
Peter Meier 1d75610cd3 feat(organisations-block): enhance OrganisationsBlock with carousel presentation option and improved layout
Deploy / verify (push) Successful in 37s
Deploy / deploy (push) Successful in 58s
- Added "carousel" option to the presentation property in OrganisationsBlockData for horizontal slider functionality.
- Updated OrganisationsBlock.svelte to support carousel layout with smooth scrolling feature.
- Refined Badge component styling for better visual consistency.
- Improved overall structure and responsiveness of the organisations display.
2026-04-19 13:13:12 +02:00
Peter Meier 62d25202a6 feat(deadline-banner): auto mode pulls all calendar_items globally
Deploy / verify (push) Successful in 40s
Deploy / deploy (push) Successful in 59s
Auto-mode deadline_banner now resolves to the next future event across
all calendar_items in the CMS instead of requiring a manually-curated
items[] pool. Server load hooks (+page.server.ts for /, /[...slug],
/post/[slug]) call resolveDeadlineBannerBlocks which fetches the
global calendar_item list once and attaches it as items[] when mode
is "auto" and items[] is not already resolved. Component logic
unchanged — it still picks the soonest future entry.

Also:
- cms.ts: getCalendarItems() bulk list fetcher
- PostOverviewBlock.svelte: design defaults to "cards" when value is
  empty string (not just null/undefined) so existing entries with
  design: "" render

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 11:02:50 +02:00
Peter Meier ffd4f599cd feat(quote): enhance QuoteBlock and QuoteCarouselBlock components
Deploy / verify (push) Successful in 44s
Deploy / deploy (push) Successful in 1m3s
- Updated QuoteBlock to support a new "center" variant for text alignment.
- Modified QuoteCarouselBlock to include an option for displaying navigation arrows.
- Enhanced type definitions for quote-related data structures to accommodate new features.
- Improved styling and layout handling for better visual presentation of quotes.
2026-04-19 09:31:30 +02:00
Peter Meier 597b920e7c feat(quote-carousel): add QuoteCarouselBlock component and related types
Deploy / verify (push) Successful in 41s
Deploy / deploy (push) Successful in 1m1s
- Introduced a new QuoteCarouselBlock component for displaying rotating quotes.
- Added QuoteCarouselBlockData interface to define the structure of the quote carousel data.
- Updated existing components and types to integrate the new quote carousel functionality.
- Enhanced blog-utils to support filtering posts by tags more effectively.
- Made various UI improvements in the Footer and PostCard components for better user experience.
2026-04-18 13:19:59 +02:00
Peter Meier 2fef91a548 Initial SvelteKit frontend port of windwiderstand.de
Deploy / verify (push) Failing after 32s
Deploy / deploy (push) Has been skipped
Full parity with Astro site: content rows, post/tag routes, pagination,
event badges + OSM map, comments, Live-Search via /api/search-index,
CMS image proxy, RSS, sitemap.

Deploy: Dockerfile + docker-compose.prod.yml + Gitea Actions workflow
to build + push to git.pm86.de registry and ssh-deploy to Contabo.
2026-04-17 22:01:30 +02:00