Hugo boasts a number of excellent themes, for academic themes, you can refer to https://github.com/Chen-Gary/hugo-theme-academic-old
.
For the installation and configuration of the academic
theme, please refer to its README document. This article will delve into advanced Hugo configuration and customization.
After reading this blog post, you will gain a deeper understanding of Hugo and be able to complete some customizations:
- Adjusting article templates
- Personalization - Integrating Live2D widget
- Personalization - Supporting embedded Bilibili videos in articles
- Internationalization & CJK
Article Templates
Generally, there are two ways to create new articles. One is to directly copy the existing file directory and make changes, and the other is to use the hugo new
command. For example, you can use hugo new content post/{post-path}/index.md
to create an article (the article directory for the academic
theme is in content/post
, while other themes might have it in content/posts
).
This command searches for templates to generate content in the following order:
archetypes/post.md
archetypes/default.md
themes/academic/archetypes/post.md
themes/academic/archetypes/default.md
When creating a blog site using the hugo new site {blog-path}
command, the default generated directory includes the archetypes/default.md
file with the following content:
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++
This file content is in the Hugo Front matter format, which is toml
. We test it using the command hugo new content post/test/index.md
, and the generated article content is as follows:
+++
title = 'Test'
date = 2023-11-22T23:53:32+08:00
draft = true
+++
Remove archetypes/default.md
and content/post/test/index.md
, and run the command hugo new content post/test/index.md
again. The newly generated article file content will be:
---
# 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: []
---
This allows us to quickly customize the Front matter content.
The academic
theme also supports various article templates, such as docs.md
, publication
, etc., which can be found in the themes/academic/archetypes
directory. For example, to create a new Courses section, you can use the command hugo new content --kind docs courses/linux-programming/_index.md
. This command applies the themes/academic/archetypes/docs.md
layout, and you can view the effect locally by visiting http://localhost:1313/courses/
.
Personalization - Integrating Live2D Widget
This section demonstrates how to customize the theme by integrating a Live2D widget (although we are using the academic
theme, who doesn’t love anime?).
Template Basic Structure
First, to customize the theme, you need to have a basic understanding of the Hugo theme structure. The academic
theme structure is located in the themes/academic/layouts
directory:
themes/academic/layouts
├── _default
│ └── _markup
├── authors
├── book
├── docs
├── partials
│ ├── comments
│ ├── functions
│ ├── jsonld
│ ├── marketing
│ └── widgets
├── project
├── publication
├── section
├── shortcodes
├── slides
├── talk
└── widget_page
Regarding the site content, it can be roughly divided into list pages and detail pages. List pages are like the course list page /courses/
, while detail pages are single pages like /courses/example/
.
The themes/academic/layouts/_default/
directory is the template entry point, where:
baseof.html
is the main framework of the site, containing the complete HTML, which loads other page components through Go HTML template syntax to form the final pagelist.html
is for list pagessingle.html
is for detail pages
Both list.html
and single.html
declare the main body of the page using define "main"
and are then referenced in baseof.html
using the code {{ block "main" . }}{{ end }}
.
Of course, we can see that there is a lot of content in the layout
directory. Hugo will load different layouts based on the site content directory structure and the type defined in the Front matter. For example, in the aforementioned courses directory, content/courses/example/_index.md
defines type: docs
, so the layout under the themes/academic/layouts/docs
directory will be applied. The detailed loading mechanism and priority of this part are quite complex. If you are interested, you can refer to the official documentation https://gohugo.io/templates/lookup-order/
.
Adding Live2D Widget
Through the code in baseof.html
, we can see that the header
part of the site HTML is referenced from {{ partial "site_head" . }}
.
Most themes provide capabilities for user customization, and academic
is no exception. By creating custom_head.html
, we can extend the theme without modifying the template. The reference relationship is as follows:
┌─────────────────────────────────────┐
│ │
│ _default/baseof.html │
│ │
└──────────────────┬──────────────────┘
│
│ {{ partial "site_head" . }}
│
┌──────────────────▼──────────────────┐
│ │
│ partials/site_head.html │
│ │
└──────────────────┬──────────────────┘
│
│ {{ partial "custom_head" . }}
│
┌──────────────────▼──────────────────┐
│ │
│ partials/custom_head.html │
│ │
└─────────────────────────────────────┘
Referring to the comments in themes/academic/layouts/partials/custom_head.html
, we create the file layouts/partials/custom_head.html
in the root directory of the site to override the default custom_head.html
file loaded by the theme, and fill it with the following content:
<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/stevenjoezhang/live2d-widget@latest/",
tools: ["hitokoto", "asteroids", "switch-model", "switch-texture", "photo", "info", "quit"]
});
})
</script>
This code loads the style and model of the Live2D widget and executes the relevant initialization code. Ultimately, we can see the Bilibili Live2D widget in the lower left corner, with the following effect:
Live2D widget, derived from Japanese “かんばんむすめ”, refers to a female shop assistant or mascot. The above sample code is referenced from https://github.com/stevenjoezhang/live2d-widget , under the GPL-3.0 license . The model
cdnPath
parameter is sourced from https://github.com/fghrsh/live2d_api/tree/master , and the model copyright belongs to the original author.
Personalization - Supporting Embedded Bilibili Videos in Articles
Markdown can include raw HTML for rendering, allowing us to embed Bilibili videos in the site by embedding HTML. Taking the video https://www.bilibili.com/video/BV1kE41147oo as an example, open the video and under it, you can find the sharing menu where you can locate the embed code section.
Click on it to copy the embed code, as follows:
<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>
Of course, if we want to improve efficiency, we can use the shortcode
feature provided by Hugo. Hugo itself provides some built-in shortcodes
, such as figure
, gist
, etc. In this section, we will create a bilibili
shortcode
to achieve the ability to quickly embed Bilibili videos.
Create a file named layouts/shortcodes/bilibili.html
in the root directory of the site, and fill it with the following content:
{{- $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>
The above code will generate the embed link for the Bilibili video based on the passed video id
parameter and set the video width to 100% and the aspect ratio to 16:9 using CSS.
Then we can use the bilibili
shortcode
in Markdown. First, open the video you want to embed, find the BV
-prefixed video ID after video/
in the video URL link, such as BV1kE41147oo
in the link https://www.bilibili.com/video/BV1kE41147oo/
, and then embed the code {{< bilibili BV1kE41147oo >}}
in the article. The result is as follows:
For more information on using shortcodes
, please refer to the Hugo official documentation https://gohugo.io/content-management/shortcodes/
.
Internationalization & CJK
As an excellent theme, academic
supports internationalization configuration. If your site audience includes users from both domestic and overseas, you can enable language switching through internationalization configuration.
The internationalization configuration resides in the config/_default/languages.toml
file, which by default only contains English configuration. Add the following code to the configuration file:
[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
Also, create a zh
directory under the content
directory and copy the content from the original content
directory into the zh
directory. Now, you should see the language switching menu in the upper right corner of the site.
After adjusting the content of the corresponding articles in the zh
directory, you can see the language switching effect of the site. Switch to Chinese, and you will see that the menu also changes to Chinese accordingly.
Hugo is written in Go and uses the goldmark markdown library. By default, markdown will render line breaks as spaces during rendering. When using CJK languages (Chinese, Japanese, Korean), there might be spaces between some words after rendering, as shown below:
We can use the CJK extension provided by goldmark to configure the CJK rendering logic. The configuration file is located at config/_default/config.toml
. Find the following section:
[markup]
defaultMarkdownHandler = "goldmark"
[markup.goldmark]
[markup.goldmark.renderer]
unsafe = true # Enable user to embed HTML snippets in Markdown content.
Add the following code below it:
[markup.goldmark.extensions.cjk]
enable = true
eastAsianLineBreaks = true
escapedSpace = true
Save the file and observe the effect.