Hugo有不少优秀的主题,学术类academic的可以参考https://github.com/Chen-Gary/hugo-theme-academic-old 。关于安装和配置academic学术主题,可以参考其README文档。本文介绍如何进行更高阶hugo配置及定制。看完本篇博客,能够对hugo有更深的了解并可以完成一些定制化:

  • 调整文章模板
  • 个性化 - 集成看板娘
  • 个性化 - 支持文章嵌入B站视频
  • 国际化 & CJK

文章模板

一般情况下我们创建新文章有两种办法,一种直接拷贝原有文件目录然后进行更改,另一种可以使用hugo new命令,如可以使用hugo new content post/{post-path}/index.md来创建文章 (academic学术主题的文章目录在content/post,其他一些主题文章目录可能在content/posts)。该命令会按如下顺序寻找模板进行内容生成:

  1. archetypes/post.md
  2. archetypes/default.md
  3. themes/academic/archetypes/post.md
  4. themes/academic/archetypes/default.md

在使用hugo new site {blog-path}创建博客站点时,默认生成的目录包含archetypes/default.md文件, 其内容如下

+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++

该文件内容为hugo Front matter,为toml格式。我们使用命令hugo new content post/test/index.md 进行测试,可以看到生成的文章内容如下:

+++
title = 'Test'
date = 2023-11-22T23:53:32+08:00
draft = true
+++

archetypes/default.mdcontent/post/test/index.md移除,再次运行命令hugo new content post/test/index.md,可以看到新生成的文章文件内容:

---
# Documentation: https://sourcethemes.com/academic/docs/managing-content/

title: "Test"
subtitle: ""
summary: ""
authors: []
tags: []
categories: []
date: 2023-11-22T23:58:38+08:00
lastmod: 2023-11-22T23:58:38+08:00
featured: false
draft: false

# Featured image
# To use, add an image named `featured.jpg/png` to your page's folder.
# Focal points: Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.
image:
  caption: ""
  focal_point: ""
  preview_only: false

# Projects (optional).
#   Associate this post with one or more of your projects.
#   Simply enter your project's folder or file name without extension.
#   E.g. `projects = ["internal-project"]` references `content/project/deep-learning/index.md`.
#   Otherwise, set `projects = []`.
projects: []
---

这样我们就可以快速对Front matter内容进行定制化。

academic主题还支持各种文章模板,如docs.mdpublication等,可以在目录themes/academic/archetypes 中找到。比如新建课程Courses,可以使用命令hugo new content --kind docs courses/linux-programming/_index.md,该命令应用themes/academic/archetypes/docs.md布局, 本地可以浏览http://localhost:1313/courses/ 查看效果。

个性化 - 集成看板娘

本章节通过集成看板娘,来演示如何定制主题(虽然我们使用的是academic学术主题,但是二次元谁不爱呢)。

模板基础结构

首先,想要定制化主题,需要对hugo主题的结构有初步了解,academic主题结构在目录themes/academic/layouts中,

themes/academic/layouts
├── _default
│   └── _markup
├── authors
├── book
├── docs
├── partials
│   ├── comments
│   ├── functions
│   ├── jsonld
│   ├── marketing
│   └── widgets
├── project
├── publication
├── section
├── shortcodes
├── slides
├── talk
└── widget_page

关于站点内容,大致可以分为列表页及详情页,列表页如课程列表页/courses/,详情页则是单页面/courses/example/themes/academic/layouts/_default/目录是模板入口,其中

  • baseof.html为站点大的框架,包含完整的HTML, 其中通过go html模板语法加载其他页面组件,组成最终的页面
  • list.html为列表页
  • single.html为详情页

list.htmlsingle.html中均会通过define "main"声明页面主体,然后在baseof.html 中通过代码{{ block "main" . }}{{ end }}被引用。

当然我们看到layout目录中有着非常多的内容,hugo会根据站点内容目录结构及Front matter中定义的类型等,加载不同的布局。如前述的courses目录,content/courses/example/_index.md中定义了type: docs, 则会应用themes/academic/layouts/docs目录下的布局。该部分的细节加载机制及优先级等, 较为复杂,感兴趣的可以参考官方文档https://gohugo.io/templates/lookup-order/

添加看板娘

通过baseof.html中的代码,我们可以看到站点HTML中的header部分引用自{{ partial "site_head" . }}。一般主题都留有给用户定制化的能力,academic也不例外,通过创建custom_head.html,我们可以在不改动模板的情况下进行扩展。其引用关系如下:

┌─────────────────────────────────────┐
│                                     │
│         _default/baseof.html        │
│                                     │
└──────────────────┬──────────────────┘
                   │
                   │  {{ partial "site_head" . }}
                   │
┌──────────────────▼──────────────────┐
│                                     │
│        partials/site_head.html      │
│                                     │
└──────────────────┬──────────────────┘
                   │
                   │ {{ partial "custom_head" . }}
                   │
┌──────────────────▼──────────────────┐
│                                     │
│      partials/custom_head.html      │
│                                     │
└─────────────────────────────────────┘

参考themes/academic/layouts/partials/custom_head.html中的注释,我们在站点根目录下创建文件layouts/partials/custom_head.html,来覆盖加载主题默认的custom_head.html文件, 并在其填入内容:

