Compare commits

..

5 commits

Author SHA1 Message Date
murmeldin 8745fcccd0 Merge branch 'staging' into production 2025-04-17 00:49:37 +02:00
murmeldin 1e245cf6cd newly added club status, currently disabled until spaceapi is set public 2025-04-17 00:48:03 +02:00
murmeldin 6281666093 datengarten post design overhaul 2025-04-17 00:45:32 +02:00
murmeldin 26c9a2e0d4 added 404 page 2025-04-17 00:43:38 +02:00
murmeldin 27e009ab0b format all config files 2025-04-16 19:05:03 +02:00
12 changed files with 397 additions and 226 deletions

67
assets/js/clubstatus.js Normal file
View file

@ -0,0 +1,67 @@
const spaceapiUrl = "https://spaceapi.hamburg.ccc.de"
const interval_ms = 60000
console.log("clubstatus.js geladen!"); /* TODO: ENTFERNEN */
function timeDistanceDE(pastDate) {
const seconds = Math.floor((Date.now() - pastDate.getTime()) / 1000)
const minutes = Math.floor(seconds / 60)
const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
if (days = 1) return `since ${days}d`
if (days > 1) return `since ${days}d`
if (hours = 1) return `since ${hours}h`
if (hours > 1) return `since ${hours}h`
if (minutes = 1) return `since ${minutes}min`
if (minutes > 1) return `since ${minutes}min`
return `gerade eben`
}
function updateRoomState(openState, lastChangeTimestamp) {
const roomstate = document.querySelector('#clubstatus-badge')
const statusItem = roomstate.querySelector(".state")
const durationItem = roomstate.querySelector(".duration")
if (!statusItem || !durationItem) return
roomstate.classList.remove("open", "closed", "unknown")
statusItem.classList.remove("open", "closed", "unknown")
if (openState === null || lastChangeTimestamp === null) {
statusItem.textContent = "unbekannt"
statusItem.classList.add("unknown")
durationItem.textContent = "(since unbekannt)"
} else {
const changeDate = new Date(lastChangeTimestamp * 1000)
const sinceText = timeDistanceDE(changeDate)
if (openState) {
statusItem.textContent = "open"
statusItem.classList.add("open")
} else {
statusItem.textContent = "closed"
statusItem.classList.add("closed")
}
durationItem.textContent = `(${sinceText})`
}
}
function fetchRoomState() {
fetch(spaceapiUrl)
.then(response => response.json())
.then(data => {
const openState = data?.state?.open ?? null
const lastChange = data?.state?.lastchange ?? null
updateRoomState(openState, lastChange)
})
.catch(err => {
console.error("Fehler beim Laden der SpaceAPI:", err)
updateRoomState(null, null)
})
}
// Initialer Abruf + dann regelmäßig
fetchRoomState()
setInterval(fetchRoomState, interval_ms)

View file

@ -1,92 +1,89 @@
theme = 'blowfish' theme = "blowfish"
baseURL = 'https://oururl.de/' baseURL = "https://oururl.de/"
defaultContentLanguage = 'de' defaultContentLanguage = "de"
relativeURLs = true relativeURLs = true
canonifyURLs = true canonifyURLs = true
pluralizeListTitles = false pluralizeListTitles = false
enableRobotsTXT = true enableRobotsTXT = true
summaryLength = 0 summaryLength = 0
buildDrafts = false buildDrafts = false
buildFuture = false buildFuture = false
enableEmoji = true enableEmoji = true
[pagination] [pagination]
pagerSize = 100 pagerSize = 100
[imaging] [imaging]
anchor = 'Center' anchor = "Center"
[taxonomies] [taxonomies]
tag = 'tags' tag = "tags"
category = 'categories' category = "categories"
author = 'authors' author = "authors"
series = 'series' series = "series"
[sitemap] [sitemap]
changefreq = 'daily' changefreq = "daily"
filename = 'sitemap.xml' filename = "sitemap.xml"
priority = 0.5 priority = 0.5
[permalinks] [permalinks]
post = '/post/:year/:month/:day/:title/' post = "/post/:year/:month/:day/:title/"
[outputs] [outputs]
home = ['html', 'rss', 'json'] home = ["html", "rss", "json"]
section = ['html', 'Calendar', 'rss', 'xml'] section = ["html", "Calendar", "rss", "xml"]
page = ['html', 'Calendar'] page = ["html", "Calendar"]
# Output Formats Configuration # Output Formats Configuration
[outputFormats.Calendar] [outputFormats.Calendar]
mediaType = 'text/calendar' mediaType = "text/calendar"
baseName = 'index' baseName = "index"
isPlainText = true isPlainText = true
notAlternative = true notAlternative = true
[outputFormats.XML] [outputFormats.XML]
mediaType = 'application/xml' mediaType = "application/xml"
baseName = 'index' baseName = "index"
isPlainText = true isPlainText = true
[outputFormats.RSS] [outputFormats.RSS]
mediaType = 'application/rss+xml' mediaType = "application/rss+xml"
# Media Types Configuration # Media Types Configuration
[mediaTypes] [mediaTypes]
[mediaTypes.'text/calendar'] [mediaTypes.'text/calendar']
suffixes = ['ics'] suffixes = ["ics"]
[mediaTypes.'application/rss+xml'] [mediaTypes.'application/rss+xml']
suffixes = ['xml', 'rss'] suffixes = ["xml", "rss"]
[related] [related]
threshold = 0 threshold = 0
toLower = false toLower = false
[[related.indices]] [[related.indices]]
name = 'tags' name = "tags"
weight = 100 weight = 100
[[related.indices]] [[related.indices]]
name = 'categories' name = "categories"
weight = 100 weight = 100
[[related.indices]] [[related.indices]]
name = 'series' name = "series"
weight = 50 weight = 50
[[related.indices]] [[related.indices]]
name = 'authors' name = "authors"
weight = 20 weight = 20
[[related.indices]] [[related.indices]]
name = 'date' name = "date"
weight = 10 weight = 10
[[related.indices]] [[related.indices]]
applyFilter = false applyFilter = false
name = 'fragmentrefs' name = "fragmentrefs"
type = 'fragments' type = "fragments"
weight = 10 weight = 10

