August 11th, 2020
MDXプラグインを使って、ブログに目次を付けてみます。gatsby-remark-table-of-contentsも試してみたのですが、あまり融通が効かなかったのでMDXを使うことにしました。
目次の生成にgatsby-plugin-mdx
を利用するので設定していきます。
yarn add gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react
pluginsにgatsby-plugin-mdx
を追加します。
plugins: [
'gatsby-plugin-mdx',
.
.
.
この時点で開発環境を立ち上げて、http://localhost:8000/___graphql
へアクセスするとGraphQLでchildMdxが選択できるようになっています。
childMdxのtableOfContentsを取得するようにGraphQLクエリを修正します。
contentfulBlogPost(slug: { eq: $slug }) {
title
publishDate(formatString: "MMMM Do, YYYY")
heroImage {
fluid(maxWidth: 1180, background: "rgb:000000") {
...GatsbyContentfulFluid_tracedSVG
}
}
body {
childMarkdownRemark {
html
}
childMdx {
tableOfContents
}
}
slug
}
コンポーネント内で再帰を使えるようなので、ネストした目次の表示は再帰を使って実装します。細かい部分は置いておいてまずは動くものを作ってみます。
import React from 'react'
type Props = {
items: any
}
const Component: React.FC<Props> = props => {
return (
<ul>
{
props.items.map(item => (
<li>
{item.title}
{item.items && (<Component items={item.items} />)}
</li>
))
}
</ul>
)
}
export default Component
試しにコンポーネントを使ってみます。
<TOC items={data.contentfulBlogPost.body.childMdx.tableOfContents.items} />
見出しが含まれたブログのページを表示すると見出しの構造の通りの目次が表示されました。
目次をクリックした時に見出しへ飛べるようにしたいのでidをつけます。
見出しにidを自動で振ってくれるプラグインをインストールします。
yarn add gatsby-remark-autolink-headers
gatsby-transformer-remarkのoptionsのpluginsに設定を追加します。
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
`gatsby-remark-autolink-headers`,
.
.
.
yarn ran dev
で開発環境を立ち上げて確認してみます。見出しのタグを確認すると以下のようにidが設定されていました。
<h1 id="Header1">Header1</h1>
react-scrollを使うのでパッケージをインストールします。
yarn add react-scroll
{item.title}
を出していた箇所をリンクに書き換えます。
const Component: React.FC<Props> = props => {
return (
<ul>
{
props.items.map(item => (
<li>
<Link
activeClass="active"
to={item.url.replace('#', '')}
spy={true}
smooth={true}
offset={0}
duration={100}
>{item.title}</Link>
{item.items && (<Component items={item.items} />)}
</li>
))
}
</ul>
)
}
これで目次をクリックすると見出しに飛べるようになりました。