How to Enable Giscus Comments System in Hugo

Table of Contents

Giscus介绍

Giscus是一个基于GitHub Discussions的开源评论系统,非常好用!

然而,不是所有的Hugo主题都支持这个评论系统,或者说大部分都不支持。🫠

所以,本篇使用了一种比较hack的方式(即不修改主题源代码),为原先不支持giscus的主题开启giscus评论系统的支持。

注意,本教程以目前所使用的Anatole主题为例,其他主题会略有不同,但原理是相似的。

Hack原理解释

首先,大部分主题应该是有Disqus或者其他的评论支持的,然后它们判断是否开启评论区一般是这么实现的:

{{- if .Site.DisqusShortname -}}
<div id="comment">
    <h2>{{ i18n "comments" }}</h2>
    {{ template "_internal/disqus.html" . }}
</div>
{{- end -}}
{{- if .Site.Params.utterances.repo -}}
<div id="comment">
    <h2>{{ i18n "comments" }}</h2>
    {{ partial "comments/utterances.html" . }}
</div>
{{- end -}}

可以看到,他们通过判断config文件中是否存在相关评论系统的配置来开启对应的Comments System。

所以这就比较好办了,因为我们可以通过Hugo Templatelayouts/partials这类目录,覆写掉原先的comments代码,而不用去修改主题源代码。

添加giscus的HTML模版

这里以修改utterancesgiscus评论系统为例,只需要在本地layouts/partials/comments目录下创建utterances.html文件,即可替换掉相关源码内容。

文件里面可以添加如下代码:

<script 
    src="https://giscus.app/client.js"
    data-repo="[ENTER REPO HERE]"
    data-repo-id="[ENTER REPO ID HERE]"
    data-category="[ENTER CATEGORY NAME HERE]"
    data-category-id="[ENTER CATEGORY ID HERE]"
    data-mapping="pathname"
    data-strict="0"
    data-reactions-enabled="1"
    data-emit-metadata="0"
    data-input-position="bottom"
    data-theme="preferred_color_scheme"
    data-lang="en"
    crossorigin="anonymous"
    async
></script>

修改配置文件

为了开启Giscus支持,还是需要在配置文件中配置Hack的评论系统的,相当于一个激活开关:

utterances:
    repo: anything here

然后不出意外的话,就OK了!

自动更换主题

现在giscus是配置好了,但是如果主题原先是支持Light/Dark这种模式的话,会发现giscus的主题不会随着网站主题的颜色变化而变化,这是不能忍的

但是好在我们可以添加JS脚本来解决这个问题,例如将原有的代码更换为以下代码时,可以在访问页面时自动适配当前主题。

<script>
    let giscusTheme = localStorage.getItem("theme");
    let giscusAttributes = {
        "src": "https://giscus.app/client.js",
        "data-repo": "[ENTER REPO HERE]",
        "data-repo-id": "[ENTER REPO ID HERE]",
        "data-category": "[ENTER CATEGORY NAME HERE]",
        "data-category-id": "[ENTER CATEGORY ID HERE]",
        "data-mapping": "pathname",
        "data-reactions-enabled": "1",
        "data-emit-metadata": "0",
        "data-theme": giscusTheme,
        "data-lang": "en",
        "crossorigin": "anonymous",
        "async": "",
    };

    let giscusScript = document.createElement("script");
    Object.entries(giscusAttributes).forEach(([key, value]) => giscusScript.setAttribute(key, value));
    document.getElementById("comment").appendChild(giscusScript);
</script>

但是又可以发现,当我们手动切换主题时,giscus的主题是不会跟着更新的。

所以,我们需要监听主题开关的点击事件,然后随之更换giscus的主题,于是最终代码:

<script>
    const getStoredTheme = () => localStorage.getItem("theme") === "dark" ? "dark" : "light";

    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": "[ENTER REPO HERE]",
            "data-repo-id": "[ENTER REPO ID HERE]",
            "data-category": "[ENTER CATEGORY NAME HERE]",
            "data-category-id": "[ENTER CATEGORY ID HERE]",
            "data-mapping": "pathname",
            "data-strict": "0",
            "data-reactions-enabled": "1",
            "data-emit-metadata": "0",
            "data-input-position": "bottom",
            "data-theme": getStoredTheme(),
            "data-lang": "en",
            "data-loading": "lazy",
            "crossorigin": "anonymous",
            "async": "",
        };

        // Dynamically create script tag.
        const giscusScript = document.createElement("script");
        Object.entries(giscusAttributes).forEach(
            ([key, value]) => giscusScript.setAttribute(key, value));
        document.getElementById("comment").appendChild(giscusScript);

        // Update giscus theme when the theme switcher is clicked.
        const themeSwitcher = document.querySelector(".themeswitch");
        if (themeSwitcher) {
            themeSwitcher.addEventListener("click", setGiscusTheme);
        }
    });
</script>

完事,收工!🎉

Ref: https://github.com/giscus/giscus/issues/336

comments