View file

@ -8,10 +8,8 @@
colorScheme = "fira" # "congo" colorScheme = "fira" # "congo"
defaultAppearance = "dark" # valid options: light or dark defaultAppearance = "dark" # valid options: light or dark
autoSwitchAppearance = false autoSwitchAppearance = false
enableSearch = true enableSearch = true
enableCodeCopy = false enableCodeCopy = false
replyByEmail = false replyByEmail = false
# mainSections = ["section1", "section2"] # mainSections = ["section1", "section2"]
@ -21,14 +19,11 @@ replyByEmail = false
disableImageOptimization = false disableImageOptimization = false
disableTextInHeader = false disableTextInHeader = false
backgroundImageWidth = 1200 backgroundImageWidth = 1200
# defaultBackgroundImage = "/img/cccb-im-winter.jpg" # used as default for background images # defaultBackgroundImage = "/img/cccb-im-winter.jpg" # used as default for background images
defaultFeaturedImage = "/img/avatar-CCCB-Logo.png" # used as default for featured images in all articles defaultFeaturedImage = "/img/avatar-CCCB-Logo.png" # used as default for featured images in all articles
# highlightCurrentMenuArea = true # highlightCurrentMenuArea = true
smartTOC = true smartTOC = true
smartTOCHideUnfocusedChildren = true smartTOCHideUnfocusedChildren = true
giteaDefaultServer = "https://git.fsfe.org" giteaDefaultServer = "https://git.fsfe.org"
forgejoDefaultServer = "https://git.berlin.ccc.de" forgejoDefaultServer = "https://git.berlin.ccc.de"
@ -117,7 +112,6 @@ forgejoDefaultServer = "https://git.berlin.ccc.de"
series = "series" series = "series"
tag = "tags" tag = "tags"
[term] [term]
showHero = false showHero = false
# heroStyle = "background" # valid options: basic, big, background, thumbAndBackground # heroStyle = "background" # valid options: basic, big, background, thumbAndBackground

1
content/404.md Normal file
View file

@ -0,0 +1 @@
Leider existiert diese Seite nicht.

View file

@ -1,6 +1,27 @@
--- ---
description: "Startseite CCCB mit Kurzkalender" description: "Startseite CCCB mit Kurzkalender"
--- ---
/* this section will be enabled when the cccb spaceapi is public
<div style="display: flex; justify-content: center;">
<div id="clubstatus-badge">spacestatus unknown</div>
</div>
<style>
#clubstatus-badge {
position: relative;
background-color: #2ecc71;
flex: initial;
color: white;
padding: 0.25em 0.6em;
font-size: 0.75rem;
border-radius: 1em;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
font-weight: bold;
}
</style>
*/
### Nächste Veranstaltungen: ### Nächste Veranstaltungen:

View file

