Files
Portfolio_Site/CUSTOMIZATION.md
2026-04-01 10:33:28 +05:45

11 KiB

Hugo + PaperMod Customization Guide

This guide covers how to customize your Hugo portfolio site using the PaperMod theme.


Table of Contents

  1. Project Structure
  2. Development Workflow
  3. Configuration (hugo.yaml)
  4. Adding Content
  5. Creating New Sections
  6. Customizing Styles (CSS)
  7. Overriding Layouts
  8. Common Customizations
  9. Deployment

Project Structure

MyPortfolio/
├── archetypes/          # Templates for new content
├── assets/
│   └── css/
│       └── extended/
│           └── custom.css   # YOUR custom CSS (this gets merged)
├── content/
│   ├── posts/           # Long-form articles
│   │   └── _index.md    # Section config
│   ├── notes/           # Short notes/TILs
│   │   └── _index.md    # Section config
│   └── search.md        # Search page
├── layouts/
│   ├── index.html       # Custom home page (no recent posts)
│   ├── partials/        # Override theme partials
│   │   ├── footer.html  # Custom footer
│   │   └── templates/
│   │       └── schema_json.html  # Fixed JSON-LD schema
│   ├── posts/
│   │   └── list.html    # Custom posts list (compact style)
│   └── notes/
│       └── list.html    # Custom notes list (compact style)
├── static/
│   └── files/           # Static files (CV.pdf, images, etc.)
├── themes/
│   └── PaperMod/        # Theme (git submodule - DON'T edit)
├── hugo.yaml            # Main configuration
└── .gitignore           # Ignores public/, etc.

Key Principle: Never Edit the Theme Directly

The themes/PaperMod/ folder is a git submodule. To customize:

  • CSS: Add to assets/css/extended/custom.css
  • Layouts: Copy the file from themes/PaperMod/layouts/ to layouts/ and modify
  • Config: Everything in hugo.yaml

Development Workflow

Local Development

# Start dev server (watches for changes)
hugo serve

# With drafts visible
hugo serve -D

# Build for production (outputs to public/)
hugo build --minify

Why public/ is Gitignored

  • public/ is generated output - it's rebuilt fresh every time
  • Your CI/CD (GitHub Actions) builds it during deployment
  • Never commit build artifacts to git

Git Workflow

# After making changes
git add .
git commit -m "Add new post about X"
git push origin master   # Triggers deployment

Configuration (hugo.yaml)

Key Sections

Site Basics

baseURL: "/"              # Use "/" for relative URLs (works on localhost + prod)
relativeURLs: true        # Makes all URLs relative
title: Saurav Dhakal
languageCode: en-us
theme: ["PaperMod"]

Menu (Header Navigation)

menu:
  main:
    - identifier: posts   # Internal ID
      name: Posts         # Display name
      url: /posts/        # URL path
      weight: 10          # Order (lower = first)
    - identifier: notes
      name: Notes
      url: /notes/
      weight: 20
    - identifier: tags
      name: Tags
      url: /tags/
      weight: 30
    - identifier: search
      name: Search
      url: /search/
      weight: 40

Home Page Info

params:
  homeInfoParams:
    Title: "Hi there 👋, I'm Saurav!"
    Content: >
      I'm a software engineer...

Social Icons

params:
  socialIcons:
    - name: github
      url: "https://github.com/yourusername"
    - name: linkedin
      url: "https://linkedin.com/in/yourusername"
    - name: x
      url: "https://x.com/yourusername"

Available icons: github, linkedin, x, twitter, email, rss, youtube, instagram, facebook, stackoverflow, etc.


Adding Content

New Post

hugo new posts/my-new-post.md

Or manually create content/posts/my-new-post.md:

---
title: "My New Post"
date: 2025-08-20
summary: "A brief description for the list view"
tags: ["tag1", "tag2"]
categories: ["Category"]
draft: false
ShowToc: true
TocOpen: false
---

Your content here...

New Note

Create content/notes/my-note.md:

---
title: "Quick TIL"
date: 2025-08-20
summary: "Today I learned about X"
tags: ["til"]
---

Short content here...

Front Matter Options

Field Description
title Post title
date Publication date (YYYY-MM-DD)
summary Short description for list views
tags Array of tags
categories Array of categories
draft If true, won't be published
ShowToc Show table of contents
TocOpen TOC expanded by default
ShowReadingTime Override global setting
ShowWordCount Override global setting
cover.image Cover image path

Creating New Sections

Example: Adding a "Projects" Section

  1. Add to menu in hugo.yaml:
menu:
  main:
    # ... existing items
    - identifier: projects
      name: Projects
      url: /projects/
      weight: 25
  1. Create content directory:
mkdir -p content/projects
  1. Create section index content/projects/_index.md:
---
title: "Projects"
description: "Things I've built"
---
  1. Add project pages content/projects/my-project.md:
---
title: "My Cool Project"
date: 2025-01-15
summary: "A brief description"
tags: ["golang", "cli"]
---

Project description...
  1. (Optional) Custom layout - If you want projects to look different, create layouts/projects/list.html

Customizing Styles (CSS)

