Hugo を使った個人サイトの作り方 8 記事ページの作成(1) BaseテンプレートとSingleテンプレート

Hugo アイキャッチ画像

前回は固定ページを作成することが出来ました。ここからは記事ページとなる小説本文を作ります。扱う内容としてはBaseテンプレートとsingleテンプレートです。

Baseテンプレート

これまで固定ページやトップページを作成してきましたが、実際のHTMLには共通部分が多いはずです。HugoにはBaseテンプレートの機能があり、大枠を共通で設定して各部を個々のテンプレートで上書きしていく設計が可能です。私のサイトではこれを最初理解できていなかったので重複が多くなってます……改善しなければ。

日本語解説がどちらも非常にわかりやすいのでそれを読め! と言いたいところですが、具体例を晒しておきます。

./themes/Museum/layouts/_default/baseof.html
 1<!DOCTYPE html>
 2<html lang="{{.Site.LanguageCode}}">
 3{{ partial "head.html" . }}
 4<body>
 5{{ partial "mobilenavi.html" .}}
 6{{ partial "header.html" .}}
 7{{- block "main" . }}
 8{{- end }}
 9<div class="local_navi">
10<ol class="breadcrumb">
11{{ template "breadcrumb" (dict "node" . "start" .) }}
12</ol>
13</div><!-- div.local_navi end -->
14{{ partial "footer.html" . }}
15</body>
16</html>

7-8行目の{{- block “main” . }}から{{- end }}が、種々のテンプレートで上書きできる部分になります。

小説本文のmarkdownファイルは、ブログでいうと記事であり、基本的にはSingleテンプレート(./themes/[yourthemename]/layouts/_default/single.html)を用いて出力されます。しかし、Baseテンプレートでこう書いておけば、Hugoの探索順序に従って記事本文の場合は「singleテンプレート」でmainと定義したブロックに置き換わってくれるのです。

トップページならばHomeテンプレート、リストページならListテンプレートにふさわしい形のmainブロックを定義しておけばいいので、サイト構造に従って変化する挙動が簡単に実現できます。

要するに文書宣言<!DOCTYPE html>などは全て重複してたってことだよ! 知ってた! でも作成者は今どき珍しい国文科卒というド文系なので、最初から細かく条件分岐を考えるなんて出来なかったんだ!(同輩たちへの突然の風評被害!)リニューアルが大変なので書き直したほうがいいんだろうな…

Singleテンプレート

というわけで、記事本文を表示するSingleテンプレートでは中身であるmain部分のみを定義していきます。{{.Content}}にmarkdownファイルに書かれた実際の内容が入ると考えてください。main部分の定義以外の内容を書くと、Baseテンプレートごと無視されるようなので注意します。

./themes/Museum/layouts/_default/single.html
 1{{- /* main部として定義 */ -}}
 2{{ define "main" }}
 3<main>
 4<article>
 5<h1>{{ .Title }}</h1>
 6<div class="post-meta">
 7<p>
 8{{- partial "coloredcategories.html" . }}
 9{{- /* 読むのにかかる時間を割り出して */ -}}
10{{- $readTime := mul (div (countwords .Content) 540.0) 60 -}}
11{{/* 分と秒に分解して */}}
12{{- $minutes := math.Floor (div $readTime 60) -}}
13{{- $seconds := mod $readTime 60 -}}
14{{- /* 0分や0秒だったら表示しないようにする */ -}}{{ countwords .Content -}}字:読了まで約
15{{- if gt $minutes 0 -}}{{ $minutes }}{{- end -}}
16{{- if gt $seconds 0 -}}{{ $seconds }}{{- end -}}
17</p>
18{{- if .Params.tags }}
19  <ul class="post-tags">
20   {{- range ($.GetTerms "tags") }}
21   <li><a href="{{ .Permalink }}" class="tag-{{ .Name }}">{{ .LinkTitle }}</a></li>
22     {{- end }}
23  </ul>
24{{- end }}
25</div><!-- post-meta -->
26{{ .Content }}
27</article>
28</main>
29{{- if .Params.series -}}
30    {{ partial "series.html" . }}
31{{- end -}}
32{{ end }}

{{ define "main" }} から {{ end }}までがmainと定義されたブロックになります。けっこう…煩雑ですね。カテゴリ、タグ、シリーズなどの分類関連は次回説明するとして、読了時間について記しておこうと思います。コードでは8行目から15行目の部分です。

読了時間

小説サイトなので読了時間機能はあったほうがいいでしょう。できれば目録ページにも表示したいところですが、今の方式だと実装できないんですよね。どうすればいいのかな。

Hugo で生成したブログに「この記事を読むのにかかる時間」を追加する | kyohsuke の記述を パクって 利用しています。ありがとうございます。

無料で読書速度を計測できる「読書速度ハカルくん」を使ってみた | 速読情報館 によると、日本人の平均読書速度は400~600文字/分らしいので、540字/分で計算することにしました。ちなみに私の読書速度はラジコンカー級でした。

さて、次回はついにHugoの分類機能(Taxonomy)を扱おうと思います。