前言

之前四五年的时间里也算写过五六百篇博客。以前的 Hexo 顶不住博客数量的压力了,所以,切到 Hugo 试一下。

涉及工具

除了搭建博客和介绍如何使用这个博客框架这样一个流程本身,还包含了对 PaperMod 这个主题的一些细节的定制。

本文涉及到的工具或者网站:

为什么

这里主要解释一下为什么要选择这样一个组合。

  • 选择 hugo 纯粹是因为快。
  • 选择 PaperMod 这个主题是因为它的 star 数量挺高的,不过,比起 hexo 的主题生态还是差得太远了,文档也相当简陋。不过,没办法,这已经算是最好的一档了。
  • 博客选择托管在 github pages 上面是因为稳定,而且没有限制,基本上没有内容审查。我之前也使用 hexo 配合 github 搭建过静态博客,之前写过大概几百篇博客,从来没有遇到过内容审查,当然,也从来没有想过写一些很敏感的东西。
  • 图床选择的是 postiamge,这个是免费的,类似的还有 imgur,但是 imgur 的图片加载速度在一些地方实在是堪忧甚至经常加载不出来,只好换上另一个有很多年头的网站了,正因为年纪大,所以给人的感觉是稳定。
  • 评论使用 giscus 是因为快,因为也是使用 github 的服务,利用的是 github discussion,所以,比 discus 之类的小厂要快。稳定性倒是差不多。以及,github 的用户是比较多的,所以会更方便大家评论交流,这一点很重要。
  • neovim/vscode 是用来编辑配置用的,编辑工具/IDE这一点见仁见智。
  • git 不用多说了。
  • flaticon 是用来挑选网站的 favicon 的。

总结一下,就是几个词儿:免费、快、稳。

安装

首先,安装 hugo,在 Windows 中,推荐使用 scoop 来安装预编译的二进制版本,

1scoop install hugo-extended

安装完之后,执行命令看一下版本信息,

1hugo version

看到类似下面的输出,就说明安装成功了,

使用

创建博客

然后,我们就使用 hugo 在本地创建一个站点,也就是一个博客,

按:这里可以参考 hugo 官网的指导。

1hugo new site SonnyCalcr

然后,

1cd SonnyCalcr
2tree . /f

可以看到默认创建的一些文件和目录,

然后,我们先将此目录初始化成 git 仓库,

1git init
2git add .
3git commit -m "first commit"

添加 PaperMod 主题

1git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod

可以看到,这个命令执行完之后新增的内容,其实就是往 thems 目录下添加了一个主题,而 .gitmodules 则是记录了添加的这个主题的模块的信息,

然后,我们可以再看 PaperMod 这个主题里面都有些什么文件,从下面的命令的输出可以看到,基本上就是一些 html、css 和 js 文件,毕竟是主题嘛,

  1❯ tree .\themes\PaperMod\ /f
  2Folder PATH listing for volume Windows
  3Volume serial number is B867-6B94
  4C:\HDISK\HUGO\SONNYCALCR\THEMES\PAPERMOD
  5│   go.mod
  6│   LICENSE
  7│   README.md
  8│   theme.toml
  9│
 10├───.github
 11│   │   PULL_REQUEST_TEMPLATE.md
 12│   │
 13│   ├───ISSUE_TEMPLATE
 14│   │       bug_report.md
 15│   │       config.yml
 16│   │       proposal.md
 17│   │
 18│   └───workflows
 19│           gh-pages.yml
 20│
 21├───assets
 22│   ├───css
 23│   │   ├───common
 24│   │   │       404.css
 25│   │   │       archive.css
 26│   │   │       footer.css
 27│   │   │       header.css
 28│   │   │       main.css
 29│   │   │       post-entry.css
 30│   │   │       post-single.css
 31│   │   │       profile-mode.css
 32│   │   │       search.css
 33│   │   │       terms.css
 34│   │   │
 35│   │   ├───core
 36│   │   │       license.css
 37│   │   │       reset.css
 38│   │   │       theme-vars.css
 39│   │   │       zmedia.css
 40│   │   │
 41│   │   ├───extended
 42│   │   │       blank.css
 43│   │   │
 44│   │   └───includes
 45│   │           chroma-mod.css
 46│   │           chroma-styles.css
 47│   │           scroll-bar.css
 48│   │
 49│   └───js
 50│           fastsearch.js
 51│           fuse.basic.min.js
 52│           license.js
 53│
 54├───i18n
 55│       ar.yaml
 56│       be.yaml
 57│       bg.yaml
 58│       bn.yaml
 59│       ca.yaml
 60│       ckb.yaml
 61│       cs.yaml
 62│       da.yaml
 63│       de.yaml
 64│       el.yaml
 65│       en.yaml
 66│       eo.yaml
 67│       es.yaml
 68│       fa.yaml
 69│       fr.yaml
 70│       he.yaml
 71│       hi.yaml
 72│       hr.yaml
 73│       hu.yaml
 74│       id.yaml
 75│       it.yaml
 76│       ja.yaml
 77│       ko.yaml
 78│       ku.yaml
 79│       mn.yaml
 80│       ms.yaml
 81│       nl.yaml
 82│       no.yaml
 83│       oc.yaml
 84│       pa.yaml
 85│       pl.yaml
 86│       pnb.yaml
 87│       pt.yaml
 88│       ro.yaml
 89│       ru.yaml
 90│       sk.yaml
 91│       sv.yaml
 92│       sw.yaml
 93│       th.yaml
 94│       tr.yaml
 95│       uk.yaml
 96│       uz.yaml
 97│       vi.yaml
 98│       zh-tw.yaml
 99│       zh.yaml
