はてなブログのコードブロックでPrism.jsを使うようにしてたところにラベルを表示できるようにした

最近ブログのデザインを変えた。その続きで少し改修した。

bufferings.hatenablog.com

何を修正したのか?

コードブロックでファイル名などのラベルを出せたらいいなと思ったので対応した。

↓これはスクリーンキャプチャ。hello.javaが表示されている。シンタックスハイライトが効いていることを確認したかっただけなのでコードの内容は関係ない。

こんな感じ

↓これは実際のコードブロック。

sealed interface Mapping<T> {
  T value();

  record A(Boolean value) implements Mapping<Boolean> {}

  record B(String value) implements Mapping<String> {}
}

↓こう書いている

```java:hello.java
sealed interface Mapping<T> {
  T value();

  record A(Boolean value) implements Mapping<Boolean> {}

  record B(String value) implements Mapping<String> {}
}
```

仕組み

僕は、はてなブログをマークダウンで書いているので、コードブロックは```javaみたいに言語を指定して書いている。そうするとこんな感じのHTMLになる。

<pre class="code lang-java" data-lang="java" data-unlink="">

classにlang-javaが設定されて、data-langにjavaが設定されている。ここで```java:hello.javaとコロンにつなげてラベルを書いてみるとこうなる。

<pre class="code java:hello.java" data-lang="java:hello.java" data-unlink="">

classのlang-javajava:hello.javaになっていて、はてなのシンタックスハイライトは効かない状態になる。だけど、僕はブログのデザインを変えたときに、コードブロックにはPrism.jsを使うようにしているので問題ない。

Prism.jsのtoolbarプラグインを使う

自分で実装しようかと思ったけど、ちょうどいいプラグインがあったから使うことにした。

preタグにdata-label属性を指定すると、その値をラベルとするDOMを生成してくれる。

これで材料が揃った

↓のdata-langの部分をコロンでスプリットして、コロンの前までを言語として扱って、コロンの後ろをラベルと扱うようにすればいい

<pre class="code java:hello.java" data-lang="java:hello.java" data-unlink="">

こう書いた

<script type="module">
  function splitLangAndLabel(dataLang) {
    if (!dataLang) return [dataLang];

    const index = dataLang.indexOf(":");
    if (index == -1) return [dataLang];

    return [dataLang.substring(0, index), dataLang.substring(index + 1)];
  }

  document.addEventListener("DOMContentLoaded", (event) => {
    document.querySelectorAll("pre.code").forEach((pre) => {
      const [lang, label] = splitLangAndLabel(pre.dataset.lang);

      const code = document.createElement("code");
      code.textContent = pre.textContent;
      code.className = `code language-${lang}`;

      pre.innerText = "";
      if (label) {
        pre.dataset.label = label;
      }
      pre.appendChild(code);

      window.Prism.highlightElement(code);
    });
  });
</script>

これでdata-labelhello.javaが設定されてToolbarプラグインで処理されて、↓こういうHTMLがpreタグの後ろに追加される。

<div class="toolbar">
  <div class="toolbar-item">
    <span>hello.java</span>
  </div>
</div>

あとはCSSで

ごにょごにょすればいいのでGridを使ってpredivの前後を入れ替えてできあがり。

/* コードブロックのラベル */
.code-toolbar {
    display: grid;
    grid-template-rows: auto;
    margin: .5em -10px;

    .toolbar {
        grid-row: 1;
        padding: 0 10px;
        background-color: #2d2d2d;
        font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
        font-size: 0.8rem;

        .toolbar-item {
            border-bottom-right-radius: 0.25em;
            border-bottom-left-radius: 0.25em;
            width: fit-content;
            padding: 5px 10px;
            background-color: #424242;
            color: #eceff1;
        }
    }
}

自分のChromeでしか確認していないから他のブラウザでどうなるかは分かっていないし、はてなブログの生成するHTMLに変更があると動かなくなるので他の人におすすめはしないけど、自分が個人で楽しむ分には満足かな。