diff --git a/.gitignore b/.gitignore index 54e16e8..349c2d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ static/all.ics -.envrc # Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo # Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos,hugo @@ -101,4 +100,4 @@ shell.nix .direnv # Python -.venv +.venv \ No newline at end of file diff --git a/README.md b/README.md index c299d95..a544e7a 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ +![CCCB logo](static/img/logo.png) + # CCCB Website This is the website of the CCCB. -![CCCB logo](assets/img/logo.png) - ## Getting started 1. Get Hugo: -2. Clone this repo (`--recursive` is needed to check out submodules) +2. Clone this repo ```shell - git clone --recursive https://git.berlin.ccc.de/cccb-website-team/www.git cccb-website + git clone https://github.com/cccb/www ``` 3. Switch directory ```shell - cd cccb-website + cd www + ``` +3. Fetch Submodules + ```shell + git submodule update --recursive --remote --init ``` ### Run site locally @@ -31,13 +35,13 @@ Every change you make on the project will be reflected in your browser as long a ## Making a change -1. Use your local dev setup (see Getting started) or via the Forgejo editor. +1. Use your local dev setup (see Getting started) or via GitHub editor. 2. Make your change in `staging` branch. 3. Commit (and push) your change. -4. ~~GitHub Actions is running the release workflow.~~ +4. GitHub Actions is running the release workflow. - If successful, check [Staging Website](https://staging.berlin.ccc.de/) if change is correct. 5. Create merge request to merge changes from `staging` to `production` branch. Ask somebody to check merge request or if small change, merge yourself. -6. ~~GitHub Actions is running the release workflow.~~ +6. GitHub Actions is running the release workflow. - If successfull, check [Website](https://berlin.ccc.de/) if change is correct. 7. Profit! diff --git a/TODO.md b/TODO.md index 10121f4..7401796 100644 --- a/TODO.md +++ b/TODO.md @@ -2,8 +2,7 @@ - DSGVO-compliant Datenschutzerklärung reinbasteln - Entscheiden, welche Seiten sonst noch konvertiert werden sollen und welche in die ewigen Datengründe gehen können - - +- add nix config to repo # Done @@ -18,3 +17,4 @@ - Bestehende Datengarten-Termine konvertieren - ggf. template mit frontmatter - Theme forken, alle assets sollten lokal gehosted sein und nicht von irgendwelchen CDNs bezogen werden (HTTP/2 ftw!) + diff --git a/build.sh b/build.sh index 3a07414..11d85bf 100755 --- a/build.sh +++ b/build.sh @@ -1,10 +1,7 @@ #!/bin/sh -set -e -set -x - hugo $(cat .hugo-params) ./tools/merge_cals.py upcoming="$(tools/gen_upcoming.py static/all.ics 20 5 | tr '\n' ' ')" cp static/all.ics public/all.ics -sed -i "s#CALENDAR#$upcoming#g" public/index.html +sed -i "s#CALENDAR#$upcoming#g" public/index.html \ No newline at end of file diff --git a/config/_default/languages.de.toml b/config/_default/languages.de.toml index e3fc5ce..a6e4f46 100644 --- a/config/_default/languages.de.toml +++ b/config/_default/languages.de.toml @@ -25,9 +25,53 @@ title = "Chaos Computer Club Berlin" headline = "Willkommen! Wir sind ein Erfa-Kreis des Chaos Computer Club e.V. und die örtliche Niederlassung des CCC in Berlin." # bio = "A little bit about you" links = [ - { mastodon = "https://chaos.social/@clubdiscordia" }, - { forgejo = "https://git.berlin.ccc.de/explore/repos" }, { email = "mailto:mail2025@berlin.ccc.de" }, +# { link = "https://link-to-some-website.com/" }, +# { amazon = "https://www.amazon.com/hz/wishlist/ls/wishlist-id" }, +# { apple = "https://www.apple.com" }, +# { blogger = "https://username.blogspot.com/" }, +# { bluesky = "https://bsky.app/profile/username" }, +# { codepen = "https://codepen.io/username" }, +# { dev = "https://dev.to/username" }, +# { discord = "https://discord.gg/invitecode" }, +# { dribbble = "https://dribbble.com/username" }, +# { facebook = "https://facebook.com/username" }, +# { flickr = "https://www.flickr.com/photos/username/" }, +# { foursquare = "https://foursquare.com/username" }, { github = "https://github.com/cccb/" }, - + { gitlab = "https://git.berlin.ccc.de/explore/repos" }, +# { google = "https://www.google.com/" }, +# { hashnode = "https://username.hashnode.dev" }, +# { instagram = "https://instagram.com/username" }, +# { itch-io = "https://username.itch.io" }, +# { keybase = "https://keybase.io/username" }, +# { kickstarter = "https://www.kickstarter.com/profile/username" }, +# { lastfm = "https://lastfm.com/user/username" }, +# { linkedin = "https://linkedin.com/in/username" }, + { mastodon = "https://chaos.social/@clubdiscordia" }, + # { irc = "https://webirc.hackint.org/#ircs://irc.hackint.org/#cccb" }, +# { medium = "https://medium.com/username" }, +# { microsoft = "https://www.microsoft.com/" }, +# { orcid = "https://orcid.org/userid" }, +# { patreon = "https://www.patreon.com/username" }, +# { pinterest = "https://pinterest.com/username" }, +# { reddit = "https://reddit.com/user/username" }, +# { researchgate = "https://www.researchgate.net/profile/username" }, +# { slack = "https://workspace.url/team/userid" }, +# { snapchat = "https://snapchat.com/add/username" }, +# { soundcloud = "https://soundcloud.com/username" }, +# { spotify = "https://open.spotify.com/user/userid" }, +# { stack-overflow = "https://stackoverflow.com/users/userid/username" }, +# { steam = "https://steamcommunity.com/profiles/userid" }, +# { telegram = "https://t.me/username" }, +# { threads = "https://www.threads.net/@username" }, +# { tiktok = "https://tiktok.com/@username" }, +# { tumblr = "https://username.tumblr.com" }, +# { twitch = "https://twitch.tv/username" }, +# { twitter = "https://twitter.com/username" }, +# { x-twitter = "https://twitter.com/username" }, +# { whatsapp = "https://wa.me/phone-number" }, +# { youtube = "https://youtube.com/username" }, +# { ko-fi = "https://ko-fi.com/username" }, +# { codeberg = "https://codeberg.org/username"}, ] diff --git a/config/_default/menus.de.toml b/config/_default/menus.de.toml index c8bd31f..53f1159 100644 --- a/config/_default/menus.de.toml +++ b/config/_default/menus.de.toml @@ -46,7 +46,7 @@ weight = 10 [[footer]] - name = "Kategorien" + name = "Categories" pageRef = "categories" weight = 20 @@ -56,6 +56,6 @@ weight = 500 [[footer]] - name = "Datenschutz" + name = "Privacy" pageRef = "datenschutz" - weight = 600 + weight = 600 \ No newline at end of file diff --git a/content/_index.md b/content/_index.md index 11b925a..b4658f5 100644 --- a/content/_index.md +++ b/content/_index.md @@ -6,4 +6,4 @@ description: "Startseite CCCB mit Kurzkalender" CALENDAR -Weitere Termine findest du [hier](/verein/calendar/). \ No newline at end of file +Keinen Termin mehr verpeilen? Einfach den [Veranstaltungskalender abonnieren](all.ics)! diff --git a/content/post/tag_des_offenen_hackerspace.md b/content/post/tag_des_offenen_hackerspace.md index b23ef1b..97bbc46 100644 --- a/content/post/tag_des_offenen_hackerspace.md +++ b/content/post/tag_des_offenen_hackerspace.md @@ -1,31 +1,22 @@ --- -title: "Tag Des Offenen Hackspace" +title: "Tag Des Offenen Hackerspace" subtitle: "Der CCCB lädt ein zum Kennenlernen und Entdecken." date: 2025-02-10T12:00:00+02:00 dtstart: 20250329T130000 dtend: 20250329T200000 --- -{{< figure - src="/img/tdoh/20250309_001608.jpg" - title="Das Airport Display im CCCB" - alt="Das Airport Display im CCCB" - caption="Das Airport Display im CCCB" ->}} - -Der [Tag des offenen Hackspace](https://events.ccc.de/2025/02/28/tag-des-offenen-hackspace-2025/) findet dieses Jahr auch im Chaos Computer Club Berlin statt: +Der [Tag des offenen Hackerspace](https://events.ccc.de/2024/02/23/tag-des-offenen-hackspace-einladung/) findet dieses Jahr auch im CCCB statt. - Führungen durch die Räume - mit Hack- und Lachgeschichten -- Kurzvorträge ab 17 Uhr u.a. zu den Themen: - - Der CCCB stellt sich vor! +- Kurzvorträge ab 17 Uhr zu den Themen: - Freifunk - OpenWrt -- Spaß am Gerät mit dem Service-Point -- Live-Schaltungen zu anderen Hackspaces -- die Community kennenlernen + - ...und noch ein paar weitere. +- Spaß am Gerät + - Spiele und Videos auf dem Flughafen Info-Point Display +- Live-Schaltungen mit Kamera und Musik zu anderen Hackespaces + - die Community kennenlernen -Am 29.03.2025 freuen wir uns, Euch von 13 Uhr bis 20 Uhr in unseren Clubräumen begrüßen zu dürfen! -Anfahrt: https://berlin.ccc.de/verein/anfahrt/ - -All Creatures Welcome! +Am 29.03. freuen wir uns, euch ab 13 Uhr in unseren Clubräumen begrüßen zu dürfen! \ No newline at end of file diff --git a/content/veranstaltungen/amateurfunk.md b/content/veranstaltungen/amateurfunk.md index c0de50e..9544143 100644 --- a/content/veranstaltungen/amateurfunk.md +++ b/content/veranstaltungen/amateurfunk.md @@ -3,13 +3,7 @@ title: "Amateurfunk" subtitle: "Funken und Löten im CCCB" date: 2018-05-17T22:41:48+02:00 --- - -{{< figure - src="/img/chaoswelle.png" - title="Logo der Chaoswelle" - alt="Logo der Chaoswelle" - caption="Logo der Chaoswelle" ->}} +![Logo der Chaoswelle](/img/chaoswelle.png "Logo der Chaoswelle") Vor einiger Zeit fanden gelegentlich Amateurfunkkurse im CCCB statt. Im Zusammenhang damit trafen sich Funkamateure und Interessierte rund um drahtlose Kommunikation auch an den offenen Abenden. Das Treffen war Nahe zur [Interessensgemeinschaft Chaoswelle](http://chaoswelle.de), die sich im DARC e.V. Ortsverband D23 diff --git a/content/veranstaltungen/bastelabend.md b/content/veranstaltungen/bastelabend.md index e288c08..29e4f08 100644 --- a/content/veranstaltungen/bastelabend.md +++ b/content/veranstaltungen/bastelabend.md @@ -10,21 +10,7 @@ menu: parent: "Veranstaltungen" --- - -{{< figure - src="/img/club/27481933907_f240f4232d.jpg" - title="Lötkolben im CCCB" - alt="Lötkolben im CCCB" - caption="Lötkolben im CCCB" ->}} - +![Lötkolben im CCCB](/img/club/27481933907_f240f4232d.jpg) **Jeden 1. und 3. Samstag im Monat ist ab 17 Uhr Bastelabend im Club.** - - - -{{< alert "circle-info" >}} -Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. - -Generell sind aber alle, die schonmal im Club waren, herzlich eingeladen, an den Bastelabenden vorbeizukommen. -{{< /alert >}} \ No newline at end of file +Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. Generell sind aber alle herzlich eingeladen, an den Spieleabenden vorbeizukommen. \ No newline at end of file diff --git a/content/veranstaltungen/chaosradio.md b/content/veranstaltungen/chaosradio.md index 56a6535..30a1c71 100644 --- a/content/veranstaltungen/chaosradio.md +++ b/content/veranstaltungen/chaosradio.md @@ -11,12 +11,7 @@ menu: parent: "Veranstaltungen" --- -{{< figure - src="/img/chaosradio.png" - title="Chaosradio logo" - alt="Chaosradio logo" - caption="Chaosradio logo" ->}} +![Chaosradio logo](/img/chaosradio.png) [Chaosradio](https://chaosradio.ccc.de) ist der Podcast des CCCB. Seit 2020 zeichen wir ihn remote auf. Gelegentlich finden Sendungen vor Live-Publikum im Club, auf diff --git a/content/veranstaltungen/clubdiscordia.md b/content/veranstaltungen/clubdiscordia.md index 55b81e4..4217595 100644 --- a/content/veranstaltungen/clubdiscordia.md +++ b/content/veranstaltungen/clubdiscordia.md @@ -12,13 +12,7 @@ menu: parent: "Veranstaltungen" --- -{{< figure - src="/img/club/e-lab-kisten.jpg" - title="Das E-Lab im CCCB" - alt="Das E-Lab im CCCB" - caption="Das E-Lab im CCCB" ->}} - +![E-Lab im CCCB](/img/club/e-lab-kisten.jpg) Der **Club Discordia** ist ein öffentliches Treffen in den Clubräumen des CCC Berlin. Jeder, der Lust hat, ist eingeladen, **Donnerstags so ab ca. 19 Uhr bis 24 Uhr** vorbeizukommen. Wer will, kann seinen Computer mitbringen und sollte das auch tun, sonst ist es langweilig wenn die Nerds erstmal nicht mit einem reden oder wenig los ist. diff --git a/content/veranstaltungen/cms.md b/content/veranstaltungen/cms.md index 56686b9..f2256d1 100644 --- a/content/veranstaltungen/cms.md +++ b/content/veranstaltungen/cms.md @@ -10,12 +10,7 @@ menu: parent: "Veranstaltungen" --- -{{< figure - src="/img/cms-logo.jpg" - title="Chaos Macht Schule Logo" - alt="Chaos Macht Schule Logo" - caption="Chaos Macht Schule Logo" ->}} +![Chaos Macht Schule Logo](/img/cms-logo.jpg "Chaos Macht Schule Logo") Unter dem Begriff “Chaos macht Schule” finden sich mehrere regionale Projekte diverser ERFA-Kreise des CCC. Bestärkt in der bisherigen diff --git a/content/veranstaltungen/plenum.md b/content/veranstaltungen/plenum.md index 8a0d364..41a1472 100644 --- a/content/veranstaltungen/plenum.md +++ b/content/veranstaltungen/plenum.md @@ -1,5 +1,5 @@ --- -title: "Plenum (club closed - members only)" +title: "Plenum (club closed, members only)" subtitle: "Instrument der internen Konsensfindung" date: 2018-05-18T01:11:54+02:00 dtstart: 20180704T200000 diff --git a/content/veranstaltungen/spieleabend.md b/content/veranstaltungen/spieleabend.md index 2a9c6eb..09db203 100644 --- a/content/veranstaltungen/spieleabend.md +++ b/content/veranstaltungen/spieleabend.md @@ -13,9 +13,4 @@ menu: ![Dorfromantik spielen im CCCB](/img/club/dorfromantik-im-cccb.jpg) **Jeden 2. und 4. Samstag im Monat ist ab 17 Uhr Spieleabend im Club.** - -{{< alert "circle-info" >}} -Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. - -Generell sind aber alle, die schonmal im Club waren, herzlich eingeladen, an den Spieleabenden vorbeizukommen. -{{< /alert >}} \ No newline at end of file +Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. Generell sind aber alle herzlich eingeladen, an den Bastelabenden vorbeizukommen. \ No newline at end of file diff --git a/content/veranstaltungen/subbotnik.md b/content/veranstaltungen/subbotnik.md index f527cd1..648de2f 100644 --- a/content/veranstaltungen/subbotnik.md +++ b/content/veranstaltungen/subbotnik.md @@ -18,11 +18,4 @@ Ungefähr jedes viertel Jahr wird im CCCB von den Mitgliedern einmal richtig dur Der Begriff [Subbotnik](https://de.wikipedia.org/wiki/Subbotnik) ist eine in Sowjetrussland entstandene Bezeichnung für einen unbezahlten Arbeitseinsatz am Sonnabend, der in den Sprachgebrauch in der DDR und daraufhin auch in den Sprachgebrauch der CCCB-Mitglieder übernommen wurde. ---- - -{{< alert "circle-info" >}} -Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. - -Generell sind aber alle, die schonmal im Club waren, herzlich eingeladen am Subbotnik vorbeizukommen und mitzuhelfen. -{{< /alert >}} - +Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. Generell sind aber alle herzlich eingeladen, am Subbotnik vorbeizukommen und mitzuhelfen. \ No newline at end of file diff --git a/content/verein/calendar.md b/content/verein/calendar.md index c429f35..2bc48d9 100644 --- a/content/verein/calendar.md +++ b/content/verein/calendar.md @@ -22,7 +22,7 @@ menu: } #event-panel { flex: 1; - min-width: 30%; + min-width: 300px; background-color: var(--color-bg-secondary); padding: 15px; border-radius: 5px; @@ -48,62 +48,38 @@ menu: border-collapse: collapse; } #calendar-table th, #calendar-table td { - border: 1px; + border: 1px solid var(--color-border); padding: 5px; text-align: center; vertical-align: top; - height: 50px; - width: 15%; + height: 60px; + width: 14.28%; + } + #calendar-table th { + background-color: var(--color-bg-secondary); } - #calendar-table th #calendar-table td { + background-color: var(--color-bg-primary); position: relative; cursor: pointer; } #calendar-table td:hover { - background-color: rgba(255, 255, 255, 0.2); - box-shadow: 0 0 20px rgba(255, 255, 255, 0.2); + background-color: var(--color-bg-hover); } - .event-dot-greenyellow { + .event-dot { height: 8px; width: 8px; - background-color: #9acd32; + background-color: greenyellow; border-radius: 50%; display: block; margin: 5px auto 0; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); - } - .event-dot-orange { - height: 8px; - width: 8px; - background-color: #ffa500; - border-radius: 50%; - display: block; - margin: 5px auto 0; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); - } - .event-dot-red { - height: 8px; - width: 8px; - background-color: #ff4500; - border-radius: 50%; - display: block; - margin: 5px auto 0; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); } .has-event { - + background-color: var(--color-bg-secondary) !important; } .selected-day { - background-color: rgba(255, 255, 255, 0.1); - box-shadow: 0 0 20px rgba(255, 255, 255, 0.1); - border-radius: 8px; - width: 20px; - height: 20px; - border: 5px solid grey; - font-weight: lighter; - position: relative; - z-index: 1; + background-color: var(--color-bg-hover) !important; + font-weight: bold; } #event-date { font-size: 1.2em; @@ -177,22 +153,14 @@ menu: if (colonIndex > -1) { let key = line.substring(0, colonIndex); let value = line.substring(colonIndex + 1); - - // Handle properties with parameters (like TZID) - const baseKey = key.split(";")[0]; - - if (baseKey === "DTSTART") { + if (key.startsWith("DTSTART")) { event.start = value; - event.startParams = key.includes(";") ? key.substring(key.indexOf(";") + 1) : null; - } else if (baseKey === "DTEND") { + } else if (key.startsWith("DTEND")) { event.end = value; - event.endParams = key.includes(";") ? key.substring(key.indexOf(";") + 1) : null; - } else if (baseKey === "SUMMARY") { + } else if (key.startsWith("SUMMARY")) { event.summary = value; - } else if (baseKey === "DESCRIPTION") { + } else if (key.startsWith("DESCRIPTION")) { event.description = value; - } else if (baseKey === "RRULE") { - event.rrule = value; } } } @@ -202,18 +170,13 @@ menu: // Hilfsfunktion: Parst einen ICS-Datum-String ins Format "YYYY-MM-DD" function parseDateString(icsDateStr) { - // Handle different date formats - if (!icsDateStr) return null; - - // For basic date format: YYYYMMDD + // Erwartet entweder ganztägige Daten (YYYYMMDD) oder Datum+Zeit (YYYYMMDDTHHmmssZ) if (icsDateStr.length === 8) { let year = icsDateStr.substring(0, 4); let month = icsDateStr.substring(4, 6); let day = icsDateStr.substring(6, 8); return `${year}-${month}-${day}`; - } - // For datetime formats: YYYYMMDDTHHmmssZ or YYYYMMDDTHHmmss - else if (icsDateStr.includes("T")) { + } else if (icsDateStr.length >= 15) { let year = icsDateStr.substring(0, 4); let month = icsDateStr.substring(4, 6); let day = icsDateStr.substring(6, 8); @@ -222,114 +185,6 @@ menu: return null; } - // Extract date components from different date formats - function getDateComponents(icsDateStr) { - if (!icsDateStr) return null; - - // Basic handling - extract YYYY, MM, DD regardless of format - const year = parseInt(icsDateStr.substring(0, 4)); - const month = parseInt(icsDateStr.substring(4, 6)) - 1; // 0-based months - const day = parseInt(icsDateStr.substring(6, 8)); - - return { year, month, day }; - } - - function expandRecurringEvents(event, year, month) { - if (!event.rrule) return [event]; - - const rruleStr = event.rrule; - - // Get start date components - const startComponents = getDateComponents(event.start); - if (!startComponents) return [event]; - - const startDate = new Date( - startComponents.year, - startComponents.month, - startComponents.day - ); - - const rangeStart = new Date(year, month, 1); - const rangeEnd = new Date(year, month + 1, 0); - const expandedEvents = []; - - if (rruleStr.includes("FREQ=WEEKLY") && rruleStr.includes("BYDAY")) { - const bydayMatch = rruleStr.match(/BYDAY=([^;]+)/); - if (bydayMatch) { - const dayCode = bydayMatch[1]; - const dayMap = { - 'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0 - }; - const targetDay = dayMap[dayCode]; - - if (targetDay !== undefined) { - // Create events for each matching day in the month - let day = 1; - while (day <= rangeEnd.getDate()) { - const testDate = new Date(year, month, day); - if (testDate.getDay() === targetDay && testDate >= startDate) { - const newEvent = {...event}; - const eventDate = formatDateForICS(testDate); - - // Preserve time portion from original event - const timePart = event.start.includes('T') ? - event.start.substring(event.start.indexOf('T')) : ''; - const endTimePart = event.end.includes('T') ? - event.end.substring(event.end.indexOf('T')) : ''; - - newEvent.start = eventDate + timePart; - newEvent.end = eventDate + endTimePart; - expandedEvents.push(newEvent); - } - day++; - } - } - } - } - else if (rruleStr.includes("FREQ=MONTHLY") && rruleStr.includes("BYDAY")) { - const bydayMatch = rruleStr.match(/BYDAY=([^;]+)/); - if (bydayMatch) { - const bydays = bydayMatch[1].split(','); - const dayMap = { - 'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0 - }; - - bydays.forEach(byday => { - const occurrence = parseInt(byday) || 1; - const dayCode = byday.slice(-2); - const dayIndex = dayMap[dayCode]; - - let day = 1; - let count = 0; - - while (day <= rangeEnd.getDate()) { - const testDate = new Date(year, month, day); - if (testDate.getDay() === dayIndex) { - count++; - if (count === occurrence || (occurrence < 0 && day > rangeEnd.getDate() + occurrence * 7)) { - const newEvent = {...event}; - const eventDate = new Date(year, month, day); - - // Preserve time portion from original event - const timePart = event.start.includes('T') ? - event.start.substring(event.start.indexOf('T')) : ''; - const endTimePart = event.end.includes('T') ? - event.end.substring(event.end.indexOf('T')) : ''; - - newEvent.start = formatDateForICS(eventDate) + timePart; - newEvent.end = formatDateForICS(eventDate) + endTimePart; - expandedEvents.push(newEvent); - } - } - day++; - } - }); - } - } - - return expandedEvents.length > 0 ? expandedEvents : [event]; - } - // Kalender initialisieren let currentYear, currentMonth; const currentMonthElem = document.getElementById("current-month"); @@ -344,56 +199,17 @@ menu: currentMonth = 11; currentYear--; } - updateEventsForMonth(currentYear, currentMonth); + renderCalendar(currentYear, currentMonth); }); document.getElementById("next-month").addEventListener("click", function(){ currentMonth++; if (currentMonth > 11) { - currentMonth = 0; - currentYear++; + currentMonth = 0; + currentYear++; } - updateEventsForMonth(currentYear, currentMonth); + renderCalendar(currentYear, currentMonth); }); - function updateEventsForMonth(year, month) { - // Clear existing events for this month view - eventsByDate = {}; - - // Process each event, expanding recurring ones - events.forEach(ev => { - if (ev.rrule) { - // For recurring events, expand them for current month - const expandedEvents = expandRecurringEvents(ev, year, month); - expandedEvents.forEach(expandedEv => { - let dateKey = parseDateString(expandedEv.start); - if (dateKey) { - if (!eventsByDate[dateKey]) { - eventsByDate[dateKey] = []; - } - eventsByDate[dateKey].push(expandedEv); - } - }); - } else { - // For regular events, check if they fall in current month - let dateKey = parseDateString(ev.start); - if (dateKey) { - // Check if this event belongs to current month view - const eventYear = parseInt(dateKey.split('-')[0]); - const eventMonth = parseInt(dateKey.split('-')[1]) - 1; - - if (eventYear === year && eventMonth === month) { - if (!eventsByDate[dateKey]) { - eventsByDate[dateKey] = []; - } - eventsByDate[dateKey].push(ev); - } - } - } - }); - - renderCalendar(year, month); - } - function renderCalendar(year, month) { // Setze die Monatsbeschriftung (in Deutsch) const monthNames = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]; @@ -425,42 +241,11 @@ menu: let dateKey = year + "-" + monthStr + "-" + dayStr; if (eventsByDate[dateKey]) { - let dotsContainer = document.createElement("div"); - dotsContainer.className = "event-dots-container"; - cell.classList.add("has-event"); + let eventDot = document.createElement("div"); + eventDot.className = "event-dot"; + cell.appendChild(document.createElement("br")); + cell.appendChild(eventDot); - // Gruppe Events nach Typ - const events = eventsByDate[dateKey]; - const hasMembersOnly = events.some(e => e.summary.toLowerCase().includes("members only")); - const hasSubbotnik = events.some(e => e.summary.toLowerCase().includes("subbotnik")); - const hasBastelabend = events.some(e => e.summary.toLowerCase().includes("bastelabend")); - const hasSpieleabend = events.some(e => e.summary.toLowerCase().includes("spieleabend")); - const hasRegular = events.some(e => { - const title = e.summary.toLowerCase(); - return !title.includes("members only") && - !title.includes("subbotnik") && - !title.includes("bastelabend") && - !title.includes("spieleabend"); - }); - - // Füge Dots entsprechend der Event-Typen hinzu - if (hasMembersOnly) { - let dot = document.createElement("div"); - dot.className = "event-dot event-dot-red"; - dotsContainer.appendChild(dot); - } - if (hasSubbotnik || hasBastelabend || hasSpieleabend) { - let dot = document.createElement("div"); - dot.className = "event-dot event-dot-orange"; - dotsContainer.appendChild(dot); - } - if (hasRegular) { - let dot = document.createElement("div"); - dot.className = "event-dot event-dot-greenyellow"; - dotsContainer.appendChild(dot); - } - - cell.appendChild(dotsContainer); cell.dataset.dateKey = dateKey; cell.addEventListener("click", function() { // Clear previous selections @@ -509,8 +294,9 @@ menu: eventTitle.className = "event-title"; // Create a link for the event title - let titleLink = document.createElement("h"); + let titleLink = document.createElement("a"); titleLink.textContent = ev.summary; + titleLink.href = createEventLink(ev.summary); titleLink.target = "_blank"; eventTitle.appendChild(titleLink); @@ -521,26 +307,14 @@ menu: eventTime.textContent = `Start: ${formatTime(ev.start)}, End: ${formatTime(ev.end)}`; eventItem.appendChild(eventTime); - if (ev.description) { - let eventDescription = document.createElement("div"); - eventDescription.className = "event-description"; - - // Check if the description is a URL and make it a clickable link - if (ev.description.trim().startsWith('http')) { - let linkElement = document.createElement("a"); - linkElement.href = ev.description.trim(); - linkElement.textContent = ev.description.trim(); - linkElement.target = "_blank"; - eventDescription.innerHTML = ''; - eventDescription.appendChild(linkElement); - } else { - eventDescription.textContent = ev.description; - } - - eventItem.appendChild(eventDescription); - } + if (ev.description) { + let eventDescription = document.createElement("div"); + eventDescription.className = "event-description"; + eventDescription.textContent = ev.description; + eventItem.appendChild(eventDescription); + } - eventDetailsElem.appendChild(eventItem); + eventDetailsElem.appendChild(eventItem); }); } else { let noEvents = document.createElement("div"); @@ -560,44 +334,37 @@ menu: function formatTime(icsTimeStr) { // Format time for display - if (!icsTimeStr) return ""; - if (icsTimeStr.length === 8) { // All-day event return "Ganztägig"; - } else if (icsTimeStr.includes("T")) { - // Time-specific event (with or without timezone) - const timeStart = icsTimeStr.indexOf("T") + 1; - const hour = icsTimeStr.substring(timeStart, timeStart + 2); - const minute = icsTimeStr.substring(timeStart + 2, timeStart + 4); + } else if (icsTimeStr.length >= 15) { + // Time-specific event + const hour = icsTimeStr.substring(9, 11); + const minute = icsTimeStr.substring(11, 13); return `${hour}:${minute}`; } return icsTimeStr; } - function formatDateForICS(date) { - const year = date.getFullYear(); - const month = (date.getMonth() + 1).toString().padStart(2, '0'); - const day = date.getDate().toString().padStart(2, '0'); - return `${year}${month}${day}`; - } - // ICS-Datei abrufen und Events verarbeiten fetch('/all.ics') .then(response => response.text()) .then(data => { events = parseICS(data); - - // Initialize with current date + events.forEach(ev => { + let dateKey = parseDateString(ev.start); + if (dateKey) { + if (!eventsByDate[dateKey]) { + eventsByDate[dateKey] = []; + } + eventsByDate[dateKey].push(ev); + } + }); let today = new Date(); currentYear = today.getFullYear(); currentMonth = today.getMonth(); - - // Process events for current month - updateEventsForMonth(currentYear, currentMonth); + renderCalendar(currentYear, currentMonth); }) .catch(err => console.error('Fehler beim Laden der ICS-Datei:', err)); })(); - -Keinen Termin mehr verpeilen? Einfach den [Veranstaltungskalender abonnieren](all.ics)! \ No newline at end of file diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 6cc6b35..0000000 --- a/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1741332913, - "narHash": "sha256-ri1e8ZliWS3Jnp9yqpKApHaOo7KBN33W8ECAKA4teAQ=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "20755fa05115c84be00b04690630cb38f0a203ad", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-24.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 73e94d9..0000000 --- a/flake.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - description = "A flake containing a development environment for the CCCB website."; - - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; - }; - - outputs = - { self, nixpkgs }: - let - forAllSystems = - f: - nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed ( - system: - f rec { - pkgs = nixpkgs.legacyPackages.${system}; - inherit system; - } - ); - in - { - devShells = forAllSystems ( - { pkgs, ... }: - { - default = pkgs.mkShell rec { - packages = with pkgs; [ - hugo - go - (pkgs.python3.withPackages (python-pkgs: [ - python-pkgs.icalendar - python-pkgs.pytz - ])) - shellcheck - ]; - }; - } - ); - - formatter = forAllSystems ({ pkgs, ... }: pkgs.nixfmt-rfc-style); - }; -} diff --git a/static/img/club/40544370280_1703903e06.jpg b/static/img/club/40544370280_1703903e06.jpg deleted file mode 100644 index 6705505..0000000 Binary files a/static/img/club/40544370280_1703903e06.jpg and /dev/null differ diff --git a/static/img/tdoh/20250309_001608.jpg b/static/img/tdoh/20250309_001608.jpg deleted file mode 100644 index 846b3a9..0000000 Binary files a/static/img/tdoh/20250309_001608.jpg and /dev/null differ