【Hugo】进阶篇:PaperMod主题美化

该文章最近更新时间距今已超过 180 天,文章内容可能已过时,请自主甄别。

装修一下旧时代的船,才能开门迎接更多的客人。

前言

搭建完博客之后,总是会觉得这不满意,然后在搭建过程中,用相同的建站工具和主题搜索,会发现网上有很多大佬已经搭建好的站点,就会这个功能也想要,那个功能也想要。在这里,我记录了一些我搭建过程中进行基础功能拓展和美化的过程。希望可以帮助到有缘人~

以下教程为进阶版的简略教程,需要你有比较扎实的编程基础(或者不爱思考的脑袋),很多教程来自网上其他大佬,由于看了太多的教程,链接引用不全请见谅,如果有大佬看到了可以联系我加上。

以下修改html和css的代码都不建议在themes文件夹直接修改,html可以在layout目录下新建同名文件(复制过来改),css可以在assets目录下新建,最终构建都会打包到public中并使用自定义的覆盖主题文件夹中的内容。

好了,接下来就是博客裁缝的展示环节了。

拓展功能

评论

Gisucs

选用Gisucs作为评论服务,最开始我的选择是Gisucs,但是后来我放弃了。Github作为存储虽然是全免费,非常优雅,但是要求评论者拥有一个Github账号对于用户体验实在是不太友好。

Github配置

参考链接: https://giscus.app/zh-CN#repository

  1. 在某个Github公开仓库开启discussion功能(settings进入)
  2. 在Github安装Gisucs APP
  3. 记录生成的配置和代码,需要配置到自己的项目中

Hugo配置

参考链接: https://www.tofuwine.cn/posts/610b75f5/#pe-comments

  1. 添加文件 layouts/partials/comments.html,输入以下内容
<div class="comments-title" id="tw-comment-title">
    <p class="x-comments-title">{{- .Param "giscus.discussionTitle" }}</p>
    <p style="font-size: 1rem">{{- .Param "giscus.discussionSubtitle" }} </p>
</div>
<div id="tw-comment"></div>
<script>
    const getStoredTheme = () => localStorage.getItem("pref-theme") === "dark" ? "{{ .Site.Params.giscus.darkTheme }}" : "{{ .Site.Params.giscus.lightTheme }}";
    const setGiscusTheme = () => {
        const sendMessage = (message) => {
            const iframe = document.querySelector('iframe.giscus-frame');
            if (iframe) {
                iframe.contentWindow.postMessage({giscus: message}, 'https://giscus.app');
            }
        }
        sendMessage({setConfig: {theme: getStoredTheme()}})
    }

    document.addEventListener("DOMContentLoaded", () => {
        const giscusAttributes = {
            "src": "https://giscus.app/client.js",
            "data-repo": "{{ .Site.Params.giscus.repo }}",
            "data-repo-id": "{{ .Site.Params.giscus.repoId }}",
            "data-category": "{{ .Site.Params.giscus.category }}",
            "data-category-id": "{{ .Site.Params.giscus.categoryId }}",
            "data-mapping": "{{ .Site.Params.giscus.mapping  }}",
            "data-strict": "{{ .Site.Params.giscus.strict  }}",
            "data-reactions-enabled": "{{ .Site.Params.giscus.reactionsEnabled}}",
            "data-emit-metadata": "{{ .Site.Params.giscus.emitMetadata  }}",
            "data-input-position": "{{ .Site.Params.giscus.inputPosition }}",
            "data-theme": getStoredTheme(),
            "data-lang": "{{ .Site.Params.giscus.lang }}",
            "data-loading": "lazy",
            "crossorigin": "anonymous",
            "async": "",
        };

        // 动态创建 giscus script
        const giscusScript = document.createElement("script");
        Object.entries(giscusAttributes).forEach(
                ([key, value]) => giscusScript.setAttribute(key, value));
        document.querySelector("#tw-comment").appendChild(giscusScript);

        // 页面主题变更后,变更 giscus 主题
        const themeSwitcher = document.querySelector("#theme-toggle");
        if (themeSwitcher) {
            themeSwitcher.addEventListener("click", setGiscusTheme);
        }
        const themeFloatSwitcher = document.querySelector("#theme-toggle-float");
        if (themeFloatSwitcher) {
            themeFloatSwitcher.addEventListener("click", setGiscusTheme);
        }
    });
