Nuxt Content の Markdown 内の外部リンクにアイコンをつける

Nuxt Contentで Markdown をつかって記事を管理する際に、記事内の外部リンクにアイコンをつけたい場合のやり方

外部リンクを別タブにする

まず、前提として外部リンクは別のタブにすることが多いですよね。
これ自体は、rehype-external-link というパッケージを使えば簡単に設定できます。

export default defineNuxtConfig({
  content: {
      markdown: {
          rehypePlugins: {
              'rehype-external-links': {
                  target: '_blank',
                  rel: ['noopener', 'noreferrer']
              }
          }
      }
  }
})

こんな感じで、Markdown コンテンツをパースした際に自動で target="_blank"relnoopenernoreferrer をつけるといったことが出来るようになります。

ところが、同じような感じにクラスをつけようと思っても、この設定の中に class とか className といったものは無く、外部リンクにクラスをつけるといったことは出来ないようです。

外部リンクにアイコンをつける

ではどうしたらよいかという話なのですが、class 関係のオプションはないんですが、外部リンクだというメッセージを出すための content というものがありました。
いろんなところの記事を見るとここで type を element にして VUE の SFC のタグを入れたり、SVG タグを書いたりする方法で出来るっぽい感じだったのですが、どうにもエラーになってしまうようです。
(見た記事が古かったので今は出来ないのかも)

で、content はなにができるのかというと、ここに何か書くと、外部リンクの a 要素の最後、タグを閉じる直前に span が挿入されてその中に content に記入した文字列が注入される、というものでした。

また、この span のプロパティ自体は、contentProperties という別のキーで指定すれば良いみたいです。

ということで、こんな感じに書き足します。

export default defineNuxtConfig({
  content: {
      markdown: {
          rehypePlugins: {
              'rehype-external-links': {
                  target: '_blank',
                  rel: ['noopener', 'noreferrer'],
                  content: {
                    type: 'text',
                    value: 'open_in_new'
                  },
                  contentProperties: {
                    className: 'material-symbols external-link'
                  }
              }
          }
      }
  }
})

これで、外部リンクの後ろに

<span class="material-symbols external-link">open_in_new</span>

といった感じの span が挿入されるようになりますので、ここにスタイルをあてます。

.material-symbols {
  font-family: 'Material Symbols Outlined', serif;
  font-weight: 300;
  font-style: normal;
  font-size: 100%;
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;

  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;

  &.external-link {
    margin: 0 0.25em;
  }
}

別案

注入される span 自体を material-symbols 様にするのではなくて、あくまでその span についてる特定のクラスに対して material-symbols が展開されるようにする方法でもいいかもしれません。

export default defineNuxtConfig({
  content: {
    markdown: {
      rehypePlugins: {
        'rehype-external-links': {
          target: '_blank',
          rel: ['noopener', 'noreferrer'],
          content: {
            type: 'text',
            value: ''
          },
          contentProperties: {
            className: 'external-link'
          }
        }
      }
    }
  }
})

このパターンの場合は、先ほどとは違って、:afterを使いますので span 自体は空っぽにしておきます。
value が空文字でも空の span が出ることを利用してます。

<span class="external-link"></span>

なので、これに対して after にアイコンが出るように設定します。

.external-link:after {
  content: '\e89e';
  margin: 0 0.25em;
  font-family: 'Material Symbols Outlined', serif;
  font-weight: 300;
  font-style: normal;
  font-size: 100%;
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;

  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;
}

git log --format=%ct:%s

:add 2023081701.md