@ -4,14 +4,12 @@
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1"> <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<article role="main" class="blog-post"> <article role="main" class="blog-post">
<article class="max-w-prose mx-auto"> <article class="max-w-prose mx-auto">
<h1 class="text-2xl font-bold">{{ .Title }}</h1> <h1 class="mt-5 text-4xl font-extrabold text-neutral-900 dark:text-neutral pb-4">{{ .Title }}</h1>
{{ if .Params.subtitle }} {{ if .Params.subtitle }}
<h2 class="text-xl">{{ .Params.subtitle }}</h2> <h2 class="text-xl opacity-70">{{ .Params.subtitle }}</h2>
{{ end }} {{ end }}
<div class="mt-4 border p-4 bg-secondary-bg rounded">
{{ partial "talk-infobox" . }} {{ partial "talk-infobox" . }}
</div>
<div class="mt-4 content"> <div class="mt-4 content">
{{ .Content }} {{ .Content }}
@ -19,11 +17,18 @@
</article> </article>
{{ if .Params.tags }} {{ if .Params.tags }}
<div class="blog-tags"> <div class="blog-tags max-w-prose mx-auto mt-4 flex flex-wrap gap-4 border-2 p-5 pt-7 mt-6 rounded-lg opacity-75 drop-shadow-md">
<p class="opacity-50">Tags:</p>
<br>
{{ range .Params.tags }} {{ range .Params.tags }}
<a href="{{ $.Site.LanguagePrefix | absURL }}/tags/{{ . | urlize }}/">{{ . }}</a>&nbsp; <a
href="{{ $.Site.LanguagePrefix | absURL }}/tags/{{ . | urlize }}/"
class="inline-block px-3 py-1 rounded-lg text-sm font-semibold border-2 dark:bg-neutral-700 border-dotted shadow-lg shadow-blue-500/50"
>
{{ . }}
</a>
{{ end }} {{ end }}
</div><!--/.blog-tags--> </div>
{{ end }} {{ end }}
{{ if .Site.Params.socialShare }} {{ if .Site.Params.socialShare }}
@ -37,18 +42,31 @@
</article><!--/.blog-post--> </article><!--/.blog-post-->
{{ if ne .Type "page" }} {{ if ne .Type "page" }}
<ul class="pager blog-pager"> <ul class="pager blog-pager flex justify-between items-center mt-6 list-none p-0">
{{ if .PrevInSection }} {{ if .PrevInSection }}
<li class="previous"> <li class="previous">
<a href="{{ .PrevInSection.Permalink }}" data-toggle="tooltip" data-placement="top" title="{{ .PrevInSection.Title }}">&larr; {{ i18n "previousPost" }}</a> <a
</li><!--/.previous--> href="{{ .PrevInSection.Permalink }}"
class="inline-block px-4 py-2 text-lg font-semibold bg-neutral-200 dark:bg-neutral-700 rounded hover:bg-neutral-300 dark:hover:bg-neutral-600 transition-colors"
title="{{ .PrevInSection.Title }}"
>
&larr; {{ i18n "previousPost" }}
</a>
</li>
{{ end }} {{ end }}
{{ if .NextInSection }} {{ if .NextInSection }}
<li class="next"> <li class="next">
<a href="{{ .NextInSection.Permalink }}" data-toggle="tooltip" data-placement="top" title="{{ .NextInSection.Title }}">{{ i18n "nextPost" }} &rarr;</a> <a
</li><!--/.next--> href="{{ .NextInSection.Permalink }}"
class="inline-block px-4 py-2 text-lg font-semibold bg-neutral-200 dark:bg-neutral-700 rounded hover:bg-neutral-300 dark:hover:bg-neutral-600 transition-colors"
title="{{ .NextInSection.Title }}"
>
{{ i18n "nextPost" }} &rarr;
</a>
</li>
{{ end }} {{ end }}
</ul><!--/.pager .blog-pager--> </ul>
{{ end }} {{ end }}

View file

@ -0,0 +1,3 @@
{{ $js := resources.Get "js/clubstatus.js" | resources.Minify | resources.Fingerprint }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}"></script>

View file

