Building your first website using Hugo and GitHub Pages#
This repository documents how to set up a Hugo site using the Hugo Book theme with a custom landing page, global dark mode, and automatic deployment to GitHub Pages using GitHub Actions.
The setup provides:
- A custom landing page at
/ - Hugo Book documentation/blog under
/blog - Shared styling and dark mode across all pages
- Automatic deployment on push to
main
Prerequisites#
- Hugo (extended version recommended for local development)
- Git
- GitHub account
Verify Hugo:
hugo versionCreate the Hugo site#
hugo new site my-hugo-blog
cd my-hugo-blogAdd the Hugo Book theme#
git submodule add https://github.com/alex-shpak/hugo-book.git themes/hugo-bookConfigure hugo.toml:
baseURL = "https://<username>.github.io/<repo>/"
languageCode = "en-us"
title = "My Hugo Book"
theme = "hugo-book"
[params]
BookTheme = "auto"
BookSection = "blog"
customCSS = ["css/darkmode.css"]Create the landing page#
Content#
Create content/_index.md:
---
title: Home
layout: landing
---Layout#
Create layouts/_default/landing.html:
{{ define "main" }}
<link rel="stylesheet" href="{{ "css/landing.css" | relURL }}">
<section class="hero">
<h1>Welcome</h1>
<p>Engineering notes and technical articles.</p>
<a href="/blog" class="btn">Read the blog</a>
</section>
{{ end }}Styling#
Create assets/css/landing.css:
.hero {
min-height: 80vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.btn {
margin-top: 1.5rem;
padding: 0.75rem 1.25rem;
border-radius: 0.5rem;
background: #4f46e5;
color: white;
text-decoration: none;
}Add blog / documentation content#
hugo new blog/first-post.mdEnable global dark mode#
Dark mode CSS#
Create assets/css/darkmode.css:
:root {
--bg: #ffffff;
--bg-alt: #f8fafc;
--text: #0f172a;
--border: #e5e7eb;
}
html.dark {
--bg: #0f172a;
--bg-alt: #020617;
--text: #e5e7eb;
--border: #1e293b;
}
body {
background: var(--bg);
color: var(--text);
}
.book-page,
.book-menu {
background: var(--bg);
}Toggle button#
Create layouts/partials/darkmode-toggle.html:
<button id="dark-toggle">Toggle theme</button>
<script>
const root = document.documentElement;
if (
localStorage.getItem("theme") === "dark" ||
(!localStorage.getItem("theme") &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
) {
root.classList.add("dark");
}
document.getElementById("dark-toggle").onclick = () => {
root.classList.toggle("dark");
localStorage.setItem(
"theme",
root.classList.contains("dark") ? "dark" : "light"
);
};
</script>Inject toggle into header#
Create layouts/partials/header.html:
{{ partial "book-header.html" . }}
{{ partial "darkmode-toggle.html" . }}Run locally#
hugo server -DOpen http://localhost:1313.
Deploy with GitHub Actions#
Deployment is handled automatically using GitHub Actions. On every push to the main branch, the site is built and published to GitHub Pages.
Create the workflow file:
.github/workflows/deploy.ymlWith the following contents:
name: Deploy Hugo site
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: peaceiris/actions-hugo@v3
with:
hugo-version: 'latest'
- run: hugo --minify
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./publicNotes on deployment#
- The Hugo Book theme is included as a Git submodule and must be checked out recursively.
- The site is built using the latest Hugo version.
- The generated
public/directory is published to GitHub Pages. - No additional secrets are required;
GITHUB_TOKENis provided automatically.
Key project structure#
.github/workflows/
deploy.yml
assets/css/
landing.css
darkmode.css
content/
_index.md
blog/
layouts/
_default/landing.html
partials/
header.html
darkmode-toggle.html
themes/
hugo-book/
hugo.tomlNotes#
- Do not modify files inside
themes/hugo-book - Use
layouts/andassets/for all overrides - Dark mode is implemented using CSS variables and localStorage