You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(events): kuratierte externe Kalender + UID-Identity
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.
* feat(homepage): clickable Freund:innen-Logos via logos.json mapping
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.
* feat(homepage): add Kult 41 logo to Freund:innen slider
* feat(events): switch Kult 41 to single curated event
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).
* refactor(events): split curated externals into calendars/external/*.json
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).
* refactor(events): one-file-per-source under calendars/ with config manifest
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.
Copy file name to clipboardExpand all lines: CLAUDE.md
+17-1Lines changed: 17 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -117,7 +117,23 @@ These are generated by CI. Seed values exist on `main` (for local dev / E2E test
117
117
118
118
## Adding a calendar source
119
119
120
-
Add an entry to `calendars.json` — no code changes needed.
120
+
Every source lives in its own JSON file under `calendars/`. Manifest `calendars/config.json` lists which sources to process and in what order. Adding a new source = create the JSON file, list its relative path in `config.json`. Removing = remove the line (or delete the file).
-`ics-single` — single curated event ICS URL (e.g. `https://kult41.de/events/foo/ical/`)
134
+
-`ics-filtered` — full calendar with `filter.categoryAllow` / `categoryDeny` / `titleAllow` / `titleDeny` lists
135
+
136
+
Each source can also set `tags` (always-added hashtags), `cap` (per-source slot override), `eventUrl` (fallback link when ICS lacks `URL`). Sources without `id`/`ics` are skipped with a warning.
|`datenburg`| Datenburg e.V. | ics-full | no | no |
153
+
|`kult41-theater-tumult-k-i-abel`| Kult 41 | ics-single | no | no |
154
+
155
+
To add a calendar: create the source JSON in `calendars/` (or `calendars/external/`) and add its path to `sources` in `config.json`. To temporarily disable: remove the path from `sources` — the file stays put.
|`ics-filtered`| Full calendar, narrowed by lists |`categoryAllow`, `categoryDeny`, `titleAllow`, `titleDeny`|
164
+
165
+
External sources also accept `tags` (always-added hashtags), `cap` (per-source slot override), and `eventUrl` (overrides the per-event link when ICS has no `URL` field).
166
+
167
+
Example `calendars/external/kult41-theater-tumult-k-i-abel.json`:
"_comment": "Steuert welche Quellen sync-events.mjs verarbeitet und in welcher Reihenfolge. Pfade sind relativ zu diesem Verzeichnis (calendars/). Eintrag rausnehmen = Source deaktivieren ohne die Datei zu löschen.",
"_note": "Theater-Performance bei Kult 41. Passt thematisch zum Hackspace-Profil (gegenkulturelle Veranstaltung). Single-Event-ICS aus dem wp-events-plugin der kult41.de-Seite.",
0 commit comments