作ったものとか » Hugo テーマ

Hugo テーマ 3. 最近の更新リスト

2021-10-31 20:25:42 hugo

現在作成途中のテーマ cheep をもとに、最近の更新リストを実装する方法を解説します。

最近の更新リストの実物は、このサイトの右にある「LATEST」となります。

今回は、このリストを作成する部分を解説します。

最終形

最近の更新リストをテンプレートとして括り出す構成にします。

まずは、テンプレートをはめ込む側から。

themes/cheep/layouts/_default/baseof.html

1
2
3
4
5
6
7
<body>
 :
    <div class="side-area">
        {{ partial "profile.html" . }}
        {{ partial "latest.html" . }}
        {{ partial "tags.html" . }}
    </div>

partial となっている箇所の2つ目(真ん中)が最近の更新リストが入る部分です。


次に、最近の更新リストの方。

themes/cheep/layouts/partials/latest.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<div class="latest_list_container">
    <ul>
        {{ if (default true $.Site.Params.latestOnlyPage) }}
        {{ range first 10 (sort (where .Site.Pages "IsPage" true) "Lastmod" "desc") }}
        <a href="{{ .Permalink }}" title={{ .Summary }}><li>
            <span style="display:inline-block; text-decoration:none">{{ default "📄" $.Site.Params.iconLatestPage }} </span>
            {{ .Title }}
            {{ if $.Site.Params.latestSummaryLength }}
            <div class="latest_summary">
            {{ substr (replaceRE "<[^>]+>" "" .Summary) 0 $.Site.Params.latestSummaryLength }}
            </div>
            {{ end }}
        </li></a>
        {{ end }}
        {{ else }}
        {{ range first 10 (sort .Site.Pages "Lastmod" "desc") }}
        <a href="{{ .Permalink }}" title={{ .Summary }}><li>
            {{ if .IsPage }}
            <span style="display:inline-block; text-decoration:none">{{ default "📄" $.Site.Params.iconLatestPage }} </span>
            {{ else }}
            <span style="display:inline-block; text-decoration:none">{{ default "📂" $.Site.Params.iconLatestList }} </span>
            {{ end }}
            {{ .Title }}
            {{ if $.Site.Params.latestSummaryLength }}
            <div class="latest_summary">
            {{ substr (replaceRE "<[^>]+>" "" .Summary) 0 $.Site.Params.latestSummaryLength }}
            </div>
            {{ end }}
        </li></a>
        {{ end }}
        {{ end }}
    </ul>
</div>

色々とやりすぎているので、簡単なものから徐に機能追加しつつ解説していきます。

シンプルなリスト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<div class="latest_list_container">
    <ul>
        {{ range first 10 (sort .Site.Pages "Lastmod" "desc") }}
        <a href="{{ .Permalink }}" title={{ .Summary }}><li>
            <span style="display:inline-block; text-decoration:none">{{ default "📄" $.Site.Params.iconLatestPage }} </span>
            {{ .Title }}
        </li></a>
        {{ end }}
    </ul>
</div>

3行目: Lastmod の降順でループ

カッコの内側から評価されます。

.Site.Pages でサイトにあるページ(注意: カテゴリーやタグ、セクションも含まれます)を列挙して、 sortLastmod の降順(desc)で並び替えます。

その上で、{{range}} でループしています。 first 10 によって、上記の並び替え結果に対して最初の10件だけをループの対象としています。

4行目, 7行目: ループしている中身の情報を出力

{{ range }} の内側ではそれぞれのページを参照するようにコンテクストが切り替わるっているで、{{ .Permalink }}{{ .Title }} といった表現でページの内容(Hugo では「変数」と表現しているようです)を参照できます。

変数の一覧は Hugo サイトの Page Variables に列挙されています。

sort で指定している Lastmod についてもそのページに記載されています。

ページとその他(カテゴリーやタグ、セクション等)の切り分け

ページだけをリスト表示してみる

シンプルなリストでは、セクションなども混在して列挙されてしまいます。 そうなると、更新したページだけではなく、そのページが属しているセクションも更新されたことになってしまうため、何らか切り分けをして表示したいところです。 (10件の中にページ以外も含まれるため、表示件数が結果的に少なくなってしまうという弊害(?)もあります)

