<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Xiaoliang Wang</title>
    <description>The latest articles on DEV Community by Xiaoliang Wang (@tomowang).</description>
    <link>https://dev.to/tomowang</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F65539%2Fcfa1234a-c07e-4f2e-a05d-490fffb89905.png</url>
      <title>DEV Community: Xiaoliang Wang</title>
      <link>https://dev.to/tomowang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tomowang"/>
    <language>en</language>
    <item>
      <title>Create a Hugo Theme from Scratch - IV</title>
      <dc:creator>Xiaoliang Wang</dc:creator>
      <pubDate>Tue, 15 Oct 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iv-2nhf</link>
      <guid>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iv-2nhf</guid>
      <description>&lt;p&gt;This is a series of blog posts documenting my journey of building a Hugo theme from scratch: &lt;a href="https://github.com/tomowang/hugo-theme-tailwind" rel="noopener noreferrer"&gt;https://github.com/tomowang/hugo-theme-tailwind&lt;/a&gt;. The series consists of four articles, this is the fourth one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-i-46j7"&gt;I. Introduction to the background of building the Hugo theme, my ideas for the theme's features, and the development environment setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-ii-113"&gt;II. The main directory structure of the Hugo theme, the technologies involved, and the main framework of the theme I created&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iii-5fm0"&gt;III. Additional features of the Hugo theme, including dark mode, responsive design, multilingual support, code highlighting, and build pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iv-2nhf"&gt;IV. This part describes non-code-related content, including continuous integration (CI), how to submit to the official theme site, and SEO-related data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Continuous Integration
&lt;/h2&gt;

&lt;p&gt;With the functionalities mentioned in previous articles completed, most of the coding work is done. However, as a project intended for others to use, there are still some additional tasks to handle.&lt;/p&gt;

&lt;p&gt;As a Hugo theme repository, continuous integration can encompass several aspects, such as automated deployment of the example site and automated version releases based on &lt;code&gt;git&lt;/code&gt; tags. Regarding the example site, the Hugo-generated static site can be easily published to &lt;code&gt;GitHub Pages&lt;/code&gt;, and &lt;code&gt;GitHub Actions&lt;/code&gt; provides actions to operate &lt;code&gt;GitHub Pages&lt;/code&gt;. Here, I used three actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://github.com/marketplace/actions/configure-github-pages" rel="noopener noreferrer"&gt;actions/configure-github-pages&lt;/a&gt; - Configures &lt;code&gt;GitHub Pages&lt;/code&gt; and retrieves some meta information, such as base_url&lt;/li&gt;
&lt;li&gt; &lt;a href="https://github.com/marketplace/actions/upload-github-pages-artifact" rel="noopener noreferrer"&gt;actions/upload-pages-artifact&lt;/a&gt; - Uploads resources to &lt;code&gt;GitHub Pages&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://github.com/marketplace/actions/deploy-github-pages-site" rel="noopener noreferrer"&gt;actions/deploy-pages&lt;/a&gt; - Deploys to &lt;code&gt;GitHub Pages&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;GitHub Pages&lt;/code&gt; related workflow requires additional permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages&lt;/span&gt;
&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, the Hugo compilation parameter &lt;code&gt;--baseURL&lt;/code&gt; needs to use the meta information from &lt;code&gt;GitHub Pages&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Pages&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pages&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/configure-pages@v3&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build with Hugo&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# For maximum backward compatibility with Hugo modules&lt;/span&gt;
    &lt;span class="na"&gt;HUGO_ENVIRONMENT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;HUGO_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;hugo -s exampleSite --minify --gc --themesDir ../.. \&lt;/span&gt;
      &lt;span class="s"&gt;--baseURL "${{ steps.pages.outputs.base_url }}/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;GitHub Actions&lt;/code&gt; code is placed in the &lt;code&gt;.github/workflows/&lt;/code&gt; directory and is triggered automatically by committing code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7xx2m1nlm6zkbj2qh4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7xx2m1nlm6zkbj2qh4f.png" alt="hugo theme project github actions" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa9qb3q1xy6fpj9w16ru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa9qb3q1xy6fpj9w16ru.png" alt="hugo theme project github action detail" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moreover, I configured DNS resolution pointing the GitHub domain &lt;code&gt;hugo-theme-tailwind.tomo.dev -&amp;gt; tomowang.github.io&lt;/code&gt; so that users can access the example site through &lt;a href="https://hugo-theme-tailwind.tomo.dev" rel="noopener noreferrer"&gt;https://hugo-theme-tailwind.tomo.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promotion
&lt;/h2&gt;

&lt;p&gt;To reach a wider audience for the theme, the best way is to submit it to the official theme site. Hugo provides a &lt;a href="https://github.com/gohugoio/hugoThemesSiteBuilder" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; to build the official theme site &lt;a href="https://themes.gohugo.io/" rel="noopener noreferrer"&gt;https://themes.gohugo.io/&lt;/a&gt;, and it also details the submission process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Specify the supported Hugo versions in the &lt;code&gt;config.toml&lt;/code&gt; configuration file.&lt;/li&gt;
&lt;li&gt; Use the &lt;code&gt;theme.toml&lt;/code&gt; file to describe some meta information about the theme, including name, copyright, tags, author, etc.&lt;/li&gt;
&lt;li&gt; A descriptive &lt;code&gt;README&lt;/code&gt; document, which serves as the main page on GitHub and is used to display the theme details on the site.&lt;/li&gt;
&lt;li&gt; Theme screenshots and thumbnails with the following size requirements:

&lt;ol&gt;
&lt;li&gt; Screenshot (&lt;code&gt;screenshot.png&lt;/code&gt; or &lt;code&gt;screenshot.jpg&lt;/code&gt;), with a minimum size of 1500×1000 pixels&lt;/li&gt;
&lt;li&gt; Thumbnail (&lt;code&gt;tn.png&lt;/code&gt; or &lt;code&gt;tn.jpg&lt;/code&gt;), with a minimum size of 900×600 pixels&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;After completing these steps, follow the &lt;code&gt;git&lt;/code&gt; workflow to fork, modify, commit, and submit a PR to the official theme repository. I submitted my PR &lt;a href="https://github.com/gohugoio/hugoThemesSiteBuilder/pull/391" rel="noopener noreferrer"&gt;#391&lt;/a&gt;. Fortunately, the PR was quickly merged into the repository, and finally, the theme became accessible on the official theme site: &lt;a href="https://themes.gohugo.io/themes/hugo-theme-tailwind/" rel="noopener noreferrer"&gt;https://themes.gohugo.io/themes/hugo-theme-tailwind/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi900uxnlqfz7zv5s7c3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi900uxnlqfz7zv5s7c3.png" alt="hugo theme tailwind" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other promotional channels include the official forum, where there is a dedicated section &lt;a href="https://discourse.gohugo.io/c/new-themes/45" rel="noopener noreferrer"&gt;new theme&lt;/a&gt; for discussions about new themes. I created a new topic to &lt;a href="https://discourse.gohugo.io/t/clean-card-hugo-theme-for-blog-created-by-using-tailwindcss-from-scrach/47398/1" rel="noopener noreferrer"&gt;introduce&lt;/a&gt; the theme.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5bbdyq0kioatktg3pkga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5bbdyq0kioatktg3pkga.png" alt="hugo discourse new post" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, some third-party theme sites collect data based on the &lt;code&gt;topics&lt;/code&gt; configuration in the GitHub repository, such as &lt;a href="https://www.builtatlightspeed.com/submit/opensource" rel="noopener noreferrer"&gt;builtatlightspeed&lt;/a&gt;. By configuring the &lt;code&gt;hugo-theme&lt;/code&gt; topic in the GitHub repository, these theme sites can crawl and index the repository. The complete Topics I configured are &lt;code&gt;theme hugo-theme hugo gohugo hugo-blog hugo-blog-theme tailwind tailwindcss tailwind-theme hugo-blog-template&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Currently, the theme is automatically listed on the following sites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://statichunt.com/themes/hugo-theme-tailwind" rel="noopener noreferrer"&gt;https://statichunt.com/themes/hugo-theme-tailwind&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://www.builtatlightspeed.com/theme/tomowang-hugo-theme-tailwind" rel="noopener noreferrer"&gt;https://www.builtatlightspeed.com/theme/tomowang-hugo-theme-tailwind&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, there are other theme sites where you can submit through PRs, such as &lt;a href="https://jamstackthemes.dev/" rel="noopener noreferrer"&gt;https://jamstackthemes.dev/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future
&lt;/h2&gt;