</script>
  1. 添加文件 assets/css/extended/comments.css,输入以下内容
/* giscus 评论组件 */
.comments-title {
    margin-top: 2rem;
    margin-bottom: 2rem;
    display: block;
    text-align: center;
}

.x-comments-title {
    display: block;
    font-size: 1.25em;
    font-weight: 700;
    padding: 1.5rem 0 .5rem;
}
  1. hugo.yaml 中添加内容,其中 {{}} 包裹的需要替换成自己的内容,内容在Gisucs会生成
  giscus:
    repo: "{{ REPO }}"
    repoId: "{ REPO_ID }"
    category: "Announcements"
    categoryId: "{{ CATEGORYID }}"
    mapping: "pathname"
    strict: "0"
    reactionsEnabled: "1"
    emitMetadata: "0"
    inputPosition: "bottom"
    lightTheme: "light"
    darkTheme: "dark"
    lang: "zh-CN"
    discussionTitle: 欢迎来到评论区
    discussionSubtitle: 感谢您的耐心阅读!如需交流,请留个评论吧!
  1. archetypes/default.md 中添加配置 comments: true 来开启评论区,已有的博客也需要修改这个来开启

Twikoo

Twikoo 官网

因为Gisucs要求评论者具有Github账号有点使用者不太友好,所以后面更换了一个Twikoo

Twikoo的整体可以看作是一个CSS的架构,C-Hugo站点的静态JS代码,S-云函数,S-MonogoDB数据库。Twikoo的官方是懂我们这些穷鬼的,提供了很多免费部署的教程。我这边就按照官方推荐度最高的方法进行部署。MonogoDB选择MongoDB Atlas,有500MB的免费额度。Netlify部署云函数,每月 125,000 请求次数和 100 小时函数计算时长,看上去是完全够了。

MongoDB Atlas 申请资源

MongoDB Atlas

按照Twikoo官网指导,申请一个账号和500MB空间的MonogoDB数据库。

  1. 注册MongoDB Atlas账号
  2. 无脑下一步,创建一个MonogoDB实例,这里创建数据库用户的时候密码记住,后面要用
  3. 修改Network Access为 0.0.0.0 允许所有IP访问
  4. 在connect中查看代码示例,选Node.js可以看到连接串,把数据库用户密码替换进去,把整个URL复制下来,等部署云函数的时候有用

Netlify 部署云函数

Netlify

  1. 注册Netlify账号,注册的时候需要提供身份验证(有点恶心人了),密码需要设置得复杂一点,不然直接不给登录也不提示,我通过忘记密码改了一个很复杂的。(后来证明我第二次登录就忘记了)
  2. Fork官方的仓到自己的Github,从仓库部署站点,环境变量中填入 MONGODB_URI 值为MonoDB Atlas中复制出来的URL
  3. 点xxx.netlify.app进入页面,看到云函数正常运行就是部署成功了

前端部署

需要把前端JS嵌入到Hugo的Html页面中,在 layout/comments.html 文件中添加代码 (如果有其他评论组件请自行删除)

<div id="tcomment"></div>
<script src="https://cdn.jsdelivr.net/npm/twikoo@1.6.40/dist/twikoo.all.min.js"></script>
<script>
twikoo.init({
  envId: 'https://xxx.netlify.app/.netlify/functions/twikoo', 
  el: '#tcomment', // 容器元素
})
</script>

使用配置

  1. 进入管理员界面,首次进入配置密码
  2. 配置邮箱通知,Hotmail配置了无法测试通过,暂时没找到原因,后来配置了一个163的邮箱(需要填授权码,听说qq更方便一点,gmail没有尝试)
  3. 反垃圾配置,使用默认的反垃圾服务 akismet,支付一个0元账单就可以获得一个APPKey,填入配置里面就好
  4. 头像服务,默认的 weavatar,注册一个账号,上传一个自己喜欢的头像。但是这边遇到了一个比较奇怪的问题,同时输入昵称和邮箱,头像就会读取失败(但是后来发现生产上好像可以),所以我在通用设置里面把必填字段改成了只填邮箱,因为昵称填QQ号会自动生成qq邮箱。