Where to Add CSS

Only edit: assets/css/extended/custom.css

PaperMod automatically includes this file. You don't need to import it anywhere.

CSS Variables (Theme Colors)

PaperMod uses CSS variables. Override them in your custom.css:

:root {
  /* Light mode */
  --primary: #282828;       /* Main text */
  --secondary: #3c3836;     /* Secondary text */
  --tertiary: rgb(214, 214, 214);  /* Borders, etc */
  --theme: rgb(255, 255, 255);     /* Background */
  --entry: rgb(255, 255, 255);     /* Card background */
}

:root[data-theme="dark"] {
  /* Dark mode */
  --primary: #fbf1c7;
  --secondary: #ebdbb2;
  --theme: #181818;
  --entry: rgb(46, 46, 51);
}

Common CSS Customizations

Change fonts

@import url("https://fonts.googleapis.com/css2?family=Your+Font&display=swap");

body {
  font-family: "Your Font", sans-serif;
}
main a {
  text-decoration: underline;
  text-decoration-color: var(--green);
}

main a:hover {
  background-color: var(--green);
  color: white;
}

Customize post cards

main .post-entry {
  border: 2px solid #383838;
  background-color: var(--entry);
  border-radius: 8px;
}

Overriding Layouts

How Layout Override Works

Hugo looks for templates in this order:

  1. layouts/ (your overrides)
  2. themes/PaperMod/layouts/ (theme defaults)

To Override a Template

  1. Find the file in themes/PaperMod/layouts/
  2. Copy it to the same path in layouts/
  3. Modify your copy

Common Files to Override

File Purpose
layouts/partials/header.html Site header/nav
layouts/partials/footer.html Site footer
layouts/partials/post_meta.html Post metadata (date, read time)
layouts/_default/list.html List pages (posts, tags)
layouts/_default/single.html Individual post/page

Your layouts/partials/footer.html already overrides the theme's footer.

Section-Specific Layouts

Create layouts/SECTION_NAME/list.html for a custom list layout for that section.

Current custom layouts:

  • layouts/index.html - Home page with just intro + social icons (no recent posts)
  • layouts/posts/list.html - Compact list: # Title + date + 2-line description
  • layouts/notes/list.html - Compact list: # Title + date (no description)

Common Customizations

Disable Reading Time for a Section

In the section's _index.md:

---
title: "Notes"
ShowReadingTime: false
---

Or per-post in front matter.

Add a Static Page (About, Contact)

Create content/about.md:

---
title: "About"
layout: "single"
url: "/about/"
---

About me content...

Add to menu:

menu:
  main:
    - identifier: about
      name: About
      url: /about/
      weight: 50

Add Favicon

  1. Place favicon files in static/:

    • static/favicon.ico
    • static/favicon-16x16.png
    • static/favicon-32x32.png
    • static/apple-touch-icon.png
  2. Update hugo.yaml:

params:
  assets:
    favicon: "/favicon.ico"
    favicon16x16: "/favicon-16x16.png"
    favicon32x32: "/favicon-32x32.png"
    apple_touch_icon: "/apple-touch-icon.png"

Enable Comments (Disqus)

params:
  comments: true

disqusShortname: "your-disqus-shortname"

Add Google Analytics

Already configured in your hugo.yaml:

googleAnalytics: "G-XXXXXXXXXX"

Deployment

Current Setup (GitHub Actions → SSH/SCP)

Your .github/workflows/deploy.yml:

  1. Triggers on push to master
  2. Builds site with hugo build --minify
  3. Deploys public/ via SCP to your server

Required GitHub Secrets

Set these in your repo's Settings → Secrets:

  • SSH_HOST - Your server hostname/IP
  • SSH_USER - SSH username
  • SSH_KEY - Private SSH key
  • SSH_PORT - SSH port (usually 22)

Alternative: GitHub Pages

If you want to use GitHub Pages instead:

  1. Change workflow to use peaceiris/actions-gh-pages
  2. Set baseURL to https://yourusername.github.io/repo-name/

Alternative: Netlify/Vercel

These platforms auto-detect Hugo and build for you:

  1. Connect your GitHub repo
  2. Set build command: hugo --minify
  3. Set publish directory: public

Quick Reference

Useful Commands

# Local dev
hugo serve -D              # Serve with drafts

# Create content
hugo new posts/title.md    # New post
hugo new notes/title.md    # New note

# Build
hugo build --minify        # Production build

# Debug
hugo config                # Show full config
hugo list all              # List all content

File Locations

What Where
Config hugo.yaml
Custom CSS assets/css/extended/custom.css
Posts content/posts/
Notes content/notes/
Static files static/
Layout overrides layouts/

Troubleshooting

Fixed by setting:

baseURL: "/"
relativeURLs: true

Changes Not Showing

  1. Hard refresh browser (Ctrl+Shift+R)
  2. Clear public/ folder: rm -rf public/
  3. Restart hugo serve

Theme Not Loading

git submodule update --init --recursive

Search Not Working

Ensure hugo.yaml has:

outputs:
  home:
    - HTML
    - RSS
    - JSON  # Required for search

Resources