December 26, 2018

HugoのコードブロックにQiitaのようなTitleをつける

ブログを書いていると、よくソースコードを貼る時にタイトルを挿入したい事がよくあります。
ただこのブログはHugoを使ってMarkdownで書いているので、コードのタイトルを良い感じのレイアウトで挿入するのは少し難しいです。 そこで、Qiitaにあるようなコードのタイトルをコードブロック内に埋め込むレイアウトをJava ScriptとCSSを用いて実現してみたいと思います。

作るのはこういう感じのやつ

qiita sample

HugoでSyntax Highlightを有効にする

まずは、HugoでSyntax Highlightを有効化します。
公式Documentはこちら

Config.tomlを編集

基本的にはconfigを変更するだけです。
↓ 既にタイトルを表示している(完成イメージ)

pygmentsUseClasses = true
pygmentsCodefences = true 
  • pygmentsUseClasses

pygmentsUseClasses=trueでSyntax Highlightを有効にします

  • pygmentsCodefences

Hugoには

{{< highlight go >}}
hoge := 1
{{< highlight >}}

のような言語を指定したSyntax Highlight用のShortcodeが用意されているのですが、 普段Markdownを書いている人はコードブロックを以下のようなバッククォート3つで囲むのが普通だと思います。

```go
hoge := 1
```

その場合にpygmentsCodefences=trueにしてバッククォートでのSyntax Highlightを有効化します。

Themeを適用

config.tomlでSyntax Highlightを有効化したら、次にThemeを適用します。

Theme一覧がこちら にあるので、好みのThemeを決めたら以下のコマンドを入力します。
保存先はどこでも良いのですが、慣例的にCSSファイルはstatic/css以下に配置するのが良いでしょう。

hugo gen chromastyles --style [theme name] > static/css/syntax-highlight.css

CSSが作成されたら、CSSを読み込みましょう。Themeによってはconfig.tomlに追記すればCSSを読み込んでくれるものもあります。

コードブロックにタイトルを付ける

Syntax Highlightを有効化したら、コードブロックにタイトルを付けていきます。

タグ構造

Qiitaでは以下のように、言語指定の後ろをコロンで区切ってコードブロックにタイトルを付けます。 この仕様はQiita独自仕様なのですが、慣れているので同じ仕様にしたいと思います。

```go:hoge.go
hoge := 1
```

上記のコードブロックのHTMLタグ構造を調べます。

<div class="highlight">
  <pre class="chroma">
    <code class="language-go:hoge.go" data-lang="go:hoge.go">
    ...
    </code>
  </pre>
</div>

Hugoで作成したページのHTMLを見てみると、コードブロックはhighlightクラスのdivタグで囲まれていて、その下にchromaクラスのpreタグがあることがわかります。この2つのタグに関してはHugoで作成したコードブロックでは固定の値が入ります。
preタグ直下のcodeタグのクラス名にコロン区切りでタイトルが付与されているのがわかります。
今回は、このタグを利用してHTMLタグをJavaScriptでパースしていきます。

JavaScript

完成したコードは以下のようになりました。(jsは全然書かないので合ってるかわからない)

var list = document.body.getElementsByClassName("highlight");

for(i=0; i <= list.length-1; i++){
  var code = list[i].firstElementChild.firstElementChild
  var codeName =  code ? code.className.split(":")[1] : null;

  if(codeName) {
    var div = document.createElement('div');
    div.textContent = codeName;
    div.classList.add('code-name');
    code.parentNode.insertBefore(div, code);
  }
}

簡単に説明をすると、highlightのクラス名を持つタグのリスト一覧から、子要素のクラス名をコロンでパースして、code-nameをクラス名に持つdivタグをpreタグの前に挿入します。
上記のJavaScriptで変更したHTMLのタグ構造はこのようになります。

<div class="highlight">
  <div class="code-name">hoge.go</div>
  <pre class="chroma">
    <code class="language-go:hoge.go" data-lang="go:hoge.go">
    ...
    </code>
  </pre>
</div>

このjsファイルの読み込みはHTMLの下の方で行いましょう。 完成したファイルはCSSと同様static/js配下に配置しています。

<script src="/js/code-title.js"></script>

CSSを追加

HTML自体を変更する事が出来れば、あとはCSSで調整するだけです。

pre.chroma code {  
  margin-top: -28px;
  padding-top: 40px;
  padding-bottom: 12px;
}

.code-name {
  display: inline-block;
  position: relative;
  padding: 4px 8px;
  background-color: #E7E9EB;
  color: #485A60;
  font-size: 13px;
  font-weight: 400;
}

preタグにマイナスmarginとpaddingを入れて、タイトルが入ったdivタグがコードブロック内に重なるようにしています。あとは好みの色を付ければ完成です。

まとめ

以上の設定でコードブロックが、このようになりました。

code block title
(将来テーマを変えた時の為、画像にしてます)

Qiitaのような、コードブロックのタイトル表示に成功しました。ブログをHugoに移してから不便に思っていたことの1つなので解消出来て良かったです。参考になれば。

© AAkira 2023