Commit multilingual editorial frontend work

This commit is contained in:
2026-04-07 07:36:27 +02:00
parent 0eae030142
commit 77f57cf528
119 changed files with 5255 additions and 220 deletions
+92 -46
View File
@@ -1,7 +1,11 @@
---
import "../styles/global.css";
import CookieBanner from "../components/CookieBanner.astro";
import LocaleCopy from "../components/LocaleCopy.astro";
import LocaleSwitcher from "../components/LocaleSwitcher.astro";
import SectionMark from "../components/SectionMark.astro";
import { getSectionHref, launchSections } from "../data/site";
import { footerCallouts, getChromeCopy, localizedSections, policyLinkCopy } from "../data/locales";
interface Props {
title?: string;
@@ -15,47 +19,42 @@ const {
lang = "en",
} = Astro.props;
const issueDate = new Intl.DateTimeFormat("en-US", {
month: "long",
day: "numeric",
year: "numeric",
}).format(new Date());
const now = new Date();
const issueDate = {
en: new Intl.DateTimeFormat("en-US", {
month: "long",
day: "numeric",
year: "numeric",
}).format(now),
fr: new Intl.DateTimeFormat("fr-FR", {
day: "numeric",
month: "long",
year: "numeric",
}).format(now),
nb: new Intl.DateTimeFormat("nb-NO", {
day: "numeric",
month: "long",
year: "numeric",
}).format(now),
};
const pathname = Astro.url.pathname.replace(/\/+$/, "") || "/";
const activeSlug = pathname === "/" ? "home" : pathname.split("/").filter(Boolean)[0];
const primarySlugs = ["business", "education", "writing", "jazz-music", "ai-lab", "norway"];
const primaryNav = launchSections.filter((section) => primarySlugs.includes(section.slug));
const footerNav = launchSections.filter((section) => !primarySlugs.includes(section.slug));
const currentSection = launchSections.find((section) => section.slug === activeSlug);
const articleMeta = pathname.startsWith("/articles/norway")
? {
label: "Article / Norway desk",
note: "Field report / family life / fathers / immigrants",
}
const articleKey = pathname.startsWith("/articles/norway")
? "norway"
: pathname.startsWith("/articles/kongsberg-jazz-2026")
? {
label: "Article / Jazz and Music",
note: "Field report / Kongsberg x Paris",
}
? "jazz"
: pathname.startsWith("/articles/trivia-and-tunes-april-2026")
? {
label: "Article / Projects desk",
note: "Field report / music trivia / Blue Note Rhino / April build",
}
: null;
const issueLabel = currentSection
? `Section ${currentSection.label} / ${currentSection.title}`
: articleMeta
? articleMeta.label
: "Founding issue / Personal edition";
const ribbonNote = currentSection?.tone
?? (articleMeta
? articleMeta.note
: "Ringwood / Villanova / Brussels / Paris / Krakow / Oslo / Kongsberg");
? "projects"
: null;
const chromeCopy = getChromeCopy({ activeSlug, issueDate, articleKey });
---
<!doctype html>
<html lang={lang}>
<html lang={lang} data-ui-lang="en" data-cookie-analytics="false" data-cookie-embeds="false">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -74,28 +73,31 @@ const ribbonNote = currentSection?.tone
<body>
<header class="site-ribbon">
<div class="container site-ribbon__row">
<span>Founding issue / {issueDate}</span>
<span>{ribbonNote}</span>
<LocaleCopy copy={chromeCopy.ribbonIssue} />
<LocaleCopy copy={chromeCopy.ribbonNote} />
</div>
</header>
<div class="site-masthead">
<div class="container masthead">
<div class="masthead__row">
<span>{issueLabel}</span>
<span>Jazz desk / machine room / family archive / pataphysical bulletin</span>
<LocaleCopy copy={chromeCopy.issueLabel} />
<LocaleCopy copy={chromeCopy.mastheadLine} />
</div>
<a href="/" class="masthead__brand masthead__brand--site">
<p class="masthead__domain">davegilligan.com</p>
<strong>Dave Gilligan</strong>
<p class="masthead__prompt">Hybrid IT. Private AI. Jazz rooms. Literary weather.</p>
<p class="masthead__prompt">
<LocaleCopy copy={chromeCopy.domainPrompt} />
</p>
<span>
A personal site edited like a bright retro paper: systems, music, languages, Norway,
civic weather, and useful mischief under one masthead.
<LocaleCopy copy={chromeCopy.domainLede} />
</span>
</a>
<LocaleSwitcher />
<nav class="site-nav" aria-label="Primary sections">
{primaryNav.map((section) => (
<a
@@ -103,7 +105,15 @@ const ribbonNote = currentSection?.tone
class={`site-nav__link ${activeSlug === section.slug ? "site-nav__link--active" : ""}`}
>
<SectionMark slug={section.slug} className="section-mark--nav" />
<span>{section.title}</span>
<span>
<LocaleCopy
copy={{
en: localizedSections[section.slug]?.en.title ?? section.title,
fr: localizedSections[section.slug]?.fr.title ?? section.title,
nb: localizedSections[section.slug]?.nb.title ?? section.title,
}}
/>
</span>
</a>
))}
</nav>
@@ -116,27 +126,63 @@ const ribbonNote = currentSection?.tone
<div class="container site-footer__top">
<div class="site-footer__brand">
<p>davegilligan.com</p>
<strong>Jazz desk, machine room, and civic archive.</strong>
<span>
Built in Astro with React islands, backed by PHP and SQL, and art-directed like a
magazine instead of a brochure.
</span>
<strong><LocaleCopy copy={chromeCopy.footerHeadline} /></strong>
<span><LocaleCopy copy={chromeCopy.footerBody} /></span>
</div>
<div class="footer-links">
{footerNav.map((section) => (
<a href={getSectionHref(section)}>
<SectionMark slug={section.slug} className="section-mark--footer" />
<span>{section.title}</span>
<span>
<LocaleCopy
copy={{
en: localizedSections[section.slug]?.en.title ?? section.title,
fr: localizedSections[section.slug]?.fr.title ?? section.title,
nb: localizedSections[section.slug]?.nb.title ?? section.title,
}}
/>
</span>
</a>
))}
</div>
</div>
<div class="container site-footer__callouts">
<a class="footer-callout" href={footerCallouts.blueNoteLogic.href} target="_blank" rel="noreferrer">
<p class="footer-callout__label">
<LocaleCopy copy={footerCallouts.blueNoteLogic.label} />
</p>
<strong><LocaleCopy copy={footerCallouts.blueNoteLogic.title} /></strong>
<span><LocaleCopy copy={footerCallouts.blueNoteLogic.body} /></span>
</a>
<a class="footer-callout" href={footerCallouts.gilliganTech.href} target="_blank" rel="noreferrer">
<p class="footer-callout__label">
<LocaleCopy copy={footerCallouts.gilliganTech.label} />
</p>
<strong><LocaleCopy copy={footerCallouts.gilliganTech.title} /></strong>
<span><LocaleCopy copy={footerCallouts.gilliganTech.body} /></span>
</a>
</div>
<div class="container site-footer__policies">
<a class="policy-link" href={policyLinkCopy.privacy.href}>
<strong><LocaleCopy copy={policyLinkCopy.privacy.title} /></strong>
<span><LocaleCopy copy={policyLinkCopy.privacy.body} /></span>
</a>
<a class="policy-link" href={policyLinkCopy.cookies.href}>
<strong><LocaleCopy copy={policyLinkCopy.cookies.title} /></strong>
<span><LocaleCopy copy={policyLinkCopy.cookies.body} /></span>
</a>
</div>
<div class="container footer-note">
<span>Astro + React islands + PHP + SQL</span>
<span>Blue Note Logic / Gilligan TECH / Kongsberg / multilingual edition</span>
<span><LocaleCopy copy={chromeCopy.footerNoteLeft} /></span>
<span><LocaleCopy copy={chromeCopy.footerNoteRight} /></span>
</div>
</footer>
<CookieBanner />
</body>
</html>