Skip to main content

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

# Diary site (dated .md files → flat HTML, paginated index)
xuanxin diary -i input_folder -o output_folder -gtag gtag.js -home wu-99.com --page-size 20

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

  1. Parse YAML frontmatter (python-frontmatter)
  2. Protect LaTeX $...$ / $$...$$ from Markdown
  3. Convert with Python-Markdown (+ code highlighting, tables, TOC, fenced code)
  4. Custom extensions: image CSS classes, YouTube/Vimeo embeds
  5. Restore LaTeX (rendered client-side via MathJax in output HTML)
  6. Wrap in Jinja2 template → static .html files

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


Download files

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

Source Distribution

xuanxin-0.1.1.dev1.tar.gz (54.6 kB view details)

Uploaded Source

Built Distribution

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

xuanxin-0.1.1.dev1-py3-none-any.whl (58.5 kB view details)

Uploaded Python 3

File details

Details for the file xuanxin-0.1.1.dev1.tar.gz.

File metadata

  • Download URL: xuanxin-0.1.1.dev1.tar.gz
  • Upload date:
  • Size: 54.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for xuanxin-0.1.1.dev1.tar.gz
Algorithm Hash digest
SHA256 ffbb1671312df1af63998ebbc3c226735540849deea8a30ac5962558156f2a6b
MD5 81305535823352e4dfbeabdad65bd45f
BLAKE2b-256 b299dfb525b86b210b35d6b22670e453e472d434a4ef3f41cd9d5da6a2f0f457

See more details on using hashes here.

File details

Details for the file xuanxin-0.1.1.dev1-py3-none-any.whl.

File metadata

  • Download URL: xuanxin-0.1.1.dev1-py3-none-any.whl
  • Upload date:
  • Size: 58.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for xuanxin-0.1.1.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 e40a8df22021181d876ee8ed76860c666627f8df64e456862e4f6d35522d5220
MD5 3725625d35c7840fd02792ea3b159942
BLAKE2b-256 541b1112d77ed9348863059df63a34f5d5be2d95e820582bf4c73c9d489a6cf8

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