100│
101├───images
102│       screenshot.png
103│       tn.png
104│
105└───layouts
106    │   404.html
107    │   robots.txt
108    │
109    ├───partials
110    │   │   anchored_headings.html
111    │   │   author.html
112    │   │   breadcrumbs.html
113    │   │   comments.html
114    │   │   cover.html
115    │   │   edit_post.html
116    │   │   extend_footer.html
117    │   │   extend_head.html
118    │   │   footer.html
119    │   │   head.html
120    │   │   header.html
121    │   │   home_info.html
122    │   │   index_profile.html
123    │   │   post_canonical.html
124    │   │   post_meta.html
125    │   │   post_nav_links.html
126    │   │   share_icons.html
127    │   │   social_icons.html
128    │   │   svg.html
129    │   │   toc.html
130    │   │   translation_list.html
131    │   │
132    │   └───templates
133    │       │   opengraph.html
134    │       │   schema_json.html
135    │       │   twitter_cards.html
136    │       │
137    │       └───_funcs
138    │               get-page-images.html
139    │
140    ├───shortcodes
141    │       collapse.html
142    │       figure.html
143    │       inTextImg.html
144    │       ltr.html
145    │       rawhtml.html
146    │       rtl.html
147    │
148    └───_default
149        │   archives.html
150        │   baseof.html
151        │   index.json
152        │   list.html
153        │   rss.xml
154        │   search.html
155        │   single.html
156        │   terms.html
157        │
158        └───_markup
159                render-image.html

然后,可以添加一下 .gitignore 文件,我这里就直接照抄 PaperMod 的作者部署的那个网站的文件了,

 1# Compiled Object files, Static and Dynamic libs (Shared Objects)
 2*.o
 3*.a
 4*.so
 5
 6# Folders
 7_obj
 8_test
 9
10# Architecture specific extensions/prefixes
11*.[568vq]
12[568vq].out
13
14*.cgo1.go
15*.cgo2.c
16_cgo_defun.c
17_cgo_gotypes.go
18_cgo_export.*
19
20_testmain.go
21
22*.exe
23*.test
24
25/public
26.DS_Store
27.hugo_build.lock
28resources/_gen/

其实这里主要就是把 public 目录给排除掉,这个会在网页部署的时候自动生成。

接下来就是正式的主题配置了。

配置 PaperMod 主题

配置好之后相较于默认效果的一些改进

  1. 支持 giscus 进行评论,且主题支持明暗切换。
  2. 支持 mathjax,但是如果数学块公式中有超过三个花括号,那么,需要将整个数学公式包括外围的 $$ 符号都用 div 标签包裹起来。
  3. 代码字体自定义为 Jetbrains Mono。代码的亮色主题为 tokyo-night-light,暗色主题为 github-dark。
  4. 移动端隐藏返回顶部的按钮。
  5. 一些自定义 css 的效果,如字体大小、链接颜色、目录上的悬浮的鼠标图标等等。

主要就是上面几点,因为文档写得不详细,所以配置上面的内容花费了一些时间和工夫。

一些基本信息的配置

首先,把博客根目录下的 hugo.toml 文件改成 hugo.yaml,因为 PaperMod 给出的配置文件就是 yaml 格式的,所以,这里改一下文件格式,就省去了我们再去将 yaml 的配置内容转为 toml 的麻烦,

1Rename-Item .\hugo.toml hugo.yaml