@ -0,0 +1,70 @@
<footer id="site-footer" class="py-10 print:hidden">
{{/* Footer menu */}}
{{ if .Site.Params.footer.showMenu | default true }}
{{ if .Site.Menus.footer }}
<nav class="flex flex-row pb-4 text-base font-medium text-neutral-500 dark:text-neutral-400">
<ul class="flex flex-col list-none sm:flex-row">
{{ range .Site.Menus.footer }}
<li class="flex mb-1 ltr:text-right rtl:text-left sm:mb-0 ltr:sm:mr-7 ltr:sm:last:mr-0 rtl:sm:ml-7 rtl:sm:last:ml-0">
<a class="decoration-primary-500 hover:underline hover:decoration-2 hover:underline-offset-2 flex items-center" href="{{ .URL }}"
title="{{ .Title }}">
{{ if .Pre }}
<span {{ if and .Pre .Name}} class="mr-1" {{ end }}>
{{ partial "icon.html" .Pre }}
</span>
{{ end }}
{{ .Name | markdownify }}
</a>
</li>
{{ end }}
</ul>
</nav>
{{ end }}
{{ end }}
<div class="flex items-center justify-between">
{{/* Copyright */}}
{{ if .Site.Params.footer.showCopyright | default true }}
<p class="text-sm text-neutral-500 dark:text-neutral-400">
{{- with replace .Site.Params.copyright "{ year }" now.Year }}
{{ . | markdownify }}
{{- else }}
&copy;
{{ now.Format "2006" }}
{{ .Site.Params.Author.name | markdownify }}
{{- end }}
</p>
{{ end }}
{{/* Theme attribution */}}
{{ if .Site.Params.footer.showThemeAttribution | default true }}
<p class="text-xs text-neutral-500 dark:text-neutral-400">
{{ $hugo := printf `<a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
href="https://gohugo.io/" target="_blank" rel="noopener noreferrer">Hugo</a>`
}}
{{ $blowfish := printf `<a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
href="https://blowfish.page/" target="_blank" rel="noopener noreferrer">Blowfish</a>` }}
{{ i18n "footer.powered_by" (dict "Hugo" $hugo "Theme" $blowfish) | safeHTML }}
(<a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
href="https://git.berlin.ccc.de/cccb-website-team/www">Git-Repo</a>)
</p>
{{ end }}
</div>
<script>
{{ if not .Site.Params.disableImageZoom | default true }}
mediumZoom(document.querySelectorAll("img:not(.nozoom)"), {
margin: 24,
background: 'rgba(0,0,0,0.5)',
scrollOffset: 0,
})
{{ end }}
</script>
{{ $jsProcess := resources.Get "js/process.js" }}
{{ $jsProcess = $jsProcess | resources.Minify | resources.Fingerprint "sha512" }}
<script type="text/javascript" src="{{ $jsProcess.RelPermalink }}" integrity="{{ $jsProcess.Data.Integrity }}"></script>
{{/* Extend footer - eg. for extra scripts, etc. */}}
{{ if templates.Exists "partials/extend-footer.html" }}
{{ partialCached "extend-footer.html" . }}
{{ end }}
</footer>

View file

@ -1,4 +1,4 @@
<p> <p class="mt-4 gap-4 border-2 p-5 pt-7 mt-6 rounded-lg shadow-lg opacity-75 drop-shadow-md">
{{ if isset .Page.Params "speaker_url" }} {{ if isset .Page.Params "speaker_url" }}
<strong><i class="far fa-user fa-fw"></i></strong> <a href="{{ .Page.Params.Speaker_url }}">{{ .Page.Params.Speaker }}</a><br/> <strong><i class="far fa-user fa-fw"></i></strong> <a href="{{ .Page.Params.Speaker_url }}">{{ .Page.Params.Speaker }}</a><br/>
{{ else }} {{ else }}
@ -11,14 +11,14 @@
{{ with (eq $.Page.Params.Language "en") }} {{ with (eq $.Page.Params.Language "en") }}
<strong><i class="fa fa-language fa-fw"></i>🌐 Language:</strong> Englisch/English<br/> <strong><i class="fa fa-language fa-fw"></i>🌐 Language:</strong> Englisch/English<br/>
{{ end }} {{ end }}
<strong><i class="fa fa-map-marker fa-fw"></i>📍 Location:</strong> {{ partial "location" .Page.Params.Location }} <strong><i class="fa fa-map-marker fa-fw"></i>📍 Location:</strong> {{ partial "location" .Page.Params.Location }}<br/>
</p>
{{ if isset .Page.Params "recording" }} {{ if isset .Page.Params "recording" }}
<p><strong><i class="fa fa-video fa-fw"></i>📹 Livestream: </strong> <a href="{{ .Page.Params.Recording }}">{{ .Page.Params.Recording }}</a></p> <strong><i class="hover:underline hover:decoration-primary-400 hover:text-primary-500"></i>📹 Livestream: </strong> <a href="{{ .Page.Params.Recording }}">{{ .Page.Params.Recording }}</a></p>
{{ else }} {{ else }}
{{ if and (eq .Page.Params.Streaming true) (not (isset .Page.Params "recording" )) }} {{ if and (eq .Page.Params.Streaming true) (not (isset .Page.Params "recording" )) }}
<p><strong>Stream:</strong> <a href="https://streaming.media.ccc.de/datengarten">streaming.media.ccc.de/datengarten</a></p> <p><strong>Stream:</strong> <a class="hover:underline hover:decoration-primary-400 hover:text-primary-500" href="https://streaming.media.ccc.de/datengarten">streaming.media.ccc.de/datengarten</a></p>
{{ else }} {{ else }}
<p><strong><i class="fa fa-exclamation-triangle fa-fw"></i></strong> Dieser Vortrag wird <strong>nicht</strong> gestreamed</a>! / This talk will <strong>not</strong> be streamed!</p> <p><strong><i class="fa fa-exclamation-triangle fa-fw"></i></strong> Dieser Vortrag wird <strong>nicht</strong> gestreamed</a>! / This talk will <strong>not</strong> be streamed!</p>
{{ end }} {{ end }}
{{ end }} {{ end }}
</p>