記事の属性(タグ)
URL とファイル名を決める
- タグの一覧はブログの目次を間借りする(記事一覧の下にタグ一覧を置く)
- タグを持つ記事一覧の URL は
/tags/タグ/ - タグを持つ記事一覧のファイルは
/src/pages/tags/[tag].astro
記事にタグを設定
/src/content/blog/post-1.md
---
title: ブログ記事1
created: 2023-10-01
modified: 2023-10-01
tags: ['ねこ', 'いぬ']
---
ブログの目次にタグ一覧を追加
/src/pages/blog.astro
---
import { getCollection } from 'astro:content';
import BlogLayout from '../layouts/BlogLayout.astro';
import BlogTime from '../components/BlogTime.astro';
const posts = await getCollection('blog', ({ data }) => {
return data.title !== undefined && data.created !== undefined;
});
posts.sort((a, b) => {
if (!a.data.created || !b.data.created) return 0;
return b.data.created.valueOf() - a.data.created.valueOf();
});
// 記事(posts)からタグを取得し、未設定のタグは排除し、重複を取り除いた配列を作成している
const tags = [
...new Set(
posts
.map((post) => post.data.tags)
.filter((tags) => tags !== undefined)
.flat()
),
];
// なんとなくsort
tags.sort();
---
<BlogLayout title="Blog">
<h2>記事一覧</h2>
<ul class="posts">
{
posts.map((post) => (
<li>
{post.data.created && <BlogTime date={post.data.created} />}
<a href={`/posts/${post.slug}/`}>{post.data.title}</a>
</li>
))
}
</ul>
<h2>タグ一覧</h2>
<ul class="tags">
{
tags.map((tag) => (
<li>
<a href={`/tags/${tag}/`}>{tag}</a>
</li>
))
}
</ul>
</BlogLayout>
タグ一覧を作る
やっていることは [slug].astro と大差ないけど、いくつかの違いがある。
titleとcreatedに加えてtags(タグ)も必須- 各タグごとに記事を分割(重複あり)している
/src/pages/tags/[tag].astro
---
import { getCollection } from 'astro:content';
import BlogLayout from '../../layouts/BlogLayout.astro';
import BlogTime from '../../components/BlogTime.astro';
import type { CollectionEntry } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog', ({ data }) => {
return data.title !== undefined && data.created !== undefined && data.tags !== undefined;
});
const tags = [...new Set(posts.map((post) => post.data.tags).flat())];
return tags.map((tag) => {
return {
params: { tag },
props: {
posts: posts.filter((post) => {
if (tag && post.data.tags) {
return post.data.tags.includes(tag);
}
}),
},
};
});
}
interface Props { posts: CollectionEntry<'blog'>[] }
const { tag } = Astro.params;
const { posts } = Astro.props;
---
<BlogLayout title={`タグ: ${tag}`}>
<h2>記事一覧</h2>
<ul class="posts">
{
posts.map((post) => (
<li>
{post.data.created && <BlogTime date={post.data.created} />}
<a href={`/posts/${post.slug}/`}>{post.data.title}</a>
</li>
))
}
</ul>
</BlogLayout>
ひとまずおわり?
さて、ブログはこんなもんでよろしいのではないだろうか。さっさとデプロイしてしまおう。
その前に、/src 以下はこうなっている。なかなか大変だった割にファイルは少ないな。
src
├── components
│ └── BlogTime.astro
├── content
│ ├── blog
│ │ ├── post-1.md
│ │ └── post-2.md
│ └── config.ts
├── env.d.ts
├── layouts
│ ├── BlogLayout.astro
│ ├── Footer.astro
│ ├── Head.astro
│ ├── Header.astro
│ └── Nav.astro
├── pages
│ ├── blog.astro
│ ├── index.astro
│ ├── page-test.md
│ ├── posts
│ │ └── [slug].astro
│ └── tags
│ └── [tag].astro
└── styles
├── simple.css
└── style.css