然后,配置一下基本信息,基本上每一个选项我都打上了注释,

 1baseURL: "https://sonnycalcr.github.io/" # 主站的 URL
 2title: SonnyCalcr's Blog # 站点标题
 3copyright: "[©2024 SonnyCalcr's Blog](https://sonnycalcr.github.io/)" # 网站的版权声明,通常显示在页脚
 4theme: PaperMod # 主题
 5languageCode: zh-cn # 语言
 6
 7enableInlineShortcodes: true # shortcode,类似于模板变量,可以在写 markdown 的时候便捷地插入,官方文档中有一个视频讲的很通俗
 8hasCJKLanguage: true # 是否有 CJK 的字符
 9enableRobotsTXT: true # 允许生成 robots.txt
10buildDrafts: false # 构建时是否包括草稿
11buildFuture: false # 构建未来发布的内容
12buildExpired: false # 构建过期的内容
13enableEmoji: true # 允许 emoji
14pygmentsUseClasses: true
15defaultContentLanguage: zh # 顶部首先展示的语言界面
16defaultContentLanguageInSubdir: false # 是否要在地址栏加上默认的语言代码

配置导航栏

 1languages:
 2  zh:
 3    languageName: "中文" # 展示的语言名
 4    weight: 1 # 权重
 5    taxonomies: # 分类系统
 6      category: categories
 7      tag: tags
 8    # https://gohugo.io/content-management/menus/#define-in-site-configuration
 9    menus:
10      main:
11        - name: 首页
12          pageRef: /
13          weight: 4 # 控制在页面上展示的前后顺序
14        - name: 归档
15          pageRef: archives/
16          weight: 5
17        - name: 分类
18          pageRef: categories/
19          weight: 10
20        - name: 标签
21          pageRef: tags/
22          weight: 10
23        - name: 搜索
24          pageRef: search/
25          weight: 20
26        - name: 关于
27          pageRef: about/
28          weight: 21

配置归档

在 content 目录下新建 archives.md 文件,内容如下,

1---
2title: "归档"
3layout: "archives"
4url: "/archives/"
5summary: archives
6---

配置分类和标签

在 hugo 中,这俩是一样的。上面配置好了 taxonomies 之后,我们在博客的 front matter 中加上相关信息即可,就拿本篇博客举例,

1title = 'Hugo + PaperMod + Github Pages 搭建一个完善的个人博客(以 Windows11 为例)'
2date = 2024-08-04T03:25:53+08:00
3categories = ["通用技术"]
4tags = ["博客搭建", "Bilibili"]

然后执行一下 hugo server 就可以在浏览器中预览一下效果了。

配置搜索

要在 output 中加上 JSON,

1# https://github.com/adityatelange/hugo-PaperMod/wiki/Features#search-page
2outputs:
3  home:
4    - HTML # 生成的静态页面
5    - RSS # 这个其实无所谓
6    - JSON # necessary for search, 这里的配置修改好之后,一定要重新生成一下

然后,在 content 目录下新建一个 search.md 文件,

1---
2title: "搜索" # in any language you want
3layout: "search" # necessary for search
4summary: "search"
5placeholder: "搜索"
6---

然后是搜索的一些个性化设置,

 1params:
 2  # 搜索
 3  fuseOpts:
 4      isCaseSensitive: false # 是否大小写敏感
 5      shouldSort: true # 是否排序
 6      location: 0
 7      distance: 1000
 8      threshold: 0.4
 9      minMatchCharLength: 0
10      # limit: 10 # refer: https://www.fusejs.io/api/methods.html#search
11      keys: ["title", "permalink", "summary", "content"]
12      includeMatches: true

这样以来,搜索就可以正常工作了,

配置关于页面

新建两个文件,一个是 layouts\_default 目录下下的 about.html,

 1{{- define "main" }}
 2 
 3<header class="page-header">
 4    <h1>{{ .Title }}</h1>
 5    {{- if .Description }}
 6    <div class="post-description">
 7      {{ .Description }}
 8    </div>
 9    {{- end }}
10  </header>
11 
12<section>
13  <br>
14  {{ .Content }}
15</section>
16 
17{{- end }}{{/* end main */}}

另一个是 content 目录下的 about.md,

1---
2title: "关于"
3layout: "about"
4url: "/about/"
5summary: about
6---
7
8这里就可以写一些关于的相关信息了。

配置评论

这里的评论使用了 giscus 插件。

