Skip to content

Commit e0dbe95

Browse files
committed
Add post about how to make dark/light mode of comment system reconcile with website theme
1 parent 91d7811 commit e0dbe95

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
+++
2+
title = "Hugo评论系统自适应博客主题: 支持dark与light theme"
3+
date = 2024-12-04T13:25:00+08:00
4+
lastmod = 2024-12-04T14:27:41+08:00
5+
tags = ["blog", "hugo"]
6+
categories = ["blog", "hugo"]
7+
draft = false
8+
toc = true
9+
+++
10+
11+
## <span class="section-num">1</span> 问题 {#问题}
12+
13+
评论系统是博客的关键组件,Hugo 支持若干个评论系统,包括流行的 [Disqus](https://disqus.com/), 基于 GitHub 的 [Giscus](https://giscus.app)[Utteranc](https://utteranc.es/), 以及其他[评论系统](https://gohugo.io/content-management/comments/)
14+
15+
[博客](https://ramsayleung.github.io/)使用的评论系统是 Utteranc, 主题是 [PaperMod](https://github.com/adityatelange/hugo-PaperMod/), PaperMod 支持 dark 和 light 两种主题, 在初始化 Utteranc 时可以指定 theme, 如 `Github-Light`
16+
17+
```html
18+
<script src="https://utteranc.es/client.js"
19+
repo="ramsayleung/comment"
20+
issue-term="title"
21+
theme="github-light"
22+
crossorigin="anonymous"
23+
async>
24+
</script>
25+
```
26+
27+
但是 theme 在初始化时就指定好了,那么在博客切换到 dark theme 的时候, Utteranc 也不会自适应 dark theme,博客的theme与评论theme就不一致:
28+
29+
{{< figure src="/ox-hugo/responsive_comment_theme.jpg" >}}
30+
31+
32+
## <span class="section-num">2</span> 解决思路 {#解决思路}
33+
34+
解决思路其实很简单,就获取当前的 theme, 然后再初始化 Utteranc 对应的 theme; 再在用户切换 theme 之后,再重新初始化 `Utteranc`.
35+
36+
37+
### <span class="section-num">2.1</span> 获取当前Theme {#获取当前theme}
38+
39+
Hugo 并没有提供标准接口来获取当前主题, 虽然可以通过以下的方式来获取的 theme:
40+
41+
```js
42+
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
43+
console.log(isDarkMode ? 'dark' : 'light');
44+
```
45+
46+
但是这个是通过编译出来的CSS来判断当前theme,用户一旦手动切换了 theme, 上面的代码就无法生效了.
47+
48+
每个Hugo主题定义的方式可能还不一样, 以 PaperMod 为例,观察之后发现,light theme的时候body的html 为:
49+
50+
```css
51+
<body id = "top" class="">
52+
</body>
53+
```
54+
55+
dark theme 的时候 `class` 就变为了 `class`"dark"=:
56+
57+
```css
58+
<body id = "top" class="">
59+
</body>
60+
```
61+
62+
所以可以通过判断 `body` 是否包含 `dark` 的 class 来判断当前是否为 dark theme.
63+
64+
```js
65+
// 不同的Hugo theme可能会需要不同的判断方式
66+
function getCurrentTheme() {
67+
return document.body.classList.contains('dark') ? 'dark' : 'light';
68+
}
69+
```
70+
71+
72+
### <span class="section-num">2.2</span> 初始化评论系统 {#初始化评论系统}
73+
74+
[Utteranc](https://utteranc.es/) 文档提供的启用评价系统代码如下:
75+
76+
```html
77+
<script src="https://utteranc.es/client.js"
78+
repo="[ENTER REPO HERE]"
79+
issue-term="pathname"
80+
theme="github-light"
81+
crossorigin="anonymous"
82+
async>
83+
</script>
84+
```
85+
86+
因为我们需要在切换 Theme 时重新加载 Utteranc, 所以就需要通过 Javascript 来实现上面的HTML功能:
87+
88+
```js
89+
function loadUtterances(darkMode=false) {
90+
const commentContainer = document.getElementById("comments-utteranc");
91+
if (commentContainer !== null) {
92+
commentContainer.innerHTML = ''
93+
const commentScript = document.createElement("script");
94+
commentScript.setAttribute("id", "utteranc");
95+
commentScript.setAttribute("src", "https://utteranc.es/client.js");
96+
commentScript.setAttribute("data-repo", "ramsayleung/comment");
97+
commentScript.setAttribute("data-theme", darkMode ? "github-dark" : "github-light");
98+
commentScript.setAttribute("data-issue-term", "title");
99+
commentScript.setAttribute("crossorigin", "anonymous");
100+
commentScript.setAttribute("async", "true");
101+
commentContainer.appendChild(commentScript);
102+
}
103+
}
104+
```
105+
106+
107+
### <span class="section-num">2.3</span> 监听主题变动 {#监听主题变动}
108+
109+
用户可以在博客界面手动选择他们喜欢的主题,可以从 `dark` -&gt; `light`, `light` -&gt; `dark`, 我们需要做的就是监听主题的变动,在切换主题之后,重新加载评论系统。
110+
111+
```js
112+
// Watch for theme changes
113+
const themeObserver = new MutationObserver((mutations) => {
114+
mutations.forEach((mutation) => {
115+
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
116+
const isDarkMode = getCurrentTheme() === 'dark';
117+
loadUtterances(isDarkMode);
118+
console.log(`changing theme`);
119+
}
120+
});
121+
});
122+
123+
// Start observing the body element for class changes
124+
themeObserver.observe(document.body, {
125+
attributes: true,
126+
attributeFilter: ['class']
127+
});
128+
```
129+
130+
131+
## <span class="section-num">3</span> 总结 {#总结}
132+
133+
自适应评论系统的代码[在这里](https://github.com/ramsayleung/ramsayleung.github.io/blob/master/layouts/partials/comments.html), 实现的效果如下:
134+
135+
{{< figure src="/ox-hugo/responsive_comment_theme_2.jpg" >}}
136+
137+
{{< figure src="/ox-hugo/responsive_comment_theme_3.jpg" >}}
250 KB
Loading
260 KB
Loading
255 KB
Loading

0 commit comments

Comments
 (0)