更新日志

2024-11-12

新增 Memos 说说接入相关修改

2024-11-07

新增中文排版相关修改

2024-11-05

新增底栏图片修改

2024-11-04

新增游戏界面修改

2024-11-03

更新引用段落到右键菜单相关修改

2024-11-02

更新 Umami 统计的部署

2024-11-01

更新轻量友链朋友圈的部署

2024-10-26

更新一些琐碎的修改

2024-10-25

更新参考其他博客教程的改造

2024-10-23

更新 MathJax 与 Shiki 的适配方式

2024-10-20

发布文章

本文章将会持续更新,所有使用 Solitude 期间对网站的修改都会在此进行总结。

数学公式

博主作为数学系的学生,在博客中分享部分数学学习笔记算是半个刚需了。Solitude 主题自带 KaTeX 支持,如果只是简单的数学公式数学需求,是完全够用的。但是 KaTeX 的数学支持比较弱,且移动端的多行公式浏览体验不佳,因此我把博客的公式渲染引擎换成了 MathJax

最开始博客是直接引入了 MathJax 的 js 文件,在客户端进行公式渲染。但是很快我就发现该方式和 pjax 不合,尝试在引入 js 的标签中添加 pjax 也无效,因此改为在服务端渲染。

服务端渲染最简单的办法就是去使用 NexT 主题的一个插件 hexo-filter-mathjax。首先安装该插件、卸载原先的 Markdown 渲染引擎并安装对 MathJax 支持更好的 hexo-renderer-pandoc,最后清除 Hexo 缓存:

1
2
3
4
5
npm uninstall hexo-renderer-marked --save
# npm uninstall hexo-renderer-kramed --save # 根据此前安装的 Markdown 渲染引擎来卸载
npm install hexo-renderer-pandoc --save
npm install hexo-filter-mathjax --save
hexo clean

接着在 _config.yml 中添加 MathJax 与 Pandoc 相关配置即可。

_config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mathjax:
  tags: none # or 'ams' or 'all'
  single_dollars: true # enable single dollar signs as in-line math delimiters
  cjk_width: 0.9 # relative CJK char width
  normal_width: 0.6 # relative normal (monospace) width
  append_css: true # add CSS to pages rendered by MathJax
  every_page: false # if true, every page will be rendered by MathJax regardless the `mathjax` setting in Front-matter
  packages: # extra packages to load
  extension_options: {}
    # you can put your extension options here
    # see http://docs.mathjax.org/en/latest/options/input/tex.html#tex-extension-options for more detail

pandoc:
  args:
    - "-f"
    - "markdown"
    - "-t"
    - "html"
    - "--mathjax"

代码高亮

博主还在使用 Typst 进行部分课程笔记与作业的书写,也会在博客中分享一些 Typst 使用经验。不幸的是,Hexo 自带的两个代码语法高亮引擎——highlight.jsPrismjs 都不支持对比较新的 Typst 生成语法高亮。

解决办法之一是使用 Typst.ts 在 Node 环境中解析 Typst 代码语法,并发送给 highlight.js。Typst.ts 的子项目 highlighter 提供了一个实现,而下面这篇文章则给出了在 Hexo 上的使用方法与实现思路。这也是我最开始使用的方法。

另一个办法则是改用 Shiki 进行公式渲染。Shiki 的优点在于它支持导入自定义的主题与语言,因此不需要担心语言支持问题。我在几个已有项目的基础上花了点时间开发了一个更适合 Solitude 主题使用的 Shiki 插件:

目前本博客也在使用该插件进行代码语法高亮渲染。

主题适配

正在整理这部分代码,准备提 PR

在 Solitude 上使用该插件需要对主题的部分代码进行修改:

scripts/helper/stylus.jsline 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// highlight
const {syntax_highlighter: syntaxHighlighter, highlight, prismjs, shiki} = hexo.config
let {enable: highlightEnable, line_number: highlightLineNumber} = highlight
let {enable: prismjsEnable, line_number: prismjsLineNumber} = prismjs
let {enable: shikiEnable, line_number: shikiLineNumber} = shiki

// for hexo > 7.0
if (syntaxHighlighter) {
    highlightEnable = syntaxHighlighter === 'highlight.js'
    prismjsEnable = syntaxHighlighter === 'prismjs'
    shikiEnable = syntaxHighlighter === 'shiki'
}