侧面显示目录

参考资料: https://www.zhouxin.space/logs/introduce-side-toc-and-reading-percentage-to-papermod/

  1. 创建文件 layouts/partials/toc.html 输入以下代码(代码全是抄的,别问我为什么这么写)
... (omitted repetitive code)
  1. 创建 assets/css/extended/toc.css 文件,并输入以下内容(也是抄的,感谢大佬,赞美大佬)
... (omitted repetitive code)
  1. 同时在archetypes/default.yml中添加参数
showToc: true # 显示目录
TocOpen: true # 打开目录

PV/UV

不蒜子Busuanzi

使用不蒜子Busuanzi进行站点访问统计。 参考链接: https://blog.kanikig.xyz/hugo-busuanzi/

  1. 添加文件 layouts/parials/head.html 从主题文件夹 themes/layouts/parials/head.html 中拷贝内容并修改,在Styles上方添加一个if块
...
  1. 添加文件 layouts/parials/footer.html 从主题文件夹 themes/layouts/parials/footer.html 中拷贝内容并修改,在footer标签内添加一个if块
...
  1. 添加文件 layouts/_defaults/single.html 从主题文件夹 themes/layouts/_defaults/single.html 中拷贝内容并修改,在post-meta内添加一个if块
...
  1. hugo.html文件中的param节点中添加开关
params:
  busuanzi:
      enable: true

Google Analyze

只需要在 hugo.yaml 中添加以下代码即可,id更换为自己在Google Analytic中申请的跟踪ID

services:
    googleAnalytics:
        id: "G-XXXXXXXXXX"

时间线

添加一个根据时间线排列的归档页面,写的多写的久才有质感。多写写吧!

  1. 添加 content/archive.md 文件,输入以下内容
---
title: ""
layout: "archives"
url: "/archives/"
summary: archives
---
  1. hugo.html 中添加按钮,在 menu.main 节点下新增以下内容
    - identifier: archive
      name: 时间轴
      url: /archives/
      weight: 11

留言板

利用评论系统,新增一个Layout来构建一个留言板页面。

  1. 创建 layouts/message.html 文件输入一下代码(代码从 single.html 中删除了很多东西,简化得到,顺便做了一下标题居中,这回是自己写的了):
...
  1. 在命令行中创建一个新的md文件(不要直接新建文件,我试了,编译的时候不会生成文件,会导致404),输入 hugo new message.md,并在其中输入以下代码
---
title: "💬 留言板"
date: '2024-12-13T21:14:22+08:00'
draft: false # 默认为草稿模式
layout: "message"
comments: true # 评论
---
  1. hugo.yaml 中新增首页目录,添加以下代码
    - identifier: message
      name: 💬 留言板
      url: /message/
      weight: 21

添加最近修改时间

复制主题中的 post_meta.htmllayout/partials/post_meta.html 新增最近修改时间的内容,并修改发布时间的内容和国际化,

  1. layout/partials/post_meta.html 输入以下代码
...
  1. 在i18n文件夹的对应目录添加翻译
  2. hugo.yaml 中新增配置 frontmatte.lastmod: ['lastmod', ':git', 'date', 'publishDate'] 用于指定lastmod变量的赋值顺序

自定义域名

首先需要有一个域名,在对应的域名服务商添加一条解析记录,解析类型:CNAME,解析值为 xxx.github.io (xxx替换为自己的Github用户名)

再添加文件 static/CNAME ,文件的内容为自定义的域名。没有这个文件,访问域名会出现404。

友链

参考: https://aimerneige.com/zh/post/web/add-friend-link-in-papermod-blog/

这个是没有脑子直接抄的

  1. 创建一个文件 layouts/partials/friends.html 输入以下代码
...
  1. 创建 layouts/_default/friends.html 文件,输入一下代码,用于创建新的界面
...
  1. 创建 content/posts/friends.md 文件,输入以下内容
---
title: "🧑‍🤝‍🧑 Zanks的朋友们 🧑‍🤝‍🧑"
date: '2024-01-01T00:00:00+08:00'
author: "Zanks"
layout: "friends"
comments: true # 评论
---

