hugo主题stack

目录

主题介绍:

需要使用hugo的 hugo_extended版本: https://github.com/gohugoio/hugo/releases

魔改后增强功能列表

  • 显示分类目录
  • 支持直接插入markdown文件同一目录下的图片,插入图片语法: ![](picFileName)
  • 支持直接插入markdown文件同一目录下的csv文件,插入csv文件语法:![](xxx.csv), csv 将直接转为 表格. csv文件的字符编码建议用 utf8
  • 外链在新页面中打开,文章内超链接的颜色为蓝色或黄色(暗色模式)
  • 点击头像跳转到 /. (头像影响手机端搜索页面用户体验,已删除)
  • 支持prism语法高亮
  • checkbox任务列表
  • 回到顶部按钮
  • 支持 Bootstrap Icons,需要打开goldmark unsafe开关
  • 右边栏标题的图标和文字在一行上:直接干掉图标
  • 彩色标签云,彩色分类
  • 优化分类和标签页面标题显示
  • 支持mathjax
  • 支持文章随机特色图像
  • 支持php,mysql全文搜索,支持多关键字搜索交集 (主题默认基于json的搜索在文章数量多时速度慢)
  • 一般的Linux虚拟主机都提供php和mysql数据库
  • 支持本地使用 http://localhost:1313/ 调试时依然使用 json 搜索方式.
  • 支持图像zoom
  • 支持mermaid作图

windows上安装hugo的 hugo_extended 版本

参考 https://gohugo.io/getting-started/installing/https://github.com/gohugoio/hugo/releases 下载最新 hugo_extended 版本, 解压到 D:\shell\hugo.exe , 将 D:\shell\加入系统path

使用Hugo写博客需要注意的内容

  • 文章放在 content\post 目录下
  • 文章title中有冒号时,title加引号
  • 文章tag需要作为数组提供 [tag1,tag2]
  • 文章头的key: value 值,冒号后要有空格
  • 文章头的key: value 值,值如果是数组,需要用空格
  • 文章头的date格式: 2021-04-02T13:15:59+08:00, 其中+08:00为时区, 这样写 date: 2020-10-22 18:00 能解析文章但是归档显示等有问题
  • 文章slug生成的url, hugo会处理成小写

插入csv文件测试

ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1-character bytes object
c_wchar wchar_t 1-character string
c_byte char int
c_ubyte unsigned?char int
c_short short int
c_ushort unsigned?short int
c_int int int
c_uint unsigned?int int
c_long long int
c_ulong unsigned?long int
c_longlong __int64?or?long?long int
c_ulonglong unsigned?__int64?or?unsigned?long?long int
c_size_t size_t int
c_ssize_t ssize_t?or?Py_ssize_t int
c_float float float
c_double double float
c_longdouble long?double float
c_char_p char?*?(NUL terminated) bytes object or?None
c_wchar_p wchar_t?*?(NUL terminated) string or?None
c_void_p void?* int or?None

引用

思念是最暖的忧伤像一双翅膀
让我停不了飞不远在过往游荡
不告而别的你 就算为了我着想
这么沉痛的呵护 我怎么能翱翔

最暖的憂傷 - 田馥甄

图片

svg 图片测试:

相册测试:

![Photo by Florian Klauer on Unsplash](florian-klauer-nptLmg6jqDo-unsplash.jpg)  ![Photo by Luca Bravo on Unsplash](luca-bravo-alS7ewQ41M8-unsplash.jpg) 

![Photo by Helena Hertz on Unsplash](helena-hertz-wWZzXlDpMog-unsplash.jpg)  ![Photo by Hudai Gayiran on Unsplash](hudai-gayiran-3Od_VKcDEAA-unsplash.jpg)

相册语法来自 Typlog

emoji

配置文件: enableEmoji: true, EMOJI CHEAT SHEET: https://www.webfx.com/tools/emoji-cheat-sheet/

<style type="text/css">
.emoji {
  font-family: Apple Color Emoji, Segoe UI Emoji, NotoColorEmoji, Segoe UI Symbol, Android Emoji, EmojiSymbols;
}
</style>

Emoji测试: 👿

Math Typesetting

主题默认的是 KaTeX, 魔改已经替换为 mathjax.

mathjax建议用版本3,解析速度快, 但行内解析存在一个问题就是hugo默认会转义\, 行内的 \(公式\), 需要书写为 \\(公式\\)

mathjax 测试:

(带小括号的文本)

Inline math:$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $ , \\(x = {-b \pm \sqrt{b^2-4ac} \over 2a}\\)

Block math:

$$
 \varphi = 1+\frac{1} {1+\frac{1} {1+\frac{1} {1+\cdots} } } 
$$


When \\(a \ne 0\\), there are two solutions to \\(ax^2 + bx + c = 0\\) and they are
  $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$


$$
w^{(l)}{ij} = w^{(l)}{ij} - \eta\frac{\partial E(W, b)}{\partial w^{(l)}_{ij}}
$$

显示效果:

(带小括号的文本)

Inline math:$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $ , \(x = {-b \pm \sqrt{b^2-4ac} \over 2a}\)

Block math:

$$ \varphi = 1+\frac{1} {1+\frac{1} {1+\frac{1} {1+\cdots} } } $$

When \(a \ne 0\), there are two solutions to \(ax^2 + bx + c = 0\) and they are $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$

$$ w^{(l)}{ij} = w^{(l)}{ij} - \eta\frac{\partial E(W, b)}{\partial w^{(l)}_{ij}} $$

