Rust mdbook をちょっと改造してブログにする

mdbook は所定の書式に従って指定した markdown ファイルをレンダリングし、一覧できる形で Web サイト用の HTML を出力します。ライブラリのリファレンスなどによく使われています。

非常に簡単にページが作成、公開できるので今回はちょっと見栄えを改造してブログとして使うことにしました。見栄えのみの改造なので mdbook 本体には手を入れません。CSS と JS の知識のみで可能な範囲で行いました。

公開に至るまでの手順を記録しておきます。

mdBook を手早く試す

Install

コンパイル済みのバイナリファイルが用意されています。Releases · rust-lang-nursery/mdBook

自分のシステムに該当するファイルを解凍してパスを通すかパスが通っている場所に配置します。

curl https://github.com/rust-lang-nursery/mdBook/releases/download/v0.3.1/mdbook-v0.3.1-x86_64-unknown-linux-gnu.tar.gz -L -o mdbook.tar.gz
tar -zxvf mdbook.tar.gz
mv mdbook /usr/bin/mdbook

mdBook を開始する

ディレクトリを用意して init コマンドを実行すると必要なソースファイル一式が作成されます。

mkdir o296.com
cd o296.com
mdbook init

Build

以下のコマンドで book ディレクトリに HTML 一式が出力されます。

mdbook build

編集していく

ファイルの変更を監視する

以下のコマンドで関係するファイルが更新されるたびにビルドしなおされます。

mdbook serve -p 3000

watch ではファイルのビルドのみが行われますが、serve では http://localhost:3000 経由で book を閲覧でき、更新のたびにリロードされます。

ポートは任意に変更が可能です。

目次 (ページの作成)

単なるリンクと、リスト形式のリンクが使えます。

リストはデフォルト設定では章番号つきのリストとして描画されます。ネストしたリストにはネストした章番号がつきます。

[チラシの裏](./paper.md)

- [mdbook メモ](./mdbook.md)
- [Vue メモ](./vue/index.md)
  - [Vuex](./vue/vuex.md)
チラシの裏
1. mdbook メモ
2. Vue メモ
  2.1. Vuex

作成していないファイルを指定した状態でビルドすると # チラシの裏 のように見出しのみが入ったファイルが作成されます。

prefix suffix

単なるリンクは prefix と suffix としてのみ使えます。リストで挟んで使うことは出来ません。

以下はビルドできません。

[チラシの裏](./paper.md)

- [mdbook メモ](./mdbook.md)

[プログラムの話](./program.md)

- [Vue メモ](./vue/index.md)
  - [Vuex](./vue/vuex.md)

font-awesome

使用している font-awesome は 4.7 です。

設定を変更する

ある程度の見栄えや挙動の調整は book.toml の調整のみで行なえます。 詳細は Configuration - mdBook Documentation を参照してください。

最終的には以下のような設定になっています。

[output.html]
additional-css = ["theme/custom.css"] # CSS の追加
additional-js = ["theme/custom.js"]   # JS の追加
mathjax-support = true              # Mathjax 有効
no-section-label = true             # ブログなので章番号は不要

見栄えを調整する

シンタックスハイライトの色を替える

highlightjs が使用されているので、highlight.js/src/styles at master · highlightjs/highlight.js からお好みの CSS を使えます。

theme ディレクトリをつくり highlight.css とリネームして配置すればビルド時に適用されます。

(src/theme/highlight.css ではなく theme/highlight.css です。themesrc と同階層につくりましょう)

CSS の追加

theme を用いての変更は全上書きとなるので大変です。そこで元の CSS を残しつつ追加 CSS を指定できます。

additional-css = ["theme/custom.css"]

アンカーリンクで見出しがヘッダーに隠れないようにする CSS

見出しをクリックすると見出し位置までスクロールしますが、ページ頂点までスクロールしてしまうため、見出しがヘッダーに隠れてしまいます。

そこでマージンを設けて隠れないようにしています。

.header {
  padding-top: 4em;
  margin-top: -4em;
}

その他

メニューのマージンなどを調整していますが、好みなので省略します。

挙動を変更する

JS の追加

CSS と同じく追加 JS が指定できます。

additional-css = ["theme/custom.css"]

script タグはファイル末尾に挿入されるので基本的に onload などは必要ありません。

アクティブになっている記事までサイドバーをスクロールする

デフォルトではリンクをクリックするたびにサイドメニューのスクロール位置がトップに戻るため、少し不便です。

そこでいま開いているページの場所までスクロールするようにします。

(function () {
  document
    .querySelector('.sidebar-scrollbox')
    .scroll(
      0,
      document.querySelector('.sidebar .active')
      .getBoundingClientRect()
      .top - 50
    );
})();

アクティブになっている記事のページ内アンカーをサイドバーに加える

記事が長く、アンカーがあった方が便利な場合は多々あります。

mdbook にはマッピング機能はないので、現在開いているコンテンツの DOM を見て動的に挿入します。

(function () {
  var as = document.querySelectorAll('a.header')
  var newList = document.createElement('ul');
  newList.setAttribute('class', 'innerLink');
  for (var i = 1, l = as.length; i < l; i += 1) {
    var a = as[i];
    var label = a.innerText;
    var href = a.getAttribute('href');
    var newAnchor = document.createElement('a');
    newAnchor.setAttribute('href', href);
    newAnchor.innerHTML = label;
    var newItem = document.createElement('li');
    newItem.appendChild(newAnchor);
    newList.appendChild(newItem);
  }
  document.querySelector('.sidebar .active').appendChild(newList);
})();

どこかにアップロードする

ビルドしたファイルをどこかにアップロードします。

mdbook build

serve で作成されたファイルは同期のために WebSocket を使うコードが含まれているので、アップロードすべきではありません。

おわりに

これで十分便利に使えるようになりました。

というわけで、この記事時点からこのブログは mdbook で作成されています。