style.define('$highlight_enable', highlightEnable)
style.define('$highlight_line_number', highlightLineNumber)
style.define('$prismjs_enable', prismjsEnable)
style.define('$prismjs_line_number', prismjsLineNumber)
style.define('$shiki_enable', shikiEnable)          
style.define('$shiki_line_number', shikiLineNumber) 
style.define('$language', config.language)
source/js/main.jsline 495
1
2
const $syntaxHighlight = syntax === 'highlight.js' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]') 
const $syntaxHighlight = syntax === 'highlight.js' || syntax === 'shiki' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]') 
source/css/_highlight/index.stylline 5
1
2
3
4
5
6
7
8
if $highlight_enable
  @require "highlight/index.styl"

if $prismjs_enable
  @require "prismjs/index.styl"

if $shiki_enable
  @require "shiki/index.styl"
source/css/_highlight/shiki/index.styl
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
if hexo-config('highlight.enable')
  @import "diff"

figure
  pre
    margin 0
    padding 8px 0
    border none
  table
    display block
    border none
    overflow-y hidden
    overflow-x auto

    td
      padding 0
      border none
      height 100%

      &.gutter
        opacity .6
        user-select none
        min-width initial

        pre
          overflow auto
          line-height 1.6
          margin 0
          padding 8px .5rem
          border none
          color var(--efu-secondtext)
          background var(--efu-secondbg)
          border-right var(--style-border-always)
          text-align center

      &.code
        width 100%
        display flex
        position relative

        pre
          padding-right .5rem
          padding-left .5rem
          line-height 1.6
          width 100%

  .line
    &.marked
      background-color: rgba(97, 97, 97, .314)
source/css/_highlight/shiki/diff.styl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
figure.highlight
  table::-webkit-scrollbar
    color var(--efu-secondbg)
    height 6px
    background var(--efu-hl-bg)
    border-radius 6px
    display initial

  [data-theme=dark] &
    td.code
      span
        color var(--shiki-dark) !important
        // background-color var(--shiki-dark-bg) !important // 不建议使用
        font-style var(--shiki-dark-font-style) !important
        font-weight var(--shiki-dark-font-weight) !important
        text-decoration var(--shiki-dark-text-decoration) !important

这样就可以适配 Solitude 主题了。

MathJax 适配

此外,使用 Shiki 进行代码高亮渲染会导致 MathJax 的 LiteDOM adaptor 解析文档失败,因此需要把 hexo-filter-mathjax 的代码进行部分修改。

新建 mathjax.js,放到博客的 scripts 目录下:

./scripts/mathjax.js
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
"use strict";
const { mathjax } = require("mathjax-full/js/mathjax.js");
const { TeX } = require("mathjax-full/js/input/tex.js");
const { SVG } = require("mathjax-full/js/output/svg.js");
const { LiteAdaptor } = require("mathjax-full/js/adaptors/liteAdaptor.js");
const { RegisterHTMLHandler } = require("mathjax-full/js/handlers/html.js");
const { escapeHTML } = require("hexo-util");

let { AllPackages } = require("mathjax-full/js/input/tex/AllPackages.js");

const config = (hexo.config.mathjax = Object.assign(
  {
    tags: "none",
    single_dollars: true,
    cjk_width: 0.9,
    normal_width: 0.6,
    append_css: true,
    every_page: false,
    extension_options: {},
  },
  hexo.config.mathjax
));

const adaptor = new LiteAdaptor({
  fontSize: 16,
  cjkCharWidth: config.cjk_width,
  unknownCharWidth: config.normal_width,
});
RegisterHTMLHandler(adaptor);

const render = (content) => {
  if (Array.isArray(config.packages)) {
    AllPackages = AllPackages.concat(config.packages);
  }
  const tex = new TeX(
    Object.assign(
      {
        packages: AllPackages,
        tags: config.tags,
      },
      config.extension_options
    )
  );
  const svg = new SVG({
    fontCache: "none",
  });
  const html = mathjax.document(content, {
    InputJax: tex,
    OutputJax: svg,
  });

  html.render();

  const htmlContent = adaptor.innerHTML(adaptor.body(html.document));
  if (html.outputJax.math.display) {
    const latexContent = html.outputJax.math.math;
    const outputHtml = htmlContent.replace(
      "</mjx-container>",
      `<button class="copy-button" onclick="rm.copyText(\`${escapeHTML(
        latexContent.replace(/\\/g, "\\\\")
      )}\`)"><i class="solitude fas fa-copy"></i></button></mjx-container>`
    );
    return outputHtml;
  }
  return htmlContent;
};

