・luxla・

目次に魂を宿す技術(Remix × tocbot 編)

scream-there-is-not-toc
Posted on 2024/10/30

暇って、放っておくとブラウザのタブみたいにどんどん増殖するんですよね。
今日はその増殖した暇を、目次に変換してみようと思います。

🧠 はじめに:なぜ人は目次を作るのか

「人生に目次があればいいのに」と思ったことはありませんか?
でも残念ながら、我々の人生には<h2><h3>もありません。
そこで私は「せめてブログだけでも構造化しよう」と思い立ち、Remix + tocbotで自動目次を生成してみました。

きっかけは単純です。

“スクロール疲れ”という現代病を治したい。

目次さえあれば、未来の自分(または退屈している読者)が迷子にならずに済むのです。
まるでナビのない砂漠にGoogleマップを立ち上げるように。

🧩 今回の仕様:暇を技術に変換するための3箇条

  • Drupalのデータは神聖につき、触れない。
    加工はページ出力時にのみ行う。つまり“動的な静寂”を目指します。
  • 目次機能は /article/**** 限定。
    どうせ誰も会社概要に目次なんて求めていない。
  • 見た目はテキトウ。
    テキトウというのは、“デザインの自由”という意味です(※開き直りではない)。

⚙️ 必要なツール:退屈を動かす2つの神器

用途ツール一言コメント
目次生成tocbot暇人が考えた天才ツール
DOM操作html-react-parser“HTMLを食べてReactを吐く”という謎生態

💻 実装:コードという名の詩

さて、実際のコードです。
以下は、暇を技術に変えるための短い祈りのようなものです。

 

function slugify(text: string) {
  return text.toLowerCase().replace(/\s+/g, "-");
}

export default function Article() {
  const { data } = useLoaderData();
  const date = new Date(data.route.entity.created);

  useEffect(() => {
    tocbot.init({
      tocSelector: ".toc",
      contentSelector: ".content",
      headingSelector: "h2, h3",
      scrollSmooth: true,
      scrollSmoothDuration: 1000,
    });
    return () => tocbot.destroy();
  }, []);

  return (
    <>
      <div className="toc"></div>
      <div className="content">
        {parse(data.route.entity.bodyRawField.list[0].processed, {
          replace: (domNode) => {
            if (
              domNode.type === "tag" &&
              (domNode.name === "h2" || domNode.name === "h3")
            ) {
              const slug = slugify(domNode.children[0]?.data || "");
              return (
                <domNode.name id={slug}>
                  {domNode.children[0]?.data}
                </domNode.name>
              );
            }
          },
        })}
      </div>
    </>
  );
}

このコード、何がすごいかというと――
Reactの世界に“静的HTML”を密輸しているんです。

通常、Reactは「DOM? そんなの仮想だよ」って顔してるくせに、ここでは素直にHTMLを受け入れてくれています。
つまり、理想と現実の共存
プログラミングとは人生そのものですね(強引)。

🧩 技術のツボ:replaceで人生にidを付ける

html-react-parserreplaceを使うことで、
記事の中の<h2><h3>idを自動で付与しています。

まるで、「この段落には名前があるんだよ」と教えてあげるようなもの。
無名の人生より、id付きの人生のほうが検索されやすい。
SEO的にも生きやすい。

🧘 おわりに:暇の中にこそ学びがある

この目次機能、作ってみて思いました。
「結局、暇をどう使うかが人生のアルゴリズムなんだ」と。

  • 暇だからコードを書いた
  • 書いたら動いた
  • 動いたら楽しくなった
  • そして気づけば、ReactのDOM構造を理解していた

これが、“全力で暇つぶし”の美学です。
暇つぶしとは、退屈を技術で再構築する最高の遊び。

次回は「Google Analyticsで自分の暇を可視化する」を予定しています。
※もしくは「Analyticsで悟りを開く」かもしれません。

💬 補足メモ(読者向け小ネタ)

tocbotのscrollSmoothDurationを1000にしているのは、「慌てるとバグる」からです。
つまり、コードにも“間”が必要。まるで人生のように。