默认的 Categories 模板:

自定义后的 类别 模板:

查看类别页面

hugo 默认的类别页面是和 标签页面共用一个模板:themes\PaperMod\layouts\_default\terms.html

复制一份到 layouts\_default\terms.html

修改如下:

原来的 tag 从 <ul class="terms-tags">开始

定义分类元数据

如何给每一个分类设置一个分类描述属性

在 Hugo 中,为每个分类(category)设置描述属性需要在每个分类的索引页面中添加元数据。以下是详细步骤:

创建分类索引页面: 对于每个分类,你需要在 content 目录下创建一个对应的文件夹,并在该文件夹中创建一个 _index.md 文件。例如,如果你有一个名为"Technology"的分类,你需要在 content/categories/technology/_index.md 中添加描述。

添加描述元数据: 在 _index.md 文件的 front matter 中,你可以添加描述属性。例如:

---
title: "Book"
description: "All about the latest book trends and news."
image: "https://daoyuc.oss-cn-hangzhou.aliyuncs.com/imgs/20241119192511.png" # 封面图片路径
alt: "Book Category Cover" # 封面图片的替代文本
caption: "A brief description of the image" # 封面图片的标题或描述
---

This is the book category page.

在这里,description 字段就是分类的描述。我还加了 image 和 alt 属性,用于可选的为类别设定一个 背景图片。 配置模板以显示描述:

遍历分类元数据

在你的列表模板中,你可以通过 .Site.GetPage 函数获取分类页面,并访问其 Params 来获取描述。你可以在分类模板(通常是 layouts/categories/terms.html )中添加以下代码:

<ul>
  {{ range .Site.Taxonomies.categories.Alphabetical }}
    <li>
      <a href="{{ .Page.RelPermalink }}">{{ .Page.Title }}</a>
      {{ with .Page.Params.description }}
        - <span>{{ . }}</span>
      {{ end }}
    </li>
  {{ end }}
</ul>

这段代码会遍历所有的分类,对于每个分类,它会输出分类的标题和一个链接。如果分类有描述,它也会显示这个描述。

使用 with 进行安全调用: with 关键字在模板中用于安全地调用可能不存在的变量。如果 .Page.Params.description 存在,它将输出描述,否则不会输出任何内容。

应用分类文章数量

由于我选择的类别模板有 css3 实现的纸张叠加效果,所以需要根据类别下的文章数量 循环出堆叠 div (设置最大纸张数量为5)

{{- $count := .Count }}
{{- $maxCount := 5 }}
{{ $actualCount := 0 }}

{{ if lt $count $maxCount }}
{{ $actualCount = $count }}
{{ else }}
{{ $actualCount = $maxCount }}
{{ end }}

...

{{ range seq 1 $actualCount }}
<div class="child"></div>
{{ end }}

完整实现

以下是具体的实现方案:

{{ if eq .Type "categories" }}
<div class="container">
    {{- $type := .Type }}
    {{- range $key, $value := .Data.Terms.Alphabetical }}
    {{- $name := .Name }}
    {{- $count := .Count }}
    {{- $maxCount := 5 }}
    {{ $actualCount := 0 }}
    
    {{ if lt $count $maxCount }}
    {{ $actualCount = $count }}
    {{ else }}
    {{ $actualCount = $maxCount }}
    {{ end }}

    {{- with $.Site.GetPage (printf "/%s/%s" $type $name) }}
    <a href="{{ .Permalink }}">
        <div class="card" style="--cards:{{ $count }};">
        <div class="child">
                <h2>{{ .Name }}</h2>

                {{ with .Page.Params.description }}
                <span>{{ . }}</span>
                {{ end }}
                <p>{{ $count }} articles</p>
                {{ if .Page.Params.image }}
                <img src="{{ .Page.Params.image | relURL }}" alt="{{ .Page.Params.alt }}" />
                {{ end }}
            </div>
            {{ range seq 1 $actualCount }}
            <div class="child"></div>
            {{ end }}
        </div>
    </a>
    {{- end }}
    {{- end }}
</div>

{{ else if eq .Type "tags" }}

<ul class="terms-tags">
    {{- $type := .Type }}
    {{- range $key, $value := .Data.Terms.Alphabetical }}
    {{- $name := .Name }}
    {{- $count := .Count }}
    {{- with site.GetPage (printf "/%s/%s" $type $name) }}
    <li>
        <a href="{{ .Permalink }}">{{ .Name }} <sup><strong><sup>{{ $count }}</sup></strong></sup> </a>
    </li>
    {{- end }}
    {{- end }}
</ul>

{{ endif}}