hexo.extend.filter.register("after_render:html", (html, { page }) => {
  if (
    config.every_page ||
    page.mathjax ||
    (page.__index && page.posts.toArray().find((post) => post.mathjax))
  ) {
    return html
      .replace(/<span\s+class="math\s+[^"]*">\\[\(\[].*?\\[\)\]]<\/span>/gs, render)
      .replace('<div id="post">', '<div id="post"><link rel="stylesheet" href="/css/mathjax.css">');
  }
  return html;
});

接着在 source 目录下新建 css/mathjax.styl 文件:

./source/css/mathjax.styl
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
mjx-container[jax='SVG']
  direction ltr

  > svg
    overflow visible

  + br
    display none

  &[display='true']
    overflow auto hidden
    display block
    text-align center
    margin 1em 0

  &[justify='left']
    text-align left

  &[justify='right']
    text-align right

[jax='SVG']
  mjx-tool
    display inline-block
    position relative
    width 0
    height 0

    > mjx-tip
      position absolute
      top 0
      left 0

mjx-tool
  > mjx-tip
    display inline-block
    padding 0.2em
    border 1px solid #888
    font-size 70%
    background-color #f8f8f8
    color black
    box-shadow 2px 2px 5px #aaaaaa

g
  &[data-mml-node='merror']
    > g
      fill red
      stroke red

    > rect[data-background]
      fill yellow
      stroke none

  &[data-mml-node='mtable']
    > line[data-line]
      stroke-width 70px
      fill none

    > rect[data-frame]
      stroke-width 70px
      fill none

    > .mjx-dashed
      stroke-dasharray 140

    > .mjx-dotted
      stroke-linecap round
      stroke-dasharray 0, 140

    > svg
      overflow visible

  &[data-mml-node='maction'][data-toggle]
    cursor pointer

mjx-status
  display block
  position fixed
  left 1em
  bottom 1em
  min-width 25%
  padding 0.2em 0.4em
  border 1px solid #888
  font-size 90%
  background-color #f8f8f8
  color black

foreignObject[data-mjx-xml]
  font-family initial
  line-height normal
  overflow visible

.MathJax path
  stroke-width 3

.math.display
  display block
  position relative

  .copy-button
    display inline
    position relative
    right -1em
    top 0
    opacity 0
    width 0

  &:hover
    .copy-button
      opacity 1

然后就可以把 hexo-filter-mathjax 给卸载掉了。由于改为了生成后渲染,Hexo 生成的 db.json 也更加友好——这意味着本地搜索的 xml 可以大幅压缩,Algolia 搜索则可以使用 TeX 语法来搜索数学公式。

其他修改

这部分的改造比较琐碎,因此集中在一节。

Pandoc Markdown 引用支持