Markdown Syntax Guide

Markdown语法,可参考 Markdown 指南

mysql 全文检索

创建php 全文检索接口,共hugo调用

参考: https://www.jianshu.com/p/c48106149b6a

  1. 在mysql中创建全文索引表

参考: https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-ngram.html

CREATE TABLE posts (
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      slug VARCHAR (200) NOT NULL,
      title VARCHAR(200),
      body TEXT,
      FULLTEXT (title,body) WITH PARSER ngram
    ) ENGINE=InnoDB CHARACTER SET utf8mb4;

SET NAMES utf8mb4;

2.编写一个 python脚本 fts_mysql.py 填充数据

3.多词:检索方式

SELECT slug FROM posts
WHERE MATCH (title,body)
AGAINST ('+银河' IN BOOLEAN MODE);

4.编写search.php

参考:

5.修改 search.html, 调用 search.php

访问统计: 不蒜子

参考: http://ibruce.info/2015/04/04/busuanzi/

修改\themes\stack\layouts\partials\footer\footer.html

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js">
</script>

        <br />本站访客数<span id="busuanzi_value_site_uv"></span>人次
        <span id="busuanzi_container_site_pv"> 总访问量<span id="busuanzi_value_site_pv"></span>次 </span>
        <span id="busuanzi_container_page_pv">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>

性能优化: jsdeliver 托管css,js,部分图片

参考: https://elume.github.io/2020/01/28/0015_githubjsdelivrfreecdn/

  • github 创建新仓库:“cdn”,勾选自动创建readme.md文件选项。
  • 上传js,css

jsDelivr 路径解释:https://cdn.jsdelivr.net/gh/用户名/仓库名@版本号/文件路径

部分托管的文件:

  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/js/prism.js
  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/js/csv.min.js
  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/css/prism.css
  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/other/beian_ghs.png
  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/other/avatar.png
  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/other/favicon.ico
  • https://cdn.jsdelivr.net/gh/yinhedot/cdn/other/logo.png

https://cdn.jsdelivr.net/gh/yinhedot/cdn/css/style.min.css

对应:

<!-- {{- partial "head/style.html" . -}} -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/yinhedot/cdn/css/style.min.css">

https://cdn.jsdelivr.net/gh/yinhedot/cdn/js/main.js

themes\stack\layouts\partials\footer\components\script.html

对应:

<!-- <script type="text/javascript" src="{{ $script.RelPermalink }}" defer></script> -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/yinhedot/cdn/js/main.js" defer></script>

utterances评论

参考:

安装配置:

    comments:
        enabled: true
        provider: utterances # disqus

        utterances:
            repo: yinhedot/utterances
            issueTerm: pathname
            theme: dark-orange
            label: utterances

手动增加ICP备案信息

编辑 themes\stack\layouts\partials\footer\footer.html

<span class="text-ellipsis">&copy;&nbsp;2021 Copyright&nbsp;&nbsp; &nbsp;
            <a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=51019002002885" style="display:inline-block;text-decoration:none;">
        <img src="/beian_ghs.png" style="float:left;"/>川公网安备 51019002002885号</a>&nbsp; &nbsp;<a href="https://beian.miit.gov.cn/" rel="external nofollow" target="_blank">蜀ICP备20011690号</a></span>

url 以 .html结尾

uglyurls: true  # url 以 .html结尾

修复归档页面出现年份 0001的问题

编辑 themes\stack\layouts\partials\widget\archives.html

        <div class="widget-archive--list">
            {{ range $index, $item := first (add .Site.Params.widgets.archives.limit 1) ($archives) }}
                {{- $id := lower (replace $item.Key " " "-") -}}
                {{ if ne .Key "0001" }}
                    <div class="archives-year">
                        <a href="{{ $archivesPage.RelPermalink }}#{{ $id }}">
                            {{ if eq $index $.Site.Params.widgets.archives.limit }}
                                <span class="year">{{ T "widget.archives.more" }}</span>
                            {{ else }}
                                <span class="year">{{ .Key }}</span>
                                <span class="count">{{ len $item.Pages }}</span>
                            {{ end }}
                        </a> 
                    </div>
                {{ end }}  
            {{ end }}
        </div>

支持mathjax

参考:

mathjax建议用版本3,解析速度快, 但行内解析存在一个问题就是hugo默认会转义\, 行内的 \(公式\), 需要书写为 \\(公式\\)

因为不能修改hugo程序源码,只能将就hugo, MDNotes中写预处理函数.

编辑 themes\stack\layouts\partials\head\head.html

<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
      tex2jax: {
        inlineMath: [ ['$','$'], ['\\(', '\\)'] ],
        processEscapes: true
      }
    });
  </script>
<script type="text/javascript" async
    src="https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-MML-AM_CHTML">
    </script>

编辑配置文件:

    article:
        math: false

优化分类和标签页面标题显示

编辑 themes\stack\layouts\_default\list.html

原始内容:

{{ define "main" }}
    <h3 class="section-title">
        {{ if eq .Parent (.GetPage "/") }}
            {{ T "list.section" }}
        {{ else }}
            {{ .Parent.Title }}
        {{ end }}
    </h3>

    <div class="section-card">
        <div class="section-details">
            <h3 class="section-count">{{ T "list.page" (len .Pages) }}</h3>
            <h1 class="section-term">{{ .Title }}</h1>
            {{ with .Params.description }}
                <h2 class="section-description">{{ . }}</h2>
            {{ end }}
        </div>

        {{- $image := partialCached "helper/image" (dict "Context" . "Type" "section") .RelPermalink "section" -}}
        {{ if $image.exists }}
            <div class="section-image">
                {{ if $image.resource }}
                    {{- $Permalink := $image.resource.RelPermalink -}}
                    {{- $Width := $image.resource.Width -}}
                    {{- $Height := $image.resource.Height -}}

                    {{- if (default true .Page.Site.Params.imageProcessing.cover.enabled) -}}
                        {{- $thumbnail := $image.resource.Fill "120x120" -}}
                        {{- $Permalink = $thumbnail.RelPermalink -}}
                        {{- $Width = $thumbnail.Width -}}
                        {{- $Height = $thumbnail.Height -}}
                    {{- end -}}

                    <img src="{{ $Permalink }}" 
                        width="{{ $Width }}"
                        height="{{ $Height }}" 
                        loading="lazy">
                {{ else }}
                    <img src="{{ $image.permalink }}" loading="lazy" />
                {{ end }}
            </div>
        {{ end }}
    </div>

修改后:

{{ define "main" }}
    <h3 class="section-title">
        {{ if eq .Parent (.GetPage "/") }}:{{ .Title }}
            {{ T "list.section" }}
        {{ else }}
            {{ .Parent.Title }}:{{ .Title }}
        {{ end }}
    </h3>
  • 列表页显示 tag, 不显示分类 (显示太多内容,手机显示有问题)
  • 文章页的head显示 分类和标签,删掉文章末尾的 tag.

彩色标签云,彩色分类

编辑 themes\stack\layouts\partials\footer\footer.html

    <script>
        function color_tags() {
            var colorArr = ["#428BCA", "#AEDCAE", "#ECA9A7", "#DA99FF", "#FFB380", "#D9B999"];
            $('.tagCloud-tags a').each(function () {
                try {
                    tagsColor = colorArr[Math.floor(Math.random() * colorArr.length)];
                    $(this).css("background", tagsColor); 
                }
                catch (err) { }
            });
        }

        $(document).ready(function () {
            color_tags()
        });
    </script>

首页文章列表的分类移到文章下面,在文章下面添加tag列表

编辑 themes\stack\layouts\partials\article\components\details.html

details.html原始内容:

