Skip to main content

A blog-oriented static site generation engine

Project description

Blogmore

A blog-oriented static site generation engine built in Python.

[!IMPORTANT] This project is built almost 100% using GitHub Copilot. Every other Python project you will find in my repository is good old human-built code. This project is the complete opposite: as much as possible I'm trying to write no code at all as an experiment in getting to know how this process works, how to recognise such code, and to understand those who use this process every day to, in future, better guide them.

If "AI written" is a huge red flag for you I suggest you avoid this project; you'll find plenty of other pure-davep-built projects via my profile.

Features

  • Write everything in Markdown
  • All metadata comes from frontmatter
  • Uses Jinja2 for templating
  • Simple and clean design
  • Automatic tag pages and archive generation
  • Automatic icon generation - Generate favicons and platform-specific icons from a single source image
    • iOS (Apple Touch Icons)
    • Android/Chrome (with PWA manifest)
    • Windows/Edge (with tile configuration)

Installation

Using uv (recommended)

uv tool install blogmore

Using pipx

pipx install blogmore

From source

git clone https://github.com/davep/blogmore.git
cd blogmore
uv sync

Usage

Basic Usage

Create a directory with your markdown posts:

mkdir posts

Create a markdown file with frontmatter:

---
title: My First Post
date: 2024-01-15
tags: [python, blog]
---

This is my first blog post!

Generate your site:

blogmore build posts/

This will generate your site in the output/ directory.

Serve the Site Locally

To serve an existing site:

blogmore serve -o output/

Or generate and serve with auto-reload on changes:

blogmore serve posts/ -o output/

This starts a local HTTP server on port 8000 and watches for changes. Open http://localhost:8000/ in your browser.

Options:

  • -o, --output - Output directory to serve (default: output/)
  • -p, --port - Port to serve on (default: 8000)
  • --no-watch - Disable watching for changes

Example:

blogmore serve posts/ --port 3000 --output my-site/

Custom Options

blogmore build posts/ \
  --templates my-templates/ \
  --output my-site/ \
  --site-title "My Awesome Blog" \
  --site-subtitle "Thoughts on code and technology" \
  --site-url "https://example.com"

Configuration File

Blogmore supports configuration files to avoid repetitive command-line arguments. Create a blogmore.yaml or blogmore.yml file in your project directory:

# blogmore.yaml
content_dir: posts
output: my-site
templates: my-templates
site_title: "My Awesome Blog"
site_subtitle: "Thoughts on code and technology"
site_url: "https://example.com"
include_drafts: false
clean_first: false
posts_per_feed: 30
default_author: "Your Name"
extra_stylesheets:
  - https://example.com/custom.css
  - /assets/extra.css

# Serve-specific options
port: 3000
no_watch: false

# Publish-specific options
branch: gh-pages
remote: origin

Using Configuration Files

Automatic Discovery: Blogmore automatically searches for blogmore.yaml or blogmore.yml in the current directory (.yaml takes precedence):

blogmore build  # Uses blogmore.yaml if found

Specify a Config File: Use the -c or --config flag to specify a custom config file:

blogmore build --config my-config.yaml

Override Config with CLI: Command-line arguments always take precedence over configuration file values:

# Uses blogmore.yaml but overrides site_title
blogmore build --site-title "Different Title"

Configuration Options

All command-line options can be configured in the YAML file:

  • content_dir - Directory containing markdown posts
  • templates - Custom templates directory
  • output - Output directory (default: output/)
  • site_title - Site title (default: "My Blog")
  • site_subtitle - Site subtitle (optional)
  • site_url - Base URL of the site
  • include_drafts - Include posts marked as drafts (default: false)
  • clean_first - Remove output directory before generating (default: false)
  • posts_per_feed - Maximum posts in feeds (default: 20)
  • default_author - Default author name for posts without author in frontmatter
  • extra_stylesheets - List of additional stylesheet URLs
  • port - Port for serve command (default: 8000)
  • no_watch - Disable file watching in serve mode (default: false)
  • branch - Git branch for publish command (default: gh-pages)
  • remote - Git remote for publish command (default: origin)

Note: The --config option itself cannot be set in a configuration file.

Commands

Build (build, generate, gen) Generate the static site from markdown posts:

blogmore build posts/ [options]

Serve (serve, test) Serve the site locally with optional generation and auto-reload:

blogmore serve [posts/] [options]

Publish (publish) Build and publish the site to a git branch (e.g., for GitHub Pages):

blogmore publish posts/ [options]

This command:

  1. Builds your site to the output directory
  2. Checks that you're in a git repository
  3. Creates or updates a git branch (default: gh-pages)
  4. Copies the built site to that branch
  5. Commits and pushes the changes

Example for GitHub Pages:

blogmore publish posts/ --branch gh-pages --remote origin

Note: The publish command requires git to be installed and available in your PATH.

Common Options

Available for both build and serve commands:

  • content_dir - Directory containing markdown posts (required for build, optional for serve)
  • -c, --config - Path to configuration file (default: searches for blogmore.yaml or blogmore.yml)
  • -t, --templates - Custom templates directory (default: uses bundled templates)
  • -o, --output - Output directory (default: output/)
  • --site-title - Site title (default: "My Blog")
  • --site-subtitle - Site subtitle (optional)
  • --site-url - Base URL of the site
  • --include-drafts - Include posts marked as drafts
  • --clean-first - Remove output directory before generating
  • --posts-per-feed - Maximum posts in feeds (default: 20)
  • --default-author - Default author name for posts without author in frontmatter
  • --extra-stylesheet - Additional stylesheet URL (can be used multiple times)

Serve-Specific Options

  • -p, --port - Port to serve on (default: 8000)
  • --no-watch - Disable watching for changes

