0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Astro.js 記事一覧ページをTailwindでスタイリングする

Posted at

前回トップページで作成した記事一覧を表示する 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">
    続きを読む &rarr;
  </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">
          &larr; 前のページへ
        </a>
      ) : (
        <span class="px-4 py-2 border border-gray-200 rounded text-gray-400 cursor-not-allowed">
          &larr; 前のページへ
        </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">
          次のページへ &rarr;
        </a>
      ) : (
        <span class="px-4 py-2 border border-gray-200 rounded text-gray-400 cursor-not-allowed">
          次のページへ &rarr;
        </span>
      )}
    </nav>
  </div>
</BaseLayout>

開発サーバーでの確認

  • 開発サーバーを起動 (npm run dev など) して、ブログ記事一覧ページ (/blog/, /blog/2 など) にアクセスします。
  • ページ全体、記事リスト、ページネーションリンクにTailwind CSSのスタイルが適用されているか確認してください。
  • 記事リストの各項目が PostListItem.astro コンポーネントによって正しく表示されているか確認してください。

まとめ

これで記事一覧ページにスタイルが適用され、記事リスト部分もコンポーネント化されてタグごとの記事一覧ページでも再利用できるようになります。

スタイルしたページはこちらの画像のようになります。

screencapture-localhost-4321-astro-tutorial-blog-2-2025-04-24-22_18_11.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?