<div class="article-details">
    {{ if .Params.categories }}
    <header class="article-category">
        {{ range (.GetTerms "categories") }}
            <a href="{{ .RelPermalink }}" {{ with .Params.style }}style="background-color: {{ .background }}; color: {{ .color }};"{{ end }}>
                {{ .LinkTitle }}
            </a>
        {{ end }}
    </header>
    {{ end }}

    <h2 class="article-title">
        <a href="{{ .RelPermalink }}">
            {{- .Title -}}
        </a>
    </h2>

    {{ with .Params.description }}
    <h3 class="article-subtitle">
        {{ . }}
    </h3>
    {{ end }}

    {{- if not .Date.IsZero -}}
    <footer class="article-time">
        {{ partial "helper/icon" "clock" }}
        <time class="article-time--published">
            {{- .Date.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
        </time>
    </footer>
    {{- end -}}
</div>

使用的图标文件在: \themes\stack\assets\icons 下, tag图标下沉2px: style="margin-top:2px;"

右边栏标题的图标和文字在一行上:直接干掉图标

搜索 <h2 class="widget-title 删除相关图标.

支持在 Hugo 的 Markdown 里直接使用 HTML

直接配置goldmark: unsafe: true 即可, 不需要下面的操作.

支持 Bootstrap Icons

参考: https://icons.getbootstrap.com/, themes\stack\layouts\partials\head\head.html 中添加:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css">

替换icon: 直接从 https://icons.getbootstrap.com/ 下载文件到 themes\stack\assets\icons

替换的 icon:

  • tag
  • categories, 使用folder2替换的

引用icon: {{ partial "helper/icon" "search" }}

checkbox任务列表

编辑\themes\stack\layouts\post\single.html

function dom_ajust() {
        // checkbox
        $('input').each(function () {
            if ($(this).attr('type') == "checkbox") {
                if (typeof($(this).attr('checked'))!="undefined") {
                    try {
                        $(this).removeAttr("disabled");
                        $(this).attr("onclick", "return  false;");
                    } catch (err) { }
                }
            }
        });
    }

语法:

- [x] 显示分类目录
    - [x] 支持直接插入markdown文件同一目录下图片,语法: `![](picFileName)`
    - [x] 外链在新页面中打开,文章内超链接的颜色为蓝色
        - [ ] 点击头像跳转到 `/`
            - [ ] 支持prism语法高亮
            - [x] checkbox任务列表

效果:

  • 显示分类目录
    • 支持直接插入markdown文件同一目录下图片,语法: ![](picFileName)
    • 外链在新页面中打开,文章内超链接的颜色为蓝色
      • 点击头像跳转到 /
        • 支持prism语法高亮
        • checkbox任务列表

回到顶部按钮

编辑 themes\stack\layouts\partials\footer\components\custom-font.html

    //back to top
    $.goup({
        trigger: 300,
        bottomOffset: 20,
        locationOffset: 20,
        title:  'Back to TOP',
        titleAsText: false
    });

支持prism语法高亮

参考:

将 prism.css,prism.js 放入 /static/

themes\stack\layouts\partials\head\head.html 中添加:

<link rel="stylesheet" href="/prism.css">

themes\stack\layouts\partials\footer\footer.html 中添加

<script src="/prism.js"></script>

注释掉 config.yaml 中的如下行

# markup:
#     highlight:
#         noClasses: false

为了显示行号,需要给pre添加class <pre class="line-numbers">, 最后生成的代码类似下面这种:

<pre class="line-numbers language-bash" style="white-space:pre-wrap;">
<code class="language-bash">function clrhist() {
awk -i inplace -v rmv="$1" '!index($0,rmv)' "$HISTFILE"
}</code></pre>

编辑\themes\stack\layouts\post\single.html, deal_prism() 中调用了之前生成的/static/prism.js

function deal_prism() {
        $('pre').each(function () {
            if ($(this).attr('style') == "color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4") {
                try {
                    $(this).attr('style',"white-space:pre-wrap;");
                    $(this).removeClass();
                    $(this).addClass("line-numbers language-bash");
                } catch (err) { }
            }
        });
        $.getScript("/prism.js");
    }

    $(document).ready(function () {
        deal_links();
        deal_local_imgs();
        deal_prism();
    });

显示分类目录

参考 https://github.com/CaiJimmy/hugo-theme-stack/issues/169

  1. Create categories.html in layouts/partials/widget
<section class="widget tagCloud">
  <div class="widget-icon">
      <i class="bi bi-folder2"></i>
  </div>
  <h2 class="widget-title section-title">{{ T "widget.categoriesCloud.title" }}</h2>

  <div class="tagCloud-tags">
      {{ range first .Site.Params.widgets.categoriesCloud.limit .Site.Taxonomies.categories.ByCount }}
          <a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
              {{ .Page.Title }}
          </a>
      {{ end }}
  </div>
</section>
  1. 修改 config.yaml
widgets:
        enabled:
            - categories

        categoriesCloud:
            limit: 20

3.修改 themes\stack\i18n\en.yaml

widget:
    categoriesCloud:
        title: 
            other: Categories

4.修改 themes\stack\i18n\zh-CN.yaml

widget:
    categoriesCloud:
        title: 
            other: 分类
  1. Download categories.svg paste to assets/icons, from here

hugo主题stack中的图片和csv文件的处理

主题图片处理文件 themes\stack\layouts\_default\_markup\render-image.html 用到的 resources.Get 只能获取 assets 目录下的文件,参考: https://gohugo.io/hugo-pipes/introduction/#from-file-to-resource

In order to process an asset with Hugo Pipes, it must be retrieved as a resource using resources.Get, which takes one argument: the filepath of the file relative to the asset directory.

所以要想图片和 Markdown文档放在一起, 必须配置assetDir 为 content:

assetDir: "content"

hugo 默认并不能将 csv 处理为图片,会报错, csv文件由 js处理, 在 render-image.html 中需要先处理 csv:

  • alt 为文件名
  • id 用于 js调用, 使用 md5 计算
  • style 用于隐藏对应的 img 标签
{{if and $image (eq (path.Ext $image    ) ".csv")}}
        <img src="/" alt="{{.Destination}}" id="{{ md5 .Destination}}" style="display:none;" />

hugo 并不支持 svg 文件的相关图片处理, 也单列直接输出图片.

支持直接插入markdown文件同一目录下的图片和csv文件

有多个csv文件时,请求必须不是异步的: async: false

  1. 更新图片的源

编辑 themes\stack\layouts\_default\_markup\render-image.html, 如果图片不存在, id修改为文件名, src修改为 '/'

{{- else -}}

    {{ if eq (substr .Destination 0 4) "http" }}
        <img src="{{ .Destination | relURL | safeURL }}" alt="{{ .Text }}" {{ with .Title }} title="{{ . }}"{{ end }} />
    {{ else if (fileExists  (.Destination | relURL)) -}}
        <img src="{{ .Destination | relURL | safeURL }}" alt="{{ .Text }}" {{ with .Title }} title="{{ . }}"{{ end }} />
    {{ else }}
        <img src="/" alt="{{ .Destination }}"  id="{{md5 .Destination}}" />
    {{ end }}

{{- end -}}
  1. 修改src为 / 的图片的src

获取 markdown文件的目录,参考 https://gohugo.io/variables/files/#readout, \themes\stack\layouts\post\single.html 中添加函数 deal_local_imgs() , 引入隐藏的 {{.File.Dir}} .

需要用到 jquery, 在themes\stack\layouts\partials\footer\footer.html 中添加

<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-goup@1.1.3/src/jquery.goup.min.js"></script>

3.csv文件的解析

使用 CSV.js, 从 https://github.com/knrz/CSV.js 下载最新release版本 3.6.4, 将 csv.min.js 放到 static 目录,编辑\themes\stack\layouts\post\single.html

外链在新页面中打开,文章内超链接的颜色为蓝色或黄色

编辑\themes\stack\layouts\post\single.html, 文章在 <section class="article-content"> 之内

        var orignalSetItem = localStorage.setItem;

    localStorage.setItem = function (key, newValue) {
        var setItemEvent = new Event("setItemEvent");
        setItemEvent.newValue = newValue;
        window.dispatchEvent(setItemEvent);
        orignalSetItem.apply(this, arguments);
    }

    window.addEventListener("setItemEvent", function (e) {

        if (e.newValue == 'dark' || e.newValue == 'light') {
            deal_links2();
        }
    });

    function deal_links() {
        // 外网url,在新tab页打开
        $('a').each(function () {
            try {
                var url = decodeURIComponent($(this).attr("href"));
                $(this).attr('href', url);
                var parser = document.createElement('a');
                parser.href = url;
                if (parser.hostname != window.location.hostname) {
                    $(this).attr('target', '_blank');
                }
            } catch (err) { }
        });

        // css for link 
        $('.article-content a').each(function () {
            try {
                if (localStorage.getItem('StackColorScheme')=='dark') {
                    $(this).css('color', 'yellow');
                } else {
                    $(this).css('color', 'blue');
                }
            }
            catch (err) { }
        });

        // 去掉 ul, li 下的超链接的下划线
        $("ul li a").css({ "text-decoration": "none" });
    }

    function deal_links2() {
        // css for link while change dark mode
        $('.article-content a').each(function () {
            try {
                if (localStorage.getItem('StackColorScheme')=='dark') {
                    $(this).css('color', 'blue');

                } else {
                    $(this).css('color', 'yellow');
                }
            }
            catch (err) { }
        });
    }

    $(document).ready(function () {
        deal_links();
    });

参考: https://www.jianshu.com/p/519a1b42d659,在同一个网页修改本地存储,又在同一个网页监听,这样是没有效果的。在同一个页面中,需要对 localStorage 的 setItem 方法进行重写.

点击头像跳转到 /

themes\stack\layouts\partials\sidebar\left.html, 跳转到 /

<a href="/"><img src="{{ .src }}" width="300" height="300" class="site-logo" loading="lazy" alt="Avatar"></a>
                {{ else }}
                    {{ $avatar := resources.Get (.src) }}

                    {{ if $avatar }}
                        {{ $avatarResized := $avatar.Resize "300x" }}
                        <a href="/"><img src="{{ $avatarResized.RelPermalink }}" width="{{ $avatarResized.Width }}"
                            height="{{ $avatarResized.Height }}" class="site-logo" loading="lazy" alt="Avatar"></a>

bug修复,分页最后一页没有内容

a. 编辑 themes\stack\layouts\partials\article-list\default.html, 加判断条件, 只能解决空文章的问题

{{ if ne "/" (path.Dir .RelPermalink) }}
    <article class="{{ if $image.exists }}has-image{{ end }}">
        {{ partial "article/components/header" . }}
    </article>
{{ end }}

b.依然有空白页的原因排查结果: 一个md文档没有添加 head 的meta

引用样式

    /* 引用样式 */
    .article-content blockquote {
        border: 0.1em dashed #c76c0c;
    }

    .article-content blockquote:before {
        color: #392570;
        content: "\201C";
        font-size: 3em;
        position: absolute;
        left: 15px;
        top: 35px;
        line-height: 0.1em;
    }

    .article-content blockquote:after {
        color: #392570;
        content: "\201D";
        font-size: 3em;
        position: absolute;
        right: 15px;
        bottom: 0em;
        line-height: 0.1em;
    }

    .article-content p span {
        display: block;
        font-size: 16px;
        line-height: 1.3em;
        font-weight: 700;
        font-style: normal;
        margin-top: 1.1em;
        letter-spacing: 0;
        font-style: italic;
    }

代码:

> Creativity is just connecting things. When you ask creative people how they did something, they feel a little guilty because they didn't really do it, they just saw something. It seemed obvious to them after a while. That's because they were able to connect experiences they've had and synthesize new things.
> 
>  <span>Steve Jobs</span>

效果:

Creativity is just connecting things. When you ask creative people how they did something, they feel a little guilty because they didn't really do it, they just saw something. It seemed obvious to them after a while. That's because they were able to connect experiences they've had and synthesize new things.

Steve Jobs

使用 FreeFileSync 通过ftp同步本地文件夹到虚拟主机

FreeFileSync: https://freefilesync.org/download.php

使用:

  • 同步方式: 镜像
  • 左侧:本地hugo的public文件夹 ~\public
  • 右侧:远程ftp文件夹: /htdocs
  • 点击同步开始同步

自用主题, 基于原始主题 stack 的老版本已经做了比较多的定制.

安装 extended 版本 hugo

https://github.com/gohugoio/hugo/releases

下载 extended 版本, 高版本可能部分功能不支持stack主题, 目前可用版本: hugo_extended_0.86.0_Linux-64bit.deb

安装:

dpkg -i xxx.deb`
apt-get install supervisor
# vi /var/run/supervisor.sock  ---> 创建空文件保存
chmod 777 /var/run/supervisor.sock
systemctl enable supervisor.service
systemctl start supervisor.service
cd /etc/supervisor/conf.d/
vi hugo.conf

不用在VPS端构建hugo的public,本地在 rsync 相关的脚本中构建然后同步效率更高。

/etc/supervisor/conf.d/hugo.conf

如果使用 --cleanDestinationDir 参数, 该目录下的文件会不时被删除.

[program:hugo]
command=/usr/local/bin/hugo  -w --cleanDestinationDir ;被监控的进程路径
numprocs=1                    ; 启动一个进程
directory=/hugo_yinhe/     ;执行前切换路径
autostart=true                ; 随着supervisord的启动而启动
autorestart=true              ; 自动重启
startretries=10                 ; 启动失败时的最多重试次数
exitcodes=0                     ; 正常退出代码
stopsignal=KILL               ; 用来杀死进程的信号
stopwaitsecs=10               ; 发送SIGKILL前的等待时间 
stderr_logfile=/var/log/hugo_stderr.log  ; 指定日志文件
stdout_logfile=/var/log/hugo_stdout.log 
#把stderr重定向到stdout,默认 false
redirect_stderr=true          ; 重定向stderr到stdout   
stdout_logfile_maxbytes = 50MB ;stdout日志文件大小,默认 50MB
stdout_logfile_backups = 10 ; stdout日志文件备份数
  • -w, --watch watch filesystem for changes and recreate as needed
  • --cleanDestinationDir remove files from destination not found in static directories
  • -d, --destination string filesystem path to write files to

启动:

supervisorctl reload
supervisorctl start hugo

supervisor其他命令:

#启动进程
supervisorctl start xxx
#重启进程
supervisorctl restart xxx
#重启所有属于名为group的分组进程
supervisorctl stop group
#停止全部进程
supervisorctl stop all
#载入最新配置的文件
supervisorctl reload
#根据最新的配置文件,启动新配置或有改动的进程
supervisorctl update

添加网站 sns分享

参考: https://github.com/overtrue/share.js, cdn: https://cdnjs.com/libraries/social-share.js

使用 cdnjs,引入 share.min.css 与 social-share.min.js 两个链接就好。

  • themes\stack\layouts\partials\article\components\header.html: 添加 css
  • themes\stack\layouts\partials\article\components\footer.html: 添加 js
  • 腾讯微博, 点点貌似已经挂了,可以禁止掉。 列表:"weibo","qq","wechat","tencent","douban","qzone","linkedin","diandian","facebook","twitter","google"
  • themes\stack\layouts\partials\article\components\tags.html: 添加代码 <div class="social-share" data-disabled="tencent,diandian"></div>

显示markdown 文件路径

如果host 为localhost, 显示markdown 文件路径

config.yaml

params:
    contentDir: "dir to hugo /content/"
    showLocalContentDir: true # 是否显示本地目录

themes\stack\layouts\partials\article\components\content.html

    {{ .Content }}

    <div id="div_for_local_dir_id" class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-txt" data-lang="python">{{ .Site.Params.contentDir }}{{replace (.File) "\\" "/"}}</code></pre></div>
</section>

404

/etc/nginx/sites-enabled/default

location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }
        error_page 404 /404.html;

添加图片 \static\404.jpg

themes\stack\layouts\404.html

{{ define "main" }}
    <!-- <div class="not-found-card">
        <h1 class="article-title">{{ T "notFound.title" }}</h1>
        <h2 class="article-subtitle">{{ T "notFound.subtitle" }}</h2>
    </div> -->
    <a href="/"><img style="display: inline-block; width: 100%; max-width: 100%; height: auto;" src="/404.jpg" /></a>
    {{ partialCached "footer/footer" . }}
{{ end }}

全文检索数据库参数配置

支持配置文件中配置 search.php的数据库参数

1.需要 yaml 扩展

apt-get install -y php7.4-yaml
service php7.4-fpm restart
  1. public 建议使用默认目录, 这样 search.php 才不用配置路径就直接读取配置文件 config.yaml

/etc/nginx/sites-enabled/default

        root /hugo_yinhe/public;

/etc/supervisor/conf.d/hugo.conf: 不要使用 --cleanDestinationDir 参数, 会导致 matomo子目录或其他子目录被删除.

[program:hugo]
command=/usr/local/bin/hugo  -w --minify --cleanDestinationDir;被监控的进程路径
numprocs=1                    ; 启动一个进程
directory=/hugo_yinhe/     ;执行前切换路径
autostart=true                ; 随着supervisord的启动而启动
autorestart=true              ; 自动重启
startretries=10                 ; 启动失败时的最多重试次数
exitcodes=0                     ; 正常退出代码
stopsignal=KILL               ; 用来杀死进程的信号
stopwaitsecs=10               ; 发送SIGKILL前的等待时间
stderr_logfile=/var/log/hugo_stderr.log  ; 指定日志文件
stdout_logfile=/var/log/hugo_stdout.log
#把stderr重定向到stdout,默认 false
redirect_stderr=true          ; 重定向stderr到stdout
stdout_logfile_maxbytes = 50MB ;stdout日志文件大小,默认 50MB
stdout_logfile_backups = 10 ; stdout日志文件备份数
~                                                      

service supervisor restart

3.配置参数

config.yaml

###############
# 搜索配置参数
###############
search_db_servername: "localhost"
search_db_dbname: "dbname"
search_db_username: "username"
search_db_password: "password"

显示TOC文章目录

stack新版本的主题和老版本并不兼容, 在老版本上修改完成.

layouts\partials\article\components\content.html

<section class="article-content">
    {{ if (gt .WordCount 400) }}
        <h2 id="toc_head_id">目录</h2>
        <p id="WordCount_id" hidden>{{ .WordCount }}</p>
        {{ .TableOfContents }}
    {{end}}

    {{ .Content }}
</section>

文章字数达到一定数量才显示目录.

layouts\partials\article\components\footer.html

 <script>
        $(document).ready(function () {
            document.getElementById("toc_head_id").style.display = "none";
            if ($("h2").length > 4 || $("h1").length > 2 || $("h3").length > 2) {
                    document.getElementById("toc_head_id").style.display = "block";
            }
        });

    </script>

h2,h1,h3 达到一定数量, 才显示出目录块.

config.yaml

params:
    toc: true  

markup:
    tableOfContents: # 仅适用于 goldmark
        # https://gohugo.io/getting-started/configuration-markup/#table-of-contents
        endLevel: 4
        ordered: false  # 不自动用数字编号
        startLevel: 2
    highlight:
        noClasses: false

如果有 [TOC] 或者 [TOC], 强制添加目录

stack\layouts\partials\article\components\content.html

<section class="article-content">
    <p id="WordCount_id" hidden>{{ .WordCount }}</p>
    <div id="toc_id">
        <h2>目录</h2>
        {{ .TableOfContents }}
    </div>

    {{ .Content }}
</section>

layouts\partials\article\components\footer.html

$(document).ready(function () {
            // 如果有 <p>[TOC]
</p>, 则删除该内容,并将 WordCount_id 的值设置为10000
            $("p").each(function () {
                var text = $(this).text();
                if(text.toLowerCase()=="[TOC]
"){
                    // 如果存在 
                    $(this).hide();
                    document.getElementById("toc_id").style.display = "block";
                    document.getElementById("WordCount_id").text=10000;
                }
            });

            //如果字数大于400,并且有一些标题,则输出目录
            document.getElementById("toc_id").style.display = "none";
            if ($("h2").length > 4 || $("h1").length > 2 || $("h3").length > 2) {
                    if (document.getElementById("WordCount_id").text>400){
                        document.getElementById("toc_id").style.display = "block";
                    }  
            }
        });

文章置顶

文章默认按照时间排序,如果我们想置顶某篇文章,可以在FrontMatter设置weight属性(权重),权重最大文章在最前面。

weight: 1000

stack主题是否需要头图设置

config.yaml

params:
    # 是否需要头图设置
    showHeaderImgArticle: false # post是否显示头图

layouts\partials\article\components\header.html

                {{ else }}
                    {{ if .Site.Params.showHeaderImgArticle }}
                        <img src="{{ $image.permalink }}" loading="lazy" alt="Featured image of post {{ .Title }}" />
                    {{ end }}
                {{ end }}
            </a>
        </div>
    {{ end }}

    {{ partialCached "article/components/details" . .RelPermalink }}
</header>

mathjax

cdn 引入

参考:

不要用3.1.2 ,用2.7.x系列, 包含 MathJax.Hub ,需要加上配置文件 ?config=TeX-MML-AM_CHTML ,配置文件说明参考 https://docs.mathjax.org/en/v2.7-latest/start.html

<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-MML-AM_CHTML"></script>

采用本地方式引入

https://github.com/mathjax/MathJax/releases 下载 2.7.9, 解压后保留如下文件夹和文件:

  • config:只保留 TeX-MML-AM_CHTML-full.js
  • MathJax.js
  • fonts\HTML-CSS\STIX-Web
  • fonts\HTML-CSS\TeX
  • jax\output\CommonHTML\fonts\TeX

本地引入:

<script src="/static/MathJax-2.7.9/MathJax.js?config=TeX-MML-AM_CHTML-full"></script>

数学公式动态刷新的问题:使用 MathJax.Hub.Queue

参考:

要点:

  1. 不能重复定义相关变量,只能定义一次:
<head>
    <meta charset="UTF-8" />
    <script type=text/javascript>
    let isMathjaxConfig = false;
    const initMathjaxConfig = () => {
    if (!window.MathJax) {
        return;
    }
    window.MathJax.Hub.Config({
        showProcessingMessages: false,
        messageStyle: "none",
        jax: ["input/TeX", "output/HTML-CSS"],
        svg: {
            fontCache: 'global'
        },
        tex2jax: {
            inlineMath: [["\\(", "\\)"]],
            displayMath: [["$$", "$$"], ["\\[", "\\]"]],
            skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"],
            macros: {
                bf: '{\boldsymbol f}',
                bu: '{\boldsymbol u}',
                bv: '{\boldsymbol v}',
                bw: '{\boldsymbol w}'
            }
        },
        "HTML-CSS": {
            availableFonts: ["STIX", "TeX"],
            showMathMenu: false
        }
    });
    isMathjaxConfig = true;
};
</script>
  1. 文档加载后刷新公式
$(document).ready(function () {
    // mathjax
        if (isMathjaxConfig === false) {
            initMathjaxConfig();
        }
        // mathjax for vue app id #app
        window.MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('app')]);

    });

3.需要动态刷新时,重新加载 Hub.Queue

                        // mathjax
                        if (isMathjaxConfig === false) {
                            initMathjaxConfig();
                        }
                        // mathjax for vue app id #app
                        window.MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('app')]);

使用 rsync 本地文件夹同步到远程vps

vps: mkdir /hugo_yinhe

本地: sudo apt-get install rsync

本地文件夹: /mnt/d/97blog_rm/hugodir/

远程文件夹 /hugo_yinhe

本地, 将 export PATH=~/bin:"$PATH" 添加到 ~/.bashrc, 创建 ~/bin/yinhe

#!/bin/bash
# This is our first script.
# 将脚本所在目录加入 $PATH
set -x #echo on
rsync -av --delete  --exclude "resources"  --exclude "public"  --exclude "content/jsconfig.json"  --exclude  "__pycache__"  /mnt/d/97blog_rm/hugodir/  root@ip:/hugo_yinhe`

chmod 700 yinhe

本地命令(如果使用 --delete, 会删除不存在的文件):

  • -a参数除了可以递归同步以外,还可以同步元信息(比如修改时间、权限等)
  • -v参数则是将结果输出到终端,这样就可以看到哪些内容会被同步。
  • --delete参数会使得destination成为source的一个镜像。如果要使得目标目录成为源目录的镜像副本,则必须使用--delete参数,这将删除只存在于目标目录、不存在于源目录的文件。
  • ssh同步: username@remote_host:destination .rsync 默认使用 SSH 进行远程登录和数据传输。
  • --exclude 排除文件夹, 注意用相对路径即可

在新的shell里执行yinhe 即可同步

参考:

安装配置 isso评论系统

如果配置 SMTP, 发送的邮件会提供 评论链接, 删除评论的链接, 激活评论的链接, 非常方便管理评论.

mkdir /isso
chown -R www-data:www-data /isso
apt-get install python-dev sqlite3 build-essential
apt install python3-pip
pip install isso
pip install --upgrade isso
pip install gevent
mkdir /var/log/isso/
chown -R www-data:www-data /usr/local/lib/python3.8/dist-packages/isso

服务端配置, 默认配置文件路径 /etc/isso.conf, 需要创建该配置文件

[general]
; 数据库位置,注意检查权限,如果没有会自动创建。
dbpath = /isso/comments.db
; 博客的地址,可以添加多个,比如 http 和 https
host = https://yinhe.com/
log-file = /var/log/isso/isso.log
; 评论通知 for 管理员,使用 smtp
notify = smtp
; 通知用户,smtp 发邮件
reply-notifications = true
gravatar = true
gravatar-url = https://sdn.geekzu.org/avatar/{}?d=identicon

[server]
listen = http://localhost:8080/

[guard]
# 开启 SPAM 保护。防止一些恶意攻击。比如限制每个钟的新评论个数。
enabled = true
# 每分钟内最多五个新评论
ratelimit = 5
require-email = false
direct-reply = 999

; 启用后台管理系统,访问地址 isso_url/admin
; 密码的有些字符不能用?!
[admin]
enabled = true
password=password

; 是否开启审核,true 是开启,30d 表示删除 30 天没有通过审核的评论
[moderation]
enabled = true
purge-after = 30d

[smtp]
# smtp 服务器名,我选择的gmail邮箱,是这样;qq邮箱或者别的的话需要查一下
host = smtp.gmail.com
port = 465
# 加密方式,gmail必须
security = ssl
username = gmail_username
password = password 
# 通知邮件发到哪里,可以与上面的相同,那就是自己发给自己
to = xx@xx.com
from = "ISSO Comment System" <xx@xx.com>
timeout = 20

Gravatar全球头像加速, 参考:

关于Gmail 的 SMTP服务,需要设置降低Gmail的smtp安全性, 访问 https://myaccount.google.com/u/2/lesssecureapps?pageId=none, 选择:安全性较低的应用的访问权限,允许安全性较低的应用.

修改 nginx 配置文件并重启: ^~/isso/表示匹配前缀是isso的请求,proxy_pass的结尾有/, 则会把/isso/*后面的路径直接拼接到后面,即移除isso.

location ^~/isso {
                 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                 proxy_set_header X-Script-Name /isso;
                 proxy_set_header Host $host;
                 proxy_set_header X-Forwarded-Proto $scheme;
                 proxy_pass http://localhost:8080;
        }

测试:

shell1: isso run

shell2: curl http://localhost:8080/js/embed.min.js

如果看到输出很多 js 代码,成功!

关闭isso: ps -ef |grep isso | awk '{print $2}' | xargs kill -9

hugo 主题设置

hugo主题stack 配置: themes\stack\layouts\post\single.html, 注意禁止掉原来的评论系统. 用自动生成的头像css看起来正常很多.

{{ if or (not (isset .Params "comments")) (eq .Params.comments "true")}}
{{ partial "comments/include" . }}
{{ end }}

<script data-isso="https://yinhe.com/isso/"
        data-isso-css="true"
        data-isso-lang="zh"
        data-isso-reply-notifications="true"
        data-isso-reply-to-self="true"
        data-isso-require-author="false"
        data-isso-require-email="false"
        data-isso-max-comments-top="10"
        data-isso-max-comments-nested="5"
        data-isso-reveal-on-click="5"
        data-isso-avatar="true"
        data-isso-gravatar="false"
        data-isso-vote="true"
        data-vote-levels=""
        src="https://yinhe.com/isso/js/embed.min.js"></script>

<section id="isso-thread"></section>

{{ partialCached "footer/footer" . }}

设置supervisor

vi /etc/supervisor/conf.d/isso.conf

[program:isso]
command=/usr/local/bin/isso  run ;被监控的进程路径
numprocs=1                    ; 启动一个进程
autostart=true                ; 随着supervisord的启动而启动
autorestart=true              ; 自动重启
startretries=100                 ; 启动失败时的最多重试次数
exitcodes=0                     ; 正常退出代码
stopsignal=KILL               ; 用来杀死进程的信号
stopwaitsecs=10               ; 发送SIGKILL前的等待时间
stderr_logfile=/var/log/isso_stderr.log  ; 指定日志文件
stdout_logfile=/var/log/isso_stdout.log
#把stderr重定向到stdout,默认 false
redirect_stderr=true          ; 重定向stderr到stdout
stdout_logfile_maxbytes = 50MB ;stdout日志文件大小,默认 50MB
stdout_logfile_backups = 10 ; stdout日志文件备份数

重启 : supervisorctl restart isso

to do

参考

© Licensed under CC BY-NC-SA 4.0

实力永远意味着责任和危险。 —— 罗斯福. T.

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!