13. left-sidebar.tsxのカテゴリリンクを押すと、カテゴリに属する記事一覧が表示される仕組みをつくる
ステップ1:Frontmatterの追加
まず、mdx記事ファイルfrontmatter(MDXファイルの最上部に記述する、タイトルや公開日などのメタデータを載せる部分)にcategoryを加える
---
category: "Taxes"
---ステップ2:app/categories/[category]/page.tsxをつくる
page.tsx内ではlib/posts.tsの関数getPostsByCategoryとformatDateを使って、特定カテゴリに属する記事一覧を取得し表示する
import Link from "next/link";
import { getPostsByCategory, formatDate } from "@/lib/posts";
type CategoryPageProps = {
params: Promise<{
category: string;
}>;
};
export default async function CategoryPage({
params,
}: CategoryPageProps) {
const { category } = await params;
const posts = getPostsByCategory(category);
const categoryName =
category.charAt(0).toUpperCase() + category.slice(1);
return (
<div>
<h1 className="mb-8 text-3xl font-bold">
{categoryName}
</h1>
<div className="space-y-8">
{posts.map((post) => (
<article key={post.slug}>
<Link href={`/posts/${post.slug}`}>
<h2 className="text-xl font-semibold hover:underline">
{post.title}
</h2>
</Link>
{post.date && (
<p className="mt-2 text-sm text-muted-foreground">
{formatDate(post.date)}
</p>
)}
{post.excerpt && (
<p className="mt-2 text-sm leading-6 text-muted-foreground">
{post.excerpt}
</p>
)}
</article>
))}
</div>
</div>
);
}ステップ3:lib/posts.tsの変更
そして、lib/posts.ts(content/posts内のMDXファイルを読み込み、MDXを解釈して、app/layout.tsxに渡す仲介ファイル)を次のように変更する
import fs from "fs";
import path from "path";
import matter from "gray-matter";
export type Post = {
slug: string;
title: string;
date: string;
excerpt: string;
category: string;
content: string;
};
const postsDirectory = path.join(process.cwd(), "content/posts");
export function getPostSlugs(): string[] {
if (!fs.existsSync(postsDirectory)) {
return [];
}
return fs
.readdirSync(postsDirectory)
.filter((file) => file.endsWith(".mdx"))
.map((file) => file.replace(/\.mdx$/, ""));
}
export function getPostBySlug(slug: string): Post {
const fullPath = path.join(postsDirectory, `${slug}.mdx`);
const fileContents = fs.readFileSync(fullPath, "utf8");
const { data, content } = matter(fileContents);
return {
slug,
title: String(data.title ?? slug),
date: String(data.date ?? ""),
excerpt: String(data.excerpt ?? ""),
category: String(data.category ?? ""),
content,
};
}
export function getAllPosts(): Post[] {
return getPostSlugs()
.map((slug) => getPostBySlug(slug))
.sort((a, b) => (a.date < b.date ? 1 : -1));
}
export function getPostsByCategory(category: string): Post[] {
return getAllPosts().filter(
(post) => post.category.toLowerCase() === category.toLowerCase()
);
}
export function formatDate(date: string): string {
return new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
}).format(new Date(date));
}ステップ4:ローカルで確認
上手く動作するか npm run devで確認する
開発サーバーを停止させるにはControl+C」であり、Command+Cではないので注意
BACK