Markdown blog to beautiful static HTML — write .md, customize CSS, publish.
Project description
xuanxin
Write Markdown blogs anywhere, generate beautiful static HTML with easy style customization.
Quick start
cd ~/xuanxin
pip install -e .
# Write posts in examples/content/*.md, then build:
xuanxin build -i examples/content -o examples/dist -t "My Blog"
# Open in browser
python -m http.server 8080 --directory examples/dist
# → http://localhost:8080
Write a post
Create content/my-post.md:
---
title: "My First Post"
slug: "my-first-post"
date: "2025-06-06"
author: "You"
tags: ["blog"]
description: "A short intro shown on the index page."
theme: "default" # optional: default | dark | minimal
featured_image_url: "https://example.com/cover.jpg"
---
# Hello World
Your **markdown** content here.
Inline math: $E = mc^2$
https://youtu.be/VIDEO_ID ← auto-embeds YouTube
Build commands
# Basic build
xuanxin build -i content/ -o dist/
# Dark theme
xuanxin build -i content/ -o dist/ --theme dark
# Custom CSS (overrides variables & adds rules)
xuanxin build -i content/ -o dist/ --css my-style.css
# Preview HTML body for one file
xuanxin preview content/my-post.md
# List built-in themes
xuanxin themes
Customize styles (3 ways)
1. Built-in themes
default, dark, minimal — pass --theme dark or set theme: dark in frontmatter.
2. CSS variables (copy a theme file)
Each theme is just a :root { ... } block. Copy xuanxin/static/themes/default.css and change colors:
:root {
--color-primary: #059669;
--color-bg: #fafafa;
--font-serif: "Georgia", serif;
--max-width: 800px;
}
Use with --css my-theme.css.
3. Full custom CSS
Pass any CSS file with --css. It loads after the base theme, so you can override anything:
:root { --color-primary: hotpink; }
.prose h2 { border-bottom: 2px dashed var(--color-primary); }
.post { box-shadow: none; border: 2px solid black; }
See examples/custom.css for a gradient-title example.
Python API
from pathlib import Path
from xuanxin import BlogBuilder, MarkdownProcessor
# Full site build
BlogBuilder(
content_dir=Path("content"),
output_dir=Path("dist"),
site_title="My Blog",
theme="dark",
custom_css=Path("custom.css"),
).build()
# Single file MD → HTML
processor = MarkdownProcessor()
result = processor.process_file("content/post.md")
print(result["content"]) # HTML body
print(result["metadata"]) # title, slug, tags, ...
MD → HTML pipeline
- Parse YAML frontmatter (
python-frontmatter) - Protect LaTeX
$...$/$$...$$from Markdown - Convert with Python-Markdown (+ code highlighting, tables, TOC, fenced code)
- Custom extensions: image CSS classes, YouTube/Vimeo embeds
- Restore LaTeX (rendered client-side via MathJax in output HTML)
- Wrap in Jinja2 template → static
.htmlfiles
Output structure
dist/
├── index.html # post listing
├── manifest.json # build metadata
├── assets/
│ ├── theme.css # merged theme + base styles
│ └── custom.css # your overrides (if --css used)
└── posts/
├── my-first-post.html
└── ...
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xuanxin-0.1.1.dev0.tar.gz.
File metadata
- Download URL: xuanxin-0.1.1.dev0.tar.gz
- Upload date:
- Size: 35.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a8179fbb84448b2974127bd8efddcc9fc96fbaa91f803f3c6fd14900e6aac95
|
|
| MD5 |
aa150e674b5745ac50e25a990e82eafb
|
|
| BLAKE2b-256 |
6ee73cff1171734a7b059d92bf5c3a4c34bb5abd84c58f7c008fbf1be3c369a2
|
File details
Details for the file xuanxin-0.1.1.dev0-py3-none-any.whl.
File metadata
- Download URL: xuanxin-0.1.1.dev0-py3-none-any.whl
- Upload date:
- Size: 36.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23295e62913d03f4abb0d177b031c19b1c6b68700133ec7e4d19fcc24b63c9b6
|
|
| MD5 |
4e31bb9c955c807d24621bd345d95537
|
|
| BLAKE2b-256 |
6ac182764d4d23a68733eaea39be1f257566a1949cf47e1dd999a8ca616f798a
|