先在 layouts\partials 下新建一个 comments.html 文件,

 1<div id="tw-comment"></div>
 2<script>
 3    // 默认是暗色,根目录下的配置中的主题默认也是暗色
 4    const getStoredTheme = () => localStorage.getItem("pref-theme") === "light" ? "{{ .Site.Params.giscus.lightTheme }}" : "{{ .Site.Params.giscus.darkTheme }}";
 5    const setGiscusTheme = () => {
 6        const sendMessage = (message) => {
 7            const iframe = document.querySelector('iframe.giscus-frame');
 8            if (iframe) {
 9                iframe.contentWindow.postMessage({giscus: message}, 'https://giscus.app');
10            }
11        }
12        sendMessage({setConfig: {theme: getStoredTheme()}})
13    }
14
15    document.addEventListener("DOMContentLoaded", () => {
16        const giscusAttributes = {
17            "src": "https://giscus.app/client.js",
18            "data-repo": "{{ .Site.Params.giscus.repo }}",
19            "data-repo-id": "{{ .Site.Params.giscus.repoId }}",
20            "data-category": "{{ .Site.Params.giscus.category }}",
21            "data-category-id": "{{ .Site.Params.giscus.categoryId }}",
22            "data-mapping": "{{ .Site.Params.giscus.mapping }}",
23            "data-strict": "{{ .Site.Params.giscus.strict }}",
24            "data-reactions-enabled": "{{ .Site.Params.giscus.reactionsEnabled }}",
25            "data-emit-metadata": "{{ .Site.Params.giscus.emitMetadata }}",
26            "data-input-position": "{{ .Site.Params.giscus.inputPosition }}",
27            "data-theme": getStoredTheme(),
28            "data-lang": "{{ .Site.Params.giscus.lang }}",
29            "data-loading": "lazy",
30            "crossorigin": "anonymous",
31        };
32
33        // 动态创建 giscus script
34        const giscusScript = document.createElement("script");
35        Object.entries(giscusAttributes).forEach(
36                ([key, value]) => giscusScript.setAttribute(key, value));
37        document.querySelector("#tw-comment").appendChild(giscusScript);
38
39        // 页面主题变更后,变更 giscus 主题
40        const themeSwitcher = document.querySelector("#theme-toggle");
41        if (themeSwitcher) {
42            themeSwitcher.addEventListener("click", setGiscusTheme);
43        }
44        const themeFloatSwitcher = document.querySelector("#theme-toggle-float");
45        if (themeFloatSwitcher) {
46            themeFloatSwitcher.addEventListener("click", setGiscusTheme);
47        }
48    });
49</script>

然后,根据 giscus 官网的指导,最后生成一份代码,

然后,把相应的字段提取到配置中,

 1params:
 2  # 评论的设置
 3  giscus:
 4    repo: "sonnycalcr/sonnycalcr.github.io"
 5    repoId: "xxxxxx"
 6    category: "Announcements"
 7    categoryId: "xxxxx"
 8    mapping: "pathname"
 9    strict: "0"
10    reactionsEnabled: "1"
11    emitMetadata: "0"
12    inputPosition: "bottom"
13    lightTheme: "light"
14    darkTheme: "dark"
15    lang: "zh-CN"
16    crossorigin: "anonymous"

这样就可以正常使用了。

配置数学公式

这里使用的是 mathjax。

我们需要添加两个文件,一个是 layouts\partials 下的 mathjax.html 文件,如下,

 1<script type="text/javascript"
 2        async
 3        src="https://cdn.bootcss.com/mathjax/2.7.3/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
 4MathJax.Hub.Config({
 5  tex2jax: {
 6    inlineMath: [['$','$'], ['\\(','\\)']],
 7    displayMath: [['$$','$$'], ['\[\[','\]\]']],
 8    processEscapes: true,
 9    processEnvironments: true,
10    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
11    TeX: { equationNumbers: { autoNumber: "AMS" },
12         extensions: ["AMSmath.js", "AMSsymbols.js"] }
13  }
14});
15
16MathJax.Hub.Queue(function() {
17    // Fix <code> tags after MathJax finishes running. This is a
18    // hack to overcome a shortcoming of Markdown. Discussion at
19    // https://github.com/mojombo/jekyll/issues/199
20    var all = MathJax.Hub.getAllJax(), i;
21    for(i = 0; i < all.length; i += 1) {
22        all[i].SourceElement().parentNode.className += ' has-jax';
23    }
24});
25</script>
26
27<style>
28code.has-jax {
29    font: inherit;
30    font-size: 100%;
31    background: inherit;
32    border: inherit;
33    color: #515151;
34}
35</style>

另一个是 layouts\partials 下的 extend_head.html 文件,

1{{- /* Head custom content area start */ -}}
2{{- /*     Insert any custom code (web-analytics, resources, etc.) - it will appear in the <head></head> section of every page. */ -}}
3{{- /*     Can be overwritten by partial with the same name in the global layouts. */ -}}
4{{ partial "mathjax.html" . }}
5{{- /* Head custom content area end */ -}}

到这里,数学公式就可以正常使用了,我们来写一点数学公式试一下,

 1行内数学公式:$a^2 + b^2 = c^2$。
 2
 3块公式,
 4
 5$$
 6a^2 + b^2 = c^2
 7$$
 8
 9<div>
10$$
11\boldsymbol{x}_{i+1}+\boldsymbol{x}_{i+2}=\boldsymbol{x}_{i+3}
12$$
13</div>

渲染出来的效果如下,

行内数学公式:$a^2 + b^2 = c^2$。

块公式,

$$ a^2 + b^2 = c^2 $$

$$ \boldsymbol{x}_{i+1}+\boldsymbol{x}_{i+2}=\boldsymbol{x}_{i+3} $$

上面的第二个公式之所以要用 div 包裹起来,是因为这里的数学公式如果有超过了三对花括号,那么,其解析和转义就会出问题,这个和 hugo 有关目前折中的方案就是上面这种在外面套一层 div。

给代码换个字体

先到谷歌字体 中找一款开源字体,我这里选用的是 Jetbrains Mono,然后复制其信息到 layouts\partials\extend_head.html 中,

1<link rel="preconnect" href="https://fonts.googleapis.com">
2<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
3<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet">

然后,新建一个 assets\css\extended\blank.css 文件,添加样式如下,

1.post-content pre,
2code {
3  font-family: "JetBrains Mono", monospace;
4  font-size: 1rem;
5  line-height: 1.2;
6}

这样就可以生效了,如果发现不生效,可以重新执行一下 hugo server 试试。

代码明暗样式切换

我这里使用的不是 highlightjs,而是 hugo 推荐的 chroma,这样的话,我们先建立一个 assets\css\extended\chroma-styles-overrides.css 文件,

然后,执行一下命令生成你想要的样式,

1hugo gen chromastyles --style=tokyonight-day > syntax.css

