xuanxin 0.1.1.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xuanxin-0.1.1.dev0/PKG-INFO +164 -0
- xuanxin-0.1.1.dev0/README.md +143 -0
- xuanxin-0.1.1.dev0/pyproject.toml +39 -0
- xuanxin-0.1.1.dev0/setup.cfg +4 -0
- xuanxin-0.1.1.dev0/tests/test_xuanxin.py +647 -0
- xuanxin-0.1.1.dev0/xuanxin/__init__.py +18 -0
- xuanxin-0.1.1.dev0/xuanxin/book.py +226 -0
- xuanxin-0.1.1.dev0/xuanxin/builder.py +128 -0
- xuanxin-0.1.1.dev0/xuanxin/cli.py +195 -0
- xuanxin-0.1.1.dev0/xuanxin/extensions.py +207 -0
- xuanxin-0.1.1.dev0/xuanxin/footnotes.py +41 -0
- xuanxin-0.1.1.dev0/xuanxin/image_attrs.py +513 -0
- xuanxin-0.1.1.dev0/xuanxin/includes.py +185 -0
- xuanxin-0.1.1.dev0/xuanxin/latex.py +35 -0
- xuanxin-0.1.1.dev0/xuanxin/note_sections.py +106 -0
- xuanxin-0.1.1.dev0/xuanxin/paginate.py +48 -0
- xuanxin-0.1.1.dev0/xuanxin/processor.py +201 -0
- xuanxin-0.1.1.dev0/xuanxin/renderer.py +175 -0
- xuanxin-0.1.1.dev0/xuanxin/section_nav.py +58 -0
- xuanxin-0.1.1.dev0/xuanxin/static/themes/_base.css +1081 -0
- xuanxin-0.1.1.dev0/xuanxin/static/themes/dark.css +23 -0
- xuanxin-0.1.1.dev0/xuanxin/static/themes/default.css +23 -0
- xuanxin-0.1.1.dev0/xuanxin/static/themes/minimal.css +23 -0
- xuanxin-0.1.1.dev0/xuanxin/templates/book_index.html +44 -0
- xuanxin-0.1.1.dev0/xuanxin/templates/index.html +53 -0
- xuanxin-0.1.1.dev0/xuanxin/templates/post.html +123 -0
- xuanxin-0.1.1.dev0/xuanxin.egg-info/PKG-INFO +164 -0
- xuanxin-0.1.1.dev0/xuanxin.egg-info/SOURCES.txt +30 -0
- xuanxin-0.1.1.dev0/xuanxin.egg-info/dependency_links.txt +1 -0
- xuanxin-0.1.1.dev0/xuanxin.egg-info/entry_points.txt +2 -0
- xuanxin-0.1.1.dev0/xuanxin.egg-info/requires.txt +7 -0
- xuanxin-0.1.1.dev0/xuanxin.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xuanxin
|
|
3
|
+
Version: 0.1.1.dev0
|
|
4
|
+
Summary: Markdown blog to beautiful static HTML — write .md, customize CSS, publish.
|
|
5
|
+
Author: xuanxin
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: markdown,blog,static-site,html
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: markdown>=3.5
|
|
16
|
+
Requires-Dist: python-frontmatter>=1.1
|
|
17
|
+
Requires-Dist: jinja2>=3.1
|
|
18
|
+
Requires-Dist: pygments>=2.17
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
|
|
22
|
+
# xuanxin
|
|
23
|
+
|
|
24
|
+
Write Markdown blogs anywhere, generate beautiful static HTML with easy style customization.
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd ~/xuanxin
|
|
30
|
+
pip install -e .
|
|
31
|
+
|
|
32
|
+
# Write posts in examples/content/*.md, then build:
|
|
33
|
+
xuanxin build -i examples/content -o examples/dist -t "My Blog"
|
|
34
|
+
|
|
35
|
+
# Open in browser
|
|
36
|
+
python -m http.server 8080 --directory examples/dist
|
|
37
|
+
# → http://localhost:8080
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Write a post
|
|
41
|
+
|
|
42
|
+
Create `content/my-post.md`:
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
---
|
|
46
|
+
title: "My First Post"
|
|
47
|
+
slug: "my-first-post"
|
|
48
|
+
date: "2025-06-06"
|
|
49
|
+
author: "You"
|
|
50
|
+
tags: ["blog"]
|
|
51
|
+
description: "A short intro shown on the index page."
|
|
52
|
+
theme: "default" # optional: default | dark | minimal
|
|
53
|
+
featured_image_url: "https://example.com/cover.jpg"
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# Hello World
|
|
57
|
+
|
|
58
|
+
Your **markdown** content here.
|
|
59
|
+
|
|
60
|
+
Inline math: $E = mc^2$
|
|
61
|
+
|
|
62
|
+
https://youtu.be/VIDEO_ID ← auto-embeds YouTube
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Build commands
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Basic build
|
|
69
|
+
xuanxin build -i content/ -o dist/
|
|
70
|
+
|
|
71
|
+
# Dark theme
|
|
72
|
+
xuanxin build -i content/ -o dist/ --theme dark
|
|
73
|
+
|
|
74
|
+
# Custom CSS (overrides variables & adds rules)
|
|
75
|
+
xuanxin build -i content/ -o dist/ --css my-style.css
|
|
76
|
+
|
|
77
|
+
# Preview HTML body for one file
|
|
78
|
+
xuanxin preview content/my-post.md
|
|
79
|
+
|
|
80
|
+
# List built-in themes
|
|
81
|
+
xuanxin themes
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Customize styles (3 ways)
|
|
85
|
+
|
|
86
|
+
### 1. Built-in themes
|
|
87
|
+
|
|
88
|
+
`default`, `dark`, `minimal` — pass `--theme dark` or set `theme: dark` in frontmatter.
|
|
89
|
+
|
|
90
|
+
### 2. CSS variables (copy a theme file)
|
|
91
|
+
|
|
92
|
+
Each theme is just a `:root { ... }` block. Copy `xuanxin/static/themes/default.css` and change colors:
|
|
93
|
+
|
|
94
|
+
```css
|
|
95
|
+
:root {
|
|
96
|
+
--color-primary: #059669;
|
|
97
|
+
--color-bg: #fafafa;
|
|
98
|
+
--font-serif: "Georgia", serif;
|
|
99
|
+
--max-width: 800px;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Use with `--css my-theme.css`.
|
|
104
|
+
|
|
105
|
+
### 3. Full custom CSS
|
|
106
|
+
|
|
107
|
+
Pass any CSS file with `--css`. It loads **after** the base theme, so you can override anything:
|
|
108
|
+
|
|
109
|
+
```css
|
|
110
|
+
:root { --color-primary: hotpink; }
|
|
111
|
+
.prose h2 { border-bottom: 2px dashed var(--color-primary); }
|
|
112
|
+
.post { box-shadow: none; border: 2px solid black; }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
See `examples/custom.css` for a gradient-title example.
|
|
116
|
+
|
|
117
|
+
## Python API
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from pathlib import Path
|
|
121
|
+
from xuanxin import BlogBuilder, MarkdownProcessor
|
|
122
|
+
|
|
123
|
+
# Full site build
|
|
124
|
+
BlogBuilder(
|
|
125
|
+
content_dir=Path("content"),
|
|
126
|
+
output_dir=Path("dist"),
|
|
127
|
+
site_title="My Blog",
|
|
128
|
+
theme="dark",
|
|
129
|
+
custom_css=Path("custom.css"),
|
|
130
|
+
).build()
|
|
131
|
+
|
|
132
|
+
# Single file MD → HTML
|
|
133
|
+
processor = MarkdownProcessor()
|
|
134
|
+
result = processor.process_file("content/post.md")
|
|
135
|
+
print(result["content"]) # HTML body
|
|
136
|
+
print(result["metadata"]) # title, slug, tags, ...
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## MD → HTML pipeline
|
|
140
|
+
|
|
141
|
+
1. Parse YAML frontmatter (`python-frontmatter`)
|
|
142
|
+
2. Protect LaTeX `$...$` / `$$...$$` from Markdown
|
|
143
|
+
3. Convert with Python-Markdown (+ code highlighting, tables, TOC, fenced code)
|
|
144
|
+
4. Custom extensions: image CSS classes, YouTube/Vimeo embeds
|
|
145
|
+
5. Restore LaTeX (rendered client-side via MathJax in output HTML)
|
|
146
|
+
6. Wrap in Jinja2 template → static `.html` files
|
|
147
|
+
|
|
148
|
+
## Output structure
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
dist/
|
|
152
|
+
├── index.html # post listing
|
|
153
|
+
├── manifest.json # build metadata
|
|
154
|
+
├── assets/
|
|
155
|
+
│ ├── theme.css # merged theme + base styles
|
|
156
|
+
│ └── custom.css # your overrides (if --css used)
|
|
157
|
+
└── posts/
|
|
158
|
+
├── my-first-post.html
|
|
159
|
+
└── ...
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# xuanxin
|
|
2
|
+
|
|
3
|
+
Write Markdown blogs anywhere, generate beautiful static HTML with easy style customization.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd ~/xuanxin
|
|
9
|
+
pip install -e .
|
|
10
|
+
|
|
11
|
+
# Write posts in examples/content/*.md, then build:
|
|
12
|
+
xuanxin build -i examples/content -o examples/dist -t "My Blog"
|
|
13
|
+
|
|
14
|
+
# Open in browser
|
|
15
|
+
python -m http.server 8080 --directory examples/dist
|
|
16
|
+
# → http://localhost:8080
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Write a post
|
|
20
|
+
|
|
21
|
+
Create `content/my-post.md`:
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
---
|
|
25
|
+
title: "My First Post"
|
|
26
|
+
slug: "my-first-post"
|
|
27
|
+
date: "2025-06-06"
|
|
28
|
+
author: "You"
|
|
29
|
+
tags: ["blog"]
|
|
30
|
+
description: "A short intro shown on the index page."
|
|
31
|
+
theme: "default" # optional: default | dark | minimal
|
|
32
|
+
featured_image_url: "https://example.com/cover.jpg"
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Hello World
|
|
36
|
+
|
|
37
|
+
Your **markdown** content here.
|
|
38
|
+
|
|
39
|
+
Inline math: $E = mc^2$
|
|
40
|
+
|
|
41
|
+
https://youtu.be/VIDEO_ID ← auto-embeds YouTube
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Build commands
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Basic build
|
|
48
|
+
xuanxin build -i content/ -o dist/
|
|
49
|
+
|
|
50
|
+
# Dark theme
|
|
51
|
+
xuanxin build -i content/ -o dist/ --theme dark
|
|
52
|
+
|
|
53
|
+
# Custom CSS (overrides variables & adds rules)
|
|
54
|
+
xuanxin build -i content/ -o dist/ --css my-style.css
|
|
55
|
+
|
|
56
|
+
# Preview HTML body for one file
|
|
57
|
+
xuanxin preview content/my-post.md
|
|
58
|
+
|
|
59
|
+
# List built-in themes
|
|
60
|
+
xuanxin themes
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Customize styles (3 ways)
|
|
64
|
+
|
|
65
|
+
### 1. Built-in themes
|
|
66
|
+
|
|
67
|
+
`default`, `dark`, `minimal` — pass `--theme dark` or set `theme: dark` in frontmatter.
|
|
68
|
+
|
|
69
|
+
### 2. CSS variables (copy a theme file)
|
|
70
|
+
|
|
71
|
+
Each theme is just a `:root { ... }` block. Copy `xuanxin/static/themes/default.css` and change colors:
|
|
72
|
+
|
|
73
|
+
```css
|
|
74
|
+
:root {
|
|
75
|
+
--color-primary: #059669;
|
|
76
|
+
--color-bg: #fafafa;
|
|
77
|
+
--font-serif: "Georgia", serif;
|
|
78
|
+
--max-width: 800px;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Use with `--css my-theme.css`.
|
|
83
|
+
|
|
84
|
+
### 3. Full custom CSS
|
|
85
|
+
|
|
86
|
+
Pass any CSS file with `--css`. It loads **after** the base theme, so you can override anything:
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
:root { --color-primary: hotpink; }
|
|
90
|
+
.prose h2 { border-bottom: 2px dashed var(--color-primary); }
|
|
91
|
+
.post { box-shadow: none; border: 2px solid black; }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
See `examples/custom.css` for a gradient-title example.
|
|
95
|
+
|
|
96
|
+
## Python API
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from pathlib import Path
|
|
100
|
+
from xuanxin import BlogBuilder, MarkdownProcessor
|
|
101
|
+
|
|
102
|
+
# Full site build
|
|
103
|
+
BlogBuilder(
|
|
104
|
+
content_dir=Path("content"),
|
|
105
|
+
output_dir=Path("dist"),
|
|
106
|
+
site_title="My Blog",
|
|
107
|
+
theme="dark",
|
|
108
|
+
custom_css=Path("custom.css"),
|
|
109
|
+
).build()
|
|
110
|
+
|
|
111
|
+
# Single file MD → HTML
|
|
112
|
+
processor = MarkdownProcessor()
|
|
113
|
+
result = processor.process_file("content/post.md")
|
|
114
|
+
print(result["content"]) # HTML body
|
|
115
|
+
print(result["metadata"]) # title, slug, tags, ...
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## MD → HTML pipeline
|
|
119
|
+
|
|
120
|
+
1. Parse YAML frontmatter (`python-frontmatter`)
|
|
121
|
+
2. Protect LaTeX `$...$` / `$$...$$` from Markdown
|
|
122
|
+
3. Convert with Python-Markdown (+ code highlighting, tables, TOC, fenced code)
|
|
123
|
+
4. Custom extensions: image CSS classes, YouTube/Vimeo embeds
|
|
124
|
+
5. Restore LaTeX (rendered client-side via MathJax in output HTML)
|
|
125
|
+
6. Wrap in Jinja2 template → static `.html` files
|
|
126
|
+
|
|
127
|
+
## Output structure
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
dist/
|
|
131
|
+
├── index.html # post listing
|
|
132
|
+
├── manifest.json # build metadata
|
|
133
|
+
├── assets/
|
|
134
|
+
│ ├── theme.css # merged theme + base styles
|
|
135
|
+
│ └── custom.css # your overrides (if --css used)
|
|
136
|
+
└── posts/
|
|
137
|
+
├── my-first-post.html
|
|
138
|
+
└── ...
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xuanxin"
|
|
7
|
+
version = "0.1.1.dev0"
|
|
8
|
+
description = "Markdown blog to beautiful static HTML — write .md, customize CSS, publish."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [{ name = "xuanxin" }]
|
|
13
|
+
keywords = ["markdown", "blog", "static-site", "html"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"markdown>=3.5",
|
|
23
|
+
"python-frontmatter>=1.1",
|
|
24
|
+
"jinja2>=3.1",
|
|
25
|
+
"pygments>=2.17",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = ["pytest>=7.0"]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
xuanxin = "xuanxin.cli:main"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["."]
|
|
36
|
+
include = ["xuanxin*"]
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
xuanxin = ["templates/*", "static/themes/*", "static/themes/_base.css"]
|