Publish-Specific Options

  • --branch - Git branch to publish to (default: gh-pages)
  • --remote - Git remote to push to (default: origin)

Frontmatter Fields

Required:

  • title - Post title

Optional:

  • date - Publication date (YYYY-MM-DD format)
  • category - Post category (e.g., "python", "webdev")
  • tags - List of tags or comma-separated string
  • draft - Set to true to mark as draft
  • author - Author name (uses default_author if not specified)

Example:

---
title: My Blog Post
date: 2024-01-15
category: python
tags: [python, webdev, tutorial]
author: Jane Smith
draft: false
---

Categories vs Tags

Categories allow you to organize posts into distinct sections or "sub-blogs" within your site. Each post can have one category, and visitors can view all posts in a category at /category/{category-name}.html.

Tags are for cross-categorization and can be applied multiple times per post. They're useful for topics that span multiple categories.

For example, a blog might use categories like "python", "javascript", "devops" to separate major topics, while using tags like "tutorial", "advanced", "beginner" to indicate post type.

Icon Generation

Blogmore can automatically generate favicons and platform-specific icons from a single source image. Place a high-resolution square image (ideally 1024×1024 or larger) in your extras/ directory, and Blogmore will generate all necessary icon formats.

Generated Icons

From a single source image, Blogmore generates 18 icon files for all major platforms:

  • Favicon files: Multi-resolution .ico and PNG sizes (16×16, 32×32, 96×96)
  • Apple Touch Icons: Optimized for iOS devices (120×120, 152×152, 167×167, 180×180)
  • Android/Chrome icons: PWA-ready with web manifest (192×192, 512×512)
  • Windows tiles: Microsoft Edge and Windows 10+ tiles (70×70, 144×144, 150×150, 310×310, 310×150)

All icons are generated to the /icons subdirectory to avoid conflicts with other files.

Configuration

Auto-detection (no configuration needed): Place one of these files in your extras/ directory:

  • icon.png (recommended)
  • icon.jpg or icon.jpeg
  • source-icon.png
  • app-icon.png

Custom filename via CLI:

blogmore build content/ --icon-source my-logo.png

Custom filename via config file:

# Icon generation
icon_source: "my-logo.png"

Requirements

  • Source image should be square
  • Recommended size: 1024×1024 or larger
  • Supported formats: PNG, JPEG
  • Transparent backgrounds (PNG) work best

Templates

Blogmore uses Jinja2 templates. The default templates are included, but you can customize them:

  • base.html - Base template
  • index.html - Homepage listing (shows full post content)
  • post.html - Individual post page
  • archive.html - Archive page
  • tag.html - Tag page
  • category.html - Category page
  • static/style.css - Stylesheet

Markdown Features

Blogmore supports all standard Markdown features plus:

  • Fenced code blocks with syntax highlighting
  • Tables
  • Table of contents generation
  • Footnotes - Use [^1] in text and [^1]: Footnote text at the bottom
  • GitHub-style admonitions - Alert boxes for notes, tips, warnings, etc.

Admonitions (Alerts)

Blogmore supports GitHub-style admonitions (also known as alerts) to highlight important information. These use the same syntax as GitHub Markdown:

> [!NOTE]
> Useful information that users should know, even when skimming content.

> [!TIP]
> Helpful advice for doing things better or more easily.

> [!IMPORTANT]
> Key information users need to know to achieve their goal.

> [!WARNING]
> Urgent info that needs immediate user attention to avoid problems.

> [!CAUTION]
> Advises about risks or negative outcomes of certain actions.

Each admonition type has its own color scheme and icon:

  • Note - Blue with ℹ️ icon
  • Tip - Green with 💡 icon
  • Important - Purple with ❗ icon
  • Warning - Orange with ⚠️ icon
  • Caution - Red with 🚨 icon

Admonitions support all standard Markdown formatting within them, including bold, italic, code, links, and multiple paragraphs.

Example with formatting:

> [!TIP]
> You can use **bold**, *italic*, and `code` formatting.
>
> Multiple paragraphs work too!

Footnotes Example

Example with footnote:

---
title: My Post
---

This is a post with a footnote[^1].

[^1]: This is the footnote content.

Development

Setup

make setup

Run Checks

make checkall  # Run all checks (lint, format, typecheck, spell, tests)
make lint      # Check linting
make typecheck # Type checking with mypy
make test      # Run test suite

Format Code

make tidy  # Fix formatting and linting issues

Testing

Blogmore has a comprehensive test suite with 143 tests achieving 84% code coverage.

make test              # Run all tests
make test-verbose      # Run with verbose output
make test-coverage     # Run with detailed coverage report

For more information, see the tests README.

License

GPL-3.0-or-later

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

blogmore-0.7.0.tar.gz (48.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

blogmore-0.7.0-py3-none-any.whl (58.6 kB view details)

Uploaded Python 3

File details

Details for the file blogmore-0.7.0.tar.gz.

File metadata

  • Download URL: blogmore-0.7.0.tar.gz
  • Upload date:
  • Size: 48.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for blogmore-0.7.0.tar.gz
Algorithm Hash digest
SHA256 9769a483c7c5f871c0a9708b1b302458a688152b05c1ed611d18024574e182cd
MD5 772f2a8042fd8cae9a7f14920be3cf7e
BLAKE2b-256 56c9ca710cc413c45357abb469dd66b28d56d70271a89cf23aad8a40279dc426

See more details on using hashes here.

File details

Details for the file blogmore-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: blogmore-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 58.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for blogmore-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aa0d049441ca6cb9942bd49a3b5e940ed73acff72843072013900250c9ecb7a1
MD5 05a79b4329dcd976b201f643e1dce350
BLAKE2b-256 e1f492d2515cf620aea8edbeae0b7e7ea1efb56e64b0ed002043a22411faac0f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page