&lt;p&gt;After submitting the theme to the community, some users tried it out and provided feedback, suggestions, and questions, which I addressed and handled one by one. Currently, the number of Stars on the GitHub repository is as follows:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Fstars%2Ftomowang%2Fhugo-theme-tailwind" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Fstars%2Ftomowang%2Fhugo-theme-tailwind" alt="GitHub Repo stars" width="88" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is some data for reference:&lt;/p&gt;

&lt;p&gt;When searching for the keyword "hugo theme tailwind" on Google, the theme page ranks quite high.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpmex2rhzc7ht56lb8rm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpmex2rhzc7ht56lb8rm.png" alt="google search position" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From Google Analytics, we can observe that the most traffic comes from the official theme site &lt;a href="https://themes.gohugo.io" rel="noopener noreferrer"&gt;https://themes.gohugo.io&lt;/a&gt;, which is related to the Google search ranking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q69907idr68tjk0trzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q69907idr68tjk0trzp.png" alt="google analytics traffic acquisition by source" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This concludes this series of blog posts. Of course, the theme I created is relatively simple. If you are interested, you can try it out and provide valuable suggestions.&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>theme</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Create a Hugo Theme from Scratch - II</title>
      <dc:creator>Xiaoliang Wang</dc:creator>
      <pubDate>Tue, 15 Oct 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-ii-113</link>
      <guid>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-ii-113</guid>
      <description>&lt;p&gt;This is a series of blog posts documenting my process of building a Hugo theme from scratch (&lt;a href="https://github.com/tomowang/hugo-theme-tailwind" rel="noopener noreferrer"&gt;https://github.com/tomowang/hugo-theme-tailwind&lt;/a&gt;). The series consists of four articles, and this is the second one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-i-46j7"&gt;I. Introduction to the background of building the Hugo theme, my ideas for the theme's features, and the development environment setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-ii-113"&gt;II. The main directory structure of the Hugo theme, the technologies involved, and the main framework of the theme I created&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iii-5fm0"&gt;III. Additional features of the Hugo theme, including dark mode, responsive design, multilingual support, code highlighting, and build pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iv-2nhf"&gt;IV. This part describes non-code-related content, including continuous integration (CI), how to submit to the official theme site, and SEO-related data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hugo Theme Basics
&lt;/h2&gt;

&lt;p&gt;Before we start building the theme, we need to have a basic understanding of some terms, syntax, and directory structure of Hugo themes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Syntax
&lt;/h3&gt;

&lt;p&gt;Hugo uses &lt;code&gt;html/template&lt;/code&gt; to render content, and methods and variables are accessed through &lt;code&gt;{{ }}&lt;/code&gt;. Commonly used syntax is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Variable rendering - &lt;code&gt;{{ $address }}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Method call - &lt;code&gt;{{ FUNCTION ARG1 ARG2 .. }}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Loop&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;represents&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Conditional statements - &lt;code&gt;with&lt;/code&gt; &lt;code&gt;if&lt;/code&gt; &lt;code&gt;else&lt;/code&gt; etc.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isset&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Params&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Params&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Summary&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pipeline - &lt;code&gt;{{ .Title | .RenderString }}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Context &lt;code&gt;.&lt;/code&gt; and global context &lt;code&gt;$.&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use hyphen &lt;code&gt;-&lt;/code&gt; to remove extra empty strings&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a detailed description of the syntax, you can refer to the official documentation &lt;a href="https://gohugo.io/templates/introduction/" rel="noopener noreferrer"&gt;https://gohugo.io/templates/introduction/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hugo also provides many built-in variables, which are rendered through the theme file to ultimately generate static pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Site - Site object&lt;/li&gt;
&lt;li&gt;  Pages - Aggregation of pages&lt;/li&gt;
&lt;li&gt;  Page - Single page object&lt;/li&gt;
&lt;li&gt;  Menu - Menu list&lt;/li&gt;
&lt;li&gt;  Menu entry - Single menu object&lt;/li&gt;
&lt;li&gt;  Taxonomy - Single taxonomy object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using a theme to render page content, we need to call attributes or methods based on the corresponding variables to finally present the content we want.&lt;br&gt;
For example, if we want to display the reading time of a single article, we can call the &lt;code&gt;ReadingTime&lt;/code&gt; method (&lt;a href="https://gohugo.io/methods/page/readingtime/" rel="noopener noreferrer"&gt;https://gohugo.io/methods/page/readingtime/&lt;/a&gt;) of the &lt;code&gt;Page&lt;/code&gt; variable.&lt;br&gt;
Some objects have many methods, you can refer to the official documentation for details &lt;a href="https://gohugo.io/quick-reference/methods/" rel="noopener noreferrer"&gt;https://gohugo.io/quick-reference/methods/&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;After we create a basic Hugo theme, we can use the command &lt;code&gt;tree -L 2 -d .&lt;/code&gt; to view the basic structure of the theme directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── archetypes
├── assets
│   ├── css
│   └── js
├── data
├── i18n
├── layouts
│   ├── _default
│   └── partials
└── static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The meanings of the relevant directories are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;archetypes&lt;/code&gt; - Templates for creating new content pages&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;assets&lt;/code&gt; - Static resource files, usually processed through the resource pipeline&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;data&lt;/code&gt; - Used to store additional data, you can refer to &lt;a href="https://gohugo.io/templates/data-templates/" rel="noopener noreferrer"&gt;https://gohugo.io/templates/data-templates/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;i18n&lt;/code&gt; - Stores localization files&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;layouts&lt;/code&gt; - Core template layout files&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;static&lt;/code&gt; - Static files that will be copied directly to the final public directory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important one is the &lt;strong&gt;layouts&lt;/strong&gt; directory, which determines the pages supported by the template and the layout of the pages.&lt;br&gt;
Hugo uses a set of rules to query which template file should be used for the content page. A typical site consists of the following types of pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Home page&lt;/li&gt;
&lt;li&gt;  Single page&lt;/li&gt;
&lt;li&gt;  List page&lt;/li&gt;
&lt;li&gt;  Term page&lt;/li&gt;
&lt;li&gt;  Term list page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lookup order can be referred to in the official documentation &lt;a href="https://gohugo.io/templates/lookup-order/" rel="noopener noreferrer"&gt;https://gohugo.io/templates/lookup-order/&lt;/a&gt;.&lt;br&gt;
The official documentation describes the complex lookup order, but most page structures of the theme are similar, so in actual situations, only a few pages need to be defined to achieve the desired result.&lt;/p&gt;
&lt;h2&gt;
  
  
  Theme Content Construction
&lt;/h2&gt;
&lt;h3&gt;
  
  
  tailwindcss
&lt;/h3&gt;

&lt;p&gt;Before starting to build, we need to install &lt;code&gt;tailwindcss&lt;/code&gt;. I made some adjustments based on the official documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install&lt;/span&gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; tailwindcss
&lt;span class="c"&gt;# init&lt;/span&gt;
npx tailwindcss init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install &lt;code&gt;tailwindcss&lt;/code&gt; and generate &lt;code&gt;tailwind.config.js&lt;/code&gt; configuration file through the above commands.&lt;br&gt;
Since our page content is in the &lt;strong&gt;layout&lt;/strong&gt; directory, we need to adjust the &lt;code&gt;content&lt;/code&gt; configuration in &lt;code&gt;tailwind.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./layouts/**/*.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Place the &lt;code&gt;tailwindcss&lt;/code&gt; reference in &lt;code&gt;assets/css/main.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can monitor the page content and generate the actual CSS file to be used through the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tailwindcss &lt;span class="nt"&gt;-i&lt;/span&gt; assets/css/main.css &lt;span class="nt"&gt;-o&lt;/span&gt; ./static/main.css &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic Layout
&lt;/h3&gt;

&lt;p&gt;Based on my needs and the description of the Hugo directory structure in the previous section, I finally defined the following basic pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;baseof.html&lt;/code&gt; - Carries the layout of the main page&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;list.html&lt;/code&gt; - List page, term list page&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;single.html&lt;/code&gt; - Single page, the main content page&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;terms.html&lt;/code&gt; - Term page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Through the &lt;code&gt;baseof.html&lt;/code&gt; file, we define the basic template, which will be applied to all pages. Its core content is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"{{ or site.Language.LanguageCode site.Language.Lang }}"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"{{ or site.Language.LanguageDirection `ltr` }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  {{ block "title" . }}
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;
      {{ if .IsHome }}{{ $.Site.Title }}{{ with $.Site.Params.Subtitle }} —
      {{ . }}{{ end }}{{ else }}{{ .Title }} ::
      {{ $.Site.Title }}{{ with $.Site.Params.Subtitle }} — {{ . }}{{ end }}{{ end }}
    &lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  {{ end }}
  {{ partial "head.html" . }}
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full bg-slate-50"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-none justify-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ partial "header.html" . }}
  &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-auto justify-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ block "main" . }}{{ end }}
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-none justify-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ partial "footer.html" . }}
  &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use &lt;code&gt;{{ partial "head.html" . }}&lt;/code&gt; to include the content required by the &lt;code&gt;head&lt;/code&gt; tag, and refer to the CSS file generated earlier in &lt;code&gt;head.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Theme CSS (/static/main.css) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ "&lt;/span&gt;&lt;span class="na"&gt;main.css&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="na"&gt;relURL&lt;/span&gt; &lt;span class="err"&gt;}}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the HTML &lt;code&gt;body&lt;/code&gt; tag, the &lt;code&gt;header&lt;/code&gt; tag is the top navigation, the &lt;code&gt;footer&lt;/code&gt; tag is the bottom menu, and the &lt;code&gt;main&lt;/code&gt; tag is the main content.&lt;br&gt;
The content of &lt;code&gt;{{ block "main" . }}{{ end }}&lt;/code&gt; in the &lt;code&gt;main&lt;/code&gt; tag needs to be defined on other pages. For example, the simplified &lt;code&gt;list.html&lt;/code&gt; code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{ define "main" }}
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col w-full max-w-4xl lg:max-w-5xl relative"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col w-2/3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{ range (.Paginate $pages).Pages }}
          &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col gap-y-3 p-6 mt-6 rounded-lg shadow-md bg-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-4xl font-semibold text-slate-800"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ .RelPermalink }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ .Title | markdownify }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
        {{ end }}
      &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;aside&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col w-1/3 mx-3 top-0 sticky self-start"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{ partial "sidebar.html" . }}
      &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    {{ partial "pagination.html" . }}
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
{{ end }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Among them, the &lt;code&gt;section&lt;/code&gt; tag corresponds to the article list block, and the &lt;code&gt;aside&lt;/code&gt; tag corresponds to the side term display block.&lt;br&gt;
The content of the single page &lt;code&gt;single.html&lt;/code&gt; is similar, including the article title, TOC content, article body, etc.&lt;br&gt;
The advantage of &lt;code&gt;tailwindcss&lt;/code&gt; is that there is a ready-made &lt;code&gt;typography&lt;/code&gt; plugin that can directly render the content of the article without having to define complex CSS styles additionally.&lt;/p&gt;

&lt;p&gt;The overall reference relationship can refer to the following figure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12ogwwxrz1ht8ghsr5yp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12ogwwxrz1ht8ghsr5yp.png" alt="hugo theme layout structure" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to reuse some components, such as tag lists, reading time, icons, etc., we can abstract the same content and put it in the &lt;code&gt;layouts/partials&lt;/code&gt; directory.&lt;br&gt;
Taking icons as an example, I use &lt;a href="https://tabler.io/icons" rel="noopener noreferrer"&gt;https://tabler.io/icons&lt;/a&gt; as the source of icons,&lt;br&gt;
Download the corresponding icon SVG file to the &lt;code&gt;assets&lt;/code&gt; directory and define a &lt;code&gt;partial&lt;/code&gt; page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;iconFile&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetMatch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="s"&gt;"icons/%s.svg"&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;iconFile&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;iconFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;safeHTML&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;errorf&lt;/span&gt; &lt;span class="s"&gt;"Error: icon '%s.svg' is not found under 'assets/icons' folder"&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Among them, the symbol &lt;code&gt;.&lt;/code&gt; is the passed icon name parameter, so that we can quickly refer to the icon in the page, such as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;partial&lt;/span&gt; &lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="s"&gt;"calendar"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Through about 5 days of spare time development (&lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/bf54ab9b7a5f0524d563b19cf90bd19f07906ffc" rel="noopener noreferrer"&gt;#bf54ab9&lt;/a&gt;),&lt;br&gt;
the final effect is as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0knjyrfhawmbzk8kaf9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0knjyrfhawmbzk8kaf9.png" alt="hugo theme basic layout" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, this is the first phase of the content, only with a white theme (the theme switch button does not respond when clicked), no multilingual support, and no responsiveness.&lt;br&gt;
But the main page structure is already there, and &lt;code&gt;tailwindcss&lt;/code&gt; has shown its efficient and flexible characteristics in dealing with CSS styles.&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>theme</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Create a Hugo Theme from Scratch - III</title>
      <dc:creator>Xiaoliang Wang</dc:creator>
      <pubDate>Tue, 15 Oct 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iii-5fm0</link>
      <guid>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iii-5fm0</guid>
      <description>&lt;p&gt;This is a blog series that documents my journey of building a Hugo theme &lt;a href="https://github.com/tomowang/hugo-theme-tailwind" rel="noopener noreferrer"&gt;https://github.com/tomowang/hugo-theme-tailwind&lt;/a&gt; from scratch. The entire series consists of four articles, and this is the third:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-i-46j7"&gt;I. Introduction to the background of building the Hugo theme, my ideas for the theme's features, and the development environment setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-ii-113"&gt;II. The main directory structure of the Hugo theme, the technologies involved, and the main framework of the theme I created&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iii-5fm0"&gt;III. Additional features of the Hugo theme, including dark mode, responsive design, multilingual support, code highlighting, and build pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iv-2nhf"&gt;IV. This part describes non-code-related content, including continuous integration (CI), how to submit to the official theme site, and SEO-related data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dark Mode
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tailwindcss&lt;/code&gt; makes handling dark mode very convenient. Based on the original light theme, we only need to set the display style under the dark theme through the &lt;code&gt;dark:&lt;/code&gt; prefix.&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;darkMode: 'class'&lt;/code&gt; configuration in &lt;code&gt;tailwind.config.js&lt;/code&gt;, and then we can modify the styles in the theme.&lt;br&gt;
For details on dark mode, please refer to the official documentation: &lt;a href="https://tailwindcss.com/docs/dark-mode" rel="noopener noreferrer"&gt;https://tailwindcss.com/docs/dark-mode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's worth mentioning the dark mode toggle button. To keep the theme as simple as possible and avoid referencing additional front-end frameworks,&lt;br&gt;
I researched some common theme button toggle examples in &lt;code&gt;tailwindcss&lt;/code&gt; and found that using &lt;code&gt;input + peer + group&lt;/code&gt; could achieve the desired effect very well.&lt;br&gt;
The code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"darkmode-toggle flex flex-none ml-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center px-3 cursor-pointer rounded-full bg-gray-100 dark:bg-gray-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only peer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"group flex flex-row gap-1 justify-center h-8 px-1 rounded-full bg-white dark:bg-gray-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-6 w-6 flex-none rounded-full bg-yellow-400 place-self-center peer-checked:group-[]:invisible"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{ partial "icon" "brightness-down" }}
      &lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-6 w-6 flex-none rounded-full place-self-center invisible peer-checked:group-[]:visible"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{ partial "icon" "moon-stars" }}
      &lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use &lt;code&gt;&amp;lt;input type="checkbox"&amp;gt;&lt;/code&gt; to control the theme variable, and then define a group of icons using &lt;code&gt;&amp;lt;div class="group"&amp;gt;&lt;/code&gt;. Each icon uses &lt;code&gt;peer-checked:group-[]:invisible&lt;/code&gt; and &lt;code&gt;peer-checked:group-[]:visible&lt;/code&gt; to control visibility and hiding.&lt;br&gt;
This way, I only need to pay attention to the value of the &lt;code&gt;checkbox&lt;/code&gt;, while the icon switching of the button is completely handled by &lt;code&gt;tailwindcss&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;themeToggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.darkmode-toggle input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;themeToggle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;light&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regarding &lt;code&gt;group&lt;/code&gt; and &lt;code&gt;peer&lt;/code&gt;, &lt;code&gt;tailwindcss&lt;/code&gt; describes them as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state" rel="noopener noreferrer"&gt;Styling based on parent state (group-{modifier})&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-sibling-state" rel="noopener noreferrer"&gt;Styling based on sibling state (peer-{modifier})&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dark theme implementation took me a day of spare time, and the final code is at &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/75c6b41a14b49ba180767d4d38cc2dccde44311e" rel="noopener noreferrer"&gt;#75c6b41&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsive Design
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tailwindcss&lt;/code&gt; also makes responsive design easy to use. My goal is to support both mobile and PC. When designing with mobile-first in mind,&lt;br&gt;
&lt;code&gt;tailwindcss&lt;/code&gt; uses prefix-less components to design mobile styles first, and then uses prefixed components (e.g., &lt;code&gt;md:&lt;/code&gt;) to override styles at other screen sizes. My modifications are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;index ad2e93f..e5b7d76 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/layouts/_default/list.html
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/layouts/_default/list.html
&lt;/span&gt;&lt;span class="p"&gt;@@ -15,9 +15,9 @@&lt;/span&gt;
&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;div class="flex flex-col w-full max-w-4xl lg:max-w-5xl relative"&amp;gt;
     &amp;lt;div class="flex flex-row"&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;section class="flex flex-col w-2/3"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;section class="flex flex-col w-full md:w-2/3"&amp;gt;
&lt;/span&gt;         {{ range (.Paginate $pages).Pages }}
&lt;span class="gd"&gt;-          &amp;lt;article class="flex flex-col gap-y-3 p-6 mt-6 rounded-lg shadow-md bg-white dark:bg-gray-700"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+          &amp;lt;article class="flex flex-col gap-y-3 p-6 mt-6 mx-2 md:mx-0 rounded-lg shadow-md bg-white dark:bg-gray-700"&amp;gt;
&lt;/span&gt;             &amp;lt;h2 class="text-4xl font-semibold text-slate-800 dark:text-slate-200"&amp;gt;
               &amp;lt;a href="{{ .RelPermalink }}"&amp;gt;{{ .Title | markdownify }}&amp;lt;/a&amp;gt;
             &amp;lt;/h2&amp;gt;
&lt;span class="p"&gt;@@ -40,7 +40,7 @@&lt;/span&gt;
           &amp;lt;/article&amp;gt;
         {{ end }}
       &amp;lt;/section&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;aside class="flex flex-col w-1/3 mx-3 top-0 sticky self-start"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;aside class="hidden md:flex flex-col md:w-1/3 mx-3 top-0 sticky self-start"&amp;gt;
&lt;/span&gt;         {{ partial "sidebar.html" . }}
       &amp;lt;/aside&amp;gt;
     &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the code shows, I changed the &lt;code&gt;section&lt;/code&gt; tag to &lt;code&gt;w-full&lt;/code&gt; by default and then used &lt;code&gt;md:w-2/3&lt;/code&gt; to display 2/3 width on larger screens.&lt;/p&gt;

&lt;p&gt;The final code is at &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/279de84e9bdc61a11216283f405a68f2ec9584b5" rel="noopener noreferrer"&gt;#279de84&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multilingual Support
&lt;/h2&gt;

&lt;p&gt;Hugo natively supports multiple languages. First, we need to introduce configuration for multiple languages in the configuration file. For example, our example site has the configuration file &lt;code&gt;exampleSite/config/_default/languages.toml&lt;/code&gt;, with the content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[en]&lt;/span&gt;
  &lt;span class="py"&gt;languageCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'en-US'&lt;/span&gt;
  &lt;span class="py"&gt;languageDirection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'ltr'&lt;/span&gt;
  &lt;span class="py"&gt;languageName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'English'&lt;/span&gt;
  &lt;span class="py"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nn"&gt;[en.menu]&lt;/span&gt;
  &lt;span class="nn"&gt;[[en.menu.main]]&lt;/span&gt;
    &lt;span class="py"&gt;identifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"post"&lt;/span&gt;
    &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Post"&lt;/span&gt;
    &lt;span class="py"&gt;pageRef&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"post"&lt;/span&gt;
    &lt;span class="py"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

  &lt;span class="nn"&gt;[[en.menu.main]]&lt;/span&gt;
    &lt;span class="py"&gt;identifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"about"&lt;/span&gt;
    &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"About"&lt;/span&gt;
    &lt;span class="py"&gt;pageRef&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"about"&lt;/span&gt;
    &lt;span class="py"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

&lt;span class="nn"&gt;[zh-cn]&lt;/span&gt;
  &lt;span class="py"&gt;languageCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'zh-CN'&lt;/span&gt;
  &lt;span class="py"&gt;languageDirection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'ltr'&lt;/span&gt;
  &lt;span class="py"&gt;languageName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'中文'&lt;/span&gt;
  &lt;span class="py"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="nn"&gt;[zh-cn.menu]&lt;/span&gt;
  &lt;span class="nn"&gt;[[zh-cn.menu.main]]&lt;/span&gt;
    &lt;span class="py"&gt;identifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"post"&lt;/span&gt;
    &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"文章"&lt;/span&gt;
    &lt;span class="py"&gt;pageRef&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"post"&lt;/span&gt;
    &lt;span class="py"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

  &lt;span class="nn"&gt;[[zh-cn.menu.main]]&lt;/span&gt;
    &lt;span class="py"&gt;identifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"about"&lt;/span&gt;
    &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"关于"&lt;/span&gt;
    &lt;span class="py"&gt;pageRef&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"about"&lt;/span&gt;
    &lt;span class="py"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we need to organize and place the previously hardcoded strings in the theme into the &lt;code&gt;i18n&lt;/code&gt; folder and modify the strings in the theme using the &lt;code&gt;i18n&lt;/code&gt; function for replacement.&lt;br&gt;
For example, part of the strings in the &lt;code&gt;layouts/404.html&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/layouts/404.html b/layouts/404.html
index 77d8885..32ec853 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/layouts/404.html
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/layouts/404.html
&lt;/span&gt;&lt;span class="p"&gt;@@ -2,11 +2,11 @@&lt;/span&gt;
   &amp;lt;main class="grid place-items-center w-full min-h-full max-w-4xl lg:max-w-5xl px-6 py-24"&amp;gt;
     &amp;lt;div class="text-center w-full"&amp;gt;
       &amp;lt;p class="text-base font-semibold text-indigo-600 dark:text-indigo-300"&amp;gt;404&amp;lt;/p&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;h1 class="mt-4 text-3xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-5xl"&amp;gt;Page not found&amp;lt;/h1&amp;gt;
-      &amp;lt;p class="mt-6 text-base leading-7 text-slate-400"&amp;gt;Sorry, we couldn't find the page you're looking for.&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;h1 class="mt-4 text-3xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-5xl"&amp;gt;{{ T "404.page_not_found" }}&amp;lt;/h1&amp;gt;
+      &amp;lt;p class="mt-6 text-base leading-7 text-slate-400"&amp;gt;{{ T "404.sorry" }}&amp;lt;/p&amp;gt;
&lt;/span&gt;       &amp;lt;div class="mt-10 flex items-center justify-center gap-x-6"&amp;gt;
         &amp;lt;a href="/" class="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"&amp;gt;
&lt;span class="gd"&gt;-          Go back home
&lt;/span&gt;&lt;span class="gi"&gt;+          {{ T "404.go_back_home" }}
&lt;/span&gt;         &amp;lt;/a&amp;gt;
       &amp;lt;/div&amp;gt;
     &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, adjust the navigation bar to add a language switch button and a language list.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8je7wx265fkzd29mu2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8je7wx265fkzd29mu2m.png" alt="hugo multilingual language switch" width="710" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the complete code, please refer to &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/024446464dbf5a7d48c6fbb6e05cc6915d190ad0" rel="noopener noreferrer"&gt;#0244464&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Additional Benefits
&lt;/h3&gt;

&lt;p&gt;My native language is Chinese, and I can read English quite well, so I initially only implemented Chinese and English.&lt;br&gt;
But how can I add more languages to the theme? 2023 was a year of significant growth for large language models,&lt;br&gt;
and with the help of LLMs, I translated the language files into more languages like Russian and Japanese using prompts.&lt;/p&gt;

&lt;p&gt;Here, I used the &lt;code&gt;gemini&lt;/code&gt; interface to process the &lt;code&gt;i18n&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;google.generativeai&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;

&lt;span class="c1"&gt;# get key from https://makersuite.google.com/app/apikey
&lt;/span&gt;&lt;span class="n"&gt;GOOGLE_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;YOUR_GOOGLE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerativeModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gemini-pro&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;prompt_template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;You are a translator and your task is to translate l10n file to different languages.
The l10n file is provided in TOML format. The file contains {{ KEY }} for variables and use
`one` for singular and `other` for plural.

The TOML file is quoted in triple backtick. Please translate the content to {lang}
and keep the original content structure, also remove triple backtick in output:

~~~toml
{en_file_content}
~~~
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;

&lt;span class="n"&gt;en_file_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./en.toml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;en_file_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prompt_template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Chinese&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;en_file_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;en_file_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;~~~&lt;/code&gt; in code is used for rendering, since Markdown here in dev.to does not support nested code block.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the prompt, I included some hugo and code-related instructions, like the file format is &lt;code&gt;TOML&lt;/code&gt;, using &lt;code&gt;{{ KEY }}&lt;/code&gt; for variables,&lt;br&gt;
and handling singular and plural with &lt;code&gt;&lt;/code&gt;one&lt;code&gt;for singular and&lt;/code&gt;other&lt;code&gt;for plural&lt;/code&gt;.&lt;br&gt;
I also used instructions to ensure the LLM output retained the original format. I tested with Chinese, which I'm familiar with, and the above code output the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;table_of_contents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"目录"&lt;/span&gt;
&lt;span class="py"&gt;open_main_menu&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"打开主菜单"&lt;/span&gt;
&lt;span class="py"&gt;open_lang_switcher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"打开语言切换器"&lt;/span&gt;
&lt;span class="nn"&gt;[reading_time]&lt;/span&gt;
  &lt;span class="py"&gt;one&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"阅读时长一分钟"&lt;/span&gt;
  &lt;span class="py"&gt;other&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"阅读时长{{ .Count }}分钟"&lt;/span&gt;

&lt;span class="nn"&gt;[header]&lt;/span&gt;
&lt;span class="py"&gt;darkmode_toggle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"切换深色模式"&lt;/span&gt;

&lt;span class="nn"&gt;[404]&lt;/span&gt;
&lt;span class="py"&gt;go_back_home&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"返回主页"&lt;/span&gt;
&lt;span class="py"&gt;sorry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"抱歉，找不到您要查找的页面。"&lt;/span&gt;
&lt;span class="py"&gt;page_not_found&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"页面未找到"&lt;/span&gt;

&lt;span class="nn"&gt;[footer]&lt;/span&gt;
&lt;span class="py"&gt;powered_by&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"由{{ .Generator }} {{ .Heart }} {{ .Theme }}提供支持"&lt;/span&gt;
&lt;span class="py"&gt;copyright_with_since&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ .CopyrightSign }} {{ .SinceYear }} - {{ .CurrentYear}} {{ .Copyright }}"&lt;/span&gt;
&lt;span class="py"&gt;copyright_wo_since&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ .CopyrightSign }} {{ .CurrentYear}} {{ .Copyright }}"&lt;/span&gt;

&lt;span class="nn"&gt;[paginator]&lt;/span&gt;
&lt;span class="py"&gt;newer_posts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"较新的文章"&lt;/span&gt;
&lt;span class="py"&gt;older_posts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"较早的文章"&lt;/span&gt;

&lt;span class="nn"&gt;[taxonomies]&lt;/span&gt;
&lt;span class="py"&gt;categories&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"分类"&lt;/span&gt;
&lt;span class="py"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"标签"&lt;/span&gt;
&lt;span class="py"&gt;series&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"系列"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final result was quite good. The file structure was correct, and the variables were preserved. I used a similar method to generate localization files for other languages. Of course, I don't actually speak Russian, Japanese, etc., so I couldn't accurately judge the quality of the translations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Others
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Shortcodes
&lt;/h3&gt;

&lt;p&gt;Hugo provides &lt;code&gt;shortcodes&lt;/code&gt; to extend &lt;code&gt;markdown&lt;/code&gt; rendering capabilities. &lt;code&gt;shortcodes&lt;/code&gt; are reusable code snippets that can make editing &lt;code&gt;markdown&lt;/code&gt; more efficient. Hugo has some built-in common &lt;code&gt;shortcodes&lt;/code&gt;, like &lt;code&gt;figure&lt;/code&gt;, &lt;code&gt;gist&lt;/code&gt;, etc. You can refer to &lt;a href="https://gohugo.io/content-management/shortcodes/" rel="noopener noreferrer"&gt;https://gohugo.io/content-management/shortcodes/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some of my blogs use &lt;code&gt;asciinema&lt;/code&gt; to record terminal interactions, and I use &lt;code&gt;shortcodes&lt;/code&gt; to conveniently embed &lt;code&gt;asciinema&lt;/code&gt;.&lt;br&gt;
Hugo searches for &lt;code&gt;shortcodes&lt;/code&gt; code in a specific order, with the file name being the final name used in &lt;code&gt;markdown&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;/layouts/shortcodes/&amp;lt;SHORTCODE&amp;gt;.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/themes/&amp;lt;THEME&amp;gt;/layouts/shortcodes/&amp;lt;SHORTCODE&amp;gt;.html&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I created the &lt;code&gt;layouts/shortcodes/asciinema.html&lt;/code&gt; file and referenced the official embedding documentation:&lt;br&gt;
&lt;a href="https://docs.asciinema.org/manual/server/embedding/#inline-player" rel="noopener noreferrer"&gt;https://docs.asciinema.org/manual/server/embedding/#inline-player&lt;/a&gt;. I wrote the following content in the html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"asciicast-{{ $id }}"&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://asciinema.org/a/{{ $id }}.js"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;.Get 0&lt;/code&gt; means getting the first parameter. Of course, you can also use named parameters. The usage is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="c"&gt;/* asciinema 239367 */&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The effect is as follows:&lt;/p&gt;

