From 026be849e8a5c6429ee6764cdc605d85ae6ad51d Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:13:26 +0300 Subject: [PATCH] Use a social media card as og:image and link cards for download --- src/pages/speaker/[slug].astro | 43 +++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/pages/speaker/[slug].astro b/src/pages/speaker/[slug].astro index 0e835bb67..81455ea8f 100644 --- a/src/pages/speaker/[slug].astro +++ b/src/pages/speaker/[slug].astro @@ -1,4 +1,5 @@ --- +import fs from "node:fs"; import { getCollection, getEntries } from "astro:content"; import Layout from "@layouts/Layout.astro"; import Prose from "@ui/Prose.astro"; @@ -20,6 +21,22 @@ const { entry } = Astro.props; const sessions = await getEntries(entry.data.submissions); +// Social cards generated by scripts/download_social_speakers.cjs; +// multi-session speakers have one card per session, suffixed with the +// session code (social--.png), single-session speakers just +// social-.png. +const CARDS_DIR = "public/media/speakers"; +const cardFiles = fs.existsSync(CARDS_DIR) ? fs.readdirSync(CARDS_DIR) : []; +const speakerCards = cardFiles + .filter( + (f) => + f === `social-${entry.id}.png` || + new RegExp(`^social-${entry.id}-[A-Z0-9]+\\.png$`).test(f), + ) + .sort() + .map((f) => `/media/speakers/${f}`); +const socialCard = speakerCards[0]; + function isUrl(str: string): boolean { str = ensureHttps(str); const regex = /^(https?:\/\/)?([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,6})([\/\w@.-]*)$/; @@ -83,7 +100,11 @@ function getGitHosting(url: string): string | undefined { } --- - + {entry.data.name} @@ -268,6 +289,26 @@ function getGitHosting(url: string): string | undefined { )) } + + { + speakerCards.length > 0 && ( +

+ + Social media card{speakerCards.length > 1 ? "s" : ""}: + + {speakerCards.map((card, index) => ( + 1 ? `Card ${index + 1}` : "Download" + } + /> + ))} +

+ ) + }