前回トップページで作成した記事一覧を表示する RecentPosts.astro
は「最新5件を取得するロジック」を含んでいるため、ページネーションされたデータを表示するこのページでは そのまま再利用することができません。
代わりに、記事1件分の表示 をする新しいコンポーネント (PostListItem.astro
) を作成し、それを一覧ページで繰り返し使用します。
記事一覧をスタイルする手順
1.記事リストアイテムコンポーネントを作成 (src/components/PostListItem.astro
)
まず、src/components/
ディレクトリに PostListItem.astro
という名前で新しいファイルを作成します。
このコンポーネントは、記事1件分のデータ (post
) をPropsとして受け取り、それを表示するようにします。getPostUrl
ヘルパー関数もここで使います。
{/* src/components/PostListItem.astro */}
---
import type { CollectionEntry } from 'astro:content';
import { getPostUrl } from '../utils/url'; // パスは環境に合わせて調整
interface Props {
post: CollectionEntry<'blog'>; // 'blog'コレクションの記事1件分のデータを受け取る
}
const { post } = Astro.props;
---
<li class="border-b border-gray-300 pb-6"> {/* 記事間の区切り線 */}
<a href={getPostUrl(post)} class="block group">
<h2 class="text-2xl font-semibold text-blue-800 group-hover:text-blue-600 transition duration-200 mb-2">
{post.data.title}
</h2>
</a>
<div class="text-sm text-gray-500 mb-3">
<span>公開日: {post.data.pubDate.toLocaleDateString()}</span>
{post.data.tags && post.data.tags.length > 0 && (
<span class="ml-4">
タグ:
{post.data.tags.map(tag => (
<a href={`/tags/${tag}/`} class="inline-block bg-gray-200 rounded-full px-2 py-0.5 text-xs text-gray-700 hover:bg-gray-300 ml-1">
{tag}
</a>
))}
</span>
)}
</div>
{post.data.description && (
<p class="text-gray-700 leading-relaxed">{post.data.description}</p>
)}
<a href={getPostUrl(post)} class="text-blue-600 hover:underline inline-block mt-3">
続きを読む →
</a>
</li>
- Propsとして
post
を受け取るようにinterface Props
を定義します。型はCollectionEntry<'blog'>
です。 -
getPostUrl
をインポートします。 -
<li>
要素をルートとし、その中にタイトル、日付、タグ(あれば)、説明(あれば)、続きを読むリンクなどを配置し、それぞれにTailwindクラスでスタイルを適用します。
2.記事一覧ページ ([...page].astro
) を修正
* `src/pages/blog/[...page].astro` ファイルを開き、以下のように修正します。
-
フロントマター部分:
- 作成した
PostListItem.astro
をインポートします。 -
getPostUrl
のインポートは不要になります(PostListItem
に移動したため)。 - レイアウトコンポーネントも適切なもの(例:
BaseLayout
)に変更します。
- 作成した
---
// src/pages/blog/[...page].astro
import { getCollection } from 'astro:content';
import type { CollectionEntry } from 'astro:content'; // CollectionEntryをインポート
import type { Page } from 'astro'; // Page型をインポート(必要に応じて)
// import { getPostUrl } from '../../utils/url'; // ← PostListItemに移動したので削除
import BaseLayout from '../../layouts/BaseLayout.astro'; // ← レイアウトをBaseLayoutに変更(例)
import PostListItem from '../../components/PostListItem.astro'; // ← 作成したコンポーネントをインポート
export async function getStaticPaths({ paginate }) {
const allPosts = await getCollection('blog');
const sortedPosts = allPosts.sort((a, b) =>
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
return paginate(sortedPosts, { pageSize: 5 });
}
// Page型の定義 (前の手順で作成した CustomPageData などを使用)
interface CustomPageData {
data: CollectionEntry<'blog'>[];
start: number;
end: number;
size: number;
total: number;
currentPage: number;
lastPage: number;
url: {
current: string;
next?: string;
prev?: string;
};
}
interface Props {
page: CustomPageData;
}
const { page } = Astro.props as Props;
---
-
テンプレート部分:
- 全体を適切なレイアウトコンポーネントで囲みます(例:
<BaseLayout>
)。 - ページタイトル (
<h1>
)、件数表示 (<p>
)、記事リスト (<ul>
)、ページネーション (<nav>
) にTailwindクラスを追加してスタイルを適用します。 - 記事リストの
map
処理の中で、<li>
の代わりに<PostListItem post={post} />
を呼び出すように変更します。
- 全体を適切なレイアウトコンポーネントで囲みます(例:
---
// --- 上記のフロントマター ---
---
<BaseLayout title={`ブログ記事一覧 - ${page.currentPage}ページ目`}>
<div class="max-w-3xl mx-auto px-4 py-20"> {/* コンテンツ全体のコンテナ */}
<h1 class="text-3xl md:text-4xl font-bold text-center mb-4 text-gray-800">ブログ記事一覧</h1>
<p class="text-center text-gray-600 mb-8">{page.start + 1}件目から{page.end + 1}件目を表示 ({page.total}件中)</p>
<ul class="space-y-8"> {/* 記事間のスペース */}
{/* page.data を map して PostListItem コンポーネントを呼び出す */}
{page.data.map((post) => (
<PostListItem post={post} />
))}
</ul>
{/* ページネーションリンク (Tailwindでスタイル付け) */}
<nav aria-label="ページネーション" class="flex justify-center items-center space-x-4 mt-12 mb-8">
{page.url.prev ? (
<a href={page.url.prev} class="px-4 py-2 border border-gray-300 rounded hover:bg-gray-100 transition duration-200">
← 前のページへ
</a>
) : (
<span class="px-4 py-2 border border-gray-200 rounded text-gray-400 cursor-not-allowed">
← 前のページへ
</span>
)}
<span class="text-gray-700">
{page.currentPage} / {page.lastPage} ページ
</span>
{page.url.next ? (
<a href={page.url.next} class="px-4 py-2 border border-gray-300 rounded hover:bg-gray-100 transition duration-200">
次のページへ →
</a>
) : (
<span class="px-4 py-2 border border-gray-200 rounded text-gray-400 cursor-not-allowed">
次のページへ →
</span>
)}
</nav>
</div>
</BaseLayout>
開発サーバーでの確認
- 開発サーバーを起動 (
npm run dev
など) して、ブログ記事一覧ページ (/blog/
,/blog/2
など) にアクセスします。 - ページ全体、記事リスト、ページネーションリンクにTailwind CSSのスタイルが適用されているか確認してください。
- 記事リストの各項目が
PostListItem.astro
コンポーネントによって正しく表示されているか確認してください。
まとめ
これで記事一覧ページにスタイルが適用され、記事リスト部分もコンポーネント化されてタグごとの記事一覧ページでも再利用できるようになります。
スタイルしたページはこちらの画像のようになります。