Newtのマークダウンにtocbotを対応させる方法【Astro】

Newtのマークダウンにtocbotを対応させる方法【Astro】

  • 03 Dec, 2024

はじめに

tocbot を使用して目次を表示させていましたが、コンテンツ管理システムを microCMS から Newt に移行した際に、Newt では h タグに自動的に ID が付与されないことが判明しました。このままでは tocbotactive 機能が動作しません。そのため、今回、h タグに自動で ID を振り分ける対応を実施しました。


実装内容

ここでは、cheerio を用いて HTML に含まれる h2h3 タグに順番に ID を自動で付与する方法について説明します。

---
import * as cheerio from 'cheerio';

export async function getStaticPaths() {
    const { items: posts } = await newtClient.getContents<Article>({
        appUid: 'blog',
        modelUid: 'article',
        query: {
            select: ['title', 'slug', 'body'],
        },
    });

  return posts.map((post) => ({
    params: { slug: post.slug  },
    props: {
      post
    }
  }));
}

const { post } = Astro.props;
const $ = cheerio.load(post.body);

let headingCounter = 0; // カウンターを初期化

// h2とh3にIDを自動付与
$('h2, h3').each((_, elm) => {
  headingCounter++; // カウンターをインクリメント
  const generatedId = `heading-${headingCounter}`; // IDを生成
  $(elm).attr('id', generatedId); // IDをタグに付与
});

// 処理後のHTMLを取得
post.body = $.html();
---
<div set:html={post.body}></div>

上記のコードを使用することで、以下のように ID が付与された HTML を得ることができます。

<h2 id="heading-1">First Heading</h2>
<p>Some content here.</p>
<h3 id="heading-2">Subheading 1</h3>
<p>More content.</p>
<h2 id="heading-3">Second Heading</h2>
<h3 id="heading-4">Subheading 2</h3>
<p>Even more content.</p>

おわりに

今回の対応により、Newt でも tocbot を正常に動作させることができました。

Newt、かゆいところに手が届かない仕様が多い気がするので、このように適宜修正していかなければいけませんね💦