Add calendar shortcode
This commit is contained in:
parent
925737eff5
commit
6eceb15f18
6 changed files with 140 additions and 0 deletions
22
layouts/_partials/ics-line.html
Normal file
22
layouts/_partials/ics-line.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{{- /*
|
||||
One iCalendar (RFC 5545) content line: "NAME:value" plus CRLF, folded so that no line is
|
||||
longer than 75 bytes (continuation lines start with a space). Params: name, value, text
|
||||
(true to escape the value as TEXT: backslash, semicolon, comma and newlines).
|
||||
*/ -}}
|
||||
{{- $value := .value | default "" -}}
|
||||
{{- if .text -}}
|
||||
{{- $value = $value | replaceRE `\\` `\\` | replaceRE `;` `\;` | replaceRE `,` `\,` | replaceRE `\r?\n` `\n` -}}
|
||||
{{- end -}}
|
||||
{{- $out := "" -}}
|
||||
{{- $line := "" -}}
|
||||
{{- $bytes := 0 -}}
|
||||
{{- range split (printf "%s:%s" .name $value) "" -}}
|
||||
{{- if gt (add $bytes (len .)) 75 -}}
|
||||
{{- $out = printf "%s%s\r\n " $out $line -}}
|
||||
{{- $line = "" -}}
|
||||
{{- $bytes = 1 -}}
|
||||
{{- end -}}
|
||||
{{- $line = printf "%s%s" $line . -}}
|
||||
{{- $bytes = add $bytes (len .) -}}
|
||||
{{- end -}}
|
||||
{{- return printf "%s%s\r\n" $out $line -}}
|
||||
84
layouts/_shortcodes/calendar.html
Normal file
84
layouts/_shortcodes/calendar.html
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{{- /*
|
||||
Calendar links for one date of a tour: an .ics file (iCalendar, for Apple Calendar, Outlook,
|
||||
Thunderbird and most other apps) and a link that adds the event in Google Calendar.
|
||||
Meant for the list of dates on a tour page:
|
||||
|
||||
* Tag 1 (27.12.) **17:30 Uhr** {{< calendar date="2026-12-27" time="17:30" duration="210" >}}
|
||||
|
||||
Params: date (YYYY-MM-DD), time (HH:MM, local time in Hamburg), duration in minutes
|
||||
(optional, else tours.<slug>.duration in data/schedule/<event>.yaml), title (optional, else the
|
||||
title of this date in the schedule data, else the page title).
|
||||
*/ -}}
|
||||
{{- $page := .Page -}}
|
||||
{{- $lang := $page.Language.Name -}}
|
||||
{{- $other := cond (eq $lang "de") "en" "de" -}}
|
||||
{{- $event := $page.Section -}}
|
||||
{{- $slug := $page.File.ContentBaseName -}}
|
||||
{{- $date := .Get "date" -}}
|
||||
{{- $time := .Get "time" -}}
|
||||
{{- if not (and (findRE `^\d{4}-\d{2}-\d{2}$` $date) (findRE `^\d{2}:\d{2}$` $time)) -}}
|
||||
{{- errorf "calendar: date must be YYYY-MM-DD and time HH:MM, got %q %q: %s" $date $time .Position -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- $data := dict -}}
|
||||
{{- with hugo.Data.schedule }}{{ with index . $event }}{{ $data = . }}{{ end }}{{ end -}}
|
||||
{{- $tourData := dict -}}
|
||||
{{- with $data.tours }}{{ with index . $slug }}{{ $tourData = . }}{{ end }}{{ end -}}
|
||||
{{- /* This date in the schedule, for its title. */ -}}
|
||||
{{- $slot := dict -}}
|
||||
{{- range $data.days -}}
|
||||
{{- if eq .date $date -}}
|
||||
{{- range .tours }}{{ if and (eq .tour $slug) (eq .time $time) }}{{ $slot = . }}{{ end }}{{ end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- $title := .Get "title" -}}
|
||||
{{- if not $title }}{{ with $slot.title }}{{ $title = index . $lang | default (index . $other) }}{{ end }}{{ end -}}
|
||||
{{- $title = $title | default $page.Title -}}
|
||||
|
||||
{{- $minutes := int (.Get "duration" | default ($tourData.duration | default 0)) -}}
|
||||
{{- if not $minutes -}}
|
||||
{{- warnidf "warning-calendar-duration" "calendar: no duration for %s on %s %s, the calendar entry has no end time: %s" $slug $date $time .Position -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- $start := time.AsTime (printf "%sT%s:00" $date $time) "Europe/Berlin" -}}
|
||||
{{- $end := $start.Add (time.ParseDuration (printf "%dm" $minutes)) -}}
|
||||
{{- $utc := "20060102T150405Z" -}}
|
||||
|
||||
{{- /* Everyone meets at the Hackertours desk, which is where the routes on the map start. */ -}}
|
||||
{{- $location := i18n "calendar_meeting_point" -}}
|
||||
{{- with $data.map }}{{ with .origin }}{{ with .name -}}
|
||||
{{- $location = printf "%s, %s" $location (index . $lang | default (index . $other)) -}}
|
||||
{{- end }}{{ end }}{{ end -}}
|
||||
{{- /* The front matter summary: .Summary would render this page again from inside its own shortcode. */ -}}
|
||||
{{- $summary := $page.Params.summary | default $page.Description | default "" -}}
|
||||
{{- $description := printf "%s\n\n%s" ($page.RenderString $summary | plainify | htmlUnescape | strings.TrimSpace) $page.Permalink -}}
|
||||
|
||||
{{- $ics := printf "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//CCC Hansestadt Hamburg//Hackertours//%s\r\nCALSCALE:GREGORIAN\r\nMETHOD:PUBLISH\r\nBEGIN:VEVENT\r\n" (upper $lang) -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "UID" "value" (printf "%s-%s-%s-%s@%s" $event $slug $date (replace $time ":" "") (urls.Parse site.BaseURL).Host))) -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "DTSTAMP" "value" ($page.Lastmod.UTC.Format $utc))) -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "DTSTART" "value" ($start.UTC.Format $utc))) -}}
|
||||
{{- if $minutes }}{{ $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "DTEND" "value" ($end.UTC.Format $utc))) }}{{ end -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "SUMMARY" "value" $title "text" true)) -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "LOCATION" "value" $location "text" true)) -}}
|
||||
{{- with $data.map }}{{ with .origin }}{{ with .geo -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "GEO" "value" (printf "%v;%v" .lat .lon))) -}}
|
||||
{{- end }}{{ end }}{{ end -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "DESCRIPTION" "value" $description "text" true)) -}}
|
||||
{{- $ics = printf "%s%s" $ics (partial "ics-line.html" (dict "name" "URL" "value" $page.Permalink)) -}}
|
||||
{{- $ics = printf "%sEND:VEVENT\r\nEND:VCALENDAR\r\n" $ics -}}
|
||||
|
||||
{{- $file := printf "%s-%s-%s.ics" $slug $date (replace $time ":" "") -}}
|
||||
{{- $icsFile := resources.FromString (path.Join (strings.TrimPrefix "/" $page.RelPermalink) $file) $ics -}}
|
||||
{{- $google := printf "https://calendar.google.com/calendar/render?%s" (querify
|
||||
"action" "TEMPLATE"
|
||||
"text" $title
|
||||
"dates" (printf "%s/%s" ($start.UTC.Format $utc) ($end.UTC.Format $utc))
|
||||
"details" $description
|
||||
"location" $location
|
||||
"ctz" "Europe/Berlin"
|
||||
) -}}
|
||||
{{- /* The visible link texts repeat for every date; the hidden part says which date it is. */ -}}
|
||||
{{- $when := printf "%s %s" ($start | time.Format "Mon 2.1.") $time -}}
|
||||
<span class="tour-calendar"><a href="{{ $icsFile.RelPermalink }}" download="{{ $file }}">{{ i18n "calendar_ics" }}<span class="visually-hidden"> {{ $when }}</span></a> · <a href="{{ $google }}">{{ i18n "calendar_google" }}<span class="visually-hidden"> {{ $when }}</span></a></span>
|
||||
{{- /* chomp */ -}}
|
||||
Loading…
Reference in a new issue