Hugo 自定义页面

内容简介
基于主题在 Hugo 博客中添加一个新的页面。这里说的页面不是指 Hugo 利用 markdown 文件生成的页面,而是我们自己手动创建的 html 页面。

我想添加一个网站合集页面,这个页面分类展示各类有用的网站。但是 FixIt 主题中并没有提供这个页面实现,所以只能自己动手写一个。

前置知识

添加自定义页面其实并不复杂,但是需要了解一些 HTML、CSS、JavaScript 的基础,还有 Hugo 中函数的用法。其次不太推荐使用类似 Vue 这样的 JS 框架,因为 Hugo 的页面使用了大量的 golang 模板语法,就是你在主题文件中看到的{{}}语法,而 Vue 中也有到这个语法,这可能会在无意中给你的开发造成障碍,甚至在解析模板时出错。

添加自定义页面

作为一个前端小白,自己从头实现一个新的页面,有点难度。这里我参考了 FixIt 主题友链页面的实现方式,友链页面添加可以参考 Fixit-主题美化 一文。

定义站点页面的内容模板

archetypes目录下创建websites.md,内容参考archetypes/friends.md

 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
---
title: {{ replace .TranslationBaseName "-" " " | title }}
subtitle:
layout: websites
date: {{ .Date }}
description: "{{ .Site.Params.author.name }}'s websites"
keywords:
  - 'Hugo FixIt'
  - 'websites template'
  - 站点导航
comment: false
---

<!-- The `websites.yml` file placed in the `yourProject/data/` directory will be loaded automatically here. -->

---

<!-- You can define additional content below for this page. -->

## Base info

- nickname: Lruihao
- avatar: https://lruihao.cn/images/avatar.jpg
- url: https://lruihao.cn
- description: Lruihao's Note

定义站点页面的模板

layouts/page/目录下创建websites.html,内容参考layouts/page/friends.html。这里在friends.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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{{- define "title" -}}
{{- cond (.Param "capitalizeTitles") (title .Title) .Title -}}
{{- if .Site.Params.withSiteTitle }} {{ .Site.Params.titleDelimiter }} {{ .Site.Title }}{{- end -}}
{{- end -}}

{{- define "content" -}}
{{- $params := partial "function/params.html" -}}
<article class="page single special websites">
  <div class="header">
    {{- /* Title */ -}}
    <h1 class="single-title animate__animated animate__pulse animate__faster">{{- cond (.Param "capitalizeTitles")
      (title .Title) .Title -}}</h1>
    {{- /* Subtitle */ -}}
    {{- with $params.subtitle -}}<p class="single-subtitle animate__animated animate__fadeIn">{{ . | $.RenderString }}
    </p>{{- end -}}
  </div>

  {{- /* website links grouped by category */ -}}
  <script src="//at.alicdn.com/t/font_578712_g26jo2kbzd5qm2t9.js" async defer></script>
  {{- $websites := .Site.Data.websites -}}
  {{- $categories := dict -}}
  {{- range $website := $websites -}}
  {{- $category := $website.category | default "未分类" -}}
  {{- $items := index $categories $category | default slice -}}
  {{- $items = $items | append $website -}}
  {{- $categories = merge $categories (dict $category $items) -}}
  {{- end -}}
  {{- /* 获取所有分类并按权重排序 */ -}}
  {{- $sortedCategories := slice -}}
  {{- range $category, $items := $categories -}}
    {{- $weight := 9999 -}}  {{- /* 默认权重 */ -}}
    {{- range $items -}}
      {{- if isset . "category_weight" -}}
        {{- $weight = .category_weight -}}
      {{- end -}}
    {{- end -}}
    {{- $sortedCategories = $sortedCategories | append (dict "name" $category "items" $items "weight" $weight) -}}
  {{- end -}}
  {{- $sortedCategories = sort $sortedCategories "weight" "asc" -}}
  {{- /* 渲染排序后的分类 */ -}}
  {{- range $category := $sortedCategories -}}
  <h2 class="website-category">{{ $category.name }}</h2>
  <div class="website-links">
    {{ range $index, $website := $category.items }}
    <a class="website" title="{{ $website.description }}" href="{{ $website.url | safeURL }}" rel="external noopener"
      target="_blank">
      {{ if $website.avatar }}
      {{- dict "Src" $website.avatar "Alt" $website.nickname "Title" $website.description "Class" "website-avatar" |
      partial "plugin/image.html" -}}
      {{ else }}
      <svg class="website-avatar" aria-hidden="true">
        <use xlink:href="#icon-{{ add 1 $index }}"></use>
      </svg>
      {{ end }}
      <div class="website-info">
        <span class="website-nickname" title="{{ $website.nickname }}">{{ $website.nickname }}</span>
        <span class="website-description" title="{{ $website.description }}">{{ $website.description }}</span>
      </div>
    </a>
    {{ end }}
  </div>
  {{- end -}}

  {{- /* Content */ -}}
  <div class="content" id="content">
    {{- dict "Content" .Content "Ruby" $params.ruby "Fraction" $params.fraction "Fontawesome" $params.fontawesome |
    partial "function/content.html" | safeHTML -}}
  </div>

  {{- /* Comment */ -}}
  {{- partial "single/comment.html" . -}}