本站使用 hexo-renderer-pandoc 进行文章渲染,这也意味着可以使用 Pandoc 版本的扩展 Markdown 格式来书写文章。 我的多复变函数论学习笔记原文均为 Typst 编写,每隔一段时间会使用 Pandoc 转换部分笔记到 Markdown,进行简单修改后放到博客上。我的笔记包含许多的引用,这些引用转换到 Markdown 格式时会像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
**定理** (多圆柱上的 Cauchy 积分公式):
...
[]{#theorem_多圆柱上的_Cauchy_积分公式}

...

**推论**:

...

_证明_:

对 ... 应用[\[theorem_多圆柱上的_Cauchy_积分公式\]](#theorem_多圆柱上的_Cauchy_积分公式){.ref},得

...

进行简单修改(修改引用的位置和引用文本)后,Pandoc 渲染出的 html 是这样的:

1
2
3
<span id="theorem_多圆柱上的_Cauchy_积分公式"><strong>定理</strong>
(多圆柱上的 Cauchy 积分公式)</span>
<a href="#theorem_多圆柱上的_Cauchy_积分公式" class="ref" data-pjax-state="">定理 1</a>

显然,我需要为这个引用块添加跳转功能以方便阅读,这里我选择直接在主题的 main.js 里加上 ref 跳转的功能。

solitude/source/main.js
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
class toc {
// ...
}

class ref { 
  static init() { 
    const el = document.querySelectorAll('a.ref') 
    el.forEach((e) => { 
      e.addEventListener('click', (event) => { 
        event.preventDefault() 
        utils.scrollToDest(utils.getEleTop(document.getElementById(decodeURI(event.target.hash.replace('#', '')))), 300) 
      }) 
    }) 
  } 
} 

// ...
window.refreshFn = () => {
// ...
  if (is_post || is_page) {
    addHighlight();
    tabs.init();
    ref.init(); 
  }
  // ...
}

防止友链的随机访问跳转到非博客友链

修改主题中关于随机友链的 pug:

layout/includes/widgets/randomlink.pug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- var datalinks = []
- var data = site.data.links.links
if(data)
    each item in data
            each y in item.link_list
                - datalinks.push({ name: y.name,link: y.link}) 
                if y.noTravel
                    - datalinks.push({ name: y.name, link: y.link, noTravel: y.noTravel}) 
                else
                    - datalinks.push({ name: y.name, link: y.link}) 

script.
    const links = !{JSON.stringify(datalinks)}
    const travelLinks = links.filter((i) => !('noTravel' in i && i.noTravel)) 
    const randomText = '!{_p('link.random')}'
    function travelling() {
        const link = links[utils.randomNum(links.length)]; 
        const link = travelLinks[utils.randomNum(travelLinks.length)]; 

然后在 links.yml 中为不应该跳转的友链添加上 noTravel: true 即可。

links.yml
1
2
3
4
5
- name: Hexo
  link: https://hexo.io/
  descr: 快速、简洁且高效的博客框架
  avatar: https://hexo.io/icon/favicon-196x196.png
  noTravel: true

增加背景图片切换开关

改的东西太多太琐碎了,直接看 commit

修改页脚友链数量

一样,改的东西琐碎了点,直接看 commit

修改评论区样式

样式文件直接拿走即可。基于 Solitude 主题自带 Twikoo 样式进行修改,主要改了: - 把头像预览加回来了(仅限评论区顶部编辑栏) - 把 Markdown 预览和取消回复加回来了 - 补充了管理面板样式

删除无用 css

说是删除,其实是避免渲染,把主题 source/css 目录下的 var.styl 和 third_party 文件夹,名字前面都加上一个下划线来避免渲染,同时修改 index.styl 中对应的路径即可。

修改引用到评论右键菜单

这个改起来简单,直接放代码:

solitude/source/main.js
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
const sco = {
  // ...
  toTalk(txt) {
    utils.scrollToDest(utils.getEleTop(document.getElementById('post-comment')), 300);
    const toTalkFn = () => {
      const inputs = ["#wl-edit", ".el-textarea__inner", "#veditor", ".atk-textarea"];
      inputs.forEach(selector => {
        const el = document.querySelector(selector);
        if (el) {
          el.dispatchEvent(new Event('input', { bubble: true, cancelable: true }));
          el.value = '> ' + txt.replace(/\n/g, '\n> ') + '\n\n';
          el.focus();
          el.setSelectionRange(-1, -1);
        }
      });
      utils.snackbarShow(GLOBAL_CONFIG.lang.totalk, false, 2000);
    }
    hpcesia.waitTwikoo(toTalkFn)
  },
  // ...
}
const hpcesia = {
  // ...
  waitTwikoo(callback, scale = 100){
    setTimeout(() => {
      if (window.twikoo)
        callback()
      else
        waitTwikoo(callback)
    }, scale);
  }
  // ...
}
直接滑动到底部,然后等待 twikoo 加载完成即可。

新增游戏界面

其实本质是把原本的 equipment 页面套个壳。你也可以直接查看 commit 快速了解我的改动。

在 solitude/layout/includes/page 目录中新建 games.pug 文件,写入如下内容:

solitude/layout/includes/page/games.pug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
include ../widgets/page/banner
#games
    if site.data.games
        each cls in site.data.games
            .game-group
                h2.game-group-title= cls.name
                .game-group-desc= cls.desc
                .game-group-content
                    each item in cls.list
                        .game-item
                            .game-item-cover
                                img.game-item-image(src=item.image, alt=item.name)
                            .game-item-info
                                .game-item-name(onclick='utils.copy("' + item.name + '")')= item.name
                                if item.score
                                    .game-item-score= "评分: " + item.score
                                .game-item-spec= item.spec
                                .game-item-desc= item.desc
                                if item.link
                                    .game-item-toolbar
                                        a.game-item-link(href=item.link, target="_blank") 详情
                                        a.bber-reply(onclick=`sco.toTalk('${item.name}\\n\\n${item.spec}\\n\\n${item.desc}')`)
                                            i.solitude.fa-solid.fa-comment(style="font-size: 1rem;")
然后修改 solitude/layout/page.pug,加上引入 games.pug 的代码:
solitude/layout/page.pug
1
2
3
4
5
6
7
8
block content
    main.layout#content-inner(class=page.aside ? '' : 'hide-aside')
        #page
            case page.type
                //- ...
                when 'games'
                    include includes/page/games
                //- ...
最后在 ./source/_data 目录下新建 games.yml 文件,写入如下格式的内容:
1
2
3
4
5
6
7
8
9
- name: 好游戏 # 分类名称
  desc: 比较喜欢的游戏 # 分类描述
  list: # 游戏列表
    - name: Mincraft # 游戏名称
      score: 9/10 # 游戏评分,可选
      spec: 神作,无需多言 # 副标题
      desc: "探索随机生成的世界,建造从最简单的住宅到最宏伟的城堡等一切不可思议之物。您可以在创造模式中享用无限资源,也可以在生存模式中挖掘整个世界,合成武器和盔甲,抵御各种危险生物。攀登崎岖的群山,探明复杂的洞穴,挖掘大型矿脉。探索错综的洞穴与石笋洞穴生物群系。用蜡烛照亮世界,展示出自己作为知识渊博的地下冒险者和登山大师的风采!" # 游戏描述
      link: http://www.minecraft.net/ # 游戏链接
      image: https://bu.dusays.com/2024/11/04/672882a184cb7.webp # 游戏封面
此时使用 hexo generate,游戏页面的 HTML 已可正确渲染。如果发现不能正常渲染请使用 hexo clean 清除缓存后重试。

接着来为该界面添加样式。在 solitude/scripts/helper/stylus.js 中定义 games 页面样式引入所需的 stylus 变量:

solitude/scripts/helper/stylus.js
1
2
3
4
5
6
7
8
9
hexo.extend.filter.register('stylus:renderer', function (style) {
    // ...
    style.define('$equipment', !!(data && data.equipment))
    style.define('$games', !!(data && data.games)) 

    // highlight
    const {syntax_highlighter: syntaxHighlighter, highlight, prismjs, shiki} = hexo.config
    // ...
});
再在 solitude/source/css/_page/index.styl 中添加引入样式的代码:
solitude/source/css/_page/index.styl
1
2
3
4
5
6
7
8
// ...
if $about
  @import "_about/about"

if $games
  @import "games.styl"

// ...
最后新建 solitude/source/css/_page/games.styl,写入如下内容:
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
#games
  margin-top 26px

  .game-group
    .game-group-title
      line-height 1

    .game-group-desc
      line-height 1
      margin 4px 0 8px 0
      color var(--efu-secondtext)

    .game-group-content
      display flex
      flex-direction row
      flex-wrap wrap
      margin 0 -8px

      .game-item
        width calc(33% - 12px)
        border-radius 12px
        border var(--style-border-always)
        overflow hidden
        margin 8px 6px
        background var(--efu-card-bg)
        box-shadow var(--efu-shadow-border)
        min-height 400px
        position relative
        user-select none

        +maxWidth1200()
          width calc(50% - 12px)

        +maxWidth768()
          width 100%

        .game-item-cover
          width 100%
          height 200px
          background var(--efu-secondbg)
          display flex
          justify-content center

          .game-item-image
            object-fit cover
            width 100%

        .game-item-info
          padding 8px 16px 16px 16px

          .game-item-name
            font-size 18px
            font-weight 700
            line-height 1
            margin-bottom 8px
            white-space nowrap
            text-overflow ellipsis
            width fit-content
            display inline

            &:hover
              color var(--efu-vip)
              cursor pointer

          .game-item-score
            display inline
            position absolute
            right 1em
            font-size 0.8em
            color var(--efu-secondtext)

          .game-item-spec
            font-size 12px
            color var(--efu-secondtext)
            line-height 1
            margin-bottom 12px
            white-space nowrap
            overflow hidden
            text-overflow ellipsis

          .game-item-desc
            line-height 1.4em
            color var(--efu-secondtext)
            height 5.6em
            display -webkit-box
            overflow hidden
            -webkit-line-clamp 4
            -webkit-box-orient vertical
            font-size 14px

          .game-item-toolbar
            display flex
            justify-content space-between
            position absolute
            bottom 9px
            left 0
            width 100%
            padding 0 16px

            .game-item-link
              font-size 12px
              background var(--efu-gray-op)
              padding 4px 8px
              border-radius 8px
              cursor pointer

              &:hover
                background var(--efu-main)
                color var(--efu-white)
至此,大功告成。

中英混排间距与标点压缩

我使用的是赫蹏(hètí)来进行标点压缩与中英文间距调整,参考:

因为直接改的主题,因此要改的东西多了点,可以参看 commit 了解我的修改。

非原创修改

这部分的改造主要是参考其他博客的教程进行的,且不需要对 Solitude 主题做出较大的改动,因此只放教程博文链接和少量的修改。

访问统计

直接照着做就行,Solitude 主题配置方法一模一样。

侧边栏来访者卡片

直接照着做就行。

友链朋友圈

我这边使用的是 LiuShen 大佬的轻量友链朋友圈,使用 GitHub Action + Netlify 的方式进行部署。

本身没什么好说的,大部分都是直接照着部署即可,不过针对 Solitude 主题需要进行少量修改。

首先是 link.js,也就是用来生成 friend.json 的代码,我根据自己对主题的修改和主题本身的 links.yml 文件结构做了小小的修改:

link.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const YML = require("yamljs");
const fs = require("fs");

let friends = [];
let data_f = YML.parse(
  fs.readFileSync("source/_data/links.yml")
    .toString()
    .replace(/(?<=rss:)\s*\n/g, ' ""\n')
).links; 

data_f.forEach((entry, index) => {
  let lastIndex = 3;
  if (index < lastIndex) {
    const filteredLinkList = entry.link_list.filter((i) => !("noTravel" in i && i.noTravel)); 
    friends = friends.concat(filteredLinkList);
  }
});

// ...

还有就是 Netlify 部署静态网页所需的一点小改动。因为我博客是部署在 GitHub Page 上的,所以需要配置一下跨域。在 main 分支的 static 目录下新建 netlify.toml 文件,里面写上

netlify.toml
1
2
3
4
[[headers]]
  for = "/*"
  [headers.values]
    access-control-allow-origin = "https://blog.hpcesia.com" # 改成你自己的博客地址

同时修改 .github/workflow/friend_circle_lite.yml,commit 中加上 netlify.toml:

.github/workflow/friend_circle_lite.yml
1
2
3
4
5
- name: Commit changes
     run: |
       mkdir pages
       cp -r main ./static/netlify.toml ./static/index.html ./static/readme.md ./static/favicon.ico ./static/bg-light.webp ./static/bg-dark.webp all.json errors.json pages/
       cd pages

然后再运行 Action 即可。

Umami 统计

Umami 是一个可以自部署的开源网站统计工具,可以代替 51LA 进行网站统计。

我自己选择的部署方式是 Vercel + Supabase + Cloudflare Worker,全免费部署。首先需要将 Umami 部署到 Vercel 上,这里我参考的是一篇英文的保姆级教程:

然后需要利用 Cloudflare Worker 来将 Umami 的 API 暴露出来,这里我参考的是梦爱吃鱼大佬的文章:

最后是在 Solitude 主题中接入,翻看源码可以发现关于页面的统计卡片事实上是实现了 Umami 统计的接入的(但是主题文档压根没提),于是我们只需要修改一下 about.yml 即可:

_data/about.yml
1
2
3
4
tj:
  provider: custom
  url: https://umami-api.hpcesia.com/ # 换成你自己部署的 API 入口
  img: https://7.isyangs.cn/1/65eb2e9109826-1.png

底栏图片

我参考的是下面这篇文章的修改方法:

因为我不准备放小动物(目前放的是七七探头.webp),因此稍微修改了一下,你可以直接看 commit 来查看我的修改方式。

Memos 说说接入

参考的是:

根据 0.22 版本 Memos 的 API 变化和 Solitude 主题的更新,做了一些修改,篇幅较长,单独开了一篇文章: