feat: kuratierte externe Kalender (Kult 41) + clickable Freund:innen-Logos#14
Merged
Conversation
Neuer Quell-Typ ics-filtered in calendars.json mit categoryAllow/categoryDeny und titleAllow/titleDeny. Erste Anwendung: Kult 41 (Hauptkalender events.ics, Konzerte gefiltert, cap 15). Zweiter Typ ics-single bleibt vorbereitet für künftige Single-Event-ICS-URLs. Parser-Erweiterungen: extrahiert UID, URL, TZID. Non-Europe/Berlin TZIDs werden geloggt (warn-once) statt umgerechnet — bisheriges Verhalten bleibt. firstSeen und RSS-GUID nutzen jetzt UID statt date|summary, mit date|title-Fallback für Migration von alten events-data.json-Einträgen. events.js: bei externer eventUrl wird direkt verlinkt statt /timeGridDay/<datum> anzuhängen — sonst 404 auf kult41.de. Tests: Inline-Funktionskopien rausgezogen, Tests importieren echte Symbole aus sync-events.mjs. 12 neue Tests (applyFilter, UID/URL-Parsing, TZID-Warn, eventUrl-Fallback, cap, calTags). 55/55 pass.
Bestehender Logo-Slider rendert <img> ohne Link. Neue images/logo-slider/logos.json maps Dateinamen → display name + optionale URL. Wenn URL gesetzt: Logo wird in <a target=_blank rel=noopener> gewrappt mit aria-label "<Name> (externer Link)". Ohne URL: bisheriges <img>-only Verhalten (backward compat). Der zweite slider__set (aria-hidden Duplikat für nahtloses Scrolling) bekommt tabindex=-1, sonst doppelte Tab-Stops. CSS: .logo-slider__link nutzt display:contents damit das Layout (.logo-slider__item img Selektor) greift, plus focus-visible outline auf dem img. Erste verlinkte Logos: FrOSCon (froscon.org), FSFE (fsfe.org), Kult 41 (kult41.de/veranstaltungen/programm). Die übrigen vier Einträge in logos.json haben url:"" als Platzhalter zum Nachtragen. Kult 41 Logo-Datei muss noch nach images/logo-slider/kult41.png — der Eintrag in logos.json ist vorbereitet, npm run build:logos zieht ihn automatisch ein sobald die Datei da ist.
Statt Master-Feed mit Konzert-Filter (15 Events) ziehen wir aktuell nur das eine thematisch passende Event: Theater Tumult: K.I. und Abel + Reggae. Der ics-single-Typ war genau dafür vorbereitet — pro Event ein JSON-Block mit der einzelnen ICS-URL des Plugins (wp-events-plugin/Events Manager). Output: 1 VEVENT → 1 card. Link geht direkt zur kult41.de-Event-Seite. Weitere Events können einfach durch zusätzliche ics-single-Einträge ergänzt werden (jeweils mit unique id).
Pro kuratiertem externen Event/Source eine eigene File statt eines wachsenden Arrays in calendars.json. Schöneres git-diff bei Add/Remove, klare 1:1-Sicht "Datei = Quelle". calendars.json bleibt für die stabilen primary feeds (bitcircus + datenburg). calendars/external/*.json ergänzt — jede Datei = ein Source-Objekt im selben Format wie ein calendars.json-Eintrag. sync-events.mjs mergt beides über neuen loadCalendars()-Helper, der defekte/unvollständige Files mit Warnung überspringt statt das ganze Sync zu brechen. Workflow zieht jetzt auch calendars/ aus main, sonst fehlen externals auf dem live-Branch. Erstes externes File: Theater Tumult bei Kult 41. Docs in CLAUDE.md und README beschreiben die neue Convention plus die source types (ics-full/ics-single/ics-filtered).
…nifest calendars.json (root) → weg. Stattdessen lebt jede Quelle in einer eigenen JSON-Datei unter calendars/. calendars/config.json ist das Manifest, das auflistet welche Sources verarbeitet werden und in welcher Reihenfolge. Eintrag rausnehmen = Source deaktivieren, ohne die Datei zu löschen. Konsistent für stable primary feeds (bitcircus, datenburg) UND kuratierte externals (calendars/external/*) — alles über das gleiche Pattern. loadCalendars() liest jetzt das Manifest und lädt die referenzierten Files. Fehlende oder defekte Files werden mit Warning übersprungen, das Sync läuft weiter (eine kaputte Source kann nicht alles brechen). Workflow zieht nur noch calendars/ aus main. Docs in CLAUDE.md + README zeigen die neue Struktur und Tabelle der aktiven Sources.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Calendar-Pipeline und Homepage-Slider ausgebaut, plus Refactor der Config-Struktur.
Calendar-Pipeline
calendars/mitconfig.jsonals Manifest. Eintrag aussourcesraus = Quelle deaktiviert, ohne die Datei zu löschen. Konsistent für bitcircus, datenburg UND kuratierte externals.ics-single— eine ICS-URL pro Event (z.B.kult41.de/events/foo/ical/). Aktuell: Theater Tumult bei Kult 41.ics-filtered— full calendar mitcategoryAllow/Deny,titleAllow/DenyListen.UID,URL,TZIDaus VEVENTs.firstSeenund RSS-guidlaufen auf UID mitdate|title-Fallback (Migration ohne RSS-Spam).Europe/BerlinTZIDs werden geloggt (warn-once pro source/zone), Zeiten bleiben floating local — kein Behavior-Change für die Nextcloud-Quellen.events.js: externeeventUrlwerden direkt verlinkt statt/timeGridDay/<datum>anzuhängen — sonst 404 auf kult41.de.cappro Source (Default 30), verhindert dass ein dichter Kalender alle Slots frisst.Freund:innen-Logos
images/logo-slider/logos.jsonmapped Dateinamen → display name + optionale URL.build-logo-slider.mjswrappt<img>in<a target=_blank rel=noopener>mitaria-label, wenn URL gesetzt.tabindex="-1"— sonst doppelte Tab-Stops.di.day,inlaws,leihbar,BSB Selbstwerk) habenurl:""als Platzhalter zum Nachtragen.Tests
sync-events.mjs(keine Drift mehr).applyFilter(Allow/Deny/Title/Category), UID/URL-Parsing, TZID-Warn-once,eventUrl-Fallback,cap-Override,calTags-Merge.Workflow
sync-events.ymlzieht jetztscripts/ calendars/aus main (stattscripts/ calendars.json), damit externals aufliveverfügbar sind.Test plan
npm run test:quick— 55/55 passnpm run build:layout+npm run build:logos— kein unerwarteter HTML-Drift