208 lines
7.4 KiB
TypeScript
208 lines
7.4 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import messages from "../../../messages/en/index";
|
|
import { getAllBlogPosts, type BlogPost } from "../../../lib/content";
|
|
import { routeMetadata } from "../../../lib/siteMetadata";
|
|
import PageHeader from "../../components/type/PageHeader";
|
|
import CaseStudy from "../../components/cards/CaseStudy";
|
|
import UseCasesOrgs from "../../components/sections/UseCasesOrgs";
|
|
import Groups from "../../components/sections/Groups";
|
|
import type { GroupsItem } from "../../components/sections/Groups";
|
|
import TripleStep from "../../components/type/TripleStep";
|
|
import ContentLockup from "../../components/type/ContentLockup";
|
|
import ContentThumbnailTemplate from "../../components/content/ContentThumbnailTemplate";
|
|
import TripleTextBlock from "../../components/type/TripleTextBlock";
|
|
import type { TripleTextBlockColumn } from "../../components/type/TripleTextBlock";
|
|
import FaqAccordion from "../../components/sections/Accordion";
|
|
import AskOrganizer from "../../components/sections/AskOrganizer";
|
|
import WorkerCoopMark from "../../../public/assets/vector/worker-coop.svg";
|
|
import MutualAidMark from "../../../public/assets/vector/mutual-aid.svg";
|
|
import OpenSourceMark from "../../../public/assets/vector/open-source.svg";
|
|
import DaoMark from "../../../public/assets/vector/dao.svg";
|
|
|
|
/**
|
|
* Figma: "Learn" (22083:854797). Use-cases index sections, the guides, and
|
|
* the FAQ share this page. Pilot stories stay at /use-cases/[slug].
|
|
*/
|
|
|
|
export const metadata: Metadata = routeMetadata("/learn", {
|
|
title: messages.metadata.learn.title,
|
|
description: messages.metadata.learn.description,
|
|
});
|
|
|
|
const CASE_STUDY_TILE_RADIUS_CLASS = "rounded-[23.093px]";
|
|
|
|
const CASE_STUDY_LINK_CLASS = [
|
|
CASE_STUDY_TILE_RADIUS_CLASS,
|
|
"block shrink-0 cursor-pointer outline-none transition-[opacity,transform] duration-200",
|
|
"hover:opacity-95",
|
|
"focus-visible:ring-2 focus-visible:ring-[var(--color-border-default-brand-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-default-primary)]",
|
|
"active:scale-[0.98]",
|
|
].join(" ");
|
|
|
|
const GROUP_MARKS = [
|
|
WorkerCoopMark,
|
|
MutualAidMark,
|
|
OpenSourceMark,
|
|
DaoMark,
|
|
] as const;
|
|
|
|
function asArray<T>(value: unknown): T[] {
|
|
return Array.isArray(value) ? value : [];
|
|
}
|
|
|
|
export default function LearnPage() {
|
|
const page = messages.pages.learn;
|
|
const summaries = page.articleSummaries as Record<string, string>;
|
|
|
|
const groupItems: GroupsItem[] = page.groups.items.map((item, index) => {
|
|
const Mark = GROUP_MARKS[index] ?? GROUP_MARKS[0];
|
|
return {
|
|
...item,
|
|
icon: (
|
|
<Mark
|
|
aria-hidden
|
|
className="block size-9 shrink-0"
|
|
width={36}
|
|
height={36}
|
|
/>
|
|
),
|
|
};
|
|
});
|
|
|
|
const postsBySlug = new Map(
|
|
getAllBlogPosts().map((post) => [post.slug, post]),
|
|
);
|
|
const guidePost: BlogPost = {
|
|
slug: "how-communityrule-works",
|
|
frontmatter: {
|
|
title: page.guideCard.title,
|
|
description: page.guideCard.summary,
|
|
author: "",
|
|
date: "2026-11-01",
|
|
thumbnail: {
|
|
vertical: "how-communityrule-works-vertical.svg",
|
|
horizontal: "how-communityrule-works-horizontal.svg",
|
|
},
|
|
},
|
|
content: "",
|
|
htmlContent: "",
|
|
filePath: "messages/en/pages/learn.json#guideCard",
|
|
lastModified: new Date("2026-11-01"),
|
|
};
|
|
const articlePosts = page.articleOrder.flatMap((slug) => {
|
|
const post = postsBySlug.get(slug);
|
|
if (!post) return [];
|
|
const summary = summaries[slug];
|
|
if (!summary || summary === post.frontmatter.description) return [post];
|
|
return [
|
|
{
|
|
...post,
|
|
frontmatter: { ...post.frontmatter, description: summary },
|
|
},
|
|
];
|
|
});
|
|
|
|
const caseStudyLinks = page.caseStudyTiles.links;
|
|
const caseStudySurfaces = ["lavender", "neutral", "rose"] as const;
|
|
const caseStudyAlts = [
|
|
page.caseStudyTiles.mutualAidColoradoAlt,
|
|
page.caseStudyTiles.foodNotBombsAlt,
|
|
page.caseStudyTiles.boulderStreetMedicsAlt,
|
|
];
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[var(--color-surface-default-primary)]">
|
|
<PageHeader
|
|
title={page.pageHeader.title}
|
|
headingAlign="center"
|
|
sectionMinimal
|
|
singleLineTitleFromLg
|
|
/>
|
|
|
|
<UseCasesOrgs>
|
|
{caseStudySurfaces.map((surface, index) => {
|
|
const link = caseStudyLinks[index];
|
|
const card = (
|
|
<CaseStudy surface={surface} imageAlt={caseStudyAlts[index]} />
|
|
);
|
|
if (!link?.href) {
|
|
return <div key={surface}>{card}</div>;
|
|
}
|
|
return (
|
|
<Link
|
|
key={surface}
|
|
href={link.href}
|
|
aria-label={link.ariaLabel}
|
|
className={CASE_STUDY_LINK_CLASS}
|
|
>
|
|
{card}
|
|
</Link>
|
|
);
|
|
})}
|
|
</UseCasesOrgs>
|
|
|
|
<Groups title={page.groups.title} items={groupItems} />
|
|
|
|
<TripleStep
|
|
heading={page.tripleStep.heading}
|
|
steps={asArray<{ title: string; body: string }>(page.tripleStep.steps)}
|
|
ctaText={page.tripleStep.ctaText}
|
|
ctaHref={page.tripleStep.ctaHref}
|
|
/>
|
|
|
|
<ContentLockup
|
|
title={page.contentLockup.title}
|
|
subtitle={page.contentLockup.subtitle}
|
|
ctaText={page.contentLockup.ctaText}
|
|
ctaHref={page.contentLockup.ctaHref}
|
|
variant="learn"
|
|
alignment="left"
|
|
headingLevel="h2"
|
|
/>
|
|
|
|
<div
|
|
data-testid="learn-article-grid"
|
|
className="flex flex-col space-y-[var(--space-050)] sm:space-y-[var(--space-200)] sm:px-[var(--space-500)] sm:pt-[var(--space-600)] sm:pb-[var(--space-600)] smd:flex-row smd:flex-wrap smd:justify-center smd:gap-[var(--space-200)] smd:space-y-0 smd:px-[var(--space-500)] smd:pt-[var(--space-600)] smd:pb-[var(--space-600)] md:gap-[var(--space-400)] md:px-[var(--space-800)] xmd:gap-[var(--space-300)] lg:gap-[var(--space-400)] lg:px-[var(--space-1800)] lg:pt-[var(--space-800)] lg:pb-[var(--space-1800)] lg2:gap-x-[var(--space-400)] lg2:gap-y-[var(--space-600)] xl:gap-x-[var(--space-400)] xl:gap-y-[var(--space-400)] [&>*]:min-w-0 [&>*]:w-full smd:[&>*]:w-[calc((100%-var(--space-200))/2)] md:[&>*]:w-[calc((100%-var(--space-400))/2)] xmd:[&>*]:w-[calc((100%-2*var(--space-300))/3)] lg:[&>*]:w-[calc((100%-2*var(--space-400))/3)] lg2:[&>*]:w-[calc((100%-3*var(--space-400))/4)] xl:[&>*]:w-[calc((100%-4*var(--space-400))/5)]"
|
|
>
|
|
<ContentThumbnailTemplate
|
|
post={guidePost}
|
|
variant="responsive"
|
|
href={page.guideCard.href}
|
|
showByline={false}
|
|
showLeadingImage={false}
|
|
leadingImageAlt=""
|
|
/>
|
|
{articlePosts.map((post) => (
|
|
<ContentThumbnailTemplate
|
|
key={post.slug}
|
|
post={post}
|
|
variant="responsive"
|
|
showByline={false}
|
|
leadingImageAlt=""
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<TripleTextBlock
|
|
layoutPreset="useCases"
|
|
title={page.tripleTextBlock.title}
|
|
ctaText={page.tripleTextBlock.ctaText}
|
|
ctaHref={page.tripleTextBlock.ctaHref}
|
|
columns={asArray<TripleTextBlockColumn>(page.tripleTextBlock.columns)}
|
|
/>
|
|
|
|
<FaqAccordion id="faq" title={page.faq.title} items={page.faq.items} />
|
|
|
|
<section className="bg-[var(--color-surface-default-primary)]">
|
|
<AskOrganizer
|
|
title={page.askOrganizer.title}
|
|
subtitle={page.askOrganizer.subtitle}
|
|
buttonText={page.askOrganizer.buttonText}
|
|
variant="centered"
|
|
/>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|