Featured image of post Hexo迁移到hugo指北|Hugo配置|自定义|美化

Hexo迁移到hugo指北|Hugo配置|自定义|美化

本文介绍了从 Hexo 到 Hugo 的博客迁移过程,包括配置文件设定、自定义主题、添加阅读进度条、友链页面等实用技巧。涵盖 Stack 主题的自定义样式调整和页面优化,帮助博客作者提升网站加载速度和个性化定制体验。

最近,我将我的博客从Hexo迁移到了Hugo。起因是最近在查资料的时候,发现了一个很好看的博客,看到是用Hugo生成的,于是就萌生了从Hexo迁移到护国的想法。 Hexo其实也挺好用的,当时我自建blog的时候,就已经有Hugo了,但是当时Hugo的资料不多,于是就选了了Hexo。这是想要换到Hugo,主要是看中了 Hugo中 Stack 这个主题。 还一个原因是我不喜欢Hexo使用 Node.js。我一个写后端的,平时也用不到Node,而且对 npm 的命令也不熟悉,总之用起来就很别扭。 Hugo还一个优点是构建的速度比Hexo快得多,当然我目前使用Hexo还没有在构建上花费太多时间。好了闲话就说到这里把,下面我将分享一些关于如何将Hexo迁移到Hugo的经验。

在开始之前,需要先下载Hugo,可以去GitHub下载。下载的时候,需要根据自己的系统选择对应的版本,下载的时候记得下载 extended 的版本。 这是支持 SCSSPostCSS 的版本。 下载完成后,解压到一个目录,然后将解压后的目录添加到环境变量中。 安装完成后,可以通过 hugo version 命令查看是否安装成功。

我将分 Hugo配置自定义 这两个部分来讲。

Hugo配置

因为 Hugo 中,很多目录在 项目目录themes(主题) 目录下都有,所以在介绍的时候,没有特殊说明都是在 项目目录 下。

Hugo配置文件

Hugo配置文件支持多种格式,比如 tomlyamljson。我选择的是 yaml 格式。Hugo的配置文件是 根目录的config.yaml

下面根据层级来介绍一下Hugo的配置文件

这是根层的配置,主要是一些基本的配置,比如网站的基础URL、网站的语言、默认的内容语言、使用的主题、每页显示多少文章、网站的标题等。

 1baseurl: https://lqxhub.github.io # 网站的基础URL
 2languageCode: zh-cn # 网站的语言
 3defaultContentLanguage: "zh-cn" # 默认的内容语言
 4theme: hugo-theme-stack # 使用的主题
 5paginate: 10 # 每页显示多少文章
 6title: "QX 的笔记" # 网站的标题
 7hasCJKLanguage: true # 是否使用CJK语言,用到中文的时候需要设置为true
 8summaryLength: 200 # 摘要的长度
 9enablePermalinks: true # 启用永久链接
10enableEmoji: true # 开启 Emoji 支持
11enableInlineShortcodes: true # 开启内联 Shortcodes 支持
12noTimes: false # 同步文件的修改时间。

这些配置没有什么好说的,就是一些基本的配置,根据自己的需求来配置就好。

1permalinks:
2  post: /posts/:slug/ # 文章的永久链接
3  page: /:slug/ # 页面的永久链接

这个配置是文章和页面的永久链接,文章的永久链接是 /posts/:slug/,页面的永久链接是 /:slug/。 这里的 :slug 是文章生成的 hash 值,因为我再Hexo中的文章的 hash值,所以这里也使用 hash值。 后面在构建的时候,页面的 URL 格式是 baseurl/posts/slug。比如这篇文章的 URLhttps://lqxhub.github.io/posts/a660c9b1/

 1params:
 2  mainSections: # 首页从哪些部分获取文章
 3    - post
 4  dateFormat: # 日期格式,必须是符合 Go 语言的日期格式
 5    published: Jan 02, 2006 # 发布日期
 6    lastUpdated: Jan 02, 2006 15:04 MST # 最后更新日期
 7
 8  footer: # 页脚的配置
 9    enable: true # 是否启用页脚
10    since: 2021 # 网站创建年份
11    customText: "© QX" # 页脚的自定义文本
12    copyright: true # 是否显示版权信息
13    author: true # 是否显示作者信息
14
15  favicon: icons/favicon.ico # 浏览器 Tab 页的网站图标
16  sidebar: # 侧边栏的配置
17    emoji: 😉
18    subtitle: "雄关漫道真如铁,而今迈步从头越"
19    avatar: # 作者头像
20      enabled: true
21      local: true
22      src: img/avatar.gif
23
24    featuredImageField: image # 文章的封面图片从哪个字段获取,这里是从image字段获取
25    rssFullContent: false # RSS 是否开启全内容 / false 则为只有摘要
26
27  article: # 文章的配置
28    headingAnchor: true # 是否开启标题锚点
29    math: true # 这里关闭是因为我们使用的是 MathJax
30    toc: false # TOC 文章也右边的导航
31    readingTime: true # 阅读时间
32    license: # 文章的版权信息
33      enabled: true # 是否启用版权信息
34      default: 'Licensed under CC BY-NC-SA 4.0' # 默认的版权信息
35
36  widgets: # 网页中右边的小部件
37    homepage: # 首页的小部件
38      - type: search # 搜索框
39      - type: archives # 归档
40        params:
41          limit: 5 # 归档显示的数量
42      - type: categories # 分类
43        params:
44          limit: 10 # 分类显示的数量
45      - type: tag-cloud # 标签云
46        params:
47          limit: 10 # 标签云显示的数量
48    page:
49      - type: "toc" # TOC 文章也右边的导航
50
51  colorScheme: # 颜色主题
52    toggle: true  # 是否显示切换按钮
53    # Available values: auto, light, dark
54    default: auto # 默认的颜色主题

这里配置项比较多,挑几个不好理解的来说一下。

这部分就是 footer 配置对应图片应该能看懂,这里就不多说了。

相关的配置都在图片里标注了

sidebar 配置是侧边栏的配置,这里配置了作者的头像、作者的名字、作者的座右铭、作者的头像等。

widgets 配置是网页中右边的小部件,这里配置了首页的小部件,包括搜索框、归档、分类、标签等。有不想显示的,在配置中删除就行。

下面是 mene 相关的配置

 1menu:
 2  main:
 3    - identifier: home
 4      name: 首页
 5      url: /
 6      weight: -100
 7      params:
 8        newTab: false
 9        icon: home
10    - identifier: categories
11      name: 分类
12      url: /categories
13      weight: 1
14      params:
15        newTab: false
16        icon: categories
17  social:
18    - identifier: email
19      name: Email
20      url: mailto:lqxlucky@qq.com
21      params:
22        newTab: true
23        icon: email
24    - identifier: github
25      name: GitHub
26      url: https://github.com/lqxhub
27      params:
28        newTab: true
29        icon: brand-github

这是精简后的,在图片中,sidebar 下面的是 social 的配置,再往下是 main 的配置。

这里说一下 main 中的一些问题

  • identifier:标识符
  • name 菜单的名字
  • url 菜单的链接
  • weight 是权重,权重越小,菜单越靠前。
  • newTab 是否在新标签页打开
  • icon 菜单的图标

如果不需要自定义的话,直接配置就行了,在构建的时候,会自动生成菜单。一些 icon 可能主题中没有,需要自己添加,我再配置时有好几个没有找到, 我使用 chatGPT 生成了一些图标

如果要自定义,那么需要在 content 目录下创建一个和 访问这个页面的 URL 同名的目录,然后在新建的目录下创建一个 _index.md 文件, 然后在 _index.md 文件中配置

分类 为例,content/categories/_index.md 的配置如下:

1---
2title: "分类"
3license: false
4---

这里主要是改一下 title,只有 网页的标题和 配置中的 name 相同时,在点击对应的菜单后,对应的菜单名才会高亮。

social 都是常见的内容,这里就不多说了。

页面渲染相关的配置:

 1markup:
 2  defaultMarkdownHandler: goldmark
 3  tableOfContents: # TOC 文章也右边的导航
 4    ordered: true # 是否有序
 5    startLevel: 2 # 从 2级标题开始
 6    endLevel: 5 # 到 5级标题结束
 7  highlight: # 代码高亮配置
 8    codeFences: true # 是否启用代码块
 9    guessSyntax: true # 是否猜测语法
10    lineNoStart: 1 # 代码块的起始行号
11    lineNos: true # 是否显示行号
12    lineNumbersInTable: false # 是否在表格中显示行号
13    noClasses: true # 是否不使用类
14    style: "dracula" # 代码块的样式
15    tabWidth: 4 # tab 的宽度

这部分也是比较好理解的,主要是代码高亮的配置,这里使用的是 dracula 主题。 不同主题的效果,可以去这里查看。

页面中的配置

在每篇文章的 front matter 中,可以配置一些文章的信息,比如文章的标题、作者、日期、标签、分类等。 可以使用 yamltoml 等,我使用的是 YAML 格式。 使用 --- 来分隔 是 yaml 格式的配置,使用 +++ 来分隔是 toml 格式的配置。

1+++
2date = 2024-10-20T17:31:37+08:00
3title = "Linux下使用iouring实现一个tcp服务"
4slug = "f0e9829c"
5categories = ["linux", "C++"]
6tags = ["linux", "iouring", "tcp", "C++"]
7description = "探索 Linux io_uring 异步 I/O 接口,通过 liburing 库实现高效 TCP 服务。本文深入 io_uring 的基础概念,包括 Submission Queue 和 Completion Queue,并通过示例代码演示如何初始化、提交 I/O 请求和处理完成事件。了解 io_uring 如何提升 I/O 密集型应用的性能,以及在实际部署中需要注意的错误处理和连接管理。"
8image = "https://cdn.jsdelivr.net/gh/lqxhub/images@master/blog/6a84474a44a97bccecbbc9c5a3b9f7aea2571c97.jpg"
9+++

这里简单说一下

  • date 文章的日期,必须是 GO 语言的日期格式
  • title 文章的标题
  • slug 文章的永久链接
  • categories 文章的分类,可以有多个,Hugo在构建的时候,会自动生成分类的页面
  • tags 文章的标签,可以有多个,Hugo在构建的时候,会自动生成标签的页面
  • description 文章的描述,会在首页的文章列表中显示,也是 SEO 的一部分
  • image 文章的封面图片,会在首页的文章列表中显示

在说一下 分类 中的封面

也就是图片中标注的部分,这个是分类的封面,如果不配置的话,会使用默认的封面,如果想要自定义的话,可以在 content/categories 目录下创建一个和 分类 同名的目录, 比如 content/categories/linux,然后在 linux 目录下创建一个 _index.md 文件,然后在 _index.md 文件中配置

1---
2title: "linux"
3slug: "linux"
4image: "https://cdn.jsdelivr.net/gh/lqxhub/images@master/blog/Linux.jpg"
5weight: 10
6---

其中 image 就是分类的封面,weight 是权重,权重越小,分类越靠前。

搜索 页面的配置,在添加了搜索页面的时候,需要在 content/search 目录下创建一个 index.md 文件,然后在 index.md 文件中配置

1---
2title: "搜索"
3layout: "search"
4outputs: 
5  - "html"
6  - "json"
7sitemap:
8  priority: 0.1
9---

