A personal static blog generator written in Clojure. It converts Markdown files to HTML for my personal website. The generated static site is hosted on Digital Ocean App Platform.
The generator takes Markdown files from the posts and pages directories, processes them through Pandoc, and applies styling and layout templates using Hiccup. It includes:
- Automatic conversion of Markdown to HTML using Pandoc
- Development server
- Responsive design using Tailwind CSS
- Automatic table of contents generation
- Read time estimation
- RSS feed generation
- Support for custom pages
- Code syntax highlighting
- LaTeX rendering in the browser
posts/- Blog posts written in Markdownpages/- Custom static pagessrc/- Clojure source code for generating the sitestatic/- Generated site outputcss/- Tailwind CSS source files
- Pandoc for Markdown conversion
- Clojure (1.10+)
- Tailwind CSS standalone binary
The project uses just as a command runner for common tasks.
# Install e2e dependencies
just e2e-install
# Start the dev server and Tailwind CSS watcher
just dev
# Regenerate all static files (one-off)
just build
# Preview at http://localhost:8081If you don't have just installed:
# Start an nREPL server (for editor connection)
clj -M:nreplIn the REPL:
(blog.dev-server/start-server) ; Start server on port 8081
(blog.core/regenerate-site) ; Regenerate all static filesIn a separate terminal:
tailwindcss -i ./css/input.css -o ./static/css/output.css --watchWe use Playwright for smoke tests and visual "agentic flows" to ensure the site looks correct.
# Run smoke tests
just smoke
# Run a navigation flow and capture screenshots
just flow-nav
# Take a screenshot of a specific route
just screenshot /resumeScreenshots are saved to e2e/screenshots/.
Start the nREPL server with clj -M:nrepl. It will print a port number.
- Emacs/CIDER:
M-x cider-connect-clj→ localhost → port - VS Code/Calva: Command Palette → "Calva: Connect to a Running REPL Server"
- IntelliJ/Cursive: Run → Edit Configurations → Clojure REPL → Remote
Write Markdown files in the posts/ directory using the filename format YYYY-MM-DD-title.md.
Posts use YAML frontmatter for metadata:
---
title: My Post Title
date: 2024-01-15
description: A description of the post
thumbnail: /img/thumbnail.png
tags: [tag1, tag2, tag3]
---
Post content here...After regenerating static files, commit changes and Digital Ocean automatically publishes the updated site.
Place Markdown content in the pages/ directory. Some pages skip Markdown entirely and are written directly in Clojure using Hiccup (like the resume page which uses EDN data).
The site is automatically deployed when changes are pushed to the main branch. Digital Ocean App Platform publishes all files from the static/ directory.
The code for this blog generator is provided under the MIT License:
MIT License
Copyright (c) 2023-2025 Justin Good
The blog content (posts, articles, and other written materials) is Justin Good.
All rights reserved. The content of this blog may not be used for training AI models, machine learning algorithms, or other automated systems without explicit permission from the author. You may read, share, and link to the content, but usage for AI training, republishing, or commercial purposes requires prior written consent.