然后,把 syntax.css 中的内容复制到 chroma-styles-overrides.html 文件中,如果是暗色主题,那么,生成的样式则要包裹在 .dark {} 里面,我这里生成了两个样式,白天的样式是 tokyonight-day,黑暗的样式是 github-dark,同时,要记得将生成的样式中有些空缺的部分给补上默认的颜色,我这里白天的颜色补的是黑色,夜晚的颜色补的是白色,不然代码的样式会出问题,我这里完整的样式如下,

  1/* Background */ .bg { color:#3760bf;background-color:#e1e2e7; }
  2/* PreWrapper */ .chroma { color:#3760bf;background-color:#e1e2e7; }
  3/* Other */ .chroma .x { color: #000 }
  4/* Error */ .chroma .err { color:#c64343 }
  5/* CodeLine */ .chroma .cl { color: #000 }
  6/* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit }
  7/* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; }
  8/* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; }
  9/* LineHighlight */ .chroma .hl { background-color:#a1a6c5 }
 10/* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6172b0 }
 11/* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6172b0 }
 12/* Line */ .chroma .line { display:flex; }
 13/* Keyword */ .chroma .k { color:#9854f1 }
 14/* KeywordConstant */ .chroma .kc { color:#8c6c3e }
 15/* KeywordDeclaration */ .chroma .kd { color:#9d7cd8 }
 16/* KeywordNamespace */ .chroma .kn { color:#007197 }
 17/* KeywordPseudo */ .chroma .kp { color:#9854f1 }
 18/* KeywordReserved */ .chroma .kr { color:#9854f1 }
 19/* KeywordType */ .chroma .kt { color:#0db9d7 }
 20/* Name */ .chroma .n { color: #000 }
 21/* NameAttribute */ .chroma .na { color:#2e7de9 }
 22/* NameBuiltin */ .chroma .nb { color:#587539 }
 23/* NameBuiltinPseudo */ .chroma .bp { color:#587539 }
 24/* NameClass */ .chroma .nc { color:#b15c00 }
 25/* NameConstant */ .chroma .no { color:#b15c00 }
 26/* NameDecorator */ .chroma .nd { color:#2e7de9;font-weight:bold }
 27/* NameEntity */ .chroma .ni { color:#007197 }
 28/* NameException */ .chroma .ne { color:#8c6c3e }
 29/* NameFunction */ .chroma .nf { color:#2e7de9 }
 30/* NameFunctionMagic */ .chroma .fm { color:#2e7de9 }
 31/* NameLabel */ .chroma .nl { color:#587539 }
 32/* NameNamespace */ .chroma .nn { color:#8c6c3e }
 33/* NameOther */ .chroma .nx { color: #000 }
 34/* NameProperty */ .chroma .py { color:#8c6c3e }
 35/* NameTag */ .chroma .nt { color:#9854f1 }
 36/* NameVariable */ .chroma .nv { color: #000 }
 37/* NameVariableClass */ .chroma .vc { color: #000 }
 38/* NameVariableGlobal */ .chroma .vg { color: #000 }
 39/* NameVariableInstance */ .chroma .vi { color: #000 }
 40/* NameVariableMagic */ .chroma .vm { color: #000 }
 41/* Literal */ .chroma .l { color: #000 }
 42/* LiteralDate */ .chroma .ld { color: #000 }
 43/* LiteralString */ .chroma .s { color:#587539 }
 44/* LiteralStringAffix */ .chroma .sa { color:#9d7cd8 }
 45/* LiteralStringBacktick */ .chroma .sb { color:#587539 }
 46/* LiteralStringChar */ .chroma .sc { color:#587539 }
 47/* LiteralStringDelimiter */ .chroma .dl { color:#2e7de9 }
 48/* LiteralStringDoc */ .chroma .sd { color:#a1a6c5 }
 49/* LiteralStringDouble */ .chroma .s2 { color:#587539 }
 50/* LiteralStringEscape */ .chroma .se { color:#2e7de9 }
 51/* LiteralStringHeredoc */ .chroma .sh { color:#a1a6c5 }
 52/* LiteralStringInterpol */ .chroma .si { color:#587539 }
 53/* LiteralStringOther */ .chroma .sx { color:#587539 }
 54/* LiteralStringRegex */ .chroma .sr { color:#007197 }
 55/* LiteralStringSingle */ .chroma .s1 { color:#587539 }
 56/* LiteralStringSymbol */ .chroma .ss { color:#587539 }
 57/* LiteralNumber */ .chroma .m { color:#8c6c3e }
 58/* LiteralNumberBin */ .chroma .mb { color:#8c6c3e }
 59/* LiteralNumberFloat */ .chroma .mf { color:#8c6c3e }
 60/* LiteralNumberHex */ .chroma .mh { color:#8c6c3e }
 61/* LiteralNumberInteger */ .chroma .mi { color:#8c6c3e }
 62/* LiteralNumberIntegerLong */ .chroma .il { color:#8c6c3e }
 63/* LiteralNumberOct */ .chroma .mo { color:#8c6c3e }
 64/* Operator */ .chroma .o { color:#587539;font-weight:bold }
 65/* OperatorWord */ .chroma .ow { color:#587539;font-weight:bold }
 66/* Punctuation */ .chroma .p { color: #000 }
 67/* Comment */ .chroma .c { color:#a1a6c5;font-style:italic }
 68/* CommentHashbang */ .chroma .ch { color:#a1a6c5;font-style:italic }
 69/* CommentMultiline */ .chroma .cm { color:#a1a6c5;font-style:italic }
 70/* CommentSingle */ .chroma .c1 { color:#a1a6c5;font-style:italic }
 71/* CommentSpecial */ .chroma .cs { color:#a1a6c5;font-style:italic }
 72/* CommentPreproc */ .chroma .cp { color:#a1a6c5;font-style:italic }
 73/* CommentPreprocFile */ .chroma .cpf { color:#a1a6c5;font-weight:bold;font-style:italic }
 74/* Generic */ .chroma .g { color: #000 }
 75/* GenericDeleted */ .chroma .gd { color:#c64343;background-color:#e9e9ed }
 76/* GenericEmph */ .chroma .ge { font-style:italic }
 77/* GenericError */ .chroma .gr { color:#c64343 }
 78/* GenericHeading */ .chroma .gh { color:#8c6c3e;font-weight:bold }
 79/* GenericInserted */ .chroma .gi { color:#587539;background-color:#e9e9ed }
 80/* GenericOutput */ .chroma .go { color: #000 }
 81/* GenericPrompt */ .chroma .gp { color: #000 }
 82/* GenericStrong */ .chroma .gs { font-weight:bold }
 83/* GenericSubheading */ .chroma .gu { color:#8c6c3e;font-weight:bold }
 84/* GenericTraceback */ .chroma .gt { color:#c64343 }
 85/* GenericUnderline */ .chroma .gl { text-decoration:underline }
 86/* TextWhitespace */ .chroma .w { color: #000 }
 87
 88.dark {
 89  /* Background */ .bg { color:#e6edf3;background-color:#0d1117; }
 90  /* PreWrapper */ .chroma { color:#e6edf3;background-color:#0d1117; }
 91  /* Other */ .chroma .x { color: #fff }
 92  /* Error */ .chroma .err { color:#f85149 }
 93  /* CodeLine */ .chroma .cl { color: #fff }
 94  /* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit }
 95  /* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; }
 96  /* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; }
 97  /* LineHighlight */ .chroma .hl { background-color:#6e7681 }
 98  /* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679 }
 99  /* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681 }
100  /* Line */ .chroma .line { display:flex; }
101  /* Keyword */ .chroma .k { color:#ff7b72 }
102  /* KeywordConstant */ .chroma .kc { color:#79c0ff }
103  /* KeywordDeclaration */ .chroma .kd { color:#ff7b72 }
104  /* KeywordNamespace */ .chroma .kn { color:#ff7b72 }
105  /* KeywordPseudo */ .chroma .kp { color:#79c0ff }
106  /* KeywordReserved */ .chroma .kr { color:#ff7b72 }
107  /* KeywordType */ .chroma .kt { color:#ff7b72 }
108  /* Name */ .chroma .n { color: #fff }
109  /* NameAttribute */ .chroma .na { color: #fff }
110  /* NameBuiltin */ .chroma .nb { color: #fff }
111  /* NameBuiltinPseudo */ .chroma .bp { color: #fff }
112  /* NameClass */ .chroma .nc { color:#f0883e;font-weight:bold }
113  /* NameConstant */ .chroma .no { color:#79c0ff;font-weight:bold }
114  /* NameDecorator */ .chroma .nd { color:#d2a8ff;font-weight:bold }
115  /* NameEntity */ .chroma .ni { color:#ffa657 }
116  /* NameException */ .chroma .ne { color:#f0883e;font-weight:bold }
117  /* NameFunction */ .chroma .nf { color:#d2a8ff;font-weight:bold }
118  /* NameFunctionMagic */ .chroma .fm { color: #fff }
119  /* NameLabel */ .chroma .nl { color:#79c0ff;font-weight:bold }
120  /* NameNamespace */ .chroma .nn { color:#ff7b72 }
121  /* NameOther */ .chroma .nx { color: #fff }
122  /* NameProperty */ .chroma .py { color:#79c0ff }
123  /* NameTag */ .chroma .nt { color:#7ee787 }
124  /* NameVariable */ .chroma .nv { color:#79c0ff }
125  /* NameVariableClass */ .chroma .vc { color: #fff }
126  /* NameVariableGlobal */ .chroma .vg { color: #fff }
127  /* NameVariableInstance */ .chroma .vi { color: #fff }
128  /* NameVariableMagic */ .chroma .vm { color: #fff }
129  /* Literal */ .chroma .l { color:#a5d6ff }
130  /* LiteralDate */ .chroma .ld { color:#79c0ff }
131  /* LiteralString */ .chroma .s { color:#a5d6ff }
132  /* LiteralStringAffix */ .chroma .sa { color:#79c0ff }
133  /* LiteralStringBacktick */ .chroma .sb { color:#a5d6ff }
134  /* LiteralStringChar */ .chroma .sc { color:#a5d6ff }
135  /* LiteralStringDelimiter */ .chroma .dl { color:#79c0ff }
136  /* LiteralStringDoc */ .chroma .sd { color:#a5d6ff }
137  /* LiteralStringDouble */ .chroma .s2 { color:#a5d6ff }
138  /* LiteralStringEscape */ .chroma .se { color:#79c0ff }
139  /* LiteralStringHeredoc */ .chroma .sh { color:#79c0ff }
140  /* LiteralStringInterpol */ .chroma .si { color:#a5d6ff }
141  /* LiteralStringOther */ .chroma .sx { color:#a5d6ff }
142  /* LiteralStringRegex */ .chroma .sr { color:#79c0ff }
143  /* LiteralStringSingle */ .chroma .s1 { color:#a5d6ff }
144  /* LiteralStringSymbol */ .chroma .ss { color:#a5d6ff }
145  /* LiteralNumber */ .chroma .m { color:#a5d6ff }
146  /* LiteralNumberBin */ .chroma .mb { color:#a5d6ff }
147  /* LiteralNumberFloat */ .chroma .mf { color:#a5d6ff }
148  /* LiteralNumberHex */ .chroma .mh { color:#a5d6ff }
149  /* LiteralNumberInteger */ .chroma .mi { color:#a5d6ff }
150  /* LiteralNumberIntegerLong */ .chroma .il { color:#a5d6ff }
151  /* LiteralNumberOct */ .chroma .mo { color:#a5d6ff }
152  /* Operator */ .chroma .o { color:#ff7b72;font-weight:bold }
153  /* OperatorWord */ .chroma .ow { color:#ff7b72;font-weight:bold }
154  /* Punctuation */ .chroma .p { color: #fff }
155  /* Comment */ .chroma .c { color:#8b949e;font-style:italic }
156  /* CommentHashbang */ .chroma .ch { color:#8b949e;font-style:italic }
157  /* CommentMultiline */ .chroma .cm { color:#8b949e;font-style:italic }
158  /* CommentSingle */ .chroma .c1 { color:#8b949e;font-style:italic }
159  /* CommentSpecial */ .chroma .cs { color:#8b949e;font-weight:bold;font-style:italic }
160  /* CommentPreproc */ .chroma .cp { color:#8b949e;font-weight:bold;font-style:italic }
161  /* CommentPreprocFile */ .chroma .cpf { color:#8b949e;font-weight:bold;font-style:italic }
162  /* Generic */ .chroma .g { color: #fff }
163  /* GenericDeleted */ .chroma .gd { color:#ffa198;background-color:#490202 }
164  /* GenericEmph */ .chroma .ge { font-style:italic }
165  /* GenericError */ .chroma .gr { color:#ffa198 }
166  /* GenericHeading */ .chroma .gh { color:#79c0ff;font-weight:bold }
167  /* GenericInserted */ .chroma .gi { color:#56d364;background-color:#0f5323 }
168  /* GenericOutput */ .chroma .go { color:#8b949e }
169  /* GenericPrompt */ .chroma .gp { color:#8b949e }
170  /* GenericStrong */ .chroma .gs { font-weight:bold }
171  /* GenericSubheading */ .chroma .gu { color:#79c0ff }
172  /* GenericTraceback */ .chroma .gt { color:#ff7b72 }
173  /* GenericUnderline */ .chroma .gl { text-decoration:underline }
174  /* TextWhitespace */ .chroma .w { color:#6e7681 }
175}

我在上面提到的生成的样式中空缺的部分,可以看一下下面的样例,

要记得把他们的颜色都补上。

然后,修改一下配置即可,

 1params:
 2  assets:
 3      disableHLJS: true
 4markup:
 5  goldmark:
 6    renderer:
 7      unsafe: true # 可以 unsafe,有些 html 标签和样式可能需要
 8  highlight:
 9    anchorLineNos: false # 不要给行号设置锚标
10    codeFences: true # 代码围栏
11    noClasses: false # TODO: 不知道干啥的,暂时没必要了解,不影响展示
12    lineNos: true # 代码行
13    lineNumbersInTable: false # 不要设置成 true,否则如果文章开头是代码的话,摘要会由一大堆数字(即代码行号)开头文章
14    # 这里设置 style 没用,得自己加 css
15    # style: "github-dark"
16    # style: monokai

修改网页的 favicon

先到 flaticon 网站中找一个 icon 图片,然后放到 static 目录下,

然后,修改配置,

1params:
2  # 设置网站的标签页的图标,即 favicon
3  assets:
4      favicon: "favicon.png"
5      favicon16x16: "favicon.png"
6      favicon32x32: "favicon.png"
7      apple_touch_icon: "favicon.png"
8      safari_pinned_tab: "favicon.png"

其他一些小的样式修改

这个就直接看我的代码仓库就可以了,修改的基本都是 css,代码都在 assets 目录下,


部署到 Github Pages

这里其实有两种方式,一种是直接建立一个以 username.github.io 为名的 Github 仓库,然后,进行部署,另一种是在此基础上新建一个普通的项目,然后可以挂到 username.github.io 域名的后面。

我们这里就选用简单的第一种比较直接的方式。

新建一个仓库,没有什么好说的,然后把我们当前的这个仓库和远程仓库关联起来,然后推送过去。然后按照 Hugo 的文档指导来操作即可。

对于官方给出的 .github/workflows/hugo.yaml, 把其中的分支名改一下即可,或者同时把其中的 Hugo 的版本信息改成和本地的一致也可以。之后,每次推送就可以看到 Github 在部署了。

一些常用的 Hugo 命令

其实可能只有两个需要我们去记忆或者说熟悉,

  • hugo new content content/posts/xxxxx.md
  • hugo server

一些不足

PaperMod 的搜索十分简陋。但是,问题倒也不大。从好的方面来讲,该分享的内容是不影响分享的,而且,正式因为搜索不太好用,所以对个人的隐私可能反而会友好一点。

附录

参考:

  1. https://pengfeixc.com/blogs/developer-handbook/git-submodules
  2. 添加 About 页面
  3. 修改字体
  4. https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
  5. https://cursor.in/
  6. https://github.com/francoischalifour/medium-zoom
  7. https://shaohanyun.top/posts/env/hugo_mathjax/