Build public home, contact, and content pages
This commit is contained in:
108
src/app/[slug]/page.tsx
Normal file
108
src/app/[slug]/page.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user