CONTENT
ここから
7. 共通ヘッダーを作る
components/Header.tsx を作成します。
// components/Header.tsx
import Link from 'next/link';
/**
* 役割: アプリ全体のヘッダーを表示する
* 入力: なし
* 出力: トップページへのリンクを含むヘッダーUI
*/
export function Header() {
return (
<header className="border-b border-slate-200 bg-white/80 backdrop-blur">
<div className="mx-auto flex max-w-6xl items-center justify-between px-5 py-4">
<Link href="/" className="group">
<div className="text-lg font-black tracking-tight text-slate-950">
岐阜ローカルエンタメ通信
</div>
<div className="text-xs font-medium text-slate-500">
Local Entertainment News
</div>
</Link>
<nav className="hidden items-center gap-6 text-sm font-semibold text-slate-600 sm:flex">
<Link href="/" className="hover:text-slate-950">
Home
</Link>
<a href="#posts" className="hover:text-slate-950">
Posts
</a>
</nav>
</div>
</header>
);
}
ヘッダーは全ページに表示される共通パーツです。
Link を使うと、ページ移動がなめらかになります。
8. カテゴリバッジを作る
components/CategoryBadge.tsx を作成します。
// components/CategoryBadge.tsx
import type { BlogCategory } from '@/types/blogs';
type CategoryBadgeProps = {
category: BlogCategory;
};
/**
* 役割: 記事カテゴリを小さなバッジとして表示する
* 入力: category
* 出力: カテゴリ名を表示するラベルUI
*/
export function CategoryBadge({ category }: CategoryBadgeProps) {
return (
<span className="inline-flex rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-bold text-slate-700">
{category}
</span>
);
}
小さな部品ですが、こういうものを分けておくと便利です。
記事カードでも、詳細ページでも同じ見た目を使えます。
9. 記事カードを作る
components/BlogCard.tsx を作成します。
// components/BlogCard.tsx
import { CategoryBadge } from '@/components/CategoryBadge';
import type { BlogPost } from '@/types/blogs';
import Link from 'next/link';
type BlogCardProps = {
post: BlogPost;
};
/**
* 役割: ブログ記事をカード形式で表示する
* 入力: BlogPost
* 出力: 記事詳細ページへのリンク付きカードUI
*/
export function BlogCard({ post }: BlogCardProps) {
return (
<article className="group rounded-3xl border border-slate-200 bg-white p-6 shadow-sm transition hover:-translate-y-1 hover:shadow-xl">
<div className="mb-4 flex flex-wrap items-center gap-3">
<CategoryBadge category={post.category} />
<time className="text-xs font-semibold text-slate-400">
{post.publishedAt}
</time>
<span className="text-xs font-semibold text-slate-400">
{post.readingMinutes}分で読める
</span>
</div>
<h2 className="text-xl font-black leading-snug tracking-tight text-slate-950 group-hover:text-slate-700">
<Link href={`/posts/${post.slug}`}>{post.title}</Link>
</h2>
<p className="mt-3 line-clamp-3 text-sm leading-7 text-slate-600">
{post.description}
</p>
<div className="mt-5 flex flex-wrap gap-2">
{post.tags.map((tag) => (
<span
key={tag}
className="rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-500"
>
#{tag}
</span>
))}
</div>
<div className="mt-6 text-sm font-bold text-slate-950">
記事を読む →
</div>
</article>
);
}
ここでのポイント
post という記事データを受け取って、カードとして表示しています。
<BlogCard post={post} />
このように使えるようになります。
カードUIはブログアプリの主役です。
Tailwind CSSで余白、角丸、影、ホバー演出をまとめて指定しています。