109 lines
3.2 KiB
TypeScript
109 lines
3.2 KiB
TypeScript
import type { Metadata } from 'next';
|
|
import Link from 'next/link';
|
|
import { notFound } from 'next/navigation';
|
|
import { Section } from '@/components/Section';
|
|
import { contentPages, getContentPage, site } from '@/lib/site';
|
|
|
|
type ContentPageProps = {
|
|
params: Promise<{
|
|
slug: string;
|
|
}>;
|
|
};
|
|
|
|
export function generateStaticParams() {
|
|
return contentPages.map((page) => ({ slug: page.slug }));
|
|
}
|
|
|
|
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
|
|
const { slug } = await params;
|
|
const page = getContentPage(slug);
|
|
|
|
if (!page) {
|
|
return {
|
|
title: site.name,
|
|
description: site.description,
|
|
};
|
|
}
|
|
|
|
return {
|
|
title: page.seoTitle,
|
|
description: page.seoDescription,
|
|
};
|
|
}
|
|
|
|
export default async function ContentPage({ params }: ContentPageProps) {
|
|
const { slug } = await params;
|
|
const page = getContentPage(slug);
|
|
|
|
if (!page) {
|
|
notFound();
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<section className="page-hero">
|
|
<p className="brand-kicker">Content page</p>
|
|
<h2>{page.title}</h2>
|
|
<p>{page.intro}</p>
|
|
</section>
|
|
|
|
<div className="page-layout">
|
|
<Section
|
|
eyebrow="Editable content"
|
|
title="Rendered from the shared content page model"
|
|
description="This route keeps editorial and policy pages consistent without making each one a special-case template."
|
|
>
|
|
<div className="content-stack">
|
|
{page.sections.map((section) => (
|
|
<article key={section.title} className="content-card">
|
|
<h3>{section.title}</h3>
|
|
{section.paragraphs.map((paragraph) => (
|
|
<p key={paragraph}>{paragraph}</p>
|
|
))}
|
|
{section.bullets ? (
|
|
<ul>
|
|
{section.bullets.map((bullet) => (
|
|
<li key={bullet}>{bullet}</li>
|
|
))}
|
|
</ul>
|
|
) : null}
|
|
</article>
|
|
))}
|
|
</div>
|
|
</Section>
|
|
|
|
<aside className="content-sidebar">
|
|
<article className="content-card">
|
|
<p className="footer-label">Next move</p>
|
|
<p className="mb-0">
|
|
This page can now be expanded with real CMS or database content later without changing the route structure.
|
|
</p>
|
|
</article>
|
|
<article className="content-card">
|
|
<h3>Browse other pages</h3>
|
|
<ul className="link-list">
|
|
{contentPages
|
|
.filter((item) => item.slug !== slug)
|
|
.slice(0, 4)
|
|
.map((item) => (
|
|
<li key={item.slug}>
|
|
<Link href={`/${item.slug}`}>{item.title}</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</article>
|
|
<article className="content-card">
|
|
<h3>Need help?</h3>
|
|
<p className="mb-0">
|
|
<Link className="inline-link" href="/contact">
|
|
Open the contact page
|
|
</Link>{' '}
|
|
if the content page does not answer your question.
|
|
</p>
|
|
</article>
|
|
</aside>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|