排名不分先后,按时间顺序添加。如需新增请留言,或通过其他方式联系我。
  1. 创建 data/friends.yml 文件,用于存储友链的数据,以下仅为示范
- title: "伞"
  intro: "一只咸鱼的学习记录"
  link: "https://umb.ink/"
  image: "https://avatars.githubusercontent.com/u/53655863?v=4"
- title: "HelloWorld的小博客"
  intro: "这里是一个小白的博客"
  link: "https://mzdluo123.github.io/"
  image: "https://avatars.githubusercontent.com/u/23146087?v=4"

全站文章和字数统计

参考:https://huuuuuuo-github-io.vercel.app/post/hugo%E6%80%BB%E5%AD%97%E6%95%B0%E7%BB%9F%E8%AE%A1/

可以将以下代码加入到任何喜欢的页面,我放在了About页面

...

右侧边栏

底部悬浮按钮

参考了一个个性化的PaperMod主题 https://github.com/tofuwine/PaperMod-PE 实现的效果是在页面的右侧添加了一个前往评论区的按钮,重写了官方回到顶部的按钮(添加了阅读进度)

  1. static/js 目录下引入两个文件分别用于实现按钮的动态样式,实现逻辑来自PaperMod-PE源码。
...
...
  1. 删除原有回到顶部的按钮,或通过配置disableScrollToTop关闭(代码位于 footer.html
  2. 添加 right_aside.html 文件添加右侧边栏的代码
...
  1. 添加CSS asset/css/extended/right_side.css 实现样式
...

作者信息栏

此部分代码在网上没找到样例可以抄,大部分都是靠着本人一边GPT一边理解自己实现的。 实现了一个可以悬浮在右侧边栏的框,展示头像、社交信息和最近更新的文章。

  1. 添加一个在 right-side.html 中的<aside>节点下添加以下代码
...
  1. asset/css/extended/right_side.css 添加样式
...

代码显示优化

代码来自 tofuwine 的个性化主题,仅css略作修改:

...
...
...

最后,在 footer.htmlextend_footer.html 中引入脚本实现折叠动画

...

ShortCode拓展

Hugo可以通过添加ShortCode来拓展Markdown的渲染能力,类似于组件。 所有的ShortCode定义都可以按照在 layouts/shortcode 中添加 html 文件和在 assets/css/extended 下新增 css 文件的方式来实现。如需JS则在 static/js 中添加js并在html中引入。

使用方式:

<shortcode>
content
</shortcode>

为了方便管理,我新建了一个shortcode目录用于存放shortcode的css代码,需要在 extend_head.html 中引入。引入代码如下:

{{ $styles := resources.Match "css/extended/shortcode/*.css" }}
{{ $style := $styles | resources.Concat "assets/css/shortcode.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" integrity="{{ $style.Data.Integrity }}" crossorigin="anonymous">

admonition

代码来自 YazidLee/hugo-backup 仅略作修改

添加以下文件

...
...
...

最后,在 footer.htmlextend_footer.html 中引入脚本实现折叠动画

...

效果展示:

一个 技巧 横幅

界面显示优化

配置默认语言为中文

hugo.html 文件中添加配置 defaultContentLanguage: zh 可以汉化大部分主题的内容

日期格式显示优化

hugo.html 文件中的Param节点下添加配置 DateFormat: "2006-01-02" (go的时间配置必须要用这个日期,yyyy-MM-dd不行)

标签页添加词云

参考资料: https://blog.xlap.top/post/tech/wordcloud4hugo/#%E9%A1%B9%E7%9B%AE%E5%9C%B0%E5%9D%80 感谢开源作者和大佬代码,我直接抄了

  1. 下载 wordcloud2.js 拷贝到 static/js/ 目录下,下载地址
  2. 修改 head.html 引入js文件,新增以下代码:
{{- if eq .Section "tags"}}
{{/* 标签云 */}}
<link rel="stylesheet" href="/css/word-cloud.css"/>
<script src="/js/wordcloud2.js"></script>
{{- end }}
  1. 创建 staic/css/word-cloud.css 文件输入以下代码:
...