Overview

I have always been syncing my personal notes to a private GitHub remote repository. Lately, I felt like publishing/distilling some of them as public blog posts.

I wish the architecture of the blog site to be

  • git-based
  • markdown-based
  • automatically deployed
  • part of the original notes repository

Corresponding technology selections are

  • Git for version control
  • Hugo for markdown to static pages
  • GitHub Page + GitHub Actions for CI/CD
  • Git submodules for repo linking

Problems and Solutions

1. Notes Distilled to Blogs with Git submodule

Without breaking the private nature of the repository while making part of the repository public, I utilized git submodule.

  • obsidian-vault: A strictly private GitHub repository containing all personal notes (PARA system).
  • blogs: A separate, public GitHub repository nested inside the vault.

Nesting blogs inside notes as a submodule makes it possible to edit both parts locally without changing the project directory. However, it is not an essential requirement since no hard dependencies exist between notes and blogs.

2. The Publishing Automation Pipeline (Hugo + GitHub Pages)

Blogs are written as individual markdown files. To host structured text content on a server, they need to be converted to HTML files (possibly bundled with stylesheets). Hugo is a great tool for markdown-to-html conversion and blog hosting. Thus, Hugo is chosen as the static site generator for this blog site.

With the submodule isolating the public content, a CI/CD pipeline can be attached directly to the blogs repository. When a new note is pushed from the local blogs/ directory, GitHub Actions automatically executes Hugo build process and deploys it to GitHub Pages.

3. Customize Font and Favicon (PaperMod Theme)

Change Font

Get import URL from Google Font

@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700&display=swap');

Place custom css file to static/fonts/<fontname>.css (Lora as an example)

@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700&display=swap');
body, html, p, li {
    font-family: 'lora', serif !important;
}

h1, h2, h3, h4, h5, h6 {
    font-family: 'lora', serif !important;
}

Extend it with layouts/partials/extend_head.html

<link rel="stylesheet" href="{{ "fonts/lora.css" | absURL }}">

Change Favicons

place favicons under static/icons/

obsidian/blogs [main] > ls static/icons
android-chrome-192x192.png      apple-touch-icon.png            favicon-32x32.png               site.webmanifest
android-chrome-512x512.png      favicon-16x16.png               favicon.ico

adjust config.yaml according to config.yaml

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

Architecture

flowchart TB
  subgraph Local
    neovim["Neovim"]
    obsidian-vault["Obsidian Vault"]
    obsidian-vault --> neovim
  end

  subgraph Remote
    direction TB
    subgraph Obsidian["https://github.com/James-Leste/obsidian-vault"]
      subgraph Notes
        0-inbox["0 Inbox/"]
        1-Projects["1 Projects/"]
        2-Areas["2 Areas/"]
        3-Resources["3 Resources/"]
        4-Archive["4 Archive/"]
      end
      subgraph sub-blogs["blogs/ (submodule)"]
        hugo-project["Hugo project"]
      end
      Notes -- "distill (manual)" --> sub-blogs
    end
    
    subgraph blogs["https://github.com/James-Leste/blogs"]
      blog-content["blog content"]
      github-action["GitHub Action"]
      github-page["GitHub Page"]
      subgraph CI-CD["Automation"]
        direction RL
        github-action -- "hugo serve" --> github-page
      end
    end
    blog-content ---- sub-blogs

    blogs-public-site["https://james-leste.github.io/blogs/"]
    blogs -- "render" --> blogs-public-site
  end

  Local -- "git push" --> blog-content

Fig 1. The architecture of the automation of this blog site

Hugo

Git submodule

GitHub