</article>
{{- end -}}

data/目录下面创建websites.yml,这是和模板对应的站点配置文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 站点信息
- nickname: Hugo
  avatar: https://gohugo.io/favicon.ico
  url: https://gohugo.io/
  description: |
    Hugo is one of the most popular open-source static site generators.
    With its amazing speed and flexibility,
    Hugo makes building websites fun again.
  category: 本站技术支持
  category_weight: 1

- nickname: FixIt
  avatar: https://fixit.lruihao.cn/favicon.ico
  url: https://fixit.lruihao.cn/zh-cn/
  description: 一个简洁、优雅且高效的 Hugo 主题
  category: 本站技术支持
  category_weight: 1

- nickname: Font Awesome
  avatar: https://fontawesome.com/favicon.ico
  url: https://fontawesome.com/icons
  description: 一个包含很多icon的开源图标库
  category: 工具类
  category_weight: 2

调整站点页面样式

assets/css/_custom.scss文件中添加以下代码:

 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
.website {
  display: flex;
  align-items: center;
}

.website-info {
  display: flex;
  flex-direction: column;
  margin-left: 10px;
}

.website-description {
  font-size: 0.8em;
  color: #666;
}

.website-links {
  display: flex;
  flex-wrap: wrap; // 允许换行
  gap: 20px; // 卡片间距
  margin-bottom: 30px; // 分类间间距
}

.website {
  display: flex;
  align-items: center;
  height: 80px;
  min-height: 80px;
  width: 250px; // 固定卡片宽度
  overflow: hidden;
  flex: 0 0 auto;
  max-width: none;
  box-sizing: border-box;
  padding: 12px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.02);
  transition: all 0.2s ease;

  &:hover {
    background: rgba(0, 0, 0, 0.05);
  }
}

.website-avatar {
  width: 60px;
  height: 60px;
  object-fit: cover;
  flex-shrink: 0;
}

.website-info {
  display: flex;
  flex-direction: column;
  justify-content: center; // 保持垂直居中
  height: 100%;
  margin-left: 12px;
  overflow: hidden;
  width: calc(100% - 72px);
}

.website-nickname {
  font-weight: bold;
  margin-bottom: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.website-description {
  display: -webkit-box;
  -webkit-line-clamp: 1; // 限制显示1行
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.8em;
  color: #666;
  line-height: 1.4;
  max-height: 3.6em; // 3行高度
}

创建站点链接页面

创建一个站点链接页面,在 Front matter 中设置layout: websites,然后运行hugo命令生成页面:

1
2
hugo new content websites/index.md
hugo server -D
Buy me a coffee
beneliu 支付宝支付宝
beneliu 微信微信
0%