If you haven't created a zola site yet, create a new zola site with the following command (assuming your site is called myblog
):
zola init myblog
Enter the directory:
cd myblog
Add the serene theme:
git submodule add -b latest https://github.com/isunjn/serene.git themes/serene
Copy the content of myblog/themes/serene/config.example.toml
to myblog/config.toml
, refer to the comments in the file and Zola's documentation to modify accordingly
There is a sections
config item in your config.toml
, which enumerates the sections your website has. You should have at least one blog
section. The name and path can be changed, be noticed that if you changed the blog section path (e.g. from /posts
to /blog
), then you should also change blog_section_path
config item.
The myblog directory now looks like this:
├── config.toml
├── content/
├── sass/
├── static/
├── templates/
└── themes/
└── serene/
Create myblog/content/_index.md
and myblog/content/posts/_index.md
with the following content:
myblog/content/_index.md
:
+++
template = 'home.html'
[extra]
lang = 'en'
+++
Words about you
myblog/content/posts/_index.md
:
+++
title = "My Blog"
description = "My blog site."
sort_by = "date"
template = "blog.html"
page_template = "post.html"
insert_anchor_links = "right"
generate_feeds = true
[extra]
lang = 'en'
+++
The path and the directory should match. If you changed the blog section path to /blog
, then you create myblog/content/blog/_index.md
, rather than myblog/content/posts/_index.md
. The same goes for the others.
If you want to display a projects page (as you see in the demo site), create myblog/content/projects/_index.md
:
+++
title = "My Projects"
description = "My projects page."
template = "projects.html"
[extra]
lang = 'en'
+++
The blog
and projects
are two sections that serene supports by default, they have specific structures and styles, defined in template blog.html
and projects.html
.
Serene also support a special template called prose.html
, it applies the same styles of blog post page and you can use it as a section template for a custom section page, for example if you want a separate about
page, you can add a { name = "about", path = "/about", is_external = false }
to the sections
config item and create a myblog/content/about/_index.md
with the following content:
+++
title = "About me"
description = "A about page of ..."
template = "prose.html"
insert_anchor_links = "none"
[extra]
lang = 'en'
math = false
mermaid = false
copy = false
comment = false
reaction = false
+++
Hi, My name is ....
(more markdown content goes here)
Now the myblog directory may looks like this:
├── config.toml
├── content/
│ ├── posts/
│ │ └── _index.md
│ ├── projects/
│ │ └── _index.md
│ ├── about/
│ │ └── _index.md
│ └── _index.md
├── sass/
├── static/
├── templates/
└── themes/
└── serene/
-
Create a new directory
img
undermyblog/static
, put favicon related files here, you can use tools like favicon.io to generate those files -
Also put your avatar picture file
avatar.webp
here, webp format is recommended... ├── static/ │ └── img/ │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ └── avatar.webp ...
-
Copy
myblog/themes/serene/static/icon
directory tomyblog/static/icon
, the icon value inlinks
is the file name of the svg file in it, without the.svg
suffix -
Find the svg file of the icon you want, modify (in case you don't kown, svg is just a plian text files) its width and height to 20, and the color to
currentColor
:... width="20" height="20" ... fill="currentColor" ...
-
The default icons came from Remix Icon
-
Copy
myblog/themes/serene/highlight_themes
directory tomyblog/highlight_themes
. -
If you set
highlight_theme
inconfig.toml
to one of zola's built-in highlight themes, you will get that theme used in both light and dark mode. -
By default serene use different themes for light/dark modes, configured by
highlight_theme
,extra_syntaxes_and_themes
andhighlight_themes_css
. The default highlight themeserene-light
serene-dark
is a modified version of Tomorrow theme. -
If you want a different theme, find the
.tmTheme
TextMate file of your theme, put it inmyblog/static/highlight_themes
, and then modify thetheme
value ofhighlight_themes_css
to that file's name, without.tmTheme
extension. This will generate ahl-light.css
and ahl-dark.css
file inmyblog/static/
, you may have to delete them first before you change thetheme
value, so zola can re-generate. -
You can find some TextMate themes on this website.
- By default there is theme toggle button to switch between light and dark theme, you can set
force_theme
inconfig.toml
to force a specific theme
-
You can add rss to your site, Zola's default feed file is located in the root directory of the site, set
generate_feeds = true
inconfig.toml
,feed_filenames
can be set to["atom.xml"]
or["rss.xml"]
, corresponding to two different rss file standards, you should also setgenerate_feeds = false
inmyblog/content/posts/_index.md
-
The serene theme looks more like a personal website, the posts are in the
/posts
directory, you may want the feed file to be in the/posts
directory instead of the root directory, this requires you to setgenerate_feeds = false
feed_filenames = ["feed.xml"]
inconfig.toml
, and setgenerate_feeds = true
inmyblog/content/posts/_index.md
-
feed.xml
usestitle
anddescription
frommyblog/content/posts/_index.md
, the other two useconfig.toml
's
-
Serene has a projects page where you can showcase your projects, products, etc.
-
Create a new
data.toml
undermyblog/content/projects/
, add projects information in it, the format is as follows,img
is optional:[[project]] name = "" desc = "" tags = ["", ""] img = "" links = [ { name = "", url = "" }, { name = "", url = "" }, ] [[project]] name = "" desc = "" tags = ["", ""] img = "" links = [ { name = "", url = "" }, { name = "", url = "" }, ]
-
If one of your posts has strong timeliness, you can set an outdated alert to be displayed on the page after certain days
-
outdate_alert
andoutdate_alert_days
inconfig.toml
set the default whether to be outdated and how many days to be outdated. These two can also be configured on a separate post, you can setoutdate_alert
inconfig.toml
tofalse
, and then enable it separately in the front matter of time-sensitive posts -
outdate_alert_text_before
andoutdate_alert_text_after
are the specific content of the alert, before and after the number of days respectively
-
Serene supports using giscus as the comment system
-
To enable it, you need to create
myblog/templates/_giscus_script.html
and put the script configured on the giscus website into it, then change the value ofdata-theme
tohttps://<your-domain-name>/giscus_light.css
, replace<your-domain-name>
with you domain name, same asbase_url
inconfig.toml
, if you setforce_theme
todark
, replacegiscus_light.css
withgiscus_dark.css
-
comment = true
inconfig.toml
sets all posts to enable comments, you can setcomment = false
under[extra]
in the front matter of the post to control whether a specific post displays comments
-
Serene supports a feature called anonymous emoji reactions, visitors of you site can react to your posts with emojis, without the need to log in or register.
-
You need to setup a backend api endpoint to enable it. The endpoint should handle both
GET
andPOST
:-
Get
request query:
slug
, the slug of the postresponse:
{ "👍": [123, true], // emoji: [count, reacted] "👀": [456, false] }
-
Post
request body:
{ "slug": "post-slug", "target": "👍", "reacted": true }
response:
{ "success": true }
-
-
For conivence, you can use this template repo to setup your own endpoint. All you need is a Cloudflare account. The free tier is good enough for a low-traffic personal blog.
-
After you setup your endpoint, set
reaction_endpoint = "<your-endpoint>"
andreaction = true
inconfig.toml
to enable it. -
Giscus also support a reaction feature, but it requires visitors to log in to GitHub, you can also disable it in giscus's settings.
- To place scripts for analytics tools (such as Google Analytics, Umami, etc.), you can create a new
myblog/templates/_head_extend.html
and put the corresponding content in it. The content of this file will be added to the html head of each page
-
Serene uses the Signika font of Google Fonts by default.If you want a different font, create a newmyblog/templates/_custom_font.html
and put the font link tags you copied from google fonts website into it, and then modify--main-font
or--code-font
inmyblog/sass/main.scss
. -
For performance reason, you may want to self-host font files (optional):
- Open google-webfonts-helper and choose your font
- Modify
Customize folder prefix
of step 3 to/font/
and then copy the css - Replace the content of
myblog/templates/_custom_font.html
with a<style> </style>
tag, with the css you just copied in it. - Download step 4 font files and put them in
myblog/static/font/
folder
-
Copy
myblog/themes/serene/templates/_custom_css.html
tomyblog/templates/_custom_css.html
, variables in this file are used to control styles, such as the theme color--primary-color
, you can modify them as you want -
If you want to customize more, you only need to copy that file under the
templates
,static
,sass
directory in the correspondingthemes/serene
to the same name directory ofmyblog
, and modify it. Be careful not to directly modify the files under the serene directory, because these modifications may cause conflicts if the theme is updated
- Show a few recent posts on homepage by settng
recent = true
inconfig.toml
-
The content inside the two
+++
at the top of the post markdown file is called front matter, and the supported configuration items are as follows:+++ title = "" date = 2022-01-01 draft = true [taxonomies] categories = ["one"] tags = ["one", "two", "three"] [extra] lang = "en" toc = true comment = true copy = true math = false mermaid = false outdate_alert = true outdate_alert_days = 120 display_tags = true truncate_summary = false featured = false reaction = false +++ new post about something... <!-- more --> more post content...
-
You can add a
<!-- more -->
line, the content before it will become the summary/description of the post. You can settruncate_summary = true
to remove the summary from the post webpage. -
A post marked
featured = true
will display a*
mark in front of it in list, you can use this to mark a post as "most worthy to read" -
If you set
blog_categorized = true
, posts will be sorted alphabetically by default, you can manually set the order by adding the prefix of__[0-9]{2}__
in front of the category name, for example,categories = ["__01__Balabala"]
-
Post files are created under
myblog/content/posts
, after done writing, changedraft
to false
-
Zola supports 'shortcodes', which can be used to add some extra styles or templates in addition to the standard markdown format
-
Zola support some annotations for code blocks. Serene add another one to display the file name:
codeblock
, use it like this:{% codeblock(name="path/to/file") %} // a markdown code block ... {% end %}
-
In addition to
![img](/path/to/img)
of standard markdown, serene also supports afigure
shortcode to add some explanatory text to the image:{{ figure(src="/path/to/img", alt="alt text", caption="caption text") }}
This will be displayed as
<figure></figure>
in HTML on the web page instead of<img>
, and the content of the caption will be centered below the image. The alt attribute is optional but recommended to help enhance accessibilityAdding attribution information to a image is very common, you can directly use the
via
attribute, which will display a link named via below the image:{{ figure(src="/path/to/img", alt="some alt text", via="https://example.com") }}
-
Special quote,
cite
is optional:{% quote(cite="") %} // content... {% end %}
-
Expandable detail,
default_open
is optional:{% detail(title="", default_open=false) %} // content... {% end %}
-
Serene also uses shortcodes to implement callouts, the effect is shown in this page of the demo site, there are currently 6 types:
note
important
warning
alert
question
tip
, the format is as follows, the header attribute is optional:{% note(header="Note") %} note text {% end %}
-
If people read your posts via rss reader, these callouts will appear as normal
<blockquote>
-
Set
math = true
ormath = "katex"
in the front matter to enable formula rending with KaTeX:$...$
for inline formula,$$...$$
for block-level formula. -
Set
math = "typst"
to enable formula rendering with Typst:$...$
for inline formula,$ ... $
(insert space at start and end) for block-level formula.
-
Set
mermaid = true
in the front matter to enable Mermaid support, and then insert a chart in the following format:{% mermaid() %} flowchart LR A[Hard] -->|Text| B(Round) B --> C{Decision} C -->|One| D[Result 1] C -->|Two| E[Result 2] {% end %}
Local preview:
zola serve
Build the site:
zola build
To deploy a static site, please refer to zola's documentation about deployment
-
Please check the CHANGELOG.md on github for breaking changes before updating the theme
-
If you copied some files from
myblog/themes/serene
tomyblog/
for customization, such as_custom_css.html
ormain.scss
, then you should record what you have modified before you update, re-copy those files and re-apply your modification after updating. Theconfig.toml
should be re-copied too. -
You can watch (
watch > custom > releases > apply
) this project on github to be reminded of a new release
git submodule update --remote themes/serene
If you like this theme, you may give it a star
Happy blogging :)