<link rel="stylesheet" href="https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/waifu.css">
<script src="https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/live2d.min.js"></script>
<script src="https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/waifu-tips.js"></script>
<script>
    window.addEventListener('load', () => {
        // https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/model_list.json
        localStorage.setItem("modelId", 2);  // 2 -> "bilibili-live/22"
        initWidget({
            waifuPath: "https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/waifu-tips.json",
            cdnPath: "https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/",
            tools: ["hitokoto", "asteroids", "switch-model", "switch-texture", "photo", "info", "quit"]
        });
    })
</script>

该代码会加载看板娘的样式和模型,并执行相关的初始化代码。最终我们可以在左下角看到bilibili看板娘, 效果如下:

live2d bilibili model

看板娘来源于日语かんばんむすめ,指店铺的女性服务生、活招牌。以上示例代码参考自https://github.com/stevenjoezhang/live2d-widget , License为GPL-3.0 license 。模型 cdnPath 参数源自https://github.com/fghrsh/live2d_api/tree/master , 模型版权归属于原作者。

个性化 - 支持文章嵌入B站视频

Markdown可以引入原始HTML进行渲染,这样我们就可以在站点通过内嵌HTML的方式引入B站视频。以https://www.bilibili.com/video/BV1kE41147oo 视频为例,打开视频后在视频下方我们可以找到分享菜单,可以找到其嵌入代码部分

bilibili share

点击后可以复制嵌入的代码,如下:

<iframe src="//player.bilibili.com/player.html?aid=93495162&bvid=BV1kE41147oo&cid=159633574&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>

当然如果我们要更高效完成相关工作,可以使用hugo提供的shortcode功能。hugo本身提供部分内置shortcode,如figure, gist等。本节我们通过创建bilibili shortcode来实现快速嵌入B站视频的能力。

我们在站点根目录下创建文件layouts/shortcodes/bilibili.html,填入如下内容:

{{- $vid := .Get "id" | default (.Get 0) -}}
{{ $q := "" }}

{{ if strings.HasPrefix (lower $vid) "bv" }}
  {{ $q = querify "bvid" $vid }}
{{ else }}
  {{ $q = querify "aid" $vid }}
{{ end }}

<iframe style="width: 100%; aspect-ratio: 16 / 9;"
    src="//player.bilibili.com/player.html?{{ $q | safeURL }}&p=1"
    scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true">
</iframe>

以上代码会根据传入的视频id参数,生成嵌入的B站视频链接,同时通过CSS设置视频宽度为100%,宽高比为16:9。

然后我们就可以在Markdown中使用bilibili shortcode了。首先我们打开我们要嵌入的视频, 找到视频URL链接中video/之后的BV开头的视频ID,如链接https://www.bilibili.com/video/BV1kE41147oo/ 中的BV1kE41147oo,然后在文章中嵌入代码{{< bilibili BV1kE41147oo >}}。效果如下:

更多关于shortcode的用法,可以参考hugo官方文档https://gohugo.io/content-management/shortcodes/

国际化 & CJK

作为一个优秀的主题,academic是支持国际化配置的。如果你的站点受众包括国内外的用户,可以通过国际化配置使站点支持语音切换。

国际化的配置在config/_default/languages.toml文件中,默认只有英文配置。在配置文件中添加如下代码

[zh]
  languageCode = "zh-Hans"
  contentDir = "content/zh"
  title = "学术"
  [zh.params]
    description = "测试中文站点"
  [[zh.menu.main]]
    name = "示例"
    url = "#hero"
    weight = 10

  [[zh.menu.main]]
    name = "文章"
    url = "#posts"
    weight = 20

  [[zh.menu.main]]
    name = "项目"
    url = "#projects"
    weight = 30

  [[zh.menu.main]]
    name = "出版物"
    url = "#featured"
    weight = 40

  [[zh.menu.main]]
    name = "课程"
    url = "courses/"
    weight = 50

  [[zh.menu.main]]
    name = "联系"
    url = "#contact"
    weight = 60

同时在content目录下创建zh目录,将原有的content目录下的内容复制到zh目录下。这时我们就可以在站点右上角看到语言切换菜单。

i18n

调整zh目录下同个对应文章的内容后,我们就可以看到站点的语言切换效果了。切换至中文后, 可以看到菜单也对应变成中文。

cn menu

hugo是用go语言编写的,其使用markdown库为goldmark 。 markdown在渲染时默认会将换行渲染为空格,在使用中日韩即CJK语言时,渲染后有些文字中间会有空格, 如下:

space in cjk

我们可以使用goldmark提供的CJK扩展来配置CJK渲染逻辑。配置文件在config/_default/config.toml, 找到该段:

[markup]
  defaultMarkdownHandler = "goldmark"
  [markup.goldmark]
    [markup.goldmark.renderer]
      unsafe = true  # Enable user to embed HTML snippets in Markdown content.

在其下面添加如下代码:

    [markup.goldmark.extensions.cjk]
      enable = true
      eastAsianLineBreaks = true
      escapedSpace = true

保存后可以观察效果。