diff --git a/.github/ISSUE_TEMPLATE/community-event.yml b/.github/ISSUE_TEMPLATE/community-event.yml index 439b6d3da..c5d8dd44f 100644 --- a/.github/ISSUE_TEMPLATE/community-event.yml +++ b/.github/ISSUE_TEMPLATE/community-event.yml @@ -7,7 +7,7 @@ body: attributes: value: | Thanks for submitting an event to the PowerShell.org community calendar! - Please fill out the details below. + Please fill out the details below. A maintainer will review and approve it. - type: input id: event_name @@ -29,15 +29,17 @@ body: id: start_date attributes: label: Start Date - placeholder: "YYYY-MM-DD" + description: "Format: YYYY-MM-DD" + placeholder: "2026-10-15" validations: required: true - type: input id: end_date attributes: - label: End Date (leave blank for single-day events) - placeholder: "YYYY-MM-DD" + label: End Date + description: "Format: YYYY-MM-DD — leave blank for single-day events" + placeholder: "2026-10-17" validations: required: false @@ -45,7 +47,8 @@ body: id: location attributes: label: Location - placeholder: "City, State/Country or 'Virtual'" + description: "City, State/Country — use 'Virtual' for online-only events" + placeholder: "Austin, TX" validations: required: true @@ -64,14 +67,7 @@ body: id: description attributes: label: Event Description - placeholder: "Brief description of the event (1-2 sentences)." + description: "1–2 sentences shown on the calendar page." + placeholder: "Brief description of the event." validations: required: true - - - type: textarea - id: additional_info - attributes: - label: Additional Information - placeholder: "Anything else we should know? (e.g., CFP deadlines, discount codes, etc.)" - validations: - required: false diff --git a/.github/workflows/add-event.yml b/.github/workflows/add-event.yml new file mode 100644 index 000000000..f8b56bff5 --- /dev/null +++ b/.github/workflows/add-event.yml @@ -0,0 +1,103 @@ +name: Add Community Event + +on: + issues: + types: [labeled] + +jobs: + add-event: + if: | + github.event.label.name == 'approved' && + contains(github.event.issue.labels.*.name, 'community-event') + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Parse issue and create event content file + id: parse + env: + ISSUE_BODY: ${{ github.event.issue.body }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + ISSUE_TITLE: ${{ github.event.issue.title }} + run: | + python3 - <<'PYEOF' + import os, re + + body = os.environ['ISSUE_BODY'] + issue_num = os.environ['ISSUE_NUMBER'] + + def field(label): + m = re.search(rf'### {re.escape(label)}\s+(.+?)(?=\n###|\Z)', body, re.DOTALL) + if not m: + return '' + val = m.group(1).strip() + return '' if val in ('_No response_', '') else val + + name = field('Event Name') + url = field('Event Website') + start_date = field('Start Date') + end_date = field('End Date') + location = field('Location') + virtual_s = field('Is this a virtual event?') + description = field('Event Description') + + virtual = 'true' if virtual_s.startswith(('Yes', 'Hybrid')) else 'false' + + # Generate a URL-safe slug: name + year + slug = re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-') + slug = f"{slug}-{start_date[:4]}" + + end_line = f'\nendDate: "{end_date}"' if end_date else '' + content = f"""--- + title: "{name}" + startDate: "{start_date}"{end_line} + where: "{location}" + externalUrl: "{url}" + virtual: {virtual} + --- + {description} + """ + # Dedent (the heredoc indents every line) + import textwrap + content = textwrap.dedent(content) + + filepath = f'content/calendar/{slug}.md' + os.makedirs('content/calendar', exist_ok=True) + with open(filepath, 'w') as f: + f.write(content) + + with open(os.environ['GITHUB_OUTPUT'], 'a') as out: + out.write(f'slug={slug}\n') + out.write(f'filepath={filepath}\n') + out.write(f'event_name={name}\n') + + print(f'Created {filepath}') + PYEOF + + - name: Open PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SLUG: ${{ steps.parse.outputs.slug }} + FILEPATH: ${{ steps.parse.outputs.filepath }} + EVENT_NAME: ${{ steps.parse.outputs.event_name }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + BRANCH="event/issue-${ISSUE_NUMBER}-${SLUG}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git add "$FILEPATH" + git commit -m "Add event: ${EVENT_NAME} (closes #${ISSUE_NUMBER})" + git push origin "$BRANCH" + gh pr create \ + --title "Add event: ${EVENT_NAME}" \ + --body "Closes #${ISSUE_NUMBER} + + Auto-generated from community event submission." \ + --base main \ + --head "$BRANCH" diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 39f28f1b0..6827b8b7c 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -15,7 +15,7 @@ jobs: build-and-deploy: runs-on: ubuntu-latest env: - HUGO_VERSION: 0.121.0 + HUGO_VERSION: 0.155.1 steps: - name: Install Hugo CLI run: | diff --git a/content/calendar/_index.md b/content/calendar/_index.md index 65218f71f..d43b21a1f 100644 --- a/content/calendar/_index.md +++ b/content/calendar/_index.md @@ -2,4 +2,7 @@ title: "Community Calendar" description: "Upcoming conferences, meetups, and community events for PowerShell professionals." layout: "calendar" +outputs: + - HTML + - Calendar --- diff --git a/content/calendar/psconfeu-2026.md b/content/calendar/psconfeu-2026.md new file mode 100644 index 000000000..e03551187 --- /dev/null +++ b/content/calendar/psconfeu-2026.md @@ -0,0 +1,9 @@ +--- +title: "PSConfEU 2026" +startDate: "2026-06-17" +endDate: "2026-06-20" +where: "Prague, Czech Republic" +externalUrl: "https://psconf.eu" +virtual: false +--- +Europe's largest PowerShell conference. Expert-led sessions on automation, DevOps, security, and cloud management. diff --git a/content/calendar/sql-saturday-2026.md b/content/calendar/sql-saturday-2026.md new file mode 100644 index 000000000..7f752c9cf --- /dev/null +++ b/content/calendar/sql-saturday-2026.md @@ -0,0 +1,8 @@ +--- +title: "SQL Saturday Baton Rouge 2026" +startDate: "2026-08-01" +where: "Baton Rouge, LA" +externalUrl: "https://sqlsaturday.com/baton-rouge/" +virtual: false +--- +A free community event featuring sessions on SQL Server, PowerShell, and data platform technologies. diff --git a/content/calendar/summit-2026.md b/content/calendar/summit-2026.md new file mode 100644 index 000000000..935085756 --- /dev/null +++ b/content/calendar/summit-2026.md @@ -0,0 +1,9 @@ +--- +title: "PowerShell + DevOps Global Summit 2026" +startDate: "2026-04-13" +endDate: "2026-04-16" +where: "Bellevue, WA" +externalUrl: "https://powershellsummit.org" +virtual: false +--- +The premier PowerShell and automation conference. Deep technical sessions, hands-on workshops, and community networking. diff --git a/data/events.yaml b/data/events.yaml deleted file mode 100644 index 26d800817..000000000 --- a/data/events.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# Community Calendar Events -# To add an event, submit a GitHub issue using the Community Event template -# Format: -# - name: "Event Name" -# url: "https://event-website.com" -# start_date: "2026-04-13" -# end_date: "2026-04-16" # optional, omit for single-day events -# location: "City, State/Country" -# virtual: false # set true for online events -# description: "Short description of the event." - -- name: "PowerShell + DevOps Global Summit 2026" - url: "https://powershellsummit.org" - start_date: "2026-04-13" - end_date: "2026-04-16" - location: "Bellevue, WA" - virtual: false - description: "The premier PowerShell and automation conference. Deep technical sessions, hands-on workshops, and community networking." - -- name: "PSConfEU 2026" - url: "https://psconf.eu" - start_date: "2026-06-17" - end_date: "2026-06-20" - location: "Prague, Czech Republic" - virtual: false - description: "Europe's largest PowerShell conference. Expert-led sessions on automation, DevOps, security, and cloud management." - -- name: "SQL Saturday Baton Rouge 2026" - url: "https://sqlsaturday.com/baton-rouge/" - start_date: "2026-08-01" - location: "Baton Rouge, LA" - virtual: false - description: "A free community event featuring sessions on SQL Server, PowerShell, and data platform technologies." diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..ce1899b72 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/PowerShellOrg/PowerShellOrgWebsite + +go 1.22.2 + +require github.com/finkregh/hugo-theme-component-ical v0.11.3 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..87b78a980 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/finkregh/hugo-theme-component-ical v0.11.3 h1:jyHak274hgvbwWKD/LX1x3sWFQ1IwHAj9bWpNh1qbig= +github.com/finkregh/hugo-theme-component-ical v0.11.3/go.mod h1:6EFHEOW6dsEUWQB0bPnSHq6tYYNpQQ9pRu0hy8ZZKNE= diff --git a/hugo.yaml b/hugo.yaml index 15682c2d0..5e29a0d74 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -2,6 +2,7 @@ baseURL: 'https://powershell.org' languageCode: 'en-us' title: 'PowerShell.org - Welcome Automaters!' theme: 'powershell-community' +timeZone: UTC # Enable RSS feeds enableRSSFeed: true @@ -96,7 +97,28 @@ params: # Analytics (GitHub Pages compatible) google_analytics: "" + + ical: + timezone: UTC +module: + imports: + - path: github.com/finkregh/hugo-theme-component-ical + +mediaTypes: + text/calendar: + suffixes: + - ics + +outputFormats: + Calendar: + baseName: calendar + mediaType: text/calendar + isPlainText: true + permalinkable: true + suffix: ics + protocol: https:// + # Output formats outputs: home: diff --git a/layouts/_partials/event.ics b/layouts/_partials/event.ics new file mode 100644 index 000000000..206bd8b17 --- /dev/null +++ b/layouts/_partials/event.ics @@ -0,0 +1,26 @@ +{{- /* Override of component event.ics — uses .Site.Language.Lang instead of .Locale (requires Hugo 0.159+) */ -}} +{{- if or (eq hugo.Environment "development") (eq hugo.Environment "debug") }}{{ warnidf "debug-partial-used" "Partial used: %s" templates.Current.Name }}{{ end -}} +{{- $timezone := partial "ical/get_timezone.ics" . -}} +{{- $lang := .Site.Language.Lang -}} +{{- $endDate := "" -}} +{{- if .Params.endDate -}} + {{- $endDate = (time.AsTime .Params.endDate $timezone) | time.In $timezone -}} +{{- end -}} +{{- with dict `` ` + ` "description" (dict "text" .Plain "lang" $lang) `` ` + ` "summary" (dict "text" .Title "lang" $lang) `` ` + ` "eventStart" (dict "dateTime" ((time.AsTime .Params.startDate $timezone) | time.In $timezone) "timeZoneID" $timezone) `` ` + ` "eventEnd" (cond (ne $endDate "") (dict "dateTime" $endDate "timeZoneID" $timezone) nil) `` ` + ` "location" (dict "text" (or .Params.where .Params.location) "lang" $lang) `` ` + ` "url" (or .Params.externalUrl ((.OutputFormats.Get "HTML").Permalink)) `` ` + ` "contact" (cond (and .Params.orga .Params.orgaEmail) (dict "text" (printf "%s: %s" .Params.orga .Params.orgaEmail) "lang" $lang) nil) `` ` + ` "color" "7C3AED" `` ` + ` "status" (cond (.Params.cancelled | default false) "CANCELLED" "CONFIRMED") `` ` + ` "uid" .File.UniqueID `` ` + ` "timestamp" .Date `` ` + ` "created" .Date `` ` + ` "lastmod" .Lastmod `` ` + ` "recurrenceRule" .Params.recurrenceRule `` ` + ` "_rruleTimezone" $timezone `` ` + ` -}}{{ partial "ical/comp_event.ics" . }} +{{ end -}} diff --git a/layouts/_partials/header.ics b/layouts/_partials/header.ics new file mode 100644 index 000000000..9af200765 --- /dev/null +++ b/layouts/_partials/header.ics @@ -0,0 +1,11 @@ +{{- if or (eq hugo.Environment "development") (eq hugo.Environment "debug") }}{{ warnidf "debug-partial-used" "Partial used: %s" templates.Current.Name }}{{ end -}} +{{/* Override of component header.ics — uses .Site.Language.Lang instead of .Locale (requires Hugo 0.159+) */}} +{{ with dict `` ` + ` "name" (dict "text" "PowerShell.org Community Calendar" "lang" .Site.Language.Lang) `` ` + ` "description" (dict "text" "Upcoming PowerShell conferences, meetups, and community events." "lang" .Site.Language.Lang) `` ` + ` "url" (.OutputFormats.Get "HTML").Permalink `` ` + ` "color" "7C3AED" `` ` + ` "uid" .File.UniqueID `` ` + ` "lastmod" .Lastmod `` ` + ` "source" (.OutputFormats.Get "Calendar").Permalink `` ` + ` -}}{{- partial "ical/cal_props.ics" . }}{{ end }} diff --git a/layouts/_partials/ical/prop_description.ics b/layouts/_partials/ical/prop_description.ics new file mode 100644 index 000000000..201d1dd28 --- /dev/null +++ b/layouts/_partials/ical/prop_description.ics @@ -0,0 +1,5 @@ +{{- /* Override: keeps trailing newline so LOCATION starts on a new line */ -}} +DESCRIPTION +{{- with .lang -}};{{- partial "ical/param_language.ics" . -}}{{- end -}} +{{- with .alt -}};{{- partial "ical/param_altrep.ics" . -}}{{- end -}} +:{{- partial "ical/dt_text.ics" .text }} diff --git a/themes/powershell-community/layouts/_default/calendar.html b/themes/powershell-community/layouts/_default/calendar.html index 31e2a99b5..c52e0364d 100644 --- a/themes/powershell-community/layouts/_default/calendar.html +++ b/themes/powershell-community/layouts/_default/calendar.html @@ -9,6 +9,13 @@

{{ .Title }}

{{ .Params.description }}

+ {{ with .OutputFormats.Get "Calendar" }} +
+ + Subscribe (.ics) + +
+ {{ end }} @@ -17,15 +24,15 @@

{{ .Title }}

- {{/* Sort events by start_date and split into upcoming vs past */}} + {{/* Sort events by startDate and split into upcoming vs past */}} {{ $now := now.Format "2006-01-02" }} - {{ $allEvents := sort .Site.Data.events "start_date" }} + {{ $allEvents := sort .RegularPages "Params.startDate" }} {{ $upcoming := slice }} {{ $past := slice }} {{ range $allEvents }} - {{ $compare := .start_date }} - {{ if .end_date }} - {{ $compare = .end_date }} + {{ $compare := .Params.startDate }} + {{ if .Params.endDate }} + {{ $compare = .Params.endDate }} {{ end }} {{ if ge $compare $now }} {{ $upcoming = $upcoming | append . }} @@ -45,36 +52,36 @@

Upcoming Events

{{ if $upcoming }}