&lt;p&gt;{{&amp;lt; asciinema 239367 &amp;gt;}}&lt;/p&gt;

&lt;h3&gt;
  
  
  Render Hooks
&lt;/h3&gt;

&lt;p&gt;Hugo uses &lt;a href="https://github.com/yuin/goldmark" rel="noopener noreferrer"&gt;&lt;code&gt;goldmark&lt;/code&gt;&lt;/a&gt; to render &lt;code&gt;markdown&lt;/code&gt;, and &lt;code&gt;render hooks&lt;/code&gt; allow developers to override the rendering of specific components. Currently supported are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;image&lt;/li&gt;
&lt;li&gt;link&lt;/li&gt;
&lt;li&gt;heading&lt;/li&gt;
&lt;li&gt;codeblock&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simply, we can add additional attributes to the &lt;code&gt;a&lt;/code&gt; tag rendered by the link to ensure security. For example, add the file&lt;br&gt;
&lt;code&gt;layouts/_default/_markup/render-link.html&lt;/code&gt; with the content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ .Destination | safeURL }}"&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ . }}"&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}{{&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasPrefix&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Destination&lt;/span&gt; &lt;span class="s"&gt;"http"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener"&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;safeHTML&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code adds the &lt;code&gt;rel="noopener"&lt;/code&gt; attribute when rendering links to external sites.&lt;/p&gt;

&lt;p&gt;Of course, more complex operations can be added to the rendering of images, such as lazy loading, scaling images to fit different resolutions,&lt;br&gt;
and converting images to compressed formats. You can refer to the processing in &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/blob/main/layouts/_default/_markup/render-image.html" rel="noopener noreferrer"&gt;&lt;code&gt;layouts/_default/_markup/render-image.html&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Code Block Syntax Highlighting and Copying
&lt;/h3&gt;

&lt;p&gt;Hugo uses &lt;a href="https://github.com/alecthomas/chroma" rel="noopener noreferrer"&gt;&lt;code&gt;chroma&lt;/code&gt;&lt;/a&gt; for code highlighting. It works well with the default configuration, but I want to go further,&lt;br&gt;
such as having the code block theme switch along with the light and dark modes, and providing code block copying functionality.&lt;/p&gt;

&lt;p&gt;To support custom styles, we need to adjust the code highlighting configuration in the &lt;code&gt;config/_default/hugo.toml&lt;/code&gt; file to use CSS classes to apply highlighting styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[markup.highlight]&lt;/span&gt;
  &lt;span class="py"&gt;noClasses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use the command to generate code highlighting styles for our light and dark themes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hugo gen chromastyles &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;solarized-light
hugo gen chromastyles &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;solarized-dark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write the styles into the main style file. For the dark theme, you can use the column editing mode of the IDE to add &lt;code&gt;.dark&lt;/code&gt; before each line of style to restrict it.&lt;br&gt;
The effects under light and dark themes are as follows:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hthz48jw9qdat3m76b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hthz48jw9qdat3m76b3.png" alt="hugo syntex highlight light" width="800" height="270"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcavpwmt7pnfshoed6h9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcavpwmt7pnfshoed6h9l.png" alt="hugo syntex highlight dark" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, in some cases, &lt;code&gt;chroma&lt;/code&gt;'s default CSS styles may conflict with &lt;code&gt;tailwindcss&lt;/code&gt;'s &lt;code&gt;typography&lt;/code&gt; plugin. For example, when the line number configuration is enabled, you will find that there is a large gap between the code line numbers and the code block:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1ojj7fqz0xiftd5ftcn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1ojj7fqz0xiftd5ftcn.png" alt="hugo syntex highlight lineno error" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because &lt;code&gt;chroma&lt;/code&gt; uses table elements when rendering line numbers, while &lt;code&gt;typography&lt;/code&gt; adds additional margins to &lt;code&gt;pre&lt;/code&gt; elements.&lt;br&gt;
In this case, we need to find the conflict points and then override some styles. The following CSS styles will remove the margins and border-radius of the &lt;code&gt;pre&lt;/code&gt; elements in code blocks with line numbers and change the &lt;code&gt;display&lt;/code&gt; property of the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* fix highlight with line number */&lt;/span&gt;
&lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="nc"&gt;.chroma&lt;/span&gt; &lt;span class="nc"&gt;.lntable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.7142857em&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.8571429em&lt;/span&gt; &lt;span class="m"&gt;1.1428571em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.375rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="nc"&gt;.chroma&lt;/span&gt; &lt;span class="nc"&gt;.lntable&lt;/span&gt; &lt;span class="nt"&gt;pre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.8571429em&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* https://caniuse.com/css-has */&lt;/span&gt;
&lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="nc"&gt;.chroma&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="nc"&gt;.lntable&lt;/span&gt; &lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="nc"&gt;.lntable&lt;/span&gt; &lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="nc"&gt;.lntd&lt;/span&gt;&lt;span class="nd"&gt;:last-child&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;flex-grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code block copying is achieved by checking if there are &lt;code&gt;pre&lt;/code&gt; elements on the page, then finding the &lt;code&gt;.highlight&lt;/code&gt; elements on the page, and adding corresponding copy buttons.&lt;br&gt;
I used the statement &lt;code&gt;{{- if (findRE "&amp;lt;pre" .Content 1) }}&lt;/code&gt; in &lt;code&gt;baseof.html&lt;/code&gt; to search for elements,&lt;br&gt;
which reduces JavaScript loading. Additionally, note that code blocks with line numbers will render two &lt;code&gt;code&lt;/code&gt; elements, and we need to take the last one.&lt;br&gt;
Relevant code can be found at &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/4d62bbaecc10084a6140a5de2193ad8f7c5ef9f8" rel="noopener noreferrer"&gt;#4d62bba&lt;/a&gt;&lt;br&gt;
and &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/df6ac6d5916620d7d262110b15522d5af944c9b4" rel="noopener noreferrer"&gt;#df6ac6d&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pipes
&lt;/h3&gt;

&lt;p&gt;When allowing users to modify the theme, we need to keep the original &lt;code&gt;CSS&lt;/code&gt; and &lt;code&gt;JavaScript&lt;/code&gt; code.&lt;br&gt;
But for general direct users, we need to shield these code compilation logic while ensuring that the final generated static resources are compressed.&lt;br&gt;
Here we can use the &lt;code&gt;pipes&lt;/code&gt; feature provided by Hugo.&lt;br&gt;
For &lt;code&gt;tailwindcss&lt;/code&gt;, I initially placed the original CSS style in &lt;code&gt;assets/css/main.css&lt;/code&gt;, the compiled code in the static folder &lt;code&gt;static/main.css&lt;/code&gt;, and directly referenced the static file in &lt;code&gt;head.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Theme CSS (/static/main.css) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ "&lt;/span&gt;&lt;span class="na"&gt;main.css&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="na"&gt;relURL&lt;/span&gt; &lt;span class="err"&gt;}}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wanted to display the original CSS style during development but use the compressed version with a hashed filename when deployed.&lt;br&gt;
Ultimately, I adjusted the location of the &lt;code&gt;CSS&lt;/code&gt; files, placing both the pre-compiled and post-compiled &lt;code&gt;CSS&lt;/code&gt; code in &lt;code&gt;assets/css&lt;/code&gt;&lt;br&gt;
(so that Hugo can process the resources), and adjusted the inclusion of &lt;code&gt;CSS&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt; &lt;span class="s"&gt;"css/index.css"&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getenv&lt;/span&gt; &lt;span class="s"&gt;"HUGO_THEME_DEVELOPMENT"&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt; &lt;span class="s"&gt;"css/main.css"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;postCSS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dict&lt;/span&gt; &lt;span class="s"&gt;"config"&lt;/span&gt; &lt;span class="s"&gt;"./postcss.config.js"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hugo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDevelopment&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteAsTemplate&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="s"&gt;"css/main.dev.%v.css"&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixMilli&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;minify&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;fingerprint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ $styles.RelPermalink }}"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, I use &lt;code&gt;HUGO_THEME_DEVELOPMENT&lt;/code&gt; to identify the theme development mode, and process CSS styles using &lt;code&gt;PostCSS&lt;/code&gt; in theme development mode.&lt;br&gt;
When using the &lt;code&gt;hugo server&lt;/code&gt; command, Hugo is in development mode, &lt;code&gt;hugo.IsDevelopment&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;,&lt;br&gt;
and filenames with timestamps are used in development mode to prevent caching. In production mode, &lt;code&gt;| minify | fingerprint&lt;/code&gt; is applied for compression and file caching.&lt;/p&gt;