まずは、ページのみをリスト表示するように変えてみます。

更新前

1
{{ range first 10 (sort .Site.Pages "Lastmod" "desc") }}

↓更新後↓

1
{{ range first 10 (sort (where .Site.Pages "IsPage" true) "Lastmod" "desc") }}

sort の前に、where つまり (where .Site.Pages "IsPage" true) を挟むことで、ページの変数が特定の値のものに絞り込んでいます。

ページとそれ以外で表示内容を変えてみる

{{ range }} の内容は、再度、where で絞り込みをしないようにして、ループの中で条件分岐をしてみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<div class="latest_list_container">
    <ul>
        {{ range first 10 (sort .Site.Pages "Lastmod" "desc") }}
        <a href="{{ .Permalink }}" title={{ .Summary }}><li>
            {{ if .IsPage }}
            <span style="display:inline-block; text-decoration:none">{{ default "📄" $.Site.Params.iconLatestPage }} </span>
            {{ else }}
            <span style="display:inline-block; text-decoration:none">{{ default "📂" $.Site.Params.iconLatestList }} </span>
            {{ end }}
            {{ .Title }}
            </div>
            {{ end }}
        </li></a>
        {{ end }}
    </ul>
</div>

サイト(テーマの利用側)のパラメーターで制御できるようにする

この変更を入れると、ほとんど最終形と同じになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="latest_list_container">
    <ul>
        {{ if $.Site.Params.latestOnlyPage }}
        {{ range first 10 (sort (where .Site.Pages "IsPage" true) "Lastmod" "desc") }}
        <a href="{{ .Permalink }}" title={{ .Summary }}><li>
            <span style="display:inline-block; text-decoration:none">{{ default "📄" $.Site.Params.iconLatestPage }} </span>
            {{ .Title }}
        </li></a>
        {{ end }}
        {{ else }}
        {{ range first 10 (sort .Site.Pages "Lastmod" "desc") }}
        <a href="{{ .Permalink }}" title={{ .Summary }}><li>
                {{ if .IsPage }}
                <span style="display:inline-block; text-decoration:none">{{ default "📄" $.Site.Params.iconLatestPage }} </span>
                {{ else }}
                <span style="display:inline-block; text-decoration:none">{{ default "📂" $.Site.Params.iconLatestList }} </span>
                {{ end }}
                {{ .Title }}
                </li></a>
        {{ end }}
        {{ end }}
    </ul>
</div>

サイトのパラメーターとして latestOnlyPage を使うようにします。 これは、テーマを使う側の config.toml(拡張子はサイトに寄ってはyaml等になっているかもしれません) にパラメーターを記述する必要があります。

1
2
[params]
  latestOnlyPage = true

さて、テンプレートの方ですが、3行目と10行目で条件分岐をしています。

それぞれ3行目の方ではページのみを表示、10行目の方ではページもそれ以外も表示しています。

デフォルトの挙動を変更する

config.toml に記述をしていない場合でも、ページのみを表示するように変更してみます。

更新前

1
{{ if $.Site.Params.latestOnlyPage }}

↓更新後↓

1
{{ if (default true $.Site.Params.latestOnlyPage) }}

default 関数を挟むことで、設定をしていない場合のデフォルト値を true にしています。 (default 関数 )

default 関数

default 関数は、第一引数にデフォルト値(今回は true)を、第二引数に対象の値をとります。

最後の引数が対象の値なので、以下のような書き方も可能です。

1
{{ if $.Site.Params.latestOnlyPage | default true }}

ページのサマリーを表示する

最後です。

ページのタイトルだけでは物足りないので、ページのサマリーも表示してみます。

(-_-) oO( 特にこのサイトは自作ソフトウェアの解説ページが多いので、結果的に無味乾燥なタイトルのページが多いんです )

1
2
3
4
5
6
{{ .Title }}
{{ if $.Site.Params.latestSummaryLength }}
<div class="latest_summary">
{{ substr (replaceRE "<[^>]+>" "" .Summary) 0 $.Site.Params.latestSummaryLength }}
</div>
{{ end }}

サイトのパラメーター $.Site.Params.latestSummaryLength を参照し、表示する文字数を制限するようにしています。