2021-06-17

記事の目次を表示するようにした

再び、このGatsby製ブログの機能改善について。
記事の見出しから目次を生成し、記事ページの上部(タイトルの直下)に表示するようにした。

目次の生成方法について調査

記事の見出しにアンカーリンクがつくようにした でもそうだったように、gatsbyプラグインを使って目次の生成ができるようなので最初はプラグインについて調べていた。

しかし、gatsby-transformer-remark を入れている時点で GraphQL を使って tableOfContents という属性が取れる事に気がついた。
実際にローカルホストで GraphiQL を使って確認してみると、記事の見出しから目次をHTMLで取得できることを確認できた。

GraphiQLのUI
tableOfContentsが取得できる

目次用コンポーネントを作る

ここまでくれば、あとはコンポーネントに切り出してスタイルを当てるだけで十分そうだなと考え、次のような Toc コンポーネントを新規作成。

// src/components/toc.js
const Toc = ({ tableOfContents }) => {
  return (
    <div
      className={`bg-gray-50 pt-4 pb-2 px-4 rounded text-sm`}
    >
      <span className={`block font-semibold`}>
        目次
      </span>
      <div
        dangerouslySetInnerHTML={{ __html: tableOfContents }}
      >
      </div>
    </div>
  )
}

export default Toc

あとはこれを記事詳細のコンポーネントから呼び出せば良いだけとなる。

見出しが存在しない場合は目次コンポーネントをレンダリングしない

目次を表示するときに1点気をつけたことは、見出しが1つも存在しない記事を考慮すること。 見出しが1つも無いと謎のグレーの枠だけが表示されてしまうため、そういった場合はそもそもコンポーネントをレンダリングしないようにする。

ReactやJSXには全然明るくないのだが、調べたところ次のようにすると簡潔に書けるようだったのでそのようにした。

const { markdownRemark } = data
const { frontmatter, html, tableOfContents } = markdownRemark

return (
  <Layout>
    // ...

    {tableOfContents && <Toc tableOfContents={tableOfContents} />}

    // ...
  </Layout>
)

以上。徐々にブログの機能が増えて楽しくなってきた。