initial commit

This commit is contained in:
2026-09-11 02:46:56 +02:00
commit 20b384039c
288 changed files with 46557 additions and 0 deletions
+266
View File
@@ -0,0 +1,266 @@
/* ============================================================================
ABOUT - /en/about and /ar/about
----------------------------------------------------------------------------
Section 1 of docs/SHARPER_Website_Draft_Section_EN_AR.docx: who SHARP-ER is,
the three consortium members and their roles, the three focus areas, and the
SHARP I / II legacy the project builds on.
The draft copy is the fallback; every block here is overridden field by
field by api::about-page.about-page as soon as an editor fills it in.
========================================================================= */
import { Link } from "react-router";
import { ArrowIcon, Button } from "~/components/ui/Button";
import { Card } from "~/components/ui/Card";
import { createTranslator, sectionPath } from "~/i18n";
import { buildBreadcrumbJsonLd, buildMeta } from "~/lib/seo";
import type { Route } from "./+types/about";
import {
isRichTextBlock,
type CmsAboutPage,
} from "./_page-kit/cms-types";
import { list, loadSingle, toImage } from "./_page-kit/cms.server";
import { pageCopy } from "./_page-kit/copy";
import { routeLocale } from "./_page-kit/locale";
import { RichText } from "./_page-kit/rich-text";
import {
InfoPanel,
PageHero,
PageSection,
Prose,
SectionHeader,
} from "./_page-kit/sections";
export async function loader({ params }: Route.LoaderArgs) {
const locale = routeLocale(params);
const page = await loadSingle<CmsAboutPage>("about-page", {
locale,
populate: {
hero: { populate: { media: true, ctas: true } },
consortium: { populate: { partner: { populate: { logo: true } } } },
pillars: true,
legacyLink: true,
blocks: { on: { "blocks.rich-text": { populate: "*" } } },
seo: { populate: { ogImage: true } },
},
});
return {
locale,
hero: {
eyebrow: page?.hero?.eyebrow ?? null,
headline: page?.hero?.headline ?? null,
subheading: page?.hero?.subheading ?? null,
media: toImage(page?.hero?.media, "large") ?? null,
},
body: page?.body ?? null,
richTextBlocks: list(page?.blocks)
.filter(isRichTextBlock)
.map((block) => ({ id: block.id, body: block.body })),
pillars: list(page?.pillars).map((pillar) => ({
title: pillar.title,
description: pillar.description ?? "",
})),
consortium: list(page?.consortium)
.filter((member) => member.partner !== null && member.partner !== undefined)
.map((member) => ({
id: member.partner?.documentId ?? String(member.id ?? member.partner?.id),
name: member.partner?.name ?? "",
role: member.roleDescription ?? member.partner?.description ?? "",
website: member.partner?.website ?? null,
})),
legacy: {
headline: page?.legacyHeadline ?? null,
body: page?.legacyBody ?? null,
link: page?.legacyLink
? {
label: page.legacyLink.label,
href: page.legacyLink.href,
isExternal: page.legacyLink.isExternal ?? false,
}
: null,
},
seo: {
title: page?.seo?.metaTitle ?? null,
description: page?.seo?.metaDescription ?? null,
image: toImage(page?.seo?.ogImage, "large") ?? null,
noIndex: page?.seo?.noIndex ?? false,
},
};
}
export function meta({ loaderData, matches }: Route.MetaArgs) {
const root = matches[0].loaderData;
const locale = loaderData?.locale ?? root.locale;
const t = createTranslator(locale);
const copy = pageCopy(locale).about;
return buildMeta({
locale,
pathname: root.pathname,
siteUrl: root.siteUrl,
title: loaderData?.seo.title ?? t("nav.sections.about"),
description: loaderData?.seo.description ?? copy.lead,
...(loaderData?.seo.image
? { image: { url: loaderData.seo.image.src, alt: loaderData.seo.image.alt } }
: {}),
noIndex: loaderData?.seo.noIndex ?? false,
jsonLd: buildBreadcrumbJsonLd(root.siteUrl, [
{ name: t("nav.sections.home"), pathname: sectionPath("home", locale) },
{ name: t("nav.sections.about"), pathname: sectionPath("about", locale) },
]),
});
}
export default function About({ loaderData }: Route.ComponentProps) {
const { locale, hero, body, richTextBlocks, legacy } = loaderData;
const t = createTranslator(locale);
const copy = pageCopy(locale).about;
const whatWeDoCopy = pageCopy(locale).whatWeDo;
const pillars = loaderData.pillars.length > 0 ? loaderData.pillars : copy.pillars;
const consortium =
loaderData.consortium.length > 0
? loaderData.consortium
: copy.consortium.map((member) => ({
id: member.name,
name: member.name,
role: member.role,
website: null,
}));
return (
<>
<PageHero
title={hero.headline ?? copy.heroHeadline}
eyebrow={hero.eyebrow ?? t("nav.sections.aboutAndStrategy")}
lead={hero.subheading ?? copy.lead}
{...(hero.media ? { media: hero.media } : {})}
/>
<PageSection className="pt-0 md:pt-0">
<Prose>
{body ? (
<RichText markdown={body} />
) : (
<p className="body-md text-[var(--text-secondary)]">{copy.body}</p>
)}
{richTextBlocks.map((block) => (
<RichText key={block.id} markdown={block.body} />
))}
<p className="body-sm-bold text-[var(--text-accent)]">{copy.fundingNote}</p>
</Prose>
</PageSection>
{/* WHERE WE FOCUS */}
<PageSection aria-labelledby="about-pillars-heading">
<div className="flex flex-col gap-2xl">
<SectionHeader id="about-pillars-heading" title={copy.pillarsHeading} />
<ul className="grid list-none grid-cols-1 gap-lg md:grid-cols-3">
{pillars.map((pillar) => (
<li key={pillar.title}>
<InfoPanel title={pillar.title}>{pillar.description}</InfoPanel>
</li>
))}
</ul>
</div>
</PageSection>
{/* THE CONSORTIUM */}
<PageSection aria-labelledby="about-consortium-heading">
<div className="flex flex-col gap-2xl">
<SectionHeader
id="about-consortium-heading"
title={copy.consortiumHeading}
/>
<ul className="grid list-none grid-cols-1 gap-lg md:grid-cols-3">
{consortium.map((member) => (
<li key={member.id}>
<InfoPanel title={member.name}>
<span className="block">{member.role}</span>
{member.website ? (
<a
href={member.website}
target="_blank"
rel="noopener noreferrer"
className="mt-xs inline-block body-sm-bold text-[var(--text-link)] underline underline-offset-2 hover:text-[var(--text-link-hover)]"
>
{member.name}
</a>
) : null}
</InfoPanel>
</li>
))}
</ul>
</div>
</PageSection>
{/* SHARP I AND II */}
<PageSection aria-labelledby="about-legacy-heading">
<div className="flex flex-col gap-lg">
<SectionHeader
id="about-legacy-heading"
title={legacy.headline ?? copy.legacyHeading}
/>
<Prose>
{legacy.body ? (
<RichText markdown={legacy.body} />
) : (
<p className="body-md text-[var(--text-secondary)]">
{copy.legacyBody}
</p>
)}
</Prose>
{/* The draft marks the legacy page as "[link: …]" with no target yet,
so the button appears only once the CMS supplies a real one. */}
{legacy.link ? (
legacy.link.isExternal ? (
<Button
as="a"
href={legacy.link.href}
target="_blank"
rel="noopener noreferrer"
variant="secondary"
iconEnd={<ArrowIcon />}
className="self-start"
>
{legacy.link.label}
</Button>
) : (
<Button
as={Link}
to={legacy.link.href}
prefetch="intent"
variant="secondary"
iconEnd={<ArrowIcon />}
className="self-start"
>
{legacy.link.label}
</Button>
)
) : null}
</div>
</PageSection>
<PageSection>
<Card.CTA
headline={whatWeDoCopy.heroHeadline}
body={whatWeDoCopy.lead}
action={{
href: sectionPath("whatWeDo", locale),
label: t("actions.learnWhatWeDo"),
}}
/>
</PageSection>
</>
);
}