无意浏览了一下 Hugo 官网的主题目录,发现了一个简约风格的 Paper 主题,非常喜欢,第二天发现了一个 PaperMod,差不多算是增强版。

之前就没遇到过心爱的主题,一直将就着,好多功能也没有弄,这两天一顿折腾,记录一下折腾经过。

Hugo & PaperMod

开始

更新 Hugo,新建站点,导入 PaperMod 主题,导入 PaperMod 演示站的 config.yml

配置时可以参考着 Hugo 官方文档的 Configure HugoPaperMod Wiki

baseURL: "https://dvel.me/"
title: "Dvel's Blog"
paginate: 100
languageCode: "zh-Hans"
DefaultContentLanguage: "zh"
theme: hugo-PaperMod-6.0

buildDrafts: false
buildFuture: false
buildExpired: false

enableInlineShortcodes: true
enableRobotsTXT: false
enableEmoji: true
hasCJKLanguage: true

minify:
    disableXML: true

permalinks:
    post: "/post/:slug"

menu:
    main:
        - name: Home
          url: /
          weight: 1
        - name: Archives
          url: archives/
          weight: 2
        - name: Tags
          url: tags/
          weight: 3
        - name: Friends
          url: friends/
          weight: 4
        - name: About
          url: about/
          weight: 5
        - name: 🔍
          url: search/
          weight: 10

outputs:
    home:
        - HTML
        - RSS
        - JSON

params:
    env: production # to enable google analytics, opengraph, twitter-cards and schema.
    description: "Dvel's Blog"
    author: Dvel

    defaultTheme: auto  # light | dark | auto
    disableThemeToggle: false
    ShowShareButtons: false
    ShowReadingTime: false
    displayFullLangName: true
    ShowPostNavLinks: true
    ShowBreadCrumbs: false
    ShowCodeCopyButtons: true
    ShowToc: true
    tocopen: true
    comments: true
    DateFormat: "2006-01-02"
    hideSummary: true

    profileMode:
        enabled: false
        # title: PaperMod
        # imageUrl: "#"
        # imageTitle: my image
        # # imageWidth: 120
        # # imageHeight: 120
        # buttons:
        #     - name: Archives
        #       url: archives
        #     - name: Tags
        #       url: tags

    homeInfoParams:
        Title: "Dvel's Blog"
        Content: >
                        Less is More.

    socialIcons:
        - name: github
          url: "https://github.com/iDvel"
        - name: KoFi
          url: "https://ko-fi.com/idvel"
        - name: RSS
          url: "index.xml"
        - name: email
          url: "mailto:[email protected]"

    assets:
        favicon: "favicon.ico"
        favicon16x16: "favicon-16x16.png"
        favicon32x32: "favicon-32x32.png"
        apple_touch_icon: "apple-touch-icon.png"
        safari_pinned_tab: "safari_pinned_tab.png"

    fuseOpts:
        isCaseSensitive: false
        shouldSort: true
        location: 0
        distance: 1000
        threshold: 0.4
        minMatchCharLength: 0
        keys: ["title", "permalink", "summary", "content"]

taxonomies:
    # category: categories
    tag: tags
    # series: series

markup:
    goldmark:
        renderer:
            unsafe: true
    highlight:
        codeFences: true
        lineNos: false
        # anchorLineNos: false
        guessSyntax: true
        noClasses: true
        style: dracula

# ...

HTML lang

单语言的站点可以直接设置 languageCode: "zh-CN" 并在 baseof.html 修改为:

<!-- <html lang="{{ .Site.Language }}" dir="{{ .Language.LanguageDirection | default "auto" }}"> -->
<html lang="{{ .Site.LanguageCode }}">

RSS 输出全文

创建最高优先级的 <站点目录>/layouts/index.rss.xml 文件就可以了。

使用官方模板,将

<description>{{ .Summary | html }}</description>

改为

<description>{{ .Content | html }}</description>

设置文章中链接以新标签的方式打开

参考:在 Hugo Goldmark Markdown 中设置以新标签打开链接

PaperMod 的悬浮目录

参考:Hugo博客目录放在侧边 | PaperMod主题

相关功能已经在 PR 中了,不知道什么时候会合并进来。

实测 Cloudflare 的 Rocket Loader 会让「跟随滚动」的功能失效,不太理解为什么,如果要开启这个功能的话,建议对 toc.html 进行如下修改,以让 Rocket Loader 忽略它:

- <scrip>
+ <script data-cfasync="false">

Hack 字体

太喜欢这个字体了,IDE、编辑器、终端全是它。

extend_head.html 中引入:

<link rel='stylesheet' href='//cdn.jsdelivr.net/npm/[email protected]/build/web/hack.css'>

