Files
davegilligan-new/src/pages/articles/kongsberg-jazz-2026.astro
T
daveadmin 6b509fe052 Add complete Open Graph metadata layer across all 20 pages
- Add og:title, og:description, og:image, og:url, og:type, og:site_name to BaseLayout
- Add og:locale (en_GB) + og:locale:alternate (fr_FR, nb_NO) multilingual signals
- Add article:published_time, article:section, article:author on all 5 article pages
- Add Twitter/X summary_large_image card and canonical link on every page
- Generate 13 Jazz Noir branded 1200x630 PNG OG images (satori + resvg-js)
- Add scripts/generate-og-images.mjs + Special Elite font for future regeneration
- Add public/images/articles/ and public/assets/ which were previously untracked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 01:38:51 +02:00

120 lines
5.1 KiB
Plaintext

---
import { jazzArticle, jazzBody, jazzImages, jazzSources } from "../../data/jazz";
import BaseLayout from "../../layouts/BaseLayout.astro";
import LocaleCopy from "../../components/LocaleCopy.astro";
const pageCopy = {
eyebrow: {
en: "Article / Jazz and Music",
fr: "Article / Jazz et Musique",
nb: "Artikkel / Jazz og Musikk",
},
published: { en: "Published", fr: "Publié", nb: "Publisert" },
sidebarH2: {
en: "Direct article link",
fr: "Lien direct vers l'article",
nb: "Direkte artikkellenke",
},
sidebarNote: {
en: "This is the clean standalone version of the Kongsberg Jazz piece, separate from the wider jazz desk.",
fr: "Voici la version autonome épurée de l'article sur le Jazz de Kongsberg, séparée du bureau jazz général.",
nb: "Dette er den rene frittstående versjonen av Kongsberg Jazz-artikkelen, atskilt fra den bredere jazzdesken.",
},
fieldReport: { en: "Field report", fr: "Reportage de terrain", nb: "Feltrapport" },
location: { en: "Kongsberg x Paris", fr: "Kongsberg x Paris", nb: "Kongsberg x Paris" },
alsoRead: { en: "Also read", fr: "À lire aussi", nb: "Les også" },
jazzDesk: { en: "Jazz desk", fr: "Bureau Jazz", nb: "Jazzdesk" },
crossPromo: {
en: "The wider jazz issue includes venue notes, free-show pointers, and the more magazine-like version of this piece.",
fr: "Le numéro jazz plus large comprend des notes de salle, des indications de spectacles gratuits et la version plus magazine de cet article.",
nb: "Det bredere jazznummeret inkluderer stedsnotater, pekere til gratiskonserter og den mer magasinlignende versjonen av denne artikkelen.",
},
crossPromoCta: { en: "Open Jazz and Music", fr: "Ouvrir Jazz et Musique", nb: "Åpne Jazz og Musikk" },
creditsTitle: { en: "Source Credits", fr: "Sources", nb: "Kildehenvisninger" },
creditsMeta: {
en: "Festival details and venue framing are paraphrased from the official festival and venue sites linked below.",
fr: "Les détails du festival et la présentation des salles sont paraphrasés à partir des sites officiels du festival et des salles liés ci-dessous.",
nb: "Festivaldetaljer og stedsramme er omskrevet fra de offisielle festival- og stedssidene lenket nedenfor.",
},
};
---
<BaseLayout
title={`${jazzArticle.title} | Dave Gilligan`}
description={jazzArticle.excerpt.en}
ogType="article"
ogImage="/images/og/jazz-music.png"
ogArticlePublishedTime={jazzArticle.publishedAt.replace(' ', 'T') + 'Z'}
ogArticleSection="Jazz and Music"
>
<main class="jazz-page">
<section class="container jazz-hero">
<div class="jazz-hero__copy">
<span class="eyebrow"><LocaleCopy copy={pageCopy.eyebrow} /></span>
<h1>{jazzArticle.title}</h1>
<p class="jazz-hero__lede"><LocaleCopy copy={jazzArticle.excerpt} /></p>
</div>
<aside class="panel jazz-hero__note">
<div class="capsule__kicker">
<span><LocaleCopy copy={pageCopy.published} /></span>
<span>{jazzArticle.publishedAt.slice(0, 10)}</span>
</div>
<h2><LocaleCopy copy={pageCopy.sidebarH2} /></h2>
<p><LocaleCopy copy={pageCopy.sidebarNote} /></p>
</aside>
</section>
<section class="container jazz-gallery">
{jazzImages.map((image) => (
<figure class="jazz-gallery__figure">
<img src={image.src} alt={image.alt} loading="lazy" />
<figcaption>
<span>{image.credit} / {image.license}</span>
<a href={image.sourceUrl} target="_blank" rel="noreferrer">{image.sourceLabel}</a>
</figcaption>
{image.note && <p class="jazz-gallery__note">{image.note}</p>}
</figure>
))}
</section>
<section class="container jazz-layout">
<article class="panel jazz-article">
<div class="capsule__kicker">
<span><LocaleCopy copy={pageCopy.fieldReport} /></span>
<span><LocaleCopy copy={pageCopy.location} /></span>
</div>
{jazzBody.en.map((_, i) => (
<p><LocaleCopy copy={{ en: jazzBody.en[i], fr: jazzBody.fr[i], nb: jazzBody.nb[i] }} /></p>
))}
</article>
<aside class="jazz-sidebar">
<article class="panel jazz-sidebar__card">
<div class="capsule__kicker">
<span><LocaleCopy copy={pageCopy.alsoRead} /></span>
<span><LocaleCopy copy={pageCopy.jazzDesk} /></span>
</div>
<p><LocaleCopy copy={pageCopy.crossPromo} /></p>
<a class="button button--dark" href="/jazz-music"><LocaleCopy copy={pageCopy.crossPromoCta} /></a>
</article>
</aside>
</section>
<section class="container source-block">
<div class="section-header">
<div class="section-header__title"><LocaleCopy copy={pageCopy.creditsTitle} /></div>
<div class="section-header__meta"><LocaleCopy copy={pageCopy.creditsMeta} /></div>
</div>
<div class="source-list">
{jazzSources.map((source) => (
<article>
<a href={source.href} target="_blank" rel="noreferrer">{source.label}</a>
</article>
))}
</div>
</section>
</main>
</BaseLayout>