&lt;p&gt;Regarding the environments corresponding to different Hugo commands, you can refer to the following table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hugo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;production&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hugo --environment staging&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;staging&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hugo server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;development&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hugo server --environment staging&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;staging&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Similarly, we can handle &lt;code&gt;JavaScript&lt;/code&gt; files in a similar way, such as for code block copying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;jsCopy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt; &lt;span class="s"&gt;"js/code-copy.js"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt; &lt;span class="s"&gt;"code-copy.js"&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;hugo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDevelopment&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;jsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;jsCopy&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;minify&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;fingerprint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ $jsCopy.RelPermalink }}"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lighthouse
&lt;/h3&gt;

&lt;p&gt;I've completed most of the code writing, but I still need to check if the pages rendered by my theme conform to some standards and best practices.&lt;br&gt;
I used the built-in &lt;code&gt;lighthouse&lt;/code&gt; developer tool in &lt;code&gt;chrome&lt;/code&gt; to check the site.&lt;/p&gt;

&lt;p&gt;It can be seen that the performance score of the site is good, but there is room for improvement in accessibility and SEO. For example, the contrast of some colors in the theme, the &lt;code&gt;alt&lt;/code&gt; attribute of images, etc.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ve1hbfio9ui6j0n3cx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ve1hbfio9ui6j0n3cx4.png" alt="hugo theme lighthouse original report" width="800" height="1142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on lighthouse's suggestions, I made adjustments and optimizations for each suggestion, and finally, the lighthouse score reached a high level:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlgfzb9ahxykx0veh0ki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlgfzb9ahxykx0veh0ki.png" alt="hugo theme lighthouse report after modification" width="800" height="1117"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>theme</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Create a Hugo Theme from Scratch - I</title>
      <dc:creator>Xiaoliang Wang</dc:creator>
      <pubDate>Tue, 15 Oct 2024 09:00:00 +0000</pubDate>
      <link>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-i-46j7</link>
      <guid>https://dev.to/tomowang/create-a-hugo-theme-from-scratch-i-46j7</guid>
      <description>&lt;p&gt;This is a series of blog posts documenting the process of building a Hugo theme from scratch: &lt;a href="https://github.com/tomowang/hugo-theme-tailwind" rel="noopener noreferrer"&gt;https://github.com/tomowang/hugo-theme-tailwind&lt;/a&gt;. The series includes four parts, and this is the first one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-i-46j7"&gt;I. Introduction to the background of building the Hugo theme, my ideas for the theme's features, and the development environment setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-ii-113"&gt;II. The main directory structure of the Hugo theme, the technologies involved, and the main framework of the theme I created&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iii-5fm0"&gt;III. Additional features of the Hugo theme, including dark mode, responsive design, multilingual support, code highlighting, and build pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tomowang/create-a-hugo-theme-from-scratch-iv-2nhf"&gt;IV. This part describes non-code-related content, including continuous integration (CI), how to submit to the official theme site, and SEO-related data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;As a developer with over ten years of experience, I've been exposed to various technologies, including frontend, backend, big data, and machine learning. When I wanted to share my personal development projects and life experiences, I decided to build a blog site.&lt;/p&gt;

