Apr 25, 2024
Updated Apr 25, 2024

Astroブログ作成:Astroで記事一覧ページを作る方法

はじめに

前回に続き、今回は、Astroを使った記事一覧ページを作成します。

Astroとは

Astroは、静的サイトジェネレーション(SSG)とJAMstackの機能を備えたフレームワークです。HTML、CSS、JavaScriptを記述することで、高速で読み込み速度の速いウェブサイトを作成することができます。

記事一覧ページの機能

Article List

今回は、以下の機能を実装することにします。

  • タグ情報に合わせて、サーバ関連、ネットワーク関連などの記事一覧と新着情報の記事一覧を表示する

  • 記事が多い場合は、Pagining機能を使って次の記事一覧を表示する

  • 記事のタイトル、概要、投稿日、ヒーロー画像などを表示する

  • 記事へのリンクを表示する

記事一覧ページの作成

作成するファイルは、pages/blog/tags[tag]/[…page].astroになります。getStaticPaths関数でタグに関連する記事の一覧を作成します。なお新着情報は、タグとは関係ないため、新着順に記事一覧を作成しています。また、paginateを使って複数のページに分割して作成しています。今回は1つのページに9つの記事一覧が表示できるようにしました。

[..page].astro
---
import BlogPList from '../../../layouts/BlogList.astro';
import type { GetStaticPathsOptions, Page } from 'astro';
import { getBlogs, type blog } from '../../../lib/utility';
export const getStaticPaths = async ({ paginate }: GetStaticPathsOptions) => {
  const posts = await getBlogs(false);
  var uniqueTags = [...new Set(posts.map((post: blog) => post.data.tags).flat())];
  uniqueTags.push('news');
  return uniqueTags.flatMap((tag) => {
    const filteredPosts = tag === 'news' ? posts : posts.filter((post: blog) => post.data.tags.includes(tag));
    var heroImages: string[] = [];
    filteredPosts.map((post: blog) => {
      heroImages.push(post.data.heroImage);
    });
    return paginate(filteredPosts, {
      params: { tag: String(tag) },
      props: { tag: tag },
      pageSize: 9,
    });
  });
};
type Props = {
  tag: string;
  tagPosts: blog[];
  page: Page;
};
const { page, tag } = Astro.props;
---
 
<BlogPList tag={tag} page={page} />
 

タグは、各記事のFrontMatterにタグを設定しています。複数の関連するタグを設定していますので、各タグごとに記事の一覧が作成されます。

記事.mdx Front Matter
---
title: 'EdgeRouterXをIPoEとPPPoEにしてみた。'
pubDate: 2020-08-10T22:40:00.000Z
heroImage: edgerouterx01.jpg
description: EdgerouterXでIPoEとPPPoEの両方を設定してみた。インターネット接続はIPoE(DS-Lite)、インターネットからホームサーバーへの接続はPPPoEです。
author: akibo.I
tags: [network, edgerouter, DS-Lite, PPPoE, router, IPv6]
---
 

記事一覧以外のコンポーネント

今回はAstro標準サンプルをもとに以下のコンポーネントを作成しました。

Noコンポーネント内容備考
1BaseHeadベッダーのベースコンポーネントベッダー関連
2Headerヘッダーベッダー関連
3HeaderLinkメニューの一覧、リンクベッダー関連
4Footerフッターフッター関連
5Card記事の要約記事一覧、前後記事
6PrevNextNavi前後記事の誘導他記事誘導ナビ
7Pagination目次一覧を複数ページナビ他記事誘導ナビ
8Tagnaviタグ用ナビ他記事誘導ナビ
9Toc目次ナビ他記事誘導ナビ
10Themeダークモード切り替えナビ他記事誘導ナビ
  • 追加コンポーネント

title=”Toc,Tagnavi,Theme components”

  • ダークモード対応

追加で作成したコンポーネントの中から、ダークモード対応コンポーネントを載せておきます。今回のブログは、Static Site Generation SSGモードで作成していますが、ダークモード対応するために、クライアントの操作で切り替えをできるようにします。

Theme.astro
---
import { Icon } from 'astro-icon/components'
---
 
<button id="themeToggle" class="flex border-0">
  <div class="flex">
    <Icon
      name="mdi:white-balance-sunny"
      class="text-4xl dark:text-lg sm:text-4xl sm:dark:text-lg"
    />
    <Icon name="mdi:weather-night" class="text-lg dark:text-4xl sm:text-lg sm:dark:text-4xl" />
  </div>
</button>
 
<script is:inline>
  const theme = (() => {
    if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
      return localStorage.getItem('theme')
    }
    if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
      return 'dark'
    }
    return 'light'
  })()
  if (theme === 'light') {
    document.documentElement.classList.remove('dark')
  } else {
    document.documentElement.classList.add('dark')
  }
  window.localStorage.setItem('theme', theme)
  const handleToggleClick = () => {
    const element = document.documentElement
    element.classList.toggle('dark')
    const isDark = element.classList.contains('dark')
    localStorage.setItem('theme', isDark ? 'dark' : 'light')
  }
  document.getElementById('themeToggle').addEventListener('click', handleToggleClick)
</script>
 

共通の関数

今回いくつか共通的な処理があったので、まとめてutility.tsを作成して利用しています。ヒーロー画像は、OGPでも使えるように外部からのリンクを想定してpublicに配置しています。最後にその関数を載せておきます。

utility.ts
export async function getHeroImage(img: string) {
  let imagePath = `/public/images/${img}`;
  const images = import.meta.glob<{ default: ImageMetadata }>('/public/images/*.{jpeg,jpg,png,gif}');
  if (!images[imagePath]) {
    imagePath = `/public/images/${DEFAULT_IMAGE}`;
  }
  return images[imagePath]();
}
 

最後に

Astroに初めて挑戦した感想は、なんといっても簡単、すぐに動くものができる。インストールしてすぐにnpm run devで実行できるところが素晴らしいと思いました。あとは、インストールされたファイル、フォルダ構成をカスタマイズ、追加することでイメージ通りに作ることができました。nuxtやGatsby.jsの経験あればハードルは高くないと思います。またドキュメントも充実していたので助かりました。

また今回初めて、tailwindcssrehype-pretty-codeを使って、node.jsの拡張性に驚きを覚えました。それに触発されて、ニッチだけど誰かに役に立つようなものが作れないか試行錯誤しています。近いうちに公開できればと思います。

Astroを使ってブログを作ってみたい方は、ぜひこの記事を参考にしてください。