個別のページにタグを持たせたい
当初はHugoとかを用いてお勉強したことをまとめていこうと思っていたけど、今はとりあえずここに残していこうとしている。 で、今の作りだとページが増えてくると欲しい情報を探すのが大変になりそう。 検索機能を持たせられるといいのかもしれないけど、まずは個別のページにタグを設けてひっこ抜けるようにしたい。
やりたいことは
- 個別ページにタグを持たせる
- タグ一覧を作る
- タグ毎にページの一覧を作る
個別のページにタグを設ける
どこに書くか
個別のページに設定するからマークダウンファイルの中に書けばいいと思う。 Hugo だと front matter の中にカテゴリとかタグを書けたはずなので、それを参考にして ftont matter に書くようにする。 元々の front matter は title と date を持たせている。
---
title: '個別のページにタグを持たせたい'
date: '2022-10-29'
---
gray-matter
posts.js の中でインポートしている gray-matter というライブラリがマークダウンファイルの front matter を解析してくれるらしい。 以下の内容の front-metter だったら、
---
title: Hello
slug: home
---
<h1>Hello world!</h1>
以下の内容のオブジェクトに変換してくれる。
{
content: '<h1>Hello world!</h1>',
data: {
title: 'Hello',
slug: 'home'
}
}
タグの設け方
ページにタグを持たせるなら複数持たせたいけど、front-matter に指定するならどうしたらいいか。 結論、YAML?のリストみたいな書き方をすればいいらしい。
---
title: '個別のページにタグを持たせたい'
date: '2022-10-29'
tag:
- 'note'
- 'nextjs'
---
[id].js の方にタグを書き出す処理を書いた。 繰り返し処理の書き方が不思議。
<p class="post_tag">
{postData.tags.map((val) =>
<span class="post_tag_item">{val}</span>
)}
</p>
タグ一覧のページを追加
はじめに lib/posts.js
にタグ一覧を取得する関数を追加。
export function getAllTags() {
const allPosts = getSortedPostsData();
let tags = [];
allPosts.map((post) => {
tags = [...tags, ...post.tags];
});
let sortedTags = [...new Set(tags)];
return sortedTags.sort();
}
タグの一覧を表示するページとして pages/tag.js
を追加。
export default function Tag({ allTags }) {
return (
<Layout home>
<Head>
<title>タグ一覧</title>
</Head>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<h2>タグ一覧</h2>
<ul class="tags">
{allTags.map((tag) => (
<li class="tag_item" key={tag}>
<Link href={`/tag/${encodeURIComponent(tag)}`}>
<a>{tag}</a>
</Link>
</li>
))}
</ul>
</section>
</Layout>
)
}
export async function getStaticProps() {
// Add the "await" keyword like this:
const allTags = getAllTags();
return {
props: {
allTags,
},
};
}
これでタグの一覧が表示されるようなったが、front matter にタグが設定されていないマークダウンファイルがあるとエラーで落ちてしまうのは注意。
タグ毎のページを作成
タグ毎のページのURLは /tag/タグ名
となるようにしたい。
考え方は個別のページと似ていると思うので、pages/tag/[tag].js
を作る。
export default function Tag({ postData, tag }) {
return (
<Layout home>
<Head>
<title>Tag: {tag}</title>
</Head>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<h2>Tag: {tag}</h2>
<ul class="posts">
{postData.map(({ id, date, title }) => (
<li class="post_item" key={id}>
<Link href={`/posts/${id}`}>
<a>{title}</a>
</Link>
<br />
<small class="post_date">
<Date dateString={date} />
</small>
</li>
))}
</ul>
</section>
</Layout>
)
}
export async function getStaticPaths() {
const tags = getAllTags();
const paths = tags.map((tag) => {
return {
params: {
tag: tag,
},
};
});
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const tag = params.tag;
const allPosts = getSortedPostsData();
const postData = allPosts.filter( (data) => data.tags.includes(tag) );
return {
props: {
postData,
tag,
},
};
}
個別ページのタグにリンクを
タグにリンクを持たせたら完成。
<p class="post_tag">
{postData.tags.map((val) =>
<span class="post_tag_item">
<Link href={`/tag/${encodeURIComponent(val)}`}>
<a>{val}</a>
</Link>
</span>
)}
</p>
感想
- javascriptが勉強不足でした。
- Next.jsは難しかった。
- あとでもう少しわかりやすくまとめたい。