Skip to content

Repository files navigation

Hugo Dhruv Archives Theme

Custom Hugo theme for dhruv-archives.com with modular, param-driven customization and a redesigned homepage UI.

Credits

Built on top of hugo-paper. I disabled the "github" fork updates connection because the repo has comptletely diverged from origial code. But i have still tried to keep the history commits alive. Credits where due :)

My Bits and Bobs

First, the philosophy. Most customizations are exposed as params.* in your hugo.toml so the theme stays modular.

  • Modular typography + font loading via Hugo params + Google Fonts (heading_*, body_*, google_fonts) (compiled into CSS variables via assets/font-variables.css)
  • Responsive homepage featured "postcard" area (fluid across devices) with random media sourced from:
    • static/animation/ (top-level files only)
    • CSS-driven golden-ratio framing:
      • mobile (<=768px): landscape crop
      • desktop (>=769px): portrait crop
    • Filename mode masking:
      • *-dark.* only in dark mode
      • *-bright.* only in light mode
      • untagged files are eligible in both modes
    • Optional per-file crop focus via params.postcardFocus in hugo.toml:
      • set landscape and portrait as "x% y%"
  • Homepage intro blocks via params.aboutItems
  • Animated theme toggle with custom assets (/static/button/*.webp)
  • Flexoki-inspired light/dark background palette controlled by params.color
  • Grid-style post listing on list/home pages
  • Optional local-first Playground hub with tabbed puzzle modes, progress tracking, and an instrument tuner
  • Private / Protected Posts (Optional): build-time encryption + in-browser unlock UI (see section below)

Screenshots

The images in ./images/ are snapshots and may not match your latest local changes.

Latest (images/new/):

Protected content gate:

Protected content gate screenshot

Homepage (mobile):

Homepage mobile screenshot

Homepage (desktop):

Homepage desktop screenshot

Homepage (mobile, alt):

Homepage mobile screenshot (alt)

Snapshot (light):

Theme snapshot (light)

Snapshot (dark):

Theme snapshot (dark)

Install

As a git submodule:

git submodule add https://github.com/dhruv0000/hugo-dhruv-archives-theme themes/hugo-dhruv-archives

Then in your hugo.toml:

theme = "hugo-dhruv-archives"

Run:

hugo server

Config Template

Copy/paste and tweak:

theme = "hugo-dhruv-archives"
baseURL = "https://example.com/"
languageCode = "en-us"
title = "Your Site Title"

[params]
  # which sections count as "posts" (affects home + prev/next nav)
  mainSections = ["blog"]

  # valid: linen, wheat, gray, light
  color = "linen"

  # fonts (optional)
  google_fonts = [
    ["Jersey 15", "400"],
    ["Courier Prime", "400,700"]
  ]

  heading_font = "Jersey 15"
  heading_weight = "400"
  body_font = "Courier Prime"
  body_weight = "400,700"
  body_h_weight = "700"

  # social (optional)
  github = "YOUR_GITHUB_ID"
  twitter = "YOUR_TWITTER_ID"
  linkedin = "YOUR_LINKEDIN_ID"
  behance = "YOUR_BEHANCE_ID"
  rss = true

  # icons (optional)
  favicon = "favicon.ico"
  appleTouchIcon = "apple-touch-icon.png"

  [[params.aboutItems]]
    title = "./whoami"
    description = "Short blurb for the homepage."

  [params.puzzles]
    enabled = true
    navLabel = "Playground"
    title = "Playground"
    description = "Runtime puzzles, an instrument tuner, and a local progress desk."

    [params.puzzles.modes.equationGrid]
      enabled = true
      label = "Equation Grid"
      order = 1

    [params.puzzles.modes.cageLogic]
      enabled = true
      label = "Cage Logic"
      order = 2

    [params.puzzles.modes.game2048]
      enabled = true
      label = "2048"
      order = 3

    [params.puzzles.modes.instrumentTuner]
      enabled = true
      label = "Instrument Tuner"
      order = 4

  # optional postcard crop focus (per file)
  [params.postcardFocus]
    [params.postcardFocus."cowboy-bright.webm"]
      landscape = "55% 50%"
      portrait = "70% 52%"

[menu]
  [[menu.main]]
    identifier = "blog"
    name = "Blog"
    url = "/blog/"
    weight = 10

  [[menu.main]]
    identifier = "puzzles"
    name = "Playground"
    url = "/puzzles/"
    weight = 10

Playground Hub

The theme can render an optional /puzzles/ playground page driven by params.puzzles.

  • Shared progress desk stored in browser-local storage
  • Tabbed puzzle modules (Equation Grid, Cage Logic, 2048)
  • Instrument tuner with preset tunings, custom note sequences, mic capture, and local progress tracking
  • Nav item visibility is tied to enabled playground modes

Additional Supported Params (From old template)

[services]
  [services.disqus]
    shortname = "YOUR_DISQUS_SHORTNAME"

[params]
  # social icons rendered in header:
  # twitter, github, instagram, linkedin, mastodon, threads, bluesky, behance, rss
  mastodon = "https://mastodon.instance/@you"
  threads = "@your_handle"
  bluesky = "your-handle.bsky.social"
  rss = true

  # profile card
  avatar = "email@example.com" # or image URL
  name = "Your Name"
  bio = "Your bio"

  # behavior
  disableHLJS = true
  disablePostNavigation = true
  monoDarkIcon = true
  gravatarCdn = "https://cdn.v2ex.com/gravatar/"
  math = true
  localKatex = false
  graphCommentId = "YOUR_GRAPHCOMMENT_ID"
  direction = "rtl"

  [params.giscus]
    repo = "owner/repo"
    repoId = "..."
    category = "General"
    categoryId = "..."
    mapping = "pathname"
    strict = "1"
    reactionsEnabled = "0"
    emitMetadata = "0"
    inputPosition = "top"
    theme = "light"
    lang = "en"
    loading = "lazy"

Front matter:

comments = false
math = true
mermaid = true

Private / Protected Posts (Optional)

This theme supports password-protected pages intended for:

  • Unfinished drafts you want to publish later
  • Private diary entries
  • Personal notes / study notes
  • "Friends-only" writeups (shared password)

How it works (static-site friendly):

  • At build time, your rendered post HTML is encrypted and replaced with a small unlock form + encrypted payload.
  • At runtime (in the browser), readers enter the password to decrypt and render the post.

Important limitations:

  • This is not server-side authentication. The encrypted payload is public and can be downloaded.
  • A weak password can be brute-forced offline. Use a strong password and do not treat this as high-stakes secrecy.

What The Theme Includes

  • Runtime decrypt + unlock UI: static/content-protection.js
  • Build-time encryptor reference: themes/hugo-dhruv-archives/tools/protect-content.mjs
  • Unlock styles: assets/custom.css (protected-content-* classes)
  • Single page content slot: layouts/_default/single.html (id="protected-content-slot")
  • Script include: layouts/partials/head.html (loads content-protection.js on pages)

What You Add In Your Site Repo

For a private Hugo blog setup, keep your content/site repo private and keep this theme public. Run the encryptor in your build pipeline so selected folders are shipped as encrypted payloads. This lets you publish unfinished blogs, diary pages, or personal notes behind a password prompt.

  1. Add a build step after Hugo: (If you deploy on Cloudflare Pages, set these env vars in Variables and Secrets for the matching environment. Preview branch deployments use Preview vars, and your production branch uses Production vars. Redeploy after variable changes so the build picks them up.)
hugo --minify
node themes/hugo-dhruv-archives/tools/protect-content.mjs
  1. Set one or more folder passwords via env vars (paths are relative to your site's content/):
# Protect all posts under content/blog/
CONTENT_PASSWORD__BLOG=change-this-password

# Protect only content/diary/
CONTENT_PASSWORD__DIARY=change-this-password

# Protect only content/primer/
CONTENT_PASSWORD__PRIMER=change-this-password

# Optional: KDF work factor (default is 600000)
CONTENT_PROTECTION_PBKDF2_ITERATIONS=600000

Env var mapping rules:

  • CONTENT_PASSWORD__BLOG__MY_POST=... maps to content/blog/my-post/ (__ -> /, _ -> -)
  • If both a parent folder and a more specific folder are set, the more specific one wins.

Crypto choice:

  • PBKDF2-HMAC-SHA256 + AES-256-GCM (WebCrypto in-browser).
  • Random 16-byte salt + random 12-byte IV per page.

Sources:

License

MIT (c) Dhruv Patel

About

🪺 Hugo Theme for my Personal Website

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages