I. 主题文件
Hugo PaperMod - GitHub
II. 主题安装
2.1 首次安装(2选1)
参考👉
Installation · hugo-PaperMod Wiki
1
| git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
|
2.2 更换旧主题(2选1)
2.2.1 删除旧主题子模块
先删除当前的主题子模块引用。假设当前主题是 old-theme
,你可以执行以下命令:
1
2
3
4
| git submodule deinit -f themes/old-theme
rm -rf .git/modules/themes/old-theme
git rm -f themes/old-theme
git commit -m "Remove old theme"
|
上述命令将会移除 Git 子模块引用,并且在版本控制中提交该变动。
2.2.2 添加新主题子模块
接下来,你可以添加新的主题子模块。如 PaperMod
主题,可以执行:
1
2
| git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
git submodule update --init --recursive
|
2.2.3 更新网站配置文件
在你的 config.toml 或 config.yaml 中修改 theme 配置项为新的主题名称。例如:
2.3 主题更新
在 Hugo 站点根目录下运行:
1
| git submodule update --remote --merge
|
📢 注意:
如果是从其他地方 copy | clone 过来的站点,有可能遇到(参考👉
从零开始搭建个人博客网站系列 - 知乎
):
1
| WARN found no layout file for "html" for kind "home": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
|
这个时候需要重新 clone 一下主题(参考👉
Installation · adityatelange/hugo-PaperMod Wiki
):
1
| git submodule update --init --recursive
|
2.4 查看版本
1
2
| cd themes/PaperMod/
git describe --tags
|
III. 主题配置
3.1 站点目录
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
| .(site root)
├── assets
│ └── css
│ └── extended
│ └── blank.css
├── content
│ ├── posts
│ │ ├── _index.md
│ │ ├── emoji-support.md
│ │ ├── markdown-syntax.md
│ │ └── math-typesetting.md
│ ├── archives.md
│ └── search.md
├── i18n
│ └── en.yaml
├── layouts
│ ├── _default
│ │ ├── _markup
│ │ | └── render-link.html
│ │ ├── archives.html
│ │ └── terms.html
│ └── partials
│ └── toc.html
├── static
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ └── papermod-cover.png
├── themes
| └── PaperMod
├── hugo.toml.bak
└── config.yml
|
3.2 站点配置
3.2.1 备份旧配置
3.2.2 配置新站点
官方示例
配置 config.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
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
| baseURL: "https://examplesite.com/"
title: ExampleSite
paginate: 5
theme: PaperMod
enableRobotsTXT: true
buildDrafts: false
buildFuture: false
buildExpired: false
minify:
disableXML: true
minifyOutput: true
params:
env: production # to enable google analytics, opengraph, twitter-cards and schema.
title: ExampleSite
description: "ExampleSite description"
keywords: [Blog, Portfolio, PaperMod]
author: Me
# author: ["Me", "You"] # multiple authors
images: ["<link or path of image for opengraph, twitter-cards>"]
DateFormat: "January 2, 2006"
defaultTheme: auto # dark, light
disableThemeToggle: false
ShowReadingTime: true
ShowShareButtons: true
ShowPostNavLinks: true
ShowBreadCrumbs: true
ShowCodeCopyButtons: false
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
disableSpecial1stPost: false
disableScrollToTop: false
comments: false
hidemeta: false
hideSummary: false
showtoc: false
tocopen: false
assets:
# disableHLJS: true # to disable highlight.js
# disableFingerprinting: true
favicon: "<link / abs url>"
favicon16x16: "<link / abs url>"
favicon32x32: "<link / abs url>"
apple_touch_icon: "<link / abs url>"
safari_pinned_tab: "<link / abs url>"
label:
text: "Home"
icon: /apple-touch-icon.png
iconHeight: 35
# profile-mode
profileMode:
enabled: false # needs to be explicitly set
title: ExampleSite
subtitle: "This is subtitle"
imageUrl: "<img location>"
imageWidth: 120
imageHeight: 120
imageTitle: my image
buttons:
- name: Posts
url: posts
- name: Tags
url: tags
# home-info mode
homeInfoParams:
Title: "Hi there \U0001F44B"
Content: Welcome to my blog
socialIcons:
- name: x
url: "https://x.com/"
- name: stackoverflow
url: "https://stackoverflow.com"
- name: github
url: "https://github.com/"
analytics:
google:
SiteVerificationTag: "XYZabc"
bing:
SiteVerificationTag: "XYZabc"
yandex:
SiteVerificationTag: "XYZabc"
cover:
hidden: true # hide everywhere but not in structured data
hiddenInList: true # hide on list pages and home
hiddenInSingle: true # hide on single page
editPost:
URL: "https://github.com/<path_to_repo>/content"
Text: "Suggest Changes" # edit text
appendFilePath: true # to append file path to Edit link
# for search
# https://fusejs.io/api/options.html
fuseOpts:
isCaseSensitive: false
shouldSort: true
location: 0
distance: 1000
threshold: 0.4
minMatchCharLength: 0
limit: 10 # refer: https://www.fusejs.io/api/methods.html#search
keys: ["title", "permalink", "summary", "content"]
menu:
main:
- identifier: categories
name: categories
url: /categories/
weight: 10
- identifier: tags
name: tags
url: /tags/
weight: 20
- identifier: example
name: example.org
url: https://example.org
weight: 30
# Read: https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#using-hugos-syntax-highlighter-chroma
pygmentsUseClasses: true
markup:
highlight:
noClasses: false
# anchorLineNos: true
# codeFences: true
# guessSyntax: true
# lineNos: true
# style: monokai
|
3.3 模式选择
参考👉
Features · hugo-PaperMod Wiki
Hugo PaperMod 有:常规模式(Regular Mode
)、首页信息模式(Home-Info Mode
)、个人资料模式(Profile Mode
) 三种模式可供选择。
这里选择“个人资料模式(Profile Mode
)”模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| params:
profileMode:
enabled: true
title: "<Title>" # optional default will be site title
subtitle: "This is subtitle"
imageUrl: "<image link>" # optional
imageTitle: "<title of image as alt>" # optional
imageWidth: 120 # custom size
imageHeight: 120 # custom size
buttons:
- name: Archive
url: "/archive"
- name: Github
url: "https://github.com/"
socialIcons: # optional
- name: "<platform>"
url: "<link>"
- name: "<platform 2>"
url: "<link2>"
|
💡 Tips:
请为 imageUrl
设定一个值,如:imageUrl: "apple-touch-icon.png"
这里 apple-touch-icon.png
须为实际存在的图像文件,文件默认存放在站点 ../static
目录下。
3.4 自定义导航
3.4.1 增加导航菜单
这里修改站点配置文件,增加 archives
,search
导航菜单,并调整显示顺序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| menu:
main:
- identifier: archives
name: archives
url: archives/
weight: 10
- identifier: categories
name: categories
url: categories/
weight: 20
- identifier: tags
name: tags
url: tags/
weight: 30
- identifier: search
name: search
url: search/
weight: 40
|
3.4.2 创建菜单页面
为新增加的导航菜单创建页面。在站点 ../content/
目录增加两个文件。
1
2
3
4
| .(site root)
└── content
├── archives.md
└── search.md
|
archives.md
文件内容如下:
1
2
3
4
5
6
| ---
title: "存档"
layout: "archives"
url: "/archives"
summary: "archives"
---
|
search.md
文件内容如下:
1
2
3
4
5
| ---
title: "搜索"
layout: "search"
placeholder: 输入关键字,然后回车 ...
---
|
3.5 中文翻译
💡 Tips:
为了展示中文效果,建议在站点 ../content/posts/
目录下至少发布三篇文章,每篇文章元数据包括文章的“分类”及“标签”,如下:
1
2
3
4
5
6
| .(site root)
└── content
└── posts
├── emoji-support.md
├── markdown-syntax.md
└── math-typesetting.md
|
3.5.1 导航菜单
直接在站点配置文件 config.yml
中修改,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| menu:
main:
- identifier: archives
name: 归档
url: archives/
weight: 10
- identifier: categories
name: 分类
url: categories/
weight: 20
- identifier: tags
name: 标签
url: tags/
weight: 30
- identifier: search
name: 搜索
url: search/
weight: 40
|
3.5.2 页面元素
参考👉
PaperMod 主题配置 - 修改 html 模板
1、首先汉化的是分类、标签页中文显示。创建 ../layouts/_default/terms.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
| {{- define "main" }}
{{- if .Title }}
<header class="page-header">
{{- if eq .Title "Categories" }}
<h1>{{ "分类" }}</h1>
{{- end }}
{{- if eq .Title "Tags" }}
<h1>{{ "标签" }}</h1>
<!-- <h1>🔖{{ .Title }}</h1> -->
{{- end }}
<!-- <h1>{{ .Title }}</h1> -->
{{- if .Description }}
<div class="post-description">
{{ .Description }}
</div>
{{- end }}
</header>
{{- end }}
<!-- 原始 -->
<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>
{{- end }}{{/* end main */ -}}
|
2、汉化文章页 <<PREV
, NEXT>>
等页面元素,修改站点配置文件 config.yml
,内容如下:
1
2
3
4
5
6
7
8
9
10
| # 语言设置
defaultContentLanguage: "zh"
# 单语言,必须在此处,以下设置之前
languages:
zh:
# RFC 5646 语言标记, Hugo 使用此值填充内置 RSS 模板中的语言元素和内置别名模板中 html 元素的 lang 属性
languageCode: "zh-CN"
# 语言名称,通常在渲染语言切换器时使用
languageName: "中文"
|
3.5.3 Posts 页
汉化 exampleSite/posts/
页面 Posts 显示为“文章”。在站点 ../content/posts/
下创建 _index.md
文件,内容如下:
1
2
3
| ---
title: "文章"
---
|
3.6 文章目录(大纲)
参考👉
Hugo侧边目录 | 3rd’s Blog
1、在站点配置文件 config.yml
中启用目录(大纲),如下:
1
2
3
4
| params:
# ...
showtoc: true # 显示目录
tocopen: true # 自动展开目录
|
2、PaperMod 主题默认将文章目录放在顶部,不方便阅读时跳转,修改为侧边目录。创建 toc.html
,toc.css
两个文件,目录结构如下:
1
2
3
4
5
6
7
8
| .(site root)
├── assets
│ └── css
│ └── extended
│ └── toc.css
└── layouts
└── partials
└── toc.html
|
toc.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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
| {{- $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content -}}
{{- $has_headers := ge (len $headers) 1 -}}
{{- if $has_headers -}}
<aside id="toc-container" class="toc-container wide">
<div class="toc">
<details {{if (.Param "TocOpen") }} open{{ end }}>
<summary accesskey="c" title="(Alt + C)">
<span class="details">{{- i18n "toc" | default "Table of Contents" }}</span>
</summary>
<div class="inner">
{{- $largest := 6 -}}
{{- range $headers -}}
{{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
{{- $headerLevel := len (seq $headerLevel) -}}
{{- if lt $headerLevel $largest -}}
{{- $largest = $headerLevel -}}
{{- end -}}
{{- end -}}
{{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}}
{{- $.Scratch.Set "bareul" slice -}}
<ul>
{{- range seq (sub $firstHeaderLevel $largest) -}}
<ul>
{{- $.Scratch.Add "bareul" (sub (add $largest .) 1) -}}
{{- end -}}
{{- range $i, $header := $headers -}}
{{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
{{- $headerLevel := len (seq $headerLevel) -}}
{{/* get id="xyz" */}}
{{- $id := index (findRE "(id=\"(.*?)\")" $header 9) 0 }}
{{- /* strip id="" to leave xyz, no way to get regex capturing groups in hugo */ -}}
{{- $cleanedID := replace (replace $id "id=\"" "") "\"" "" }}
{{- $header := replaceRE "<h[1-6].*?>((.|\n])+?)</h[1-6]>" "$1" $header -}}
{{- if ne $i 0 -}}
{{- $prevHeaderLevel := index (findRE "[1-6]" (index $headers (sub $i 1)) 1) 0 -}}
{{- $prevHeaderLevel := len (seq $prevHeaderLevel) -}}
{{- if gt $headerLevel $prevHeaderLevel -}}
{{- range seq $prevHeaderLevel (sub $headerLevel 1) -}}
<ul>
{{/* the first should not be recorded */}}
{{- if ne $prevHeaderLevel . -}}
{{- $.Scratch.Add "bareul" . -}}
{{- end -}}
{{- end -}}
{{- else -}}
</li>
{{- if lt $headerLevel $prevHeaderLevel -}}
{{- range seq (sub $prevHeaderLevel 1) -1 $headerLevel -}}
{{- if in ($.Scratch.Get "bareul") . -}}
</ul>
{{/* manually do pop item */}}
{{- $tmp := $.Scratch.Get "bareul" -}}
{{- $.Scratch.Delete "bareul" -}}
{{- $.Scratch.Set "bareul" slice}}
{{- range seq (sub (len $tmp) 1) -}}
{{- $.Scratch.Add "bareul" (index $tmp (sub . 1)) -}}
{{- end -}}
{{- else -}}
</ul>
</li>
{{- end -}}
{{- end -}}
{{- end -}}
{{- end }}
<li>
<a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
{{- else }}
<li>
<a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
{{- end -}}
{{- end -}}
<!-- {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}} -->
{{- $firstHeaderLevel := $largest }}
{{- $lastHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers (sub (len $headers) 1)) 1) 0)) }}
</li>
{{- range seq (sub $lastHeaderLevel $firstHeaderLevel) -}}
{{- if in ($.Scratch.Get "bareul") (add . $firstHeaderLevel) }}
</ul>
{{- else }}
</ul>
</li>
{{- end -}}
{{- end }}
</ul>
</div>
</details>
</div>
</aside>
<script>
let activeElement;
let elements;
document.addEventListener('DOMContentLoaded', function (event) {
checkTocPosition();
elements = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]');
if (elements.length > 0) {
// Make the first header active
activeElement = elements[0];
const id = encodeURI(activeElement.getAttribute('id')).toLowerCase();
document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
}
// Add event listener for the "back to top" link
const topLink = document.getElementById('top-link');
if (topLink) {
topLink.addEventListener('click', (event) => {
// Prevent the default action
event.preventDefault();
// Smooth scroll to the top
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
}, false);
window.addEventListener('resize', function(event) {
checkTocPosition();
}, false);
window.addEventListener('scroll', () => {
// Get the current scroll position
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
// Check if the scroll position is at the top of the page
if (scrollPosition === 0) {
return;
}
// Ensure elements is a valid NodeList
if (elements && elements.length > 0) {
// Check if there is an object in the top half of the screen or keep the last item active
activeElement = Array.from(elements).find((element) => {
if ((getOffsetTop(element) - scrollPosition) > 0 &&
(getOffsetTop(element) - scrollPosition) < window.innerHeight / 2) {
return element;
}
}) || activeElement;
elements.forEach(element => {
const id = encodeURI(element.getAttribute('id')).toLowerCase();
const tocLink = document.querySelector(`.inner ul li a[href="#${id}"]`);
if (element === activeElement){
tocLink.classList.add('active');
// Ensure the active element is in view within the .inner container
const tocContainer = document.querySelector('.toc .inner');
const linkOffsetTop = tocLink.offsetTop;
const containerHeight = tocContainer.clientHeight;
const linkHeight = tocLink.clientHeight;
// Calculate the scroll position to center the active link
const scrollPosition = linkOffsetTop - (containerHeight / 2) + (linkHeight / 2);
tocContainer.scrollTo({ top: scrollPosition, behavior: 'smooth' });
} else {
tocLink.classList.remove('active');
}
});
}
}, false);
const main = parseInt(getComputedStyle(document.body).getPropertyValue('--article-width'), 10);
const toc = parseInt(getComputedStyle(document.body).getPropertyValue('--toc-width'), 10);
const gap = parseInt(getComputedStyle(document.body).getPropertyValue('--gap'), 10);
function checkTocPosition() {
const width = document.body.scrollWidth;
if (width - main - (toc * 2) - (gap * 4) > 0) {
document.getElementById("toc-container").classList.add("wide");
} else {
document.getElementById("toc-container").classList.remove("wide");
}
}
function getOffsetTop(element) {
if (!element.getClientRects().length) {
return 0;
}
let rect = element.getBoundingClientRect();
let win = element.ownerDocument.defaultView;
return rect.top + win.pageYOffset;
}
</script>
{{- end }}
|
toc.css
内容如下:
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
80
81
82
83
84
85
86
| :root {
--nav-width: 1380px;
--article-width: 650px;
--toc-width: 300px;
}
.toc {
margin: 0 2px 40px 2px;
border: 1px solid var(--border);
background: var(--entry);
border-radius: var(--radius);
padding: 0.4em;
}
.toc-container.wide {
position: absolute;
height: 100%;
border-right: 1px solid var(--border);
left: calc((var(--toc-width) + var(--gap)) * -1);
top: calc(var(--gap) * 2);
width: var(--toc-width);
}
.wide .toc {
position: sticky;
top: var(--gap);
border: unset;
background: unset;
border-radius: unset;
width: 100%;
margin: 0 2px 40px 2px;
}
.toc details summary {
cursor: zoom-in;
margin-inline-start: 20px;
padding: 12px 0;
}
.toc details[open] summary {
font-weight: 500;
}
.toc-container.wide .toc .inner {
margin: 0;
}
.active {
font-size: 110%;
font-weight: 600;
}
.toc ul {
list-style-type: circle;
}
.toc .inner {
margin: 0 0 0 20px;
padding: 0px 15px 15px 20px;
font-size: 16px;
/*目录显示高度*/
max-height: 83vh;
overflow-y: auto;
}
.toc .inner::-webkit-scrollbar-thumb { /*滚动条*/
background: var(--border);
border: 7px solid var(--theme);
border-radius: var(--radius);
}
.toc li ul {
margin-inline-start: calc(var(--gap) * 0.5);
list-style-type: none;
}
.toc li {
list-style: none;
font-size: 0.95rem;
padding-bottom: 5px;
}
.toc li a:hover {
color: var(--secondary);
}
|
3.7 新标签打开链接
参考👉
设置以新标签打开链接 - Dvel’s Blog
创建 ../layouts/_default/_markup/render-link.html
文件,内容如下:
1
| <a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="noopener"{{ end }}>{{ .Text | safeHTML }}</a>
|
该方法自动为所有文章内的链接加上了 target="_blank" rel="noopener"
。
但是站内链接也都加上了 target="_blank" rel="noopener"
。
站内链接建议写 path:
1
2
3
| [title](/foo/bar/)
↓ 会被简单解析为: ↓
<a href="/foo/bar/">title</a>
|
3.8 Waline 评论系统
参考👉
使用自建 Waline | Razeen`s Blog
1、在站点配置文件 config.yml
中启用评论功能,如下:
1
2
3
| params:
# ...
comments: true # 评论功能
|
2、复制主题目录 ../themes/PaperMod/layouts/partials/comments.html
文件,粘贴到站点根目录 ../layouts/partials/
下。
3、编辑 comments.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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
| {{- /* Comments area start */ -}}
{{- /* to add comments read => https://gohugo.io/content-management/comments/ */ -}}
<head>
<!-- ... -->
<link
rel="stylesheet"
href="https://unpkg.com/@waline/client@v3/dist/waline.css"
/>
<!-- ... -->
</head>
<body>
<!-- ... -->
<div id="waline"></div>
<script type="module">
import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
const locale = {
nick: '昵称',
nickError: '请填写昵称',
mail: '邮箱',
mailError: '请填写正确的邮件地址',
link: '网址',
optional: '可选',
placeholder: '仅填写昵称即可发表回复。\n填写邮箱可收到回复提醒。\n评论区支持 Markdown 语法及预览。\n',
sofa: '来发评论吧~',
submit: '提交',
like: '喜欢',
cancelLike: '取消喜欢',
reply: '回复',
cancelReply: '取消回复',
comment: '评论',
refresh: '刷新',
more: '加载更多...',
preview: '预览',
emoji: '表情',
uploadImage: '上传图片',
seconds: '秒前',
minutes: '分钟前',
hours: '小时前',
days: '天前',
now: '刚刚',
uploading: '正在上传',
login: '登录',
logout: '退出',
admin: '博主',
sticky: '置顶',
word: '字',
wordHint: '评论字数应在 $0 到 $1 字之间!\n当前字数:$2',
anonymous: '匿名',
level0: '潜水',
level1: '冒泡',
level2: '吐槽',
level3: '活跃',
level4: '话痨',
level5: '传说',
gif: '表情包',
gifSearchPlaceholder: '搜索表情包',
profile: '个人资料',
approved: '通过',
waiting: '待审核',
spam: '垃圾',
unsticky: '取消置顶',
oldest: '按倒序',
latest: '按正序',
hottest: '按热度',
reactionTitle: '你认为这篇文章怎么样?',
};
init({
el: '#waline',
serverURL: 'https://waline.example.com',
locale,
wordLimit: 500, //评论字数限制
// emoji: false, // 表情
emoji: [
'//unpkg.com/@waline/emojis@1.2.0/qq',
'//unpkg.com/@waline/emojis@1.2.0/weibo',
'//unpkg.com/@waline/emojis@1.2.0/bmoji',
],
search: false, // GIF 表情包
reaction: false, // 文章反应
requiredMeta: ['nick'],
pageSize: 10,
imageUploader: false,
copyright: true,
pageview: true,
like: false,
dark: 'html[class="body.dark"]',
});
</script>
</body>
{{- /* Comments area end */ -}}
|
4、暗黑模式适配(参考👉
CSS 变量 | Waline
)。站点目录下创建 ../assets/css/extended/comments.css
文件,内容如下:
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
| /* 日间模式 */
#waline {
/* 字体大小 */
--waline-font-size: 18px;
/* 常规颜色 */
--waline-white: #fff;
--waline-light-grey: #999;
--waline-dark-grey: #666;
/* 主题色 */
--waline-theme-color: #27ae60;
--waline-active-color: #2ecc71;
/* 布局颜色 */
--waline-color: #444;
--waline-bg-color: #fff;
--waline-bg-color-light: #f8f8f8;
--waline-bg-color-hover: #f0f0f0;
--waline-border-color: #ddd;
--waline-disable-bg-color: #f8f8f8;
--waline-disable-color: #bbb;
--waline-code-bg-color: #282c34;
/* 特殊颜色 */
--waline-bq-color: #f0f0f0;
/* 头像 */
--waline-avatar-size: 3.25rem;
--waline-m-avatar-size: calc(var(--waline-avatar-size) * 9 / 13);
/* 徽章 */
--waline-badge-color: #3498db;
--waline-badge-font-size: 0.775em;
/* 信息 */
--waline-info-bg-color: #f8f8f8;
--waline-info-color: #999;
--waline-info-font-size: 0.625em;
/* 渲染选择 */
--waline-border: 1px solid var(--waline-border-color);
--waline-avatar-radius: 50%;
--waline-box-shadow: none;
}
/* 暗黑模式 */
body.dark #waline {
/* 常规颜色 */
--waline-white: #000; /* 这是用于表示白色的CSS变量, 在暗模式下,白色将变为黑色*/
--waline-light-grey: #666; /* 浅灰色的CSS变量, 在暗模式下,变为深灰色 */
--waline-dark-grey: #999; /* 示深灰色, 在暗模式下,变为浅灰色 */
/* 布局颜色 */
--waline-color: #9B9C9D; /* 一般文本颜色 */
--waline-bg-color: #1D1E20; /* 背景颜色 */
--waline-bg-color-light: #272727; /* 较浅的背景颜色 */
--waline-border-color: #9B9C9D; /* 边框颜色 */
--waline-disable-bg-color: #444; /* 禁用状态的背景颜色 */
--waline-disable-color: #272727; /* 禁用状态的文本颜色 */
/* 特殊颜色 */
--waline-bq-color: #272727; /* 引用块颜色 */
/* 其他颜色 */
--waline-info-bg-color: #272727; /* 信息块背景颜色 */
--waline-info-color: #666; /* 信息块字体颜色 */
}
|
3.9 版权声明
参考👉
PaperMod 添加文章版权声明 | Tofuwine’s Blog
3.9.1 版权页面
站点目录下创建 ../layouts/partials/copyright.html
文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <div class="pe-copyright">
<img src="/imgs/cc/cc.svg" width="75" height="75" align="right" />
<!-- <hr> -->
<blockquote>
{{ if .Param "reposted" }}
<p><strong>本文为转载内容,原文信息如下:</strong></p>
<p><strong>原文标题:</strong>{{- .Param "repostedTitle" -}}</p>
<p><strong>原文作者:</strong>{{- .Param "repostedAuthor" -}}</p>
<p><strong>原文链接:</strong><a href="{{- .Param "repostedLink" -}}" target="_blank">{{- .Param "repostedLink" -}}</a></p>
<p><strong>版权声明:</strong>如有侵权,请<a href="mailto://{{ .Param "contactEmail" }}">联系本站</a>删除。</p>
{{ else }}
<p><strong>文章标题:</strong>{{ .Title }}</p>
<p><strong>本文作者:</strong>{{ .Param "author" }}</p>
<p><strong>本文链接:</strong><a href="{{ .Permalink }}" target="_blank">{{ .Permalink }}</a></p>
<p><strong>版权声明:</strong>本网站所有文章除特别声明外,均采用 <a href="{{- .Param "licenseLink" -}}" target="_blank">{{- .Param "licenseName" -}}</a> 许可协议。转载请注明出处!</p>
{{ end }}
</blockquote>
</div>
|
📌 说明:
本示例版权水印文件存放路径 ../static/imgs/cc/cc.svg
3.9.2 添加样式
在站点目录下创建 ../assets/css/extended/copyright.css
文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| .pe-copyright {
margin-top: 50px; /* 上边距 */
font-size: 14px;
border: 3px solid #4A4A4A;
}
.pe-copyright hr {
border-style: dashed;
color: #e26c56;
}
.pe-copyright blockquote {
margin: 10px 0; /* 外边距:上下边距为 10px,左右为 0 */
padding: 10px 10px; /* 内边距:上下边距为 20px,左右为 10px */
}
.pe-copyright a {
box-shadow: 0 1px;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
}
|
3.9.3 加入文章页
将 PaperMod 主题目录下 ../themes/PaperMod/layouts/_default/single.html
文件复制到站点目录 ../layouts/_default/single.html
,编辑 single.html
文件,在 footer
节点上添加如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <article class="post-single">
{{- if .Content }}
<div class="post-content">
...
</div>
{{- end }}
<!-- 加入版权声明 -->
{{ if .Param "enableCopyright" }}
{{ partial "copyright.html" . }}
{{ end }}
<footer class="post-footer">
...
</footer>
</article>
|
3.9.4 启用版权声明
在站点配置文件 config.yml
中加入以下配置:
1
2
3
| params:
# ...
enableCopyright: true # 启用版权声明
|
3.9.4.1 原创文章
原创文章需在文章 frontmatter
中添加以下参数:(以下仅为示例,请根据实际自行修改)
1
2
3
4
5
| ---
author: <Author>
licenseLink: "https://creativecommons.org/licenses/by-nc/4.0/"
licenseName: "CC BY-NC 4.0"
---
|
也可直接在站点配置文件 config.yml
中加入以下配置:
1
2
3
4
5
6
| params:
# ...
author: <Author>
licenseLink: "https://creativecommons.org/licenses/by-nc/4.0/deed.zh-hans"
licenseName: "CC BY-NC-SA"
contactEmail: <userName@example.com>
|
其中 author
为 Hugo-PaperMod 已有参数。
3.9.4.2 转载文章
转载文章需在文章 frontmatter
中添加以下参数:
1
2
3
4
5
6
7
| ---
reposted: true
repostedTitle: "修改为原文章标题"
repostedAuthor: "修改为原文章作者名"
repostedLink: "修改为原文章链接"
contactEmail: your email
---
|
其中 contactEmail
参数可在 hugo 配置中指定全局默认值:
1
2
3
| params:
# ...
contactEmail: <Your Email>
|
3.10 代码块优化
参考👉
Hugo以及PaperMod主题的配置 | 似水
3.10.1 代码块高亮
修改站点配置文件 config.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
25
26
27
28
29
30
31
| params:
# ...
assets:
disableHLJS: true # to disable highlight.js
# Read: https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#using-hugos-syntax-highlighter-chroma
pygmentsUseClasses: false
markup:
goldmark:
renderer:
unsafe: true
highlight:
noClasses: true
anchorLineNos: false
codeFences: true
guessSyntax: true
lineNos: true
style: monokai
lineNumbersInTable: false
# 参数说明:https://gohugo.io/functions/transform/highlight/
# lineNos:是否在每行开头显示数字。 默认为 false
# hl_Lines:以空格分隔的列表,用于强调高亮代码中的行。 要强调第 2、3、4 和 7 行,请将该值设为 2-4 7。 该选项独立于行无起始选项。
# lineNoStart=1:第一行开头要显示的数字。 如果 lineNos 为 false 则与此无关。 默认值为 1
# anchorLineNos:是否将每个行号渲染为 HTML 锚点元素,并将周围 span 元素的 id 属性设置为行号。 如果 lineNos 为 false,则与此无关。 默认为 false
# lineAnchors:在将行号作为 HTML 锚点元素呈现时,将此值预置到周围 span 元素的 id 属性中。 当页面包含两个或多个代码块时,这将提供唯一的 id 属性。 如果 lineNos 或 anchorLineNos 为 false,则与此无关。
# hl_inline:是否在没有包装容器的情况下渲染突出显示的代码。默认为 false
# codeFences:是否高亮显示有栅栏的代码块。 默认为 true
# guessSyntax:如果 LANG 参数为空或设置为没有相应词法的语言,是否自动检测语言。 如果无法自动检测语言,则退回到纯文本词法。 默认为 false
# lineNumbersInTable:是否在 HTML 表格的两个单元格中显示高亮显示的代码。 左侧表格单元格包含行号,右侧表格单元格包含代码。 如果 lineNos 为 false 则无关。 默认为 true
# noClasses:是否使用内联 CSS 样式而不是外部 CSS 文件。 要使用外部 CSS 文件,请将此值设为 false,并使用 hugo gen chromastyles 命令生成 CSS 文件。 默认值为 true
|
3.10.2 代码块展开/折叠
1、复制主题目录 ../themes/PaperMod/layouts/partials/footer.html
文件,粘贴到站点根目录 ../layouts/partials/
下。 编辑 footer.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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
| {{- if not (.Param "hideFooter") }}
<footer class="footer">
{{- if not site.Params.footer.hideCopyright }}
{{- if site.Copyright }}
<span>{{ site.Copyright | markdownify }}</span>
{{- else }}
<span>© {{ now.Year }} <a href="{{ "" | absLangURL }}">{{ site.Title }}</a></span>
{{- end }}
{{- print " · "}}
{{- end }}
{{- with site.Params.footer.text }}
{{ . | markdownify }}
{{- print " · "}}
{{- end }}
<span>
Powered by
<a href="https://gohugo.io/" rel="noopener noreferrer" target="_blank">Hugo</a> &
<a href="https://github.com/adityatelange/hugo-PaperMod/" rel="noopener" target="_blank">PaperMod</a>
</span>
</footer>
{{- end }}
{{- if (not site.Params.disableScrollToTop) }}
<a href="#top" aria-label="go to top" title="Go to Top (Alt + G)" class="top-link" id="top-link" accesskey="g">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentColor">
<path d="M12 6H0l6-6z" />
</svg>
</a>
{{- end }}
{{- partial "extend_footer.html" . }}
<script>
let menu = document.getElementById('menu')
if (menu) {
menu.scrollLeft = localStorage.getItem("menu-scroll-position");
menu.onscroll = function () {
localStorage.setItem("menu-scroll-position", menu.scrollLeft);
}
}
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener("click", function (e) {
e.preventDefault();
var id = this.getAttribute("href").substr(1);
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({
behavior: "smooth"
});
} else {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();
}
if (id === "top") {
history.replaceState(null, null, " ");
} else {
history.pushState(null, null, `#${id}`);
}
});
});
</script>
{{- if (not site.Params.disableScrollToTop) }}
<script>
var mybutton = document.getElementById("top-link");
window.onscroll = function () {
if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {
mybutton.style.visibility = "visible";
mybutton.style.opacity = "1";
} else {
mybutton.style.visibility = "hidden";
mybutton.style.opacity = "0";
}
};
</script>
{{- end }}
{{- if (not site.Params.disableThemeToggle) }}
<script>
document.getElementById("theme-toggle").addEventListener("click", () => {
if (document.body.className.includes("dark")) {
document.body.classList.remove('dark');
localStorage.setItem("pref-theme", 'light');
} else {
document.body.classList.add('dark');
localStorage.setItem("pref-theme", 'dark');
}
})
</script>
{{- end }}
{{- if (and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") (.Param "ShowCodeCopyButtons")) }}
<script>
document.querySelectorAll('pre > code').forEach((codeblock) => {
const container = codeblock.parentNode.parentNode;
const copybutton = document.createElement('button');
copybutton.classList.add('copy-code');
copybutton.innerHTML = '{{- i18n "code_copy" | default "copy" }}';
function copyingDone() {
copybutton.innerHTML = '{{- i18n "code_copied" | default "copied!" }}';
setTimeout(() => {
copybutton.innerHTML = '{{- i18n "code_copy" | default "copy" }}';
}, 2000);
}
copybutton.addEventListener('click', (cb) => {
if ('clipboard' in navigator) {
// 不包含样式的span的内容拼接起来,也是代码块的内容
let x = codeblock.getElementsByTagName("span");
let noLineNumContent = "";
for (i = 0; i < x.length; i++) {
if (x[i].style.display || x[i].style.color);
else noLineNumContent += x[i].textContent;
}
navigator.clipboard.writeText(noLineNumContent);
copyingDone();
return;
}
const range = document.createRange();
range.selectNodeContents(codeblock);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('copy');
copyingDone();
} catch (e) { };
selection.removeRange(range);
});
if (container.classList.contains("highlight")) {
container.appendChild(copybutton);
} else if (container.parentNode.firstChild == container) {
// td containing LineNos
} else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
// table containing LineNos and code
codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
} else {
// code blocks not having highlight as parent class
codeblock.parentNode.appendChild(copybutton);
}
});
</script>
<script>
document.querySelectorAll('pre > code').forEach((codeblock) => {
const container = codeblock.parentNode.parentNode;
const unfoldbtn = document.createElement('button');
unfoldbtn.classList.add('unfoldbtn');
unfoldbtn.innerHTML = '展开';
unfoldbtn.addEventListener('click', (cb) => {
if (container.firstChild.firstChild.classList.contains('unfold')) {
container.firstChild.firstChild.classList.remove('unfold');
unfoldbtn.innerHTML = '展开';
} else {
container.firstChild.firstChild.classList.add('unfold');
unfoldbtn.innerHTML = '折叠';
}
});
if (container.classList.contains("highlight")) {
container.appendChild(unfoldbtn);
}
});
</script>
{{- end }}
|
2、复制主题目录 ../themes/PaperMod/assets/css/extended/blank.css
文件,粘贴到站点根目录 ../assets/css/extended/
下。 编辑 blank.css
,内容如下:
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
| /*
This is just a placeholder blank stylesheet so as to support adding custom styles budled with theme's default styles
Read https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#bundling-custom-css-with-themes-assets for more info
*/
.highlight:hover {
.unfoldbtn {
display: block;
}
}
.unfoldbtn {
display: none;
position: absolute;
top: 4px;
right: 18px;
color: rgba(255, 255, 255, .8);
background: rgba(78, 78, 78, .8);
border-radius: var(--radius);
padding: 0 5px;
font-size: 14px;
user-select: none;
}
code {
max-height: 13rem;
}
.unfold {
max-height: none;
}
.copy-code {
right: 58px;
}
|
3.11 查看原图
参考👉
Hugo 主题配置 | 夜云泊
1、修改站点配置文件 config.yml
,如下:
1
2
3
4
| params:
# ...
# User-defined parameters
fancybox: true # 启用图片放大功能
|
2、创建 ../layouts/_default/_markup/render-image.html
文件,内容如下:
1
2
3
4
5
6
7
| {{if .Page.Site.Params.fancybox }}
<div class="post-img-view">
<a data-fancybox="gallery" href="{{ .Destination | safeURL }}">
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}"{{ end }} />
</a>
</div>
{{ end }}
|
3、编辑 ../layouts/partials/footer.html
文件,加入以下内容:
1
2
3
4
5
| {{if .Page.Site.Params.fancybox }}
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
<script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>
{{ end }}
|
3.12 数学公式
参考👉
在Hugo PaperMod主题中加入数学支持的最简方式 - 微控圈(MCU Loop)
1、在站点目录下创建 ../layouts/partials/math.html
文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.2/dist/katex.min.css" integrity="sha384-bYdxxUwYipFNohQlHt0bjN/LCpueqWz13HufFEV1SUatKs1cm4L6fFgCi1jT643X" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.2/dist/katex.min.js" integrity="sha384-Qsn9KnoKISj6dI8g7p1HBlNpVx0I8p1SvlwOldgi3IorMle61nQy4zEahWYtljaz" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.2/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// customised options
// • auto-render specific keys, e.g.:
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
// • rendering keys, e.g.:
throwOnError : false
});
});
</script>
|
2、复制主题目录 ../themes/PaperMod/layouts/partials/extend_head.html
文件,粘贴到站点根目录 ../layouts/partials/
下。 编辑 extend_head.html
,内容如下:
1
2
3
4
5
6
7
| {{- /* Head custom content area start */ -}}
{{- /* Insert any custom code (web-analytics, resources, etc.) - it will appear in the <head></head> section of every page. */ -}}
{{- /* Can be overwritten by partial with the same name in the global layouts. */ -}}
{{ if or .Params.math .Site.Params.math }}
{{ partial "math.html" . }}
{{ end }}
{{- /* Head custom content area end */ -}}
|
3、通过在文章 front matter 中设置 math
属性 true/false
来按需加载数学公式资源。
1
2
3
4
5
6
| ---
title: 文章标题
date:
tags:
math: true
---
|
3.13 其它配置
3.13.1 不显示面包屑
在站点配置文件 config.yml
中关闭,如下:
1
2
3
| params:
# ...
ShowBreadCrumbs: false
|
3.13.2 日期格式化
修改站点配置文件 config.yml
,如下:
1
2
3
4
| params:
# ...
DateFormat: "2006-01-02" # 日期格式化
ShowFullTextinRSS: true # RSS 输出全文
|
3.13.3 修改文章作者
修改站点配置文件 config.yml
,如下:
1
2
3
| params:
# ...
author: <YourName>
|
3.13.4 表格优化
参考👉
折腾 Hugo & PaperMod 主题 - Dvel’s Blog
编辑 ../assets/css/extended/blank.css
文件,添加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* GitHub 样式的表格 */
.post-content table tr {
border: 1px solid #979da3 !important;
}
.post-content table tr:nth-child(2n),
.post-content thead {
background-color: var(--code-bg);
}
.post-content table th {
border: 1px solid #979da3 !important;
}
.post-content table td {
border: 1px solid #979da3 !important;
}
|
IV. 参考文档
田少晗的个人博客
周鑫的个人博客
似水
夜云泊
3rd’s Blog
Dvel’s Blog
Tofuwine’s Blog
微控圈(MCU Loop)