&lt;p&gt;During my initial search for a blogging platform, I considered options like WordPress, Hexo, Jekyll, and others. Ultimately, I chose Hugo for its static page generation capabilities, and I picked a nice domain name for my blog: &lt;a href="https://tomo.dev" rel="noopener noreferrer"&gt;tomo.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reason for choosing Hugo was simple. It's developed in &lt;code&gt;golang&lt;/code&gt;, making installation and build times fast. It's open-source, has a well-established community, comprehensive official documentation, and a wide variety of open-source themes. Choosing a theme for your site can be a headache, but after browsing through numerous themes on the official theme site, I finally settled on a theme called &lt;code&gt;hello friend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hello friend&lt;/code&gt; has a clean page structure, relatively simple code, and supports dark mode and responsive design. I eventually wrote my first blog post: &lt;a href="https://tomo.dev/posts/blog-using-hugo/" rel="noopener noreferrer"&gt;https://tomo.dev/posts/blog-using-hugo/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During the subsequent blogging process, I added some features and adjusted the page structure of the &lt;code&gt;hello friend&lt;/code&gt; theme. For example, I added my GitHub address to the bottom navigation, modified some JavaScript code, and added some new third-party JavaScript libraries.&lt;/p&gt;

&lt;p&gt;My native language is Chinese, and all my articles are written in Chinese. The blog didn't receive much traffic for two years after its launch. In the latter half of 2023, I started to get involved in web site promotion, such as SEO. So I thought about translating my blog into English and doing some SEO experiments.&lt;/p&gt;

&lt;p&gt;However, the &lt;code&gt;hello friend&lt;/code&gt; theme itself doesn't support multilingualism and its code is no longer maintained (although I later discovered a successor called &lt;code&gt;hello friend ng&lt;/code&gt;). Additionally, I had been away from frontend development for a while and learned that &lt;code&gt;tailwindcss&lt;/code&gt; was quite popular. Wanting to catch up with the latest frontend trends, I decided to build my own theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Building a theme and using one are two completely different modes. When using a theme, most of the time you only need to understand simple configurations and be familiar with &lt;code&gt;markdown&lt;/code&gt; syntax. However, building a theme is like developing a small product or plugin, and I had to answer the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What will be the theme's style and layout?&lt;/li&gt;
&lt;li&gt;What features should it have?&lt;/li&gt;
&lt;li&gt;What technical skills are required?&lt;/li&gt;
&lt;li&gt;How to publish, promote, and make it accessible to more people?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not a product manager or a designer, but there are many open-source themes available for reference. I wanted my theme to have a clean layout like &lt;code&gt;hello friend&lt;/code&gt;, minimize the use of complex frontend technologies, be easily extensible, and SEO-friendly.&lt;/p&gt;

&lt;p&gt;Regarding technology, &lt;code&gt;tailwindcss&lt;/code&gt; was a clear choice. I had used frontend component libraries like &lt;code&gt;bootstrap&lt;/code&gt;, &lt;code&gt;vuetify&lt;/code&gt;, and &lt;code&gt;ant design&lt;/code&gt;, so learning a new CSS library shouldn't be too difficult. As for Hugo theme-related technologies, I knew I needed some knowledge of &lt;code&gt;html/template&lt;/code&gt; syntax in golang, and the rest I could look up in the official documentation as needed.&lt;/p&gt;

&lt;p&gt;Finally, I referenced some existing themes and the &lt;code&gt;tailwindcss&lt;/code&gt; example site to draw a simple page layout diagram, including a logo, navigation menu, multilingual switcher, dark mode switcher, article list, term display block, social media links in the footer, and copyright information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhvfatq65cvptfj6067v3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhvfatq65cvptfj6067v3.png" alt="theme prototype" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the prototype, I outlined the main features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Basic features: navigation and menu, list page, article page, right-side category list, and category list and detail pages&lt;/li&gt;
&lt;li&gt;[ ] Darkmode - dark theme switcher&lt;/li&gt;
&lt;li&gt;[ ] Responsive design&lt;/li&gt;
&lt;li&gt;[ ] Multilingual support&lt;/li&gt;
&lt;li&gt;[ ] Image processing&lt;/li&gt;
&lt;li&gt;[ ] Social media links in the bottom navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And other supporting features and hidden needs for open-source projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Continuous integration&lt;/li&gt;
&lt;li&gt;[ ] Documentation and configuration examples&lt;/li&gt;
&lt;li&gt;[ ] Lighthouse score&lt;/li&gt;
&lt;li&gt;[ ] Others

&lt;ul&gt;
&lt;li&gt;[ ] Experimenting with shortcodes&lt;/li&gt;
&lt;li&gt;[ ] Google Analytics configuration&lt;/li&gt;
&lt;li&gt;[ ] User comment functionality&lt;/li&gt;
&lt;li&gt;[ ] Social tags&lt;/li&gt;
&lt;li&gt;[ ] Code block copy functionality&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Then I needed to give the theme a name. After browsing the official theme list, I finally chose &lt;a href="https://github.com/tomowang/hugo-theme-tailwind" rel="noopener noreferrer"&gt;&lt;code&gt;hugo-theme-tailwind&lt;/code&gt;&lt;/a&gt;. It turns out that a good name can bring some extra exposure and traffic to the project.&lt;/p&gt;

&lt;p&gt;I initialized the GitHub repository and submitted the first commit &lt;a href="https://github.com/tomowang/hugo-theme-tailwind/commit/d833043fd8992364491d95af124c0d353f30d3f5" rel="noopener noreferrer"&gt;#d833043&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Environment Setup
&lt;/h2&gt;

&lt;p&gt;To build a new Hugo theme, we need Hugo and Node.js. Installation of these tools is not the focus of this series, you can refer to the official documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hugo - &lt;a href="https://gohugo.io/installation/" rel="noopener noreferrer"&gt;https://gohugo.io/installation/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;nodejs environment - I use &lt;a href="https://github.com/Schniz/fnm" rel="noopener noreferrer"&gt;fnm&lt;/a&gt; and &lt;a href="https://pnpm.io/installation" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the Hugo command, execute the following command in the repository directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hugo new theme hugo-theme-tailwind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a folder &lt;code&gt;themes/hugo-theme-tailwind&lt;/code&gt; in the current directory. We need to move it to our repository and remove the theme's default content directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;themes/hugo-theme-tailwind/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; themes/
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download the official example site content to the theme's &lt;code&gt;exampleSite&lt;/code&gt; directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/gohugoio/hugoBasicExample.git exampleSite
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; exampleSite/.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the theme configuration in the example site's configuration file: &lt;code&gt;theme = "hugo-theme-tailwind"&lt;/code&gt;, and then run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hugo server &lt;span class="nt"&gt;-s&lt;/span&gt; exampleSite &lt;span class="nt"&gt;--gc&lt;/span&gt; &lt;span class="nt"&gt;--themesDir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command starts the Hugo server, allowing us to test the initial rendering of the theme. The sample log output is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start building sites …
                   | EN
-------------------+-----
  Pages            | 41
  Paginator pages  |  0
  Non-page files   |  0
  Static files     |  2
  Processed images |  0
  Aliases          |  9
  Sitemaps         |  1
  Cleaned          |  0

Built in 13175 ms
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;a href="http://localhost:1313/" rel="noopener noreferrer"&gt;http://localhost:1313/&lt;/a&gt; to see a simple page as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbqq40p20820m9iqd9b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbqq40p20820m9iqd9b5.png" alt="hugo basic example site" width="800" height="902"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have a simple, runnable initial theme and example site. I will expand and rewrite based on this basic theme in the following sections.&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>theme</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