<style>
    .container {
        max-width: 900px;
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
        grid-gap: 48px;
        margin: 0 auto;
    }

    .card {
        cursor: pointer;
        position: relative;
        height: 0;
        padding-bottom: 120%;
        --offset-multiplier: 4px;
        transition: -webkit-transform 0.6s ease;
        transition: transform 0.6s ease;
        transition: transform 0.6s ease, -webkit-transform 0.6s ease;
        --translate: 0;
        -webkit-transform: translate(var(--translate), var(--translate));
        transform: translate(var(--translate), var(--translate));
    }

    .card:hover {
        --offset-multiplier: 6px;
    }

    .card:hover {
        --translate: calc(-1px * (var(--cards) - 1));
        transition: -webkit-transform 0.3s ease;
        transition: transform 0.3s ease;
        transition: transform 0.3s ease, -webkit-transform 0.3s ease;
    }

    .child {
        position: absolute;
        width: 100%;
        height: 100%;
        padding: 0 16px;
        box-sizing: border-box;
        background: var(--entry);
        box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1), 0px -4px 8px rgba(255, 255, 255, 0.8);
        border-radius: 6px;
        transition: inherit;
        --translate: calc(var(--offset) * var(--offset-multiplier));
        -webkit-transform: translate(var(--translate), var(--translate));
        transform: translate(var(--translate), var(--translate));
        z-index: 5;
    }

    .child p {
        bottom: 1rem;
        right: 1rem;
        position: absolute;
    }

    .child img {
        position: absolute;
        left: 0.5rem;
        bottom: 0.5rem;
        width: 8rem;
        z-index: -100;
        opacity: 0.5;
    }

    .child:nth-child(1) {
        --offset: 0;
        z-index: 4;
    }

    .child:nth-child(2) {
        --offset: 1;
        z-index: 3;
    }

    .child:nth-child(3) {
        --offset: 2;
        z-index: 2;
    }

    .child:nth-child(4) {
        --offset: 3;
        z-index: 1;
    }

    .child:nth-child(5) {
        --offset: 4;
        z-index: 0;
    }

    .child:nth-child(6) {
        --offset: 5;
        z-index: -1;
    }

    .child:nth-child(7) {
        --offset: 6;
        z-index: -2;
    }

    .child:nth-child(8) {
        --offset: 7;
        z-index: -3;
    }

    .child:nth-child(9) {
        --offset: 8;
        z-index: -4;
    }

    .child:nth-child(10) {
        --offset: 9;
        z-index: -5;
    }
</style>

如果你也自定义了类别页面,欢迎在评论区交流 👇

扩展阅读

Terms.Alphabetical 包含哪些属性

在 Hugo 中,Data.Terms.Alphabetical 是一个特殊的变量,它提供了按字母顺序排序的分类法(taxonomy terms)。以下是Data.Terms.Alphabetical中包含的一些属性:

  1. .Count:分配给此术语的内容数量。
  2. .Page:返回此术语的页面引用。
  3. .Pages:返回包含术语被分配给的Page对象的Pages对象,按分类权重排序。
  4. .Term:返回术语名称。
  5. .WeightedPages:返回一个加权页面切片,其中包含术语被分配到的页面,按分类权重排序。

这些属性可以在模板中用来显示和操作分类法数据。例如,你可以使用.Count来显示每个术语有多少内容与之关联,或者使用.Pages来列出与特定术语相关联的所有页面。.Term属性允许你获取当前迭代的术语名称,而.WeightedPages则提供了一个页面列表,这些页面根据它们与术语的关联权重进行了排序。

增加分类文章字数统计

需要用到上一节提到的 .Pages 对象, 累加 Pages里的每一个 .WordCount

    {{ $wordCount := 0 }}
    {{ range .Pages }}
    {{ $wordCount = add $wordCount .WordCount }}
    {{ end }}

   ...

    <p>{{ $count }} 篇</p>
    <i>{{ $wordCount }} 字</i>

   ...

    .child p {
        color:var(--secondary);
        bottom: 2.5rem;
        right: 1rem;
        font-style: italic;
        position: absolute;
    }

    .child i {
        color:var(--secondary);
        bottom: 1rem;
        right: 1rem;
        position: absolute;
    }

模板中的变量根据情况重置值

在 Hugo 模板中,你不能直接在 if 语句中给变量赋值。不过,你可以通过定义一个新的变量来实现这个逻辑。

{{ $maxCount := 5 }}
{{ $actualCount := 0 }}

{{ if lt $count $maxCount }}
  {{ $actualCount = $count }}
{{ else }}
  {{ $actualCount = $maxCount }}
{{ end }}