🐷

[2023年6月版]Astro.js 小ネタ集 その2 Markdownの表示カスタマイズいろいろ

2023/06/07に公開

前回に引き続きAstro.jsでの小ネタを紹介していきます。

1. Markdown の"脚注"

MarkdownからHTML生成のメインのプラグイン?は remark-rehype でやってます。

https://github.com/remarkjs/remark-rehype

"脚注"のカスタマイズは主にこのプラグインのオプションです。以下のようなオプションがあります。

それぞれの説明は上記のリンクを参照ください。
Astro.js でこのオプションを指定するには以下のようになります。

astro.config.mjs

export default defineConfig({
...
  markdown: {
...
    remarkRehype: {
      footnoteLabel: "脚注"
    },
...
  }
...
});

この例では"Footnote"の表記を"脚注"に変えてます。
デフォルトでタグがh2になってるのもちょっと扱いずらいかもですね~。。。

2. Markdown の目次を表示

そもそもの"Markdownの目次"ですが、これはMarkdownの中で ######### などで指定した"見出し"のコレクションが目次になります。
見出しを抽出してリストにし、見た目を整えたものが目次となります。

Astro.js の CollectionEntryrender() メソッドの戻り値で見出しのリストが返ってきます。

src/pages/blog/[id].astro
  ...
  export async function getStaticPaths() {
    return (await getCollection('blog')).map(entry => ({
      params: { id: entry.slug },
      props: { entry },
    }))
  }

  interface Props {
    entry: CollectionEntry<'blog'>;
  }
  const { entry } = Astro.props;
  const { Content } = await entry.render();
  const { Content, headings } = await entry.render();
...

このような感じで const { Content, headings } = await entry.render();headingsに見出しのリストが返ってきます。
このクラスはMarkdownHeading型で、これの定義は以下です。

node_modules/@astrojs/markdown-remark/dist/types.d.ts
export interface MarkdownHeading {
    depth: number;
    slug: string;
    text: string;
}

depth が見出しの深さでslugがリンク用のアンカー、textが見出しの文言です。

例えば以下のような感じでサクッと見出しを作成できます。

src/layouts/Blog.astro
<article ...>
  <aside class="toc">
    <ol class="toc-level-0">
    {headings.filter(h => h.depth < 3).map((h,i) => {
    return (
        <li class={`toc-level-${h.depth} toc-item`}><a href={`#${h.slug}`}>{h.text}</a></li>
        )})}
    </ol>

  </aside>
  <slot/>
</article>

ここの例では .filter(h => h.depth < 3) で深さが1,2だけの2段の見出しに絞っています。
あとは、スタイルシートで toc-level-1 toc-level-2 toc-level-3 などやっていけばいろいろ凝った段組みも可能ですね。

別出しにせずに本文内に入れ込んで簡単に目次を表示したい場合はremarkのプラグイン remark-toc を使うのもありかと思います。

3. Markdown のコードブロックにタイトルをつける

Markdown のコードブロックでよくある、

  ```ts:ファイル名

みたいなファイル形式とファイル名を指定できるの、よくあるじゃないですか?
あれは Remark ではできなくて、プラグインでタイトルタグを生成して、スタイルシートで見た目を修正してます。
自分のブログサイトで使ってるプラグインは以下です。

https://github.com/ipikuka/remark-flexible-code-titles

まずはコイツをインストールします。

shell
$ npm install remark-flexible-code-titles

続いて Astro.js の設定ファイルでプラグインを有効にします。

astro.config.mjs
import remarkCodeTitles from "remark-flexible-code-titles";

export default defineConfig({
...
  markdown: {
    ...
    remarkPlugins: [remarkCodeTitles],
...
  }
...
});

で、準備は完了です。
これで、

  ```ts:filename

というMarkdwon だと以下のようなHTMLを生成してくれるようになります。

<div class="remark-code-container">
    <div class="remark-code-title">filename</div>
    <pre class="astro-code" tabindex="0">
      <code>
...

このようにタイトル付きのコードタグ、みたいなブロックを生成してくれます。

で、これを上記であげたように、カスタムのタグを当てればOKです。

Blog.astro
...
<style is:global>
@tailwind components;

  @layer components {
    .remark-code-title {
      @apply text-base pl-3 rounded-t-lg font-bold;
    }
    .remark-code-title+pre {
      @apply mt-0 rounded-t-none;
    }
  }
</style>

のような感じで、このサイトのコードブロック部分は作成してます。
その他にも remark-code-title などがあります。
生成されるタグは異なると思いますが、だいたいこんな流れでOKでしょう。(?)

本日はここまでといたします。
引き続きよろしくお願いいたします。

Discussion