zenn-markdown-htmlのコードブロックにコピーボタンを追加する

公開日:
目次

zenn-markdown-htmlとは

zenn-markdown-htmlはmarkdownをzenn風のデザインのhtmlに変換するライブラリです。このブログでもzenn-markdown-htmlを利用して、markdownをhtmlに変換しています。

詳しくは下記の記事を参照してください。

markdownをおしゃれなデザインに変換してくれてめっちゃ助かってます!

zenn-markdown-htmlのコードブロックにコピーボタンがない!

zenn-markdown-htmlを使ってコードブロックを表示すると、コピーボタンがないことに気づきました。Zennにはコピーボタンが着いているので、zenn-markdown-htmlを使った自分のブログでもコピーボタンを追加したいですよね。

コピーボタンを追加する方法

コピーボタンを追加する方法はいくつかあると思いますが、今回は変換されたhtmlにコピーボタンを追加する方法を紹介します。

htmlにJavaScriptで直接コピーボタンを追加する

htmlにcopyボタンを追加する方法は色々あるかと思いますが、今回はmarkdownから変換されたhtmlに対して、直接コピーボタンを追加することにします。

コードブロックを特定するには、コードブロックの前に<pre language-言語別>があるのでそれと<code>を探します。

また、コードブロックは複数ある場合も考えられるので、idを付与して、idが重複しないようにします。

私の場合は、tailwindcssを使っているので、tailwindcssのクラスを使っています。

addCopyButton.js
const addCopyButton = (html) => {
  // コードブロックが複数ある場合にidが重複しないように、idの初期値を設定
  let id = 0
  // コードブロックの前には<pre language-言語別>があるのでそれと<code>を探して、idが付与されていなければidを追加する。その前にコピーボタンを追加する
  return html.replace(/<pre.*?><code.*?>/g, (match) => {
      id++;
      return `<div class="relative"><button id="code-button-${id}" class="absolute right-0 top-0 z-10 
      bg-gray-700 text-gray-100 px-2 py-1 text-sm rounded-md" onclick="var target = document.getElementById
      ('code-${id}').innerText; navigator.clipboard.writeText(target).then(()=> {document.getElementById
      ('code-button-${id}').innerText = 'COPIED!'; setTimeout(() => {document.getElementById('code-button-${id}
      ').innerText = 'Copy' }, 2000)}, ()=>{});">Copy</button>${match.slice(0, -1)} id='code-${id}'>`;
    }
  )
}

tailwindを使わない場合は、こんな感じになるかと思います。ちなみに自分では試してないので、実際にうまくいくかは不明です。(多分うまくいくはず...)
cssで.copy-buttonに色々とスタイルを当ててください。

addCopyButton.js(tailwindを使わない場合)
const addCopyButton = (html) => {
  // コードブロックが複数ある場合にidが重複しないように、idの初期値を設定
  let id = 0
  // コードブロックの前に<pre language-言語別>があるのでそれと<code>を探して、idを追加する。その前にコピーボタンを追加する
  return html.replace(/<pre.*?><code.*?>/g, (match) => {
      id++;
      return `<button id="code-button-${id}" class="copy-button">Copy</button>${match.slice(0, -1)} id='code-${id}'>`;
    }
  )
}

prism.jsを使う方法もある

Next.jsを使っている場合は、remark-prismかrehype-prismというライブラリを利用して、prism.jsを使うこともできます。
prism.jsにはプラグインにcopy-to-clipboardというコピーボタンを追加するプラグインがあるので、それを使うこともできます。

自分で変換コードを書く前に使えるかなと思いトライしてみましたが、私の場合はうまくいきませんでした。

実際にやったのはrehype-prismを導入し、プラグインを入れてみたのですがcopy-to-clipboardだけうまくいきませんでした(line-numbersとかは使えた)。

基本的にはrehype-prismのreadmeに書いてある通りなら、copy-to-clipboardは使えるプラグインとして記載されているので可能ではあるはずです。

弱々エンジニアの私は諦めてしまいましたが、できるかたはトライしてみてください。