在自定义 CSS 文件 blank.css 中:

pre, code { 
    font-family: Hack, monospace; 
}

Markdown 风格

在 PaperMod 基础上自定义了一些渲染风格。

背景颜色与主页进行了统一。

习惯了 Typora 可以渲染空行,但其他渲染器都会忽略空行,除非手写一个 <br>,干脆就直接增加标题的上间距了。

PaperMod 的表格也有些空洞,换成了 GitHub 风格的。

blank.css 中新增自定义样式:

/* # Markdown 风格 */
/* 字体相关 */
body {
    font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
	font-size: 16px;
    line-height: 1.5;
}
/* 主题背景颜色、行内代码背景颜色 */
:root {
    --theme: rgba(22, 22, 22, 0.06);
    --code-bg: rgba(22, 22, 22, 0.06);
}
.dark {
    --theme: rgb(40,41,35);
    --code-bg: rgb(27, 27, 27);
}
/* 标题和段落颜色 */
:root {
    --primary: rgb(30, 30, 30);  /* --primary: rgb(30, 30, 30); */
    --content: rgb(40, 40, 40);  /* --content: rgb(31, 31, 31); */
}
/* 行内代码:我习惯在 `code` 左右打一个空格,不需要左右 margin 来弥补了 */
.post-content code {
    margin: unset;
}
/* 图片居中 */
.post-content img {
    margin: auto;
}
/* 行文的上下间隔 */
.post-content p,
.post-content blockquote,
.post-content figure,
.post-content table,
.post-content hr {
    margin: 0.8rem 0;
}
.post-content ul,
.post-content ol,
.post-content dl,
.post-content li {
    margin: 0.3rem 0;
}
.post-content h1,
.post-content h2,
.post-content h3,
.post-content h4,
.post-content h5,
.post-content h6 {
    margin-bottom: 0.8rem;
}
/* 一二级标题下划线,但不让首页的文章标题有下划线 */
.post-content h1, h2 {
	border-bottom: 1px solid #ccc;
}
article.post-entry h2 {
	border-bottom: unset;
}
/* 各级标题 字体大小、上边距 */
.post-content h1 {
    font-size: 3rem;
	margin-top: 3rem;
}
.post-content h2 {
    font-size: 2rem;
	margin-top: 2.5rem;
}
.post-content h3 {
	font-size: 1.8rem;
	margin-top: 2rem;
}
.post-content h4 {
	font-size: 1.6rem;
	margin-top: 1.6rem;
}
.post-content h5 {
    font-size: 1.4rem;
	margin-top: 1.4rem;
}
.post-content h6 {
    font-size: 1.2rem;
	margin-top: 1.2rem;
}
/* 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;
}

代码高亮

PaperMod 用的是 highlight.js,没有用 Hugo 默认的,代码也没有分离。实在是看不懂代码,不会改。

自己从 highlight.js 下载了 package 后分别将 highlight.min.js 和选好的 atom-one-dark.min.css 替换主题目录下的 assets/ 文件夹内原先的 JS 和 CSS 文件。

之后还得自己改已经写死了的代码块背景颜色:

:root {--hljs-bg: #282C34;}

评论功能

试用了一下 Disqus,但是界面好杂乱,就换到了 Waline。

相比 Valine 有个后端管理。

关于使用 Gmail 的邮件提醒。以前我在 Python 上用的是 TLS 587 端口,跑小脚本完全正常发件,前提是启用不安全的登录方式。Waline 则是需要 Google 账号开启二级验证,使用 App 专用的 16 位密码(不开二级验证无此功能),用的是 465 端口。这种邮件部署还是建议新开个小号来发,以防止自己的主力邮箱被标记 spam。

官方教程非常详尽,就是配置麻烦点,不能像 Disqus 那样一键搞定。

适配 PaperMod 的黑暗模式,可以将 CSS 选择器设置为 body.dark

body.dark {
    /* 下面是官网默认的黑暗模式配色 */
    /* 常规颜色 */
    --waline-white: #000;
    --waline-light-grey: #666;
    --waline-dark-grey: #999;

    /* 布局颜色 */
    --waline-text-color: #888;
    --waline-bgcolor: #1e1e1e;
    --waline-bgcolor-light: #272727;
    --waline-border-color: #333;
    --waline-disable-bgcolor: #444;
    --waline-disable-color: #272727;

    /* 特殊颜色 */
    --waline-bq-color: #272727;

    /* 其他颜色 */
    --waline-info-bgcolor: #272727;
    --waline-info-color: #666;
}

部署在 Cloudflare Pages

