Skip to content

Building a Personal Site with Oink, from Setup to Publication

Notes on building a documentation site with Hugo and Oink as a frontend beginner, covering content structure, blog posts, hugo.yml, and local preview commands.

The official Oink tutorial is comprehensive, but connecting the folders, configuration, and commands can still be confusing the first time, especially without much frontend experience. These notes from building YHY Study Website follow one path: understand Oink, learn how content/ is organized, and then write and publish a blog post.

Oink site setup diagram
Markdown → Hugo → the Oink theme → a deployable static site

What Hugo and Oink each do

Hugo is a static site generator: it reads Markdown and configuration and produces HTML. Oink is a Hugo theme: it controls the appearance of sidebars, cards, callouts, code blocks, and other components.

Content and appearance are maintained separately:

  • Site repository (my-project-docs): Markdown articles and hugo.yml configuration
  • Theme repository, github.com/pgsty/oink: templates and styles

The site declares the Oink theme in hugo.yml, and go.mod pins its version, currently v0.6.0. When you run hugo server, Hugo:

  1. Reads articles and configuration from the site repository.
  2. Reads templates and styles from the theme module downloaded according to go.mod.
  3. Renders the content with the theme to generate web pages.
One command for everyday use

When writing documentation rather than changing the theme, hugo server is enough to remember. You do not need to start with make dev.

Local preview: get the site running first

Enter the project directory and start the server:

cd D:\MyData\yhy\6data\repository\my-project-docs
hugo server

Open http://localhost:1313/ in a browser. Saving a changed .md file under content/ automatically refreshes the page.

For a more complete rerender after each change, useful when investigating styling problems:

hugo server -DFE --disableFastRender
  • -DFE: includes draft and future-dated pages for writing.
  • --disableFastRender: disables fast rendering to avoid discrepancies caused by incremental updates.

Organizing content/

Oink does not maintain a separate navigation database: the folder structure on disk determines both the sidebar structure and URL paths.

Three common concepts:

ConceptMeaning
SectionA folder with _index.md; this level also has its own entry page
PageA .md file in a folder, or index.md in a subfolder
SiblingPages in the same directory, ordered with weight: 10/20/30…

The root content structure of this site:

content/
├── _index.md           → Home page
├── search.md           → Search page (special; usually left unchanged)
├── links.md            → Friends and links
├── experience/         → Experience (documentation-style, type: docs)
├── learn/              → Learning
└── blog/               → Blog (ordered by date)

Two ways to store an article:

FormatExample pathSuitable for
Single filecontent/blog/my-post.mdText posts with images stored in static/
Page bundlecontent/blog/my-post/index.md plus images in the same directoryPosts with multiple images kept beside the text

The first hugo.yml keys to learn

You do not need to read the whole configuration at once. Start with these fields:

KeyPurpose
titleSite name shown in browser tabs, the navbar, and elsewhere
params.productionURL + baseURLFull production address; affects sitemaps, RSS, and absolute links
params.github_repoContent repository used by buttons such as “Edit this page”
params.copyrightFooter copyright information
languages.zh.menus.mainNavbar menus: Experience, Learning, Blog, and Links

baseURL is often tied to productionURL with a YAML anchor:

productionURL: &productionURL https://ryanyhy.github.io/YHY-Website/
baseURL: *productionURL

&productionURL defines the name; *productionURL references it. Changing one value updates the whole site.

Writing a blog post in five steps

  1. Choose a filename — Create a .md file under content/blog/. Its filename becomes part of the URL, so use an English slug, such as oink-site-setup-notes.md → /blog/oink-site-setup-notes/.
  2. Add front matter — Metadata at the top should include at least title, date, and description. linkTitle is the shorter title displayed in lists and cards.
  3. Write the body — Adjust syntax copied from Obsidian, as explained below. Add callouts, step lists, heading anchors, and images as needed.
  4. Preview locally — Run hugo server and open /blog/ to check the card and article page.
  5. Publish — git add → git commit → git push; GitHub Actions builds and updates GitHub Pages.

A front matter template:

---
title: Full article title
linkTitle: Short list title
description: A one-sentence summary used by search and cards.
date: 2026-08-29
tags: [Oink, Hugo]
---

Moving from Obsidian to Oink: syntax comparison

ObsidianOink / MarkdownWhat to do
==highlight==**bold**Replace throughout
[[wikilink]][text](/path/) or an external linkUse an actual link
Image ![[x.png]]![description](path)See below

Common Oink components are described in the component documentation:

Callouts

> [!NOTE] Reading note
> Write the body here.

Step lists — Start each item with 1. and add {.steps} at the end, as in the five steps above.

Heading anchors — Use ## Section {#id}. The {#id} is not displayed and supports in-page links such as [text](#id).

Images and captions — Put {caption="..."} on the next line after the image, not on the same line as ![...](...):

![Diagram](/images/blog/example.png)
{caption="The caption appears directly below the image"}
  • Global images go in static/images/... and are referenced as /images/....
  • Page-bundle images sit beside index.md and use relative paths.

Four make commands for theme development

The four commands in Makefile are aliases. Windows often has no make, and make dev / make check require the theme source at ../oink.

CommandTheme sourceSuitable for
make devLocal ../oinkQuick previews while changing the theme
make checkLocal ../oinkRunning npm test after theme changes
make buildVersion pinned in go.modProduction builds matching the deployed site
make serveVersion pinned in go.modLocal previews with production configuration

When only editing content, use the PowerShell equivalents:

GoalPowerShell
Everyday previewhugo server
Production buildhugo --cleanDestinationDir --minify
Preview close to productionhugo server --environment production --minify
How dev and check differ

dev prioritizes fast visual feedback; check takes longer and runs automated tests. When changing the theme, first get the result right with dev, then pass check.

Publishing: three Git steps

After confirming the local preview:

git add content/blog/oink-site-setup-notes.md
git commit -m "blog: add Oink site setup notes"
git push origin main
  • git add: selects files for this commit. Specify the exact path when committing only the blog post; use git add -A to stage everything.
  • git commit: creates a local snapshot.
  • git push: sends it to GitHub and triggers Actions deployment.

The order is add → commit → push.

Summary

The main idea is: Hugo generates pages, Oink controls their appearance, and the content/ folders form the navigation tree. Writing a blog post means adding front matter and Markdown, previewing with hugo server, and pushing. Put {caption=...} on its own line, and convert Obsidian’s == and [[links]] to standard Markdown before publishing.

For a more systematic introduction, read chapters 1–3 of the Oink tutorial book. This site’s RAICOM documentation is a writing example in Chinese.