Hugo Theme (Part 1) : Setup
Intro
When I started this blog, I used the Hugo theme Anatole. I liked the minimal design but still had to modify a few things. I recently started working on a new theme using Tailwind CSS. This blog series will go over some implementation details. If you looking for a guide to use the theme check out the other post Hugo Jack Theme
Check out the source at https://github.com/yasakdogra/jack
[!NOTE]
This theme is still in development. I am constantly adding more features and making changes. It’s also not very optimized.
Prerequisites
Before creating a theme, we can need to get some things ready. Let’s check what we need first. We need to use Tailwind CSS. During development, we can use the Tailwind CLI to watch for changes in our code. In production, if we want to build and deploy our site automatically using providers like Cloudflare Pages, it will be a bit hard to use Tailwind CLI. Thankfully, Hugo has built in support for PostCSS and we can use Tailwind as a PostCSS plugin.
We can add Tailwind CSS and PostCSS as NPM dependencies. I like to keep the dependencies at site level rather than theme level. So in our site directory, we can add a package.json file with the dependencies. The following commands will also do the same.
Initialize NPM
npm init
Add PostCSS
npm add -D postcss postcss-cli autoprefixer
Add Tailwind CSS
npm add -D tailwindcss @tailwindcss/typography
We also need a package that can run multiple commands, so we can let both Hugo CLI and Tailwind CLI watch for file changes. We will add the npm-run-all
package
npm add -D npm-run-all
Add the NPM commands for building and running development server
package.json
{
"scripts": {
"dev:jack": "tailwindcss -c ./themes/jack/tailwind.config.js -i ./themes/jack/assets/css/main.css -o ./themes/jack/assets/_gen/css/main.css --watch",
"dev:hugo": "hugo server --noHTTPCache",
"dev:all": "npm-run-all -p dev:jack dev:hugo",
"dev": "npm-run-all -p dev:jack dev:hugo",
"build": "hugo --cleanDestinationDir --minify"
},
}
Setup
Initialize a basic Hugo theme with name jack
hugo new theme jack
Change to theme folder and add Tailwind config
npx tailwindcss init
In tailwind.config.js, add location the files where we are going to use Tailwind utility classes. We can add all the files in the layout folder of our theme. We will also enable the Tailwind Typography plugin and dark mode with CSS class
module.exports = {
darkMode: 'class',
content: ['./themes/jack/layouts/**/*.html'],
theme: {},
plugins: [
require('@tailwindcss/typography'),
],
}
We can add more things to this file later as we need them.
In postcss.config.js, add tailwind as plugin and specify the location of its config file
module.exports = {
plugins: {
tailwindcss: {
config: './themes/jack/tailwind.config.js',
},
autoprefixer: {},
}
}
In assets/css/main.css, delete the existing CSS and add Tailwind directives
@tailwind base;
@tailwind components;
@tailwind utilities;
In layouts/_default/baseof.html, let’s add our html skeleton
<!DOCTYPE html>
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}"
dir="{{ or site.Language.LanguageDirection `ltr` }}">
<head>
{{ partial "head.html" . }}
</head>
<body>
{{ partial "header.html" . }}
{{ block "main" . }}{{ end }}
{{ partial "footer.html" . }}
{{ partial "scripts.html" . }}
</body>
</html>
In layouts/partials/head.html, we will add link to our CSS file. For development environment, we will use Tailwind CLI and css/main.css to generate the CSS file _gen/css/main.css. We can later add the _gen folder to gitignore so it does’t get checked into version control. For production mode, we will use the css/main.css file and pass it to PostCSS which will use Tailwind plugin.
{{- if eq hugo.Environment "development" }}
{{- with resources.Get "_gen/css/main.css" }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{- end }}
{{- else }}
{{- with resources.Get "css/main.css" | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{- end }}
{{- end }}
In .gitignore, add entry to ignore the assets/_gen folder
assets/_gen/
We will add a javascript file too.
In layouts/partials/head/js.html
{{- with resources.Get "js/main.js" }}
{{- if eq hugo.Environment "development" }}
{{- with . | js.Build }}
<script src="{{ .RelPermalink }}"></script>
{{- end }}
{{- else }}
{{- $opts := dict "minify" true }}
{{- with . | js.Build $opts | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{- .Data.Integrity }}" crossorigin="anonymous"></script>
{{- end }}
{{- end }}
{{- end }}
We are now ready to add some styles. For the html we can edit, we will use the utility classes in html. For the HTML generated by Hugo, we can add CSS in our assets/main.css file and use Tailwind’s @apply
directive.
Let’s make our html
and body
blocks full screen. In layouts/_default/baseof.html
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}"
dir="{{ or site.Language.LanguageDirection `ltr` }}"
class="min-h-screen"
<body class="min-h-screen px-4">
Use flex box for body and auto margins. Give it default text and background colors. Use dark:
to use classes in dark mode.
<body class="min-h-screen px-4
container flex flex-col mx-auto
bg-stone-100 dark:bg-slate-700 text-slate-800 dark:text-neutral-50">
Wrap the main block with a flex box and add typography to it
<div class="flex flex-col flex-grow mt-8 max-w-none
prose prose-xl prose-amber dark:prose-invert"
>
{{ block "main" . }}{{ end }}
</div>
Define the default font weight, link colors and some other things in tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
typography: ({ theme }) => ({
amber: {
css: {
'font-weight': '400',
'--tw-prose-links': theme('colors.amber[600]'),
'--tw-prose-invert-links': theme('colors.amber[500]'),
'blockquote p:first-of-type::before': { content: 'none' },
'blockquote p:first-of-type::after': { content: 'none' },
},
},
}),
},
},
}
We can also modify Tailwind prose
styles in our HTML by using prose-<element>:
.
Remove the bold and underline from links and change heading size
<div class="flex flex-col flex-grow mt-8 max-w-none
prose prose-xl prose-amber dark:prose-invert
prose-a:font-normal prose-a:no-underline prose-h1:text-4xl"
>
Remove the tick marks from inline code blocks
<div class="flex flex-col flex-grow mt-8 max-w-none
prose prose-xl prose-amber dark:prose-invert
prose-a:font-normal prose-a:no-underline prose-h1:text-4xl
prose-code:before:content-none prose-code:after:content-none prose-code:font-normal"
>
We will modify more prose styles later as required.
Thank you for reading. Check out the other parts in the series below.