前回、ブログと一緒にシングリッシュ用語集サイトも公開した話を書いた。今回はまたこのブログ自体の話に戻る。サイドバーを作った記録だ。
記事一覧とアーカイブだけでは物足りなかった
Hugo + PaperMod で組んだこのブログは、最初はヘッダーに「記事一覧」「アーカイブ」の2つのメニューがあるだけだった。記事数が増えてくると、日付やタグから辿れた方が使いやすい。PaperModはシングルカラムのテーマで、サイドバーという概念自体がない。ただ、コンテンツ幅(--nav-width: 1024px)は画面中央に固定されているので、広い画面では左右に何もない余白ができる。ここに何か置けるはずだと考えた。
まずはボタンだけ置いてみた
PaperModには extend_footer.html という空のフック(パーシャル)が用意されていて、上書きするだけでフッター末尾に任意のHTMLを差し込める。CSSも assets/css/extended/*.css に置いたファイルが自動で本体CSSに連結される仕組みがあるので、これを使って、画面右端に固定表示する丸ボタンを2つ置いてみた。「📅 日付別」は /archives/ へ、「🏷️ タグ別」は /tags/ へのリンクだけの、ただのショートカットだ。
はてなブログを見て、作り直すことにした
ボタンだけでは芸がない。はてなブログのサイドバーにあるような、実際にカレンダーの月表示が出て投稿日がハイライトされるもの、タグも名前と件数がその場に並ぶものにしたいと思った。
タグクラウドの方は簡単だった。PaperMod自身の /tags/ ページ(taxonomy.html)が既に同じことをしていたので、そのロジックをそのまま借りた。
{{ range $tagsPage.Data.Terms.Alphabetical }}
{{ with site.GetPage (printf "/tags/%s" .Name) }}
<a href="{{ .Permalink }}">{{ .LinkTitle }} ({{ $count }})</a>
{{ end }}
{{ end }}
カレンダーは静的サイトジェネレータなので少し工夫が要る。ビルド時に、その言語の全記事の日付・タイトル・URLをJSONとしてページに埋め込み({{ $calItems | jsonify }})、バニラJSで月表示のグリッドを描画する方式にした。外部ライブラリは使っていない。
カレンダーが、何も表示されなかった
書き終えてデプロイしたら、タグクラウドは正しく出るのに、カレンダー部分だけが空白だった。前後の月ボタン(‹ ›)だけが表示されて、日付のマス目もタイトルも出ない。
ブラウザの開発者ツールで実際のHTMLを見て気づいた。埋め込んだはずのJSONが、こうなっていた。
<script type="application/json" id="quick-cal-data">"[{\"date\":\"2026-08-21\",\"...\"}]"</script>
配列全体が、エスケープされた文字列として二重にクオートで包まれている。JSON.parse() にこれを渡すと、配列ではなく1本の文字列が返ってくる。直後の .forEach() はもちろん文字列には存在しないので、その場でエラーが起きてスクリプト全体が止まっていた。
原因はHugoのテンプレートエンジン(html/template)の仕様だった。<script> タグの中に値を差し込むと、Hugoは自動的にそれをJSの文字列リテラルとして安全にエスケープしようとする。jsonify が返すのはただの string 型なので、信頼できない値として扱われ、丸ごとクオートで包まれてしまっていた。
直したのは1箇所、safeJS を挟んで「このJSは安全だから素通ししてくれ」と明示するだけだった。
{{ $calItems | jsonify | safeJS }}
これでJSONがそのまま配列として埋め込まれるようになり、カレンダーが動くようになった。
月別ボタンも追加した
カレンダーが動くようになったところで、月ごとにジャンプできるボタンも欲しくなった。前後の月を1つずつ辿るだけでは、記事が増えてきたときに不便になる。投稿のある年月を新しい順にリストアップし、クリックするとページ遷移なしでカレンダーがその月に切り替わる仕組みを、既存のカレンダーの状態管理に乗せる形で追加した。
今の状態
このブログ自体が、動かしながら直したものの記録になった。カレンダー・月別ボタン・タグクラウドがサイドバーに揃った状態で、次は中身の記事を増やしていく番だ。
つづく。