A minimalist Hugo theme focused on content, inspired by stephango.com. Features dark/light mode, breadcrumb navigation, taxonomies (topics & tags), advanced code blocks (Dracula, line highlighting, file names, copy button), responsive post listings, newsletter demo dialog, and built-in SEO (Open Graph, Twitter Cards, JSON-LD structured data, sitemap, robots.txt).
- Hugo extended v0.146.0 or higher (uses new template system
_partials,_markup).
git submodule add https://github.com/thnhan1/nhanoki.git themes/nhanoki
git add .gitmodules themes/nhanoki
git commit -m "Add nhanoki theme as submodule"Declare in your site's config:
theme = 'nhanoki'Run dev server:
hugo server -DBelow is a complete hugo.toml with all available options:
baseURL = 'https://example.com/'
locale = 'en-US'
title = 'Your Name'
theme = 'nhanoki'
# ββ Sitemap ββββββββββββββββββββββββββββββββββββββββββ
[sitemap]
changefreq = 'weekly'
priority = 0.5
filename = 'sitemap.xml'
# ββ Author & SEO params ββββββββββββββββββββββββββββββ
[params]
author = "Your Name"
description = "A short bio or tagline for your site"
# Social profiles β used in JSON-LD structured data (Person.sameAs)
[params.social]
twitter = "yourhandle" # without @
github = "yourgithub"
# linkedin = "yourlinkedin"
# ββ Taxonomies βββββββββββββββββββββββββββββββββββββββ
[taxonomies]
topic = "topics"
tag = "tags"
# ββ Navigation menu (right side of header) βββββββββββ
[menu]
[[menu.main]]
name = "About"
url = "/about"
weight = 10
[[menu.main]]
name = "Now"
url = "/now"
weight = 20
# ββ Markup / Code blocks βββββββββββββββββββββββββββββ
[markup]
[markup.goldmark.renderer]
unsafe = true # allow raw HTML in markdown
[markup.highlight]
style = "dracula" # Chroma style (dracula, github, monokai, etc.)
noClasses = true
lineNos = true
lineNumbersInTable = false
tabWidth = 2
# ββ Output formats βββββββββββββββββββββββββββββββββββ
[outputs]
home = ["HTML", "RSS"]
page = ["HTML"]
section = ["HTML", "RSS"]
taxonomy = ["HTML", "RSS"]
term = ["HTML"]
[outputFormats]
[outputFormats.RSS]
mediatype = "application/rss+xml"
baseName = "feed"titlein config displays on the left side of the header (breadcrumb home link).- Items in
[menu.main]display on the right side of the header, next to the dark/light mode toggle.
The social links under [params.social] are used for two purposes:
- JSON-LD
sameAsβ tells Google your social profiles, strengthening your personal brand identity in search results. - Twitter card β
twitter:sitemeta tag usesparams.social.twitter.
Posts go in content/posts/. Basic front matter:
---
title: "Post title"
date: 2025-10-20T10:00:00Z
draft: false
topics: ["advice", "tools"]
---
Opening text displays as summary.
<!--more-->
Remaining content...<!--more-->sets the summary displayed on the homepage ("Keep reading β").topicsattaches the post to thetopicstaxonomy (appears as tags below the post).image(optional) β sets the Open Graph / Twitter Card image for social sharing.
Create content/about.md, content/now.md etc. with title front matter. Pages to appear in the menu should be declared in [menu.main] in config (don't use menu: main in front matter to avoid duplication).
Posts can be tagged with topics and tags:
topics: ["design", "tools"]
tags: ["blue", "green"]topicsare featured on the homepage and shown below each post.tagsexist but are not surfaced on the homepage β they have their own/tags/index.
Always use leaf bundles for posts with images: create a folder containing index.md and place images alongside it.
content/posts/my-post/
βββ index.md
βββ photo.jpg
In index.md:

β οΈ DO NOT placeindex.mddirectly incontent/posts/. This turns the entirepostsdirectory into a leaf bundle and hides other posts. Use_index.mdfor section landing pages.
The image render hook (_markup/render-image.html) resolves relative paths to page resources and adds loading="lazy".
Use fence syntax with attributes in curly braces:
```java {title="A.java" hl_lines="2 5"}
public class A {
private static String name = "Nhan";
public static void main(String[] args) {
System.out.println(name);
}
}
```titleβ shows a file name bar above the code block (optional).hl_linesβ highlights specific lines; supports ranges like"2 5-7"(optional).- Line numbers and color theme come from
[markup.highlight]in config. - Copy button β appears in the top-right corner (requires JavaScript).
The header contains:
- Breadcrumb (left side) β shows
Site Nameon all pages. When inside a sub-section (e.g., a post under/posts/), it showsSite Name / Section Title. Standalone pages like/aboutand/nowonly show the site name (no redundant slash). - Navigation links (right side) β from
[menu.main]. - Theme toggle β dark/light mode switch.
On mobile (<600px), the breadcrumb wraps to its own line.
A reusable partial for rendering a list of posts with date + title. Used by both home.html and section.html.
{{ partial "post-listing.html" .Pages.ByDate.Reverse }}
- Wide screens (β₯600px): date shows as "January 2, 2006" with a fixed width column.
- Narrow screens (<600px): date switches to "2006-01-02" compact format.
- Uses flex layout with a
gapbetween date and title.
The homepage (home.html) is structured as:
- Latest β the most recent post with title, date, reading time, summary, and "Keep reading β" link.
- Topics β an alphabetical list of all topics (from
site.Taxonomies.topics). - Writing β a full reverse-chronological list of all posts (reuses
post-listing.html).
A demo newsletter component placed between <main> and <footer> in baseof.html.
- Clicking Subscribe opens a modal dialog with a thank-you message.
- No actual email is sent β it's purely demonstrative.
- The dialog can be dismissed by clicking OK or clicking outside the dialog box.
- Edit the message in
_partials/newsletter.html.
The <head> section automatically includes:
| Feature | Details |
|---|---|
| Meta description | Uses page's .Description, .Summary, or falls back to site.Params.description (truncated to 160 chars) |
| Canonical URL | <link rel="canonical"> with .Permalink |
| Open Graph | og:title, og:type, og:url, og:site_name, og:description, og:author, og:image |
| Twitter Card | twitter:card, twitter:title, twitter:description, twitter:site |
| JSON-LD Person | Schema.org Person with name, url, description, sameAs (from [params.social]) |
| JSON-LD BlogPosting | On post pages, an additional BlogPosting or Article schema with headline, dates, author |
| Sitemap | Auto-generated /sitemap.xml when [sitemap] is configured in hugo.toml |
| robots.txt | Include in your site's static/robots.txt |
Create static/robots.txt in your site root:
User-agent: *
Allow: /
Sitemap: https://yourdomain.com/sitemap.xml
- Toggle button in the header, saves preference to
localStorage. - Default: follows
prefers-color-scheme. - Icons:
static/sun.svgandstatic/moon.svgβ replace these to change icons. - CSS: uses
.theme-dark/.theme-lightclasses on<body>.
| Breakpoint | Behavior |
|---|---|
| β₯860px | Full desktop layout with --wrap-normal: 37em content width |
| <860px | Content width switches to 88vw; heading weight increases |
| <600px | Mobile layout: breadcrumb wraps, body padding reduced, post dates switch to compact format, nav wraps |
themes/nhanoki/
βββ assets/
β βββ css/
β β βββ main.css # All styles (normalize, Flexoki palette, layout, responsive)
β β βββ font.css # Open Sans font face
β β βββ components/ # Standalone component CSS (not imported by default)
β βββ js/
β βββ main.js # Theme toggle, code copy button, newsletter dialog
βββ layouts/
β βββ baseof.html # Frame: <head>, <header>, <main>, <newsletter>, <footer>
β βββ home.html # Homepage: latest post, topics, writing archive
β βββ page.html # Single post / static page
β βββ section.html # Post list by section (/posts)
β βββ taxonomy.html # List of all terms in a taxonomy (/topics, /tags)
β βββ term.html # Posts for a single term (/topics/design)
β βββ 404.html # 404 page
β βββ _partials/
β β βββ head.html # <head>: meta tags, SEO, CSS, JS
β β βββ header.html # Nav: breadcrumb + menu + theme toggle
β β βββ breadcrumb.html # Smart breadcrumb (skips home self-link)
β β βββ menu.html # Hugo menu renderer
β β βββ post-listing.html # Reusable date+title list (responsive dates)
β β βββ newsletter.html # Demo subscribe form + dialog
β β βββ footer.html # Footer content
β β βββ terms.html # Terms list helper
β β βββ head/
β β βββ css.html # CSS build pipeline (Hugo Pipes)
β β βββ js.html # JS build pipeline (Hugo Pipes)
β βββ _markup/
β βββ render-codeblock.html # Code block with title, hl_lines, copy button
β βββ render-image.html # Image with lazy loading, page resource resolution
βββ static/
βββ favicon.ico
βββ homepage.png
βββ sun.svg # Light mode icon
βββ moon.svg # Dark mode icon
| Goal | How |
|---|---|
| Change colors | Edit CSS variables (--flexoki-*, --color-*) in assets/css/main.css |
| Content width | Adjust --wrap-normal (default 37em) and --wrap-wide (default 54em) |
| Font size | Edit body font-size and heading sizes in main.css |
| Code theme | Change style in [markup.highlight] (see Chroma styles) |
| Social links | Set [params.social] in hugo.toml |
| Newsletter message | Edit _partials/newsletter.html |
| Footer | Edit _partials/footer.html |
| Favicon | Replace static/favicon.ico |
This theme uses the Flexoki color palette (MIT) by Steph Ango. Key design tokens:
--wrap-normal: default content width (37em)--wrap-wide: wide content width (54em)--font-content: system font stack with Open Sans--font-mono: monospace stack for code--line-height: 1.5--color-tx-normal,--color-tx-muted,--color-tx-faint: text color scale- All colors adapt via
.theme-light/.theme-darkclasses
Theme uses CSS based on design by Steph Ango and color palette Flexoki (MIT).
