目次
はじめに
SSG を適用した Next.js で,目次(Table of Content)を生成する方法を紹介します。
h2 タグを大目次,h3 タグを小目次とし,こちらのような目次を生成できます。
こちらのブログは Next.js で作成しており,目次を生成しています。具体的なコードを見たい方は,こちらのリポジトリを参考にしてください。
https://github.com/kawa1214/micro-cms-nextjs-blog-boiler-template
Nextjs で SSG を適用する
Next.js では getStaticProps を用いることで,静的なファイルを事前に生成できます。
./pages/blogs/[id].tsx
export const getStaticProps: GetStaticProps = async context => {
const id = context.params.id;
const key = {
headers: { "X-API-KEY": process.env.API_KEY },
};
const res = await fetch(process.env.ENDPOINT + "/blogs/" + id, key);
const blog: BlogType = await res.json();
return {
props: {
blog: blog,
},
};
};
目次を生成する
cheerio で html を解析し,目次を生成します。
今回は,h2 を大目次,h3 を小目次としています。
./pages/blogs/[id].tsx
const Blog: React.FC<BlogProps> = ({ blog, toc }) => {
return (
<>
<div
id="blog_toc"
dangerouslySetInnerHTML={{
__html: toc,
}}
/>
</>
);
};
export default Blog;
const generateTableOfContent = (body: string) => {
const $ = cheerio.load(body, { decodeEntities: false });
let generateHtml = "";
generateHtml = generateHtml + "<ul>";
$("h2, h3").each((index, elm) => {
const text = $(elm).html();
const tag = $(elm)[0].name;
const refId = $(elm)[0].attribs.id;
generateHtml =
generateHtml +
`<li class="toc_${tag}" key=${index}>` +
` <a href="#${refId}">${text}</a>` +
"</li>";
});
generateHtml = generateHtml + "</ul>";
return generateHtml;
};
export const getStaticProps: GetStaticProps = async context => {
const id = context.params.id;
const key = {
headers: { "X-API-KEY": process.env.API_KEY },
};
const res = await fetch(process.env.ENDPOINT + "/blogs/" + id, key);
const blog: BlogType = await res.json();
const toc: string = generateTableOfContent(blog.body);
return {
props: {
blog: blog,
toc: toc,
},
};
};
生成した HTML に CSS を適用します。こちらのサンプルコードは tailwind css を使用しています。
./styles/Blog.module.css
/* blog table of content*/
#blog_toc ul {
@apply bg-white rounded px-2 py-2;
}
#blog_toc li {
@apply my-1.5 ml-4;
}
#blog_toc a:link {
@apply text-gray-900;
}
#blog_toc a:visited {
@apply text-gray-900;
}
#blog_toc a:hover {
color: #4c74b9;
}
#blog_toc a:active {
color: #4c74b9;
}
#blog_toc .toc_h3 {
@apply pl-4;
}