Files
community-rule/app/blog/[slug]/page.js
T
2025-09-08 18:34:28 -06:00

115 lines
3.2 KiB
JavaScript

import { notFound } from "next/navigation";
import Link from "next/link";
import { getBlogPostBySlug, getAllPosts } from "../../../lib/contentProcessor";
import ContentThumbnailTemplate from "../../components/ContentThumbnailTemplate";
import ContentBanner from "../../components/ContentBanner";
/**
* Generate static params for all blog posts
* This enables static generation for all blog posts at build time
*/
export async function generateStaticParams() {
try {
const posts = getAllPosts();
return posts.map((post) => ({
slug: post.slug,
}));
} catch (error) {
console.error("Error generating static params:", error);
return [];
}
}
/**
* Generate metadata for each blog post
*/
export async function generateMetadata({ params }) {
try {
const { slug } = await params;
const post = getBlogPostBySlug(slug);
if (!post) {
return {
title: "Post Not Found",
description: "The requested blog post could not be found.",
};
}
return {
title: post.frontmatter.title,
description: post.frontmatter.description,
authors: [{ name: post.frontmatter.author }],
openGraph: {
title: post.frontmatter.title,
description: post.frontmatter.description,
type: "article",
publishedTime: post.frontmatter.date,
authors: [post.frontmatter.author],
},
};
} catch (error) {
console.error("Error generating metadata:", error);
return {
title: "Blog Post",
description: "A blog post from our community.",
};
}
}
/**
* Dynamic blog post page
*/
export default async function BlogPostPage({ params }) {
// Get the blog post data
const { slug } = await params;
const post = getBlogPostBySlug(slug);
// If post doesn't exist, show 404
if (!post) {
notFound();
}
// Get related posts (for now, just get other posts)
const allPosts = getAllPosts();
const relatedPosts = allPosts.filter((p) => p.slug !== post.slug).slice(0, 3); // Show up to 3 related posts
return (
<div
className="min-h-screen"
style={{ backgroundColor: "var(--color-content-default-primary)" }}
>
{/* Content Banner */}
<ContentBanner post={post} />
{/* Main Content */}
<article className="max-w-4xl mx-auto px-4 py-8">
{/* Article Content */}
<div className="post-body max-w-none text-gray-800 leading-relaxed text-lg">
<div dangerouslySetInnerHTML={{ __html: post.htmlContent }} />
</div>
</article>
{/* Related Posts Section */}
{relatedPosts.length > 0 && (
<section className="bg-white border-t border-gray-200">
<div className="max-w-6xl mx-auto px-4 py-12">
<h2 className="text-3xl font-bold text-gray-900 mb-8 text-center">
Related Articles
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{relatedPosts.map((relatedPost) => (
<ContentThumbnailTemplate
key={relatedPost.slug}
post={relatedPost}
variant="vertical"
/>
))}
</div>
</div>
</section>
)}
</div>
);
}