Cloudflare Pages 的免费政策

  • 同一时间只能部署一个 Pages(实测每次部署大概是 2~3 分钟)
  • 每月 500 次提交
  • 无限站点
  • 无限请求
  • 无限带宽
  • 每个项目最多 10 个自定义域名
  • 每个站点最多 20000 个文件
  • 单个文件最大 25 MB

总之对于个人博客来说是绰绰有余了。

特点

相比 GitHub Pages,可以直接从私有仓库部署。

支持 Hugo 等自动部署。

CDN 大陆效果一般,直连大约至少 几百毫秒 一千毫秒。

支持裸域的 CNAME 与 MX 共存,自动搞定,这太方便了,之前 CloudXNS 至少还要自己手动操作一个其自定义的 LINK 类型及另一个域名作为跳板,Cloudflare 完全自动处理。我自己的的邮件用的也是裸域,在 Google Workspace,完全没有影响,收发件正常。

链接末尾的 .html 会自动 308 到不带 .html 的 URL,这有点坑爹了,好歹给个取消的选项呀;百度就更坑爹了,站长验证无法通过 html 文件进行验证。

可以配合 Workers 等其他免费或付费功能完成多种类的 URL 转发。

部署

十分简单,现在也都有简体中文了,默认自动响应 Git 新提交部署。

一种是直接将生成好的静态文件作为部署内容,一种是 Cloudflare 自动用 Hugo 等支持的系统做自动化部署。

没试过第二种,我选择第一种,节省部署时间,主要是保证和本地的一致性。

重定向

将带 www 的或不带 www 的也设定为自定义域名。

部署妥善后,可在「页面规则」中设定 www 与不带 www 的互相跳转,例如:

匹配 URL 转发 URL 重定向
www.dvel.me/* https://dvel.me/$1 301

会自动将带 www 的地址 301 重定向到裸域,免费用户可以使用最多三个规则。

其他重定向可参考:利用 Cloudflare Workers 进行批量 301 重定向

Mac 本地+站点图片同步

我已经弄了一个 Cloudflare Pages 图床了,但是每次要 Push 上去等两分钟才能在本地看到图片。

感觉没必要单弄个图床了,使用本地的,和博客一起 push 到 Pages 就可以了。

最舒适的体验应该是在 push 之前本地也能够预览。

使用 post/img/ 目录 ✘

图片路径需要加上 .

![](./img/xxx.jpg)

但是这样只能在本地显示。

使用 static/img/ 目录 ✔

Hugo 的 static/ 目录中的内容会自动放到网站根目录。

![](/img/xxx.jpg)

但是这样只能在网站上显示。

我想的是,只要在本机电脑上的根目录创建相同的 /img/ 文件夹,那不就两边都可以解决了吗。

在 macOS 根目录创建文件夹

可以参考 在 macOS 根目录创建文件夹,以下是 Big Sur 和 Monterey 的方法。

编辑 synthetic.conf

$ sudo vim /etc/synthetic.conf

输入内容(中间是 Tab,不是空格):

img	/Users/dvel/Dropbox/hugo/static/img

重启后就能看到根目录有了。

在根目录创建文件夹

大功告成了,使用 ![](/img/xxx.jpg) 同时支持本地和网站看图。

用 Squoosh 本地快捷图片压缩

先下载好 Squoosh 仓库 中的 cli/ 文件夹,与 cli/ 同级目录创建一个 .command 文件,可双击自动运行。

文件列表

命令从 https://squoosh.app/ 获取,调整好参数后点击这里复制。

Squoosh

脚本文件:

#!/usr/bin/env python

import os

# 从 https://squoosh.app 获取自己偏好的命令
config = """npx @squoosh/cli --webp '{"quality":100,"target_size":0,"target_PSNR":0,"method":6,"sns_strength":50,"filter_strength":60,"filter_sharpness":0,"filter_type":1,"partitions":0,"segments":4,"pass":1,"show_compressed":0,"preprocessing":0,"autofilter":0,"partition_limit":0,"alpha_compression":1,"alpha_filtering":1,"alpha_quality":100,"lossless":1,"exact":0,"image_hint":0,"emulate_jpeg_size":0,"thread_level":0,"low_memory":0,"near_lossless":100,"use_delta_palette":0,"use_sharp_yuv":0}'"""

base_dir = os.path.abspath(os.path.dirname(__file__))
in_dir = os.path.join(base_dir, 'in')
out_dir = os.path.join(base_dir, 'out')

files = [x for x in os.listdir(in_dir) if x != '.DS_Store']
for file in files:
    file_path = os.path.join(in_dir, file)
    os.system(f'cd {base_dir}/cli && {config} {file_path} -d {out_dir}')