如果没有配置 outputs 的话,搜索页中的搜索功能是无效的,这里配置了 htmljson,这样就可以在搜索页中搜索文章了。

1
2## 迁移到Hugo
3
4### 创建Hugo项目
5在迁移之前,需要先创建一个Hugo项目。在Hexo中,我们可以通过 `hexo init` 命令来创建一个Hexo项目。而在Hugo中,我们可以通过 `hugo new site` 命令来创建一个Hugo项目。
6
7```shell
8hugo new site blog

public 是构建后生成的目录,也就是生成网站的根目录 content 目录是存放文章的目录, layouts 目录是存放模板的目录,static 目录是存放静态文件的目录, 这个目录的内容在构建时会直接复制到网站的根目录下。themes 目录是存放主题的目录。这些目录都是Hugo创建项目时自动生成的。 别的目录在后面用到的时候再介绍。

迁移文章

在Hexo中,文章是存放在 source/_posts 目录下的,而在Hugo中,文章是存放在 content 目录下的。所以我们需要将Hexo中的文章迁移到Hugo中。

我的习惯还是在 content 目录下创建一个 post 目录,然后将Hexo中的文章迁移到 post 目录下。迁移完成后,目录结构如下:

然后把Hexo中的文章迁移到 post 目录下。这样就完成了文章的迁移。这时候,我们可以通过 hugo 命令来构建项目, 这时候大概率是构建失败的,因为我们还没有配置Hugo的配置文件。

首先要解决的是 front matter 的问题,Hugo中的 date 必须是 Go 语言的日期格式,这里需要改成 Go 语言的日期格式。 在Hugo中,永久连接的是 slug,如果原来文章使用了永久连接,需要改一下。

迁移图片

我的图片是使用的 GitHub 作为图床,所以图片的链接是 GitHub 的链接。不需要改动,直接使用就行。

到这里,应该能成功构建出网站了,下面是一些自定义的内容。

自定义Hugo

我使用的是 Stack 主题,这个主题是我在查资料的时候发现的,觉得挺好看的,所以就选择了这个主题。但是主题内一些东西没有,需要自己添加。

这里先介绍一下Hugo加载文件的顺序,Hugo加载文件的顺序是 themes 目录下的文件优先级最高,然后是项目中 layouts 目录下的文件,最后是 archetypes 目录下的文件。

如果项目中的 layouts 目录中有和 themes 目录中的文件同名的文件,那么项目中的文件会覆盖 themes 目录中的文件。这样我们就可以自定义主题了。

自定义友链页

layouts/shortcodes 目录下创建一个 friends.html 文件,然后在 friends.html 文件中配置

 1
 2{{- $css := resources.Get "extended/blank.css" }}
 3{{- if $css }}
 4{{- $css := $css | resources.ToCSS | resources.Minify }}
 5<link rel="stylesheet" href="{{ $css.RelPermalink }}">
 6{{- end }}
 7
 8{{- if .IsNamedParams -}}
 9<a target="_blank" href={{ .Get "url" }} title={{ .Get "name" }} class="friendurl">
10<div class="frienddiv">
11    <div class="frienddivleft">
12        <img class="myfriend" src={{ .Get "logo" }} />
13    </div>
14    <div class="frienddivright">
15        <div class="friendname">{{- .Get "name" -}}</div>
16        <div class="friendinfo">{{- .Get "word" -}}</div>
17    </div>
18</div>
19</a>
20{{- end }}

还需要在 assets/extented 目录下创建一个 blank.css 文件,然后在 blank.css 文件中自定义友链页面的样式。

  1.friendurl {
  2    text-decoration: none !important;
  3    color: black;
  4    box-shadow: none !important;
  5}
  6
  7.myfriend {
  8    width: 56px !important;
  9    height: 56px !important;
 10    border-radius: 50%!important;
 11    padding: 2px;
 12    margin-top: 20px !important;
 13    margin-left: 14px !important;
 14    background-color: #fff;
 15}
 16
 17.frienddiv {
 18    overflow: auto;
 19    height: 100px;
 20    width: 49%;
 21    display: inline-block !important;
 22    border-radius: 5px;
 23    background: none;
 24
 25    -webkit-transition: all ease-out 0.3s;
 26    -moz-transition: all ease-out 0.3s;
 27    -o-transition: all ease-out 0.3s;
 28    transition: all ease-out 0.3s;
 29}
 30
 31.dark .frienddiv:hover {
 32    background: var(--code-bg);
 33}
 34
 35.frienddiv:hover {
 36    background: var(--theme);
 37    transition: transform 1s;
 38    webkit-transform: scale(1.1);
 39    -moz-transform: scale(1.2);
 40    -ms-transform: scale(1.2);
 41    -o-transform: scale(1.2);
 42    transform: scale(1.1);
 43}
 44
 45.frienddiv:hover .frienddivleft img {
 46    transition: 0.9s !important;
 47    -webkit-transition: 0.9s !important;
 48    -moz-transition: 0.9s !important;
 49    -o-transition: 0.9s !important;
 50    -ms-transition: 0.9s !important;
 51    transform: rotate(360deg) !important;
 52    -webkit-transform: rotate(360deg) !important;
 53    -moz-transform: rotate(360deg) !important;
 54    -o-transform: rotate(360deg) !important;
 55    -ms-transform: rotate(360deg) !important;
 56}
 57
 58.frienddivleft {
 59    width: 92px;
 60    float: left;
 61    margin-right: -5px;
 62}
 63
 64.frienddivright {
 65    margin-top: 18px;
 66    margin-right: 18px;
 67}
 68
 69.friendname {
 70    text-overflow: ellipsis;
 71    font-size: 100%;
 72    margin-bottom: 5px;
 73    color: var(--primary);
 74}
 75
 76.friendinfo {
 77    text-overflow: ellipsis;
 78    font-size: 70%;
 79    color: var(--primary);
 80}
 81
 82@media screen and (max-width: 600px) {
 83    .friendinfo {
 84        display: none;
 85    }
 86    .frienddivleft {
 87        width: 84px;
 88        margin: auto;
 89    }
 90    .frienddivright {
 91        height: 100%;
 92        margin: auto;
 93        display: flex;
 94        align-items: center;
 95        justify-content: center;
 96    }
 97    .friendname {
 98        font-size: 18px;
 99    }
100}

到这,友链页面的模板就完成了,然后在 content 目录下创建一个 friends/index.md 文件,然后在 index.md 文件中配置

 1---
 2type: friend
 3hiddenFromSearch: true
 4readingTime: false
 5license: false
 6title: 友链
 7contentEnd: false
 8toc: false
 9image: "https://cdn.jsdelivr.net/gh/lqxhub/images@master/blog/54de3f8d81a4f97fb1ac4dc06eaf3fda335a5937.webp"
10---

friend.md 的内容如下,因为直接写入这段文字,会被解析,所以这里就不写了,使用图片了

这样友链页面就完成了,在构建的时候,友链页面会自动生成。

添加阅读进度条

在页面顶部加一个阅读进度条,即实用又美观。在 layouts/partials 目录下创建一个 readingbar.html 文件,然后在 readingbar.html 文件中配置

layouts/partials/head/ 目录下的 custom.html 中 添加 这段代码

 1{{ if strings.HasPrefix .RelPermalink "/posts/" }}
 2<div class="top-scroll-bar"></div>
 3<style>
 4    .top-scroll-bar {
 5        position: fixed;
 6        top: 0;
 7        left: 0;
 8        z-index: 9999;
 9        display: none;
10        width: 0;
11        height: 3px;
12        background: #ef3982;
13    }
14</style>
15
16<script>
17    $(document).ready(function () {
18        $(window).scroll(function(){
19            $(".top-scroll-bar").attr("style", "width: " + ($(this).scrollTop() / ($(document).height() - $(this).height()) * 100) + "%; display: block;");
20        });
21    });
22</script>
23{{ end }}

说一下这个 readingbar.html 文件,看名字就知道,这个文件是 Hugo 允许我们自定义 生成 HTMLhead 部分的内容。 Hugo 在构建的时候,会自动加载这个文件,所以我们可以在这个文件中添加一些 HTML 代码,比如 CSSJS 等。

添加返回顶部按钮

custom.html 文件中添加这段代码

 1<div id="back-top">
 2    <a href="#top" title="回到顶部"></a>
 3</div>
 4<style>
 5    #back-top {
 6        position: fixed;
 7        bottom: 30px;
 8        right: 80px;
 9    }
10    #back-top a {
11        width: 54px;
12        height: 54px;
13        display: block;
14        background: #ddd url(/images/back_top.svg) no-repeat center center;
15        background-color: rgba(218, 214, 214, 0.87);
16        -webkit-border-radius: 7px;
17        -moz-border-radius: 7px;
18        border-radius: 7px;
19        -webkit-transition: 1s;
20        -moz-transition: 1s;
21        transition: 1s;
22    }
23    #back-top a:hover {
24        background-color: #e88282;
25    }
26</style>
27
28<script type="text/javascript">
29    $("#back-top").hide();
30    $(document).ready(function () {
31        $(window).scroll(function () {
32            if ($(this).scrollTop() > 100) {
33                $('#back-top').fadeIn();
34            } else {
35                $('#back-top').fadeOut();
36            }
37        });
38        $('#back-top a').click(function () {
39            $('body,html').animate({
40                scrollTop: 0
41            }, 800);
42            return false;
43        });
44    });
45</script>

图片灯箱效果

Hugo 自带的图片渲染是没有灯箱效果的,所以我们需要自己添加。灯箱效果就是点击图片后,图片会放大显示。

还是在 custom.html 文件中添加这段代码

1{{if .Page.Site.Params.fancybox }}
2<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>
3<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
4<script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>
5{{ end }}

然后在 layouts/_default 目录下 新建 render-image.html文件,然后在 render-image.html 文件中配置

1<div class="post-img-view">
2    <a data-fancybox="gallery" href="{{ .Destination | safeURL }}">
3        <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}"{{ end }} />
4    </a>
5</div>

这段代码的作用是替换 Hugo 默认的图片渲染,这样就可以实现点击图片放大显示的效果了。

修改列表渲染样式

我使用的 Stack 主题,在给 homepage 添加了 Widget 后,除了主页的文章列表显示了, 标签分类 也显示了。

这不是我想要的,我只想在主页显示文章列表,所以需要修改一下 layouts/_default 目录下的 my_list.html 文件。 然后把 Stack 主题中的 layouts/_default/list.html 文件复制到 项目的layouts/_default 目录下,然后修改 my_list.html 文件中的内容。

把最后面那段代码删除就行了。也就是下面这段代码

1{{ define "right-sidebar" }}
2{{ partial "sidebar/right.html" (dict "Context" . "Scope" "homepage") }}
3{{ end }}

然后在想使用这个模板的页面中,把 layout 改成 my_list 就行了。

比如 content/categories/_index.md 文件中的配置

1---
2title: "分类"
3contentEnd: false
4license: false
5layout: my_list
6---

其实这给我们提供了一个思路,就是 Hugo 的模板是可以自定义的,我们可以根据自己的需求来修改模板,这样就可以实现自己想要的效果了。

搜索引擎验证信息

我们自建的博客,需要提交到搜索引擎中,这样搜索引擎才能收录我们的博客。这时候就需要在博客中添加搜索引擎验证信息。可以使用在网站的目录中放一个 html 文件,然后在 html 文件中添加验证信息。

也可以在每个网页中添加验证信息,这样就不需要在网站的目录中放一个 html 文件了。这条验证信息是在 head 中添加的,所以我们可以在 custom.html 文件中添加这条验证信息。

1{{ if .Site.Params.google_site_verification }}
2<meta name="google-site-verification" content="{{ .Site.Params.google_site_verification }}" />
3{{ end }}
4
5{{ if .Site.Params.bing_site_verification }}
6<meta name="msvalidate.01" content="{{ .Site.Params.bing_site_verification }}" />
7{{ end }}

添加完这段代码后,我们就可以在 config.yaml 文件中添加 google_site_verificationbing_site_verification 了。

1  google_site_verification: "XXX"
2  bing_site_verification: "XXX"

XXX 替换成对应的验证信息就行了。

这段配置需要在 params 层级下配置,这样就可以在 head 中添加搜索引擎验证信息了。

板娘

就是左下角的那个小女孩,这个是我在网上找的, GitHub

添加方法也很简单,只需要在 layouts/partials/head 目录下的 custom.html 文件中添加这段代码就行了。

1<script src="https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js"></script>

自动部署

一般都会使用 git 来管理博客的源码,然后使用 GitHub Actions 来自动部署博客。这样我们只需要在 git 仓库中提交代码,然后 GitHub Actions 就会自动构建并部署博客。 像我的博客就是这样的,我使用 GitHub Actions 来自动构建并部署博客。并且使用 GitHub的 Pages 功能来托管博客。

这时候我会使用两个 GitHub 仓库,一个用来存放 Hugo 项目的源码,一个用来存放 Hugo 项目构建后的静态文件。

并且把 存放源码的仓库设置为 private,因为GitHub的限制,GitHub Pages 只支持 public 仓库。

这样就可以实现自动部署了,只需要在 git 仓库中提交代码,然后 GitHub Actions 就会自动构建并部署博客。

在源码的仓库中,需要添加一个 .github/workflows 目录,然后在 .github/workflows 目录中创建一个 deploy.yml 文件,然后在 deploy.yml 文件中配置

 1name: Deploy
 2
 3env:
 4  GIT_USER: lqx # GitHub 用户名
 5  GIT_EMAIL: lqxlucky@qq.com # GitHub 邮箱
 6  PAGE_REPO: git@github.com:lqxhub/lqxhub.github.io.git # 存放静态文件的仓库(GitHub page的仓库)
 7
 8on:
 9  push:
10    branches:
11      - master # 源码仓库的分支
12
13  workflow_dispatch:
14
15jobs:
16  build:
17    runs-on: ubuntu-latest
18
19    steps:
20      - name: checkOut # 拉取源码
21        uses: actions/checkout@v4
22      - name: Setup Hugo # 安装 Hugo
23        uses: peaceiris/actions-hugo@v3
24        with:
25          hugo-version: '0.136.2' # Hugo 版本
26          extended: true # 是否使用扩展版本
27      - name: Build the website # 构建hugo页面
28        run: |
29          sudo timedatectl set-timezone "Asia/Shanghai" # 设置时区
30          hugo --minify # 构建页面 这里使用了 --minify 参数,这样构建的页面会更小          
31
32      - name: Deploy # 部署
33        env:
34          DEPLOY_SECRET: ${{ secrets.DEPLOY_SECRET }} # GitHub的密钥
35        run: |
36          mkdir -p ~/.ssh
37          echo "$DEPLOY_SECRET" > ~/.ssh/id_rsa
38          chmod 600 ~/.ssh/id_rsa
39          ssh-keyscan github.com >> ~/.ssh/known_hosts
40          git config --global user.name "${{ env.GIT_USER }}"
41          git config --global user.email "${{ env.GIT_EMAIL }}"
42
43          cd public  # Hugo generates the site in 'public' folder by default
44          git init
45          git remote add origin "${{ env.PAGE_REPO }}"
46          git add .
47          git commit -m "Deploy from Hugo site"
48          git push --force origin master          

这里说一下 DEPLOY_SECRET,这个是 GitHub 的密钥,需要在 托管源码的仓库(也就是私有仓库里)中添加 DEPLOY_SECRET

如图中所示,创建即可。

我使用的自定义配置

我对 Stack 主题进行了一些修改,都在 assets/scss 目录下的 custom.scss 文件中配置。

  1// assets\scss\custom.scss
  2
  3// 页面基本配色
  4:root {
  5    // 全局顶部边距
  6    --main-top-padding: 30px;
  7    // 全局卡片圆角
  8    --card-border-radius: 25px;
  9    // 标签云卡片圆角
 10    --tag-border-radius: 8px;
 11    // 卡片间距
 12    --section-separation: 40px;
 13    // 全局字体大小
 14    --article-font-size: 1.8rem;
 15    // 行内代码背景色
 16    --code-background-color: #f8f8f8;
 17    // 行内代码前景色
 18    --code-text-color: #e96900;
 19    // 暗色模式下样式
 20    &[data-scheme="dark"] {
 21      // 行内代码背景色
 22      --code-background-color: #ff6d1b17;
 23      // 行内代码前景色
 24      --code-text-color: #e96900;
 25    }
 26  }
 27
 28  //------------------------------------------------------
 29  // 修复引用块内容窄页面显示问题
 30  a {
 31    word-break: break-all;
 32  }
 33
 34  //--------------------------------------------------
 35  // 文章封面高度
 36  .article-list article .article-image img {
 37    width: 100%;
 38    height: 200px !important;
 39    object-fit: cover;
 40
 41    @include respond(md) {
 42        height: 250px !important;
 43    }
 44
 45    @include respond(xl) {
 46        height: 285px !important;
 47    }
 48  }
 49
 50  //---------------------------------------------------
 51  // 文章内容图片圆角阴影
 52  .article-page .main-article .article-content {
 53    img {
 54      max-width: 96% !important;
 55      height: auto !important;
 56      border-radius: 8px;
 57    }
 58  }
 59
 60  //------------------------------------------------
 61  // 文章内容引用块样式
 62  .article-content {
 63    blockquote {
 64      border-left: 6px solid #358b9a1f !important;
 65      background: #3a97431f;
 66    }
 67  }
 68
 69  code {
 70    word-break: break-all;
 71    border-radius: var(--tag-border-radius);
 72    font-family: var(--code-font-family);
 73    border-radius: var(--category-border-radius);
 74  }
 75
 76  // 代码块基础样式修改
 77  .highlight {
 78    border-radius: 20px;
 79    &:hover {
 80      .copyCodeButton {
 81        opacity: 1;
 82      }
 83    }
 84
 85    pre {
 86      margin: initial;
 87      padding: 0;
 88      margin: 0;
 89      width: auto;
 90    }
 91  }
 92
 93  //-------------------------------------------
 94  // 设置选中字体的区域背景颜色
 95  //修改选中颜色
 96  ::selection {
 97    color: #fff;
 98    background: #34495e;
 99  }
100
101  a {
102    text-decoration: none;
103    color: var(--accent-color);
104
105    &:hover {
106      color: var(--accent-color-darker);
107    }
108
109    &.link {
110      color: #4288b9ad;
111      font-weight: 600;
112      padding: 0 2px;
113      text-decoration: none;
114      cursor: pointer;
115
116      &:hover {
117        text-decoration: underline;
118      }
119    }
120  }
121//固定代码块的高度
122  .article-content {
123    .highlight {
124        padding: var(--card-padding);
125        pre {
126            width: auto;
127            max-height: 50em;
128        }
129    }
130  }
131
132  //-------------------------------------------------
133  //文章封面高度更改
134  .article-list article .article-image img {
135    width: 100%;
136    height: 150px;
137    object-fit: cover;
138
139    @include respond(md) {
140      height: 200px;
141    }
142
143    @include respond(xl) {
144      height: 305px;
145    }
146  }
147
148  //---------------------------------------------------
149  // 全局页面布局间距调整
150  .main-container {
151    min-height: 100vh;
152    align-items: flex-start;
153    padding: 0 15px;
154    gap: var(--section-separation);
155    padding-top: var(--main-top-padding);
156
157    @include respond(md) {
158      padding: 0 37px;
159    }
160  }
161
162  //--------------------------------------------------
163  //页面三栏宽度调整
164  .container {
165    margin-left: auto;
166    margin-right: auto;
167
168    .left-sidebar {
169      order: -3;
170      max-width: var(--left-sidebar-max-width);
171    }
172
173    .right-sidebar {
174      order: -1;
175      max-width: var(--right-sidebar-max-width);
176
177      /// Display right sidebar when min-width: lg
178      @include respond(lg) {
179        display: flex;
180      }
181    }
182
183    &.extended {
184      @include respond(md) {
185        max-width: 1024px;
186        --left-sidebar-max-width: 25%;
187        --right-sidebar-max-width: 22% !important;
188      }
189
190      @include respond(lg) {
191        max-width: 1280px;
192        --left-sidebar-max-width: 20%;
193        --right-sidebar-max-width: 30%;
194      }
195
196      @include respond(xl) {
197        max-width: 1453px; //1536px;
198        --left-sidebar-max-width: 15%;
199        --right-sidebar-max-width: 25%;
200      }
201    }
202
203    &.compact {
204      @include respond(md) {
205        --left-sidebar-max-width: 25%;
206        max-width: 768px;
207      }
208
209      @include respond(lg) {
210        max-width: 1024px;
211        --left-sidebar-max-width: 20%;
212      }
213
214      @include respond(xl) {
215        max-width: 1280px;
216      }
217    }
218  }
219
220  //-------------------------------------------------------
221  //全局页面小图片样式微调
222  .article-list--compact article .article-image img {
223    width: var(--image-size);
224    height: var(--image-size);
225    object-fit: cover;
226    border-radius: 17%;
227  }
228
229//----------------------------------------------------
230// 菜单栏样式
231// 下拉菜单改圆角样式
232.menu {
233    padding-left: 0;
234    list-style: none;
235    flex-direction: column;
236    overflow-x: hidden;
237    overflow-y: scroll;
238    flex-grow: 1;
239    font-size: 1.6rem;
240    background-color: var(--card-background);
241
242    box-shadow: var(--shadow-l2); //改个阴影
243    display: none;
244    margin: 0; //改为0
245    border-radius: 10px; //加个圆角
246    padding: 30px 30px;
247
248    @include respond(xl) {
249      padding: 15px 0;
250    }
251
252    &,
253    .menu-bottom-section {
254      gap: 30px;
255
256      @include respond(xl) {
257        gap: 25px;
258      }
259    }
260
261    &.show {
262      display: flex;
263    }
264
265    @include respond(md) {
266      align-items: flex-end;
267      display: flex;
268      background-color: transparent;
269      padding: 0;
270      box-shadow: none;
271      margin: 0;
272    }
273
274    li {
275      position: relative;
276      vertical-align: middle;
277      padding: 0;
278
279      @include respond(md) {
280        width: 100%;
281      }
282
283      svg {
284        stroke-width: 1.33;
285
286        width: 20px;
287        height: 20px;
288      }
289
290      a {
291        height: 100%;
292        display: inline-flex;
293        align-items: center;
294        color: var(--body-text-color);
295        gap: var(--menu-icon-separation);
296      }
297
298      span {
299        flex: 1;
300      }
301
302      &.current {
303        a {
304          color: var(--accent-color);
305          font-weight: bold;
306        }
307      }
308    }
309  }
310
311  //  ~\blog\assets\scss\custom.scss
312
313//------------------------------------------------
314//将滚动条修改为圆角样式
315//菜单滚动条美化
316.menu::-webkit-scrollbar {
317    display: none;
318  }
319
320  // 全局滚动条美化
321  html {
322    ::-webkit-scrollbar {
323      width: 20px;
324    }
325
326    ::-webkit-scrollbar-track {
327      background-color: transparent;
328    }
329
330    ::-webkit-scrollbar-thumb {
331      background-color: #d6dee1;
332      border-radius: 20px;
333      border: 6px solid transparent;
334      background-clip: content-box;
335    }
336
337    ::-webkit-scrollbar-thumb:hover {
338      background-color: #a8bbbf;
339    }
340  }
341
342//--------------------------------------------------
343//归档页面双栏
344/* 归档页面两栏 */
345@media (min-width: 1024px) {
346    .article-list--compact {
347      display: grid;
348      grid-template-columns: 1fr 1fr;
349      background: none;
350      box-shadow: none;
351      gap: 1rem;
352
353      article {
354        background: var(--card-background);
355        border: none;
356        box-shadow: var(--shadow-l2);
357        margin-bottom: 8px;
358        border-radius: 16px;
359      }
360    }
361  }
362
363//--------------------------------------------------
364//链接三栏
365@media (min-width: 1024px) {
366    .article-list--compact.links {
367      display: grid;
368      grid-template-columns: 1fr 1fr 1fr; //三个1fr即为三栏,两个1fr则为双栏,以此类推即可.
369      background: none;
370      box-shadow: none;
371      gap: 1rem;
372
373      article {
374        background: var(--card-background);
375        border: none;
376        box-shadow: var(--shadow-l2);
377        margin-bottom: 8px;
378        border-radius: var(--card-border-radius);
379
380        &:nth-child(odd) {
381          margin-right: 8px;
382        }
383      }
384    }
385  }
386
387
388//---------------------------------------------------------
389//首页欢迎板块样式
390.welcome {
391    color: var(--card-text-color-main);
392    background: var(--card-background);
393    box-shadow: var(--shadow-l2);
394    border-radius: 30px;
395    display: inline-block;
396  }
397
398  // 👋emoji实现摆动效果
399  .shake {
400    display: inline-block;
401    animation: shake 1s;
402    animation-duration: 1s;
403    animation-timing-function: ease;
404    animation-delay: 0s;
405    animation-iteration-count: 1;
406    animation-direction: normal;
407    animation-fill-mode: none;
408    animation-play-state: running;
409    animation-name: shake;
410    animation-timeline: auto;
411    animation-range-start: normal;
412    animation-range-end: normal;
413    animation-delay: 2s;
414    @keyframes shake {
415      0% {
416        transform: rotate(0);
417      }
418      25% {
419        transform: rotate(45deg) scale(1.2);
420      }
421      50% {
422        transform: rotate(0) scale(1.2);
423      }
424      75% {
425        transform: rotate(45deg) scale(1.2);
426      }
427      100% {
428        transform: rotate(0);
429      }
430    }
431  }
432  // 实现字符跳动动画
433  .jump-text1 {
434    display: inline-block;
435    animation: jump 0.5s 1;
436  }
437
438  .jump-text2 {
439    display: inline-block;
440    animation: jump 0.5s 1;
441    animation-delay: 0.1s;
442  }
443
444  .jump-text3 {
445    display: inline-block;
446    animation: jump 0.5s 1;
447    animation-delay: 0.2s;
448  }
449
450  .jump-text4 {
451    display: inline-block;
452    animation: jump 0.5s 1;
453    animation-delay: 0.3s;
454  }
455
456  .jump-text5 {
457    display: inline-block;
458    animation: jump 0.5s 1;
459    animation-delay: 0.4s;
460  }
461
462  .jump-text6 {
463    display: inline-block;
464    animation: jump 0.5s 1;
465    animation-delay: 0.5s;
466  }
467
468  .jump-text7 {
469    display: inline-block;
470    animation: jump 0.5s 1;
471    animation-delay: 0.6s;
472  }
473
474  .jump-text8 {
475    display: inline-block;
476    animation: jump 0.5s 1;
477    animation-delay: 0.7s;
478  }
479
480  .jump-text9 {
481    display: inline-block;
482    animation: jump 0.5s 1;
483    animation-delay: 0.9s;
484  }
485
486  @keyframes jump {
487    0% {
488      transform: translateY(0);
489    }
490    50% {
491      transform: translateY(-20px);
492    }
493    100% {
494      transform: translateY(0);
495    }
496  }
497
498  .main-container .right-sidebar {
499    order: 2;
500    max-width: var(--right-sidebar-max-width);
501
502    /// Display right sidebar when min-width: lg
503    @include respond(lg) {
504      display: flex;
505    }
506  }
507
508  main.main {
509    order: 1;
510    min-width: 0;
511    max-width: 100%;
512    flex-grow: 1;
513    display: flex;
514    flex-direction: column;
515    gap: var(--section-separation);
516
517    @include respond(md) {
518      padding-top: var(--main-top-padding);
519    }
520  }
521
522//----------------------------------------------------------
523
524.article-category {
525  display: flex;
526  flex-wrap: wrap;
527  gap: 10px;
528
529  a {
530      background: var(--card-background);
531      box-shadow: var(--shadow-l1);
532      border-radius: var(--category-border-radius);
533      padding: 8px 20px;
534      color: var(--card-text-color-main);
535      font-size: 1.4rem;
536      transition: box-shadow 0.3s ease;
537
538      &:hover {
539          box-shadow: var(--shadow-l2);
540      }
541  }
542}
543
544/* Category widget */
545.category {
546  .category-label {
547      display: flex;
548      flex-wrap: wrap;
549      gap: 10px;
550
551      a {
552          border-left: 6px solid;
553          background: var(--card-background);
554          box-shadow: var(--shadow-l1);
555          border-radius: var(--category-border-radius);
556          padding: 12px 20px;
557          color: var(--card-text-color-main);
558          font-size: 1.5rem;
559          transition: box-shadow 0.3s ease;
560
561          &:hover {
562              box-shadow: var(--shadow-l2);
563          }
564      }
565  }
566  .category-count {
567      color: var(--body-text-color);
568  }
569}
570
571.article-subtitle {
572    margin-top: -5px;
573    font-size: 1.5rem;
574
575    @include respond(md) {
576        font-size: 1.6rem;
577    }
578}
579
580/*头像旋转动画*/
581.sidebar header .site-avatar .site-logo {
582  transition: transform 1.65s ease-in-out; //旋转时间
583
584}
585
586.sidebar header .site-avatar .site-logo:hover {
587  transform: rotate(360deg); //旋转角度为360度
588}
589
590/*社交菜单居中*/
591.social-menu svg {
592  gap: 15px;
593  justify-content: center;
594  width: 30px;
595  height: 25px; //社交菜单大小
596  stroke: var(--body-text-color);
597  stroke-width: 1.33;
598}
599
600/*页面加载动画部分*/
601#loading-box .loading-left-bg,
602#loading-box .loading-right-bg {
603    position: fixed;
604    z-index: 1000;
605    width: 50%;
606    height: 100%;
607    // 我在这里小改了一下颜色,
608    background-color: #b1c0c7;
609    transition: all 0.5s;
610}
611
612#loading-box .loading-right-bg {
613    right: 0;
614}
615
616#loading-box>.spinner-box {
617    position: fixed;
618    z-index: 1001;
619    display: flex;
620    justify-content: center;
621    align-items: center;
622    width: 100%;
623    height: 100vh;
624}
625
626#loading-box .spinner-box .configure-border-1 {
627    position: absolute;
628    padding: 3px;
629    width: 115px;
630    height: 115px;
631    background: #ffab91;
632    animation: configure-clockwise 3s ease-in-out 0s infinite alternate;
633}
634
635#loading-box .spinner-box .configure-border-2 {
636    left: -115px;
637    padding: 3px;
638    width: 115px;
639    height: 115px;
640    background: rgb(63, 249, 220);
641    transform: rotate(45deg);
642    animation: configure-xclockwise 3s ease-in-out 0s infinite alternate;
643}
644
645#loading-box .spinner-box .loading-word {
646    position: absolute;
647    color: #ffffff;
648    // 我在这里小改了一下文字大小和字体,注意!
649    font-size: 1.8rem;
650    font-family: 'Zhi Mang Xing', cursive;
651}
652
653#loading-box .spinner-box .configure-core {
654    width: 100%;
655    height: 100%;
656    background-color: #37474f;
657}
658
659div.loaded div.loading-left-bg {
660    transform: translate(-100%, 0);
661}
662
663div.loaded div.loading-right-bg {
664    transform: translate(100%, 0);
665}
666
667div.loaded div.spinner-box {
668    // 你可以把这个注释掉,这样就能一直看那个动画的效果了!
669    display: none !important;
670}
671
672@keyframes configure-clockwise {
673    0% {
674        transform: rotate(0);
675    }
676
677    25% {
678        transform: rotate(90deg);
679    }
680
681    50% {
682        transform: rotate(180deg);
683    }
684
685    75% {
686        transform: rotate(270deg);
687    }
688
689    100% {
690        transform: rotate(360deg);
691    }
692}
693
694@keyframes configure-xclockwise {
695    0% {
696        transform: rotate(45deg);
697    }
698
699    25% {
700        transform: rotate(-45deg);
701    }
702
703    50% {
704        transform: rotate(-135deg);
705    }
706
707    75% {
708        transform: rotate(-225deg);
709    }
710
711    100% {
712        transform: rotate(-315deg);
713    }
714}
715
716
717/* 头像旋转 */
718.home .home-profile .home-avatar img {
719    width: 5rem;
720
721  /* 设置循环动画
722  [animation:
723	(play)动画名称
724	(2s)动画播放时长单位秒或微秒
725	(ease-out)动画播放的速度曲线为以低速结束
726	(1s)等待1秒然后开始动画
727	(1)动画播放次数(infinite为循环播放) ]*/
728
729  /* 鼠标经过头像旋转360度 */
730  -webkit-transition: -webkit-transform 1.0s ease-out;
731  -moz-transition: -moz-transform 1.0s ease-out;
732  transition: transform 1.0s ease-out;
733    &:hover {
734      /* 鼠标经过停止头像旋转
735      -webkit-animation-play-state:paused;
736      animation-play-state:paused;*/
737
738      /* 鼠标经过头像旋转360度 */
739      -webkit-transform: rotateZ(360deg);
740      -moz-transform: rotateZ(360deg);
741      transform: rotateZ(360deg);
742    }
743}

大多数都有注释,可以按需取用。

总结

以上就是我在迁移博客时遇到的问题,和一些对应的解决办法,还有一些自定义配置,希望对你有所帮助。 解决问题大多数都是在 Google 上搜索,或者问 ChatGPT

因为这篇文章是在迁移后写的,所以有些问题可能会忘记,如果文中有错误,欢迎使用 邮箱 和我交流。

发表了56篇文章 · 总计128.44k字
本博客已稳定运行
© QX
使用 Hugo 构建
主题 StackJimmy 设计