essayist 0.1.0__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.
- essayist-0.1.0/LICENSE +21 -0
- essayist-0.1.0/PKG-INFO +220 -0
- essayist-0.1.0/README.md +198 -0
- essayist-0.1.0/pyproject.toml +42 -0
- essayist-0.1.0/setup.cfg +4 -0
- essayist-0.1.0/src/essayist/__init__.py +22 -0
- essayist-0.1.0/src/essayist/__main__.py +4 -0
- essayist-0.1.0/src/essayist/builder.py +58 -0
- essayist-0.1.0/src/essayist/cli.py +90 -0
- essayist-0.1.0/src/essayist/config.py +58 -0
- essayist-0.1.0/src/essayist/core.py +361 -0
- essayist-0.1.0/src/essayist/filters/gallery.lua +119 -0
- essayist-0.1.0/src/essayist/py.typed +0 -0
- essayist-0.1.0/src/essayist/style-note.css +109 -0
- essayist-0.1.0/src/essayist/templates/footer.html +3 -0
- essayist-0.1.0/src/essayist/templates/header.html +7 -0
- essayist-0.1.0/src/essayist/templates/home.html +29 -0
- essayist-0.1.0/src/essayist/templates/index.html +32 -0
- essayist-0.1.0/src/essayist/templates/post.html +37 -0
- essayist-0.1.0/src/essayist.egg-info/PKG-INFO +220 -0
- essayist-0.1.0/src/essayist.egg-info/SOURCES.txt +27 -0
- essayist-0.1.0/src/essayist.egg-info/dependency_links.txt +1 -0
- essayist-0.1.0/src/essayist.egg-info/entry_points.txt +2 -0
- essayist-0.1.0/src/essayist.egg-info/requires.txt +8 -0
- essayist-0.1.0/src/essayist.egg-info/top_level.txt +1 -0
- essayist-0.1.0/tests/test_blog.py +186 -0
- essayist-0.1.0/tests/test_cli.py +84 -0
- essayist-0.1.0/tests/test_core.py +21 -0
- essayist-0.1.0/tests/test_example_config.py +25 -0
essayist-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ayx-dg
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
essayist-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: essayist
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Pandoc + Jinja2 static site generator for Markdown blogs.
|
|
5
|
+
Author: ayx-dg
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ayx-dg/essayist
|
|
8
|
+
Project-URL: Repository, https://github.com/ayx-dg/essayist
|
|
9
|
+
Keywords: static-site-generator,blog,markdown,pandoc,jinja2
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: jinja2
|
|
17
|
+
Requires-Dist: pyyaml
|
|
18
|
+
Requires-Dist: tomli; python_version < "3.11"
|
|
19
|
+
Provides-Extra: test
|
|
20
|
+
Requires-Dist: pytest; extra == "test"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# essayist
|
|
24
|
+
|
|
25
|
+
A lightweight static site generator for Markdown blogs, powered by
|
|
26
|
+
[Pandoc](https://pandoc.org/) and [Jinja2](https://jinja.palletsprojects.com/).
|
|
27
|
+
|
|
28
|
+
Convert a directory of Markdown posts (with YAML front matter) into a styled
|
|
29
|
+
HTML blog with an index page and an RSS feed.
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
- Python ≥ 3.10
|
|
34
|
+
- [Pandoc](https://pandoc.org/installing.html) available on `PATH`
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install essayist
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or install from source:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git clone https://github.com/ayx-dg/essayist
|
|
46
|
+
cd essayist
|
|
47
|
+
pip install -e .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick start
|
|
51
|
+
|
|
52
|
+
### 1. Set up your Markdown directory
|
|
53
|
+
|
|
54
|
+
Create a `markdown/posts/` folder and add `.md` files with YAML front matter:
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
---
|
|
58
|
+
title: My First Post
|
|
59
|
+
date: 2025-01-15
|
|
60
|
+
tags: [intro, welcome]
|
|
61
|
+
publish: public
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
# My First Post
|
|
65
|
+
|
|
66
|
+
Here is the body of my post, written in Markdown.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. Create a config file
|
|
70
|
+
|
|
71
|
+
Save this as `essayist.toml` in your project root:
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
markdown_dir = "markdown/posts"
|
|
75
|
+
post_dir = "public/posts"
|
|
76
|
+
blogname = "My Blog"
|
|
77
|
+
site_url = "https://example.com"
|
|
78
|
+
panargs = ["--mathml", "--toc", "--shift-heading-level-by=1"]
|
|
79
|
+
|
|
80
|
+
build_index = true
|
|
81
|
+
index_title = "All Posts"
|
|
82
|
+
build_rss = true
|
|
83
|
+
home_md = "markdown/index.md"
|
|
84
|
+
home_output = "public/index.html"
|
|
85
|
+
style_css = "style-note.css"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Build
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
essayist build
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Output will be written to `public/`. Open `public/index.html` in a browser.
|
|
95
|
+
|
|
96
|
+
## CLI usage
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
essayist build [--config essayist.toml] [OPTIONS]
|
|
100
|
+
essayist version
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
CLI flags override the corresponding config-file values:
|
|
104
|
+
|
|
105
|
+
| Flag | Description |
|
|
106
|
+
|------------------|------------------------------------|
|
|
107
|
+
| `-c, --config` | Path to TOML config (default: `essayist.toml`) |
|
|
108
|
+
| `--markdown-dir` | Directory with Markdown posts |
|
|
109
|
+
| `--post-dir` | Output directory for rendered HTML |
|
|
110
|
+
| `--template-dir` | Custom Jinja2 template directory |
|
|
111
|
+
| `--blogname` | Blog name for page titles |
|
|
112
|
+
| `--site-url` | Base URL for RSS feeds |
|
|
113
|
+
| `--gallery` | Enable the gallery Lua filter |
|
|
114
|
+
|
|
115
|
+
## Python API
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from essayist import Blog, Config, build_site
|
|
119
|
+
|
|
120
|
+
# High-level: load config and build everything
|
|
121
|
+
cfg = Config(
|
|
122
|
+
markdown_dir="markdown/posts",
|
|
123
|
+
post_dir="public/posts",
|
|
124
|
+
blogname="My Blog",
|
|
125
|
+
site_url="https://example.com",
|
|
126
|
+
panargs=["--mathml", "--toc"],
|
|
127
|
+
)
|
|
128
|
+
build_site(cfg)
|
|
129
|
+
|
|
130
|
+
# Or use the Blog class directly
|
|
131
|
+
blog = Blog(
|
|
132
|
+
markdown_dir="markdown/posts",
|
|
133
|
+
post_dir="public/posts",
|
|
134
|
+
template_dir="path/to/custom/templates", # None → use bundled defaults
|
|
135
|
+
)
|
|
136
|
+
blog.update_data()
|
|
137
|
+
blog.build_posts()
|
|
138
|
+
blog.build_index()
|
|
139
|
+
blog.build_rss("public/posts/rss.xml")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Config reference
|
|
143
|
+
|
|
144
|
+
All keys in `essayist.toml`:
|
|
145
|
+
|
|
146
|
+
| Key | Type | Default | Description |
|
|
147
|
+
|-------------------|-------------|-------------------|----------------------------------------------------|
|
|
148
|
+
| `markdown_dir` | string | `markdown/posts` | Directory with `.md` post files |
|
|
149
|
+
| `post_dir` | string | `public/posts` | Output directory for rendered HTML |
|
|
150
|
+
| `template_dir` | string/null | `null` (bundled) | Jinja2 template directory (`null` = use defaults) |
|
|
151
|
+
| `blogname` | string | `""` | Blog name appended to page titles |
|
|
152
|
+
| `google_group_id` | string | `""` | Enables the email-comment block in posts |
|
|
153
|
+
| `site_url` | string | `https://example.com` | Base URL used in RSS `<link>` tags |
|
|
154
|
+
| `panargs` | array | `[]` | Extra flags passed to Pandoc |
|
|
155
|
+
| `gallery` | bool | `false` | Enable the bundled image-gallery Lua filter |
|
|
156
|
+
| `build_index` | bool | `true` | Generate the post-list index page |
|
|
157
|
+
| `index_title` | string | `Index` | Title for the index page |
|
|
158
|
+
| `build_rss` | bool | `true` | Generate an RSS 2.0 feed |
|
|
159
|
+
| `rss_path` | string/null | `<post_dir>/rss.xml` | Where to write the RSS feed |
|
|
160
|
+
| `home_md` | string/null | `null` | Markdown file for the home page (if any) |
|
|
161
|
+
| `home_template` | string | `home.html` | Template used to render the home page |
|
|
162
|
+
| `home_output` | string | `public/index.html` | Output path for the home page |
|
|
163
|
+
| `style_css` | string/null | `null` | CSS file copied next to rendered posts |
|
|
164
|
+
| `data_path` | string | `data.json` | Path for the auto-generated post index |
|
|
165
|
+
|
|
166
|
+
## Post front matter
|
|
167
|
+
|
|
168
|
+
Every Markdown post should start with a YAML front matter block:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
---
|
|
172
|
+
title: Post Title # required
|
|
173
|
+
date: 2025-01-15 # used for ordering in index and RSS
|
|
174
|
+
tags: [tag1, tag2] # optional, passed to templates
|
|
175
|
+
publish: public # public | draft | unlisted
|
|
176
|
+
maillist_title: ... # optional, email comment link
|
|
177
|
+
google_group_link: ... # optional, link to mail thread
|
|
178
|
+
---
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Visibility rules:**
|
|
182
|
+
|
|
183
|
+
- `public` — appears in index and RSS
|
|
184
|
+
- `draft` — skipped entirely (existing output is cleaned up)
|
|
185
|
+
- `unlisted` — appears in RSS but not in the index
|
|
186
|
+
|
|
187
|
+
## Templates
|
|
188
|
+
|
|
189
|
+
The package ships with five default templates:
|
|
190
|
+
|
|
191
|
+
| Template | Purpose |
|
|
192
|
+
|-------------|---------------------------------|
|
|
193
|
+
| `header.html` | `<head>` block with CSS and RSS link |
|
|
194
|
+
| `footer.html` | Footer with RSS link |
|
|
195
|
+
| `post.html` | Single blog post page |
|
|
196
|
+
| `index.html` | Post listing (all public posts)|
|
|
197
|
+
| `home.html` | Home / landing page |
|
|
198
|
+
|
|
199
|
+
Supply a `template_dir` in your config to override any of these. The templates
|
|
200
|
+
use [Jinja2](https://jinja.palletsprojects.com/) syntax and receive variables
|
|
201
|
+
like `heading`, `paragraphs`, `title`, `prev_post`, `next_post`, etc.
|
|
202
|
+
|
|
203
|
+
## Bundled Lua filters
|
|
204
|
+
|
|
205
|
+
| Filter | Description |
|
|
206
|
+
|-------------|------------------------------------------|
|
|
207
|
+
| `gallery.lua` | Groups images in a paragraph into a responsive flex gallery |
|
|
208
|
+
|
|
209
|
+
Enable with `gallery = true` in config, or pass `--gallery` on the CLI.
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
pip install -e ".[test]"
|
|
215
|
+
pytest
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT
|
essayist-0.1.0/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# essayist
|
|
2
|
+
|
|
3
|
+
A lightweight static site generator for Markdown blogs, powered by
|
|
4
|
+
[Pandoc](https://pandoc.org/) and [Jinja2](https://jinja.palletsprojects.com/).
|
|
5
|
+
|
|
6
|
+
Convert a directory of Markdown posts (with YAML front matter) into a styled
|
|
7
|
+
HTML blog with an index page and an RSS feed.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Python ≥ 3.10
|
|
12
|
+
- [Pandoc](https://pandoc.org/installing.html) available on `PATH`
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install essayist
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or install from source:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/ayx-dg/essayist
|
|
24
|
+
cd essayist
|
|
25
|
+
pip install -e .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
### 1. Set up your Markdown directory
|
|
31
|
+
|
|
32
|
+
Create a `markdown/posts/` folder and add `.md` files with YAML front matter:
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
---
|
|
36
|
+
title: My First Post
|
|
37
|
+
date: 2025-01-15
|
|
38
|
+
tags: [intro, welcome]
|
|
39
|
+
publish: public
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# My First Post
|
|
43
|
+
|
|
44
|
+
Here is the body of my post, written in Markdown.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Create a config file
|
|
48
|
+
|
|
49
|
+
Save this as `essayist.toml` in your project root:
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
markdown_dir = "markdown/posts"
|
|
53
|
+
post_dir = "public/posts"
|
|
54
|
+
blogname = "My Blog"
|
|
55
|
+
site_url = "https://example.com"
|
|
56
|
+
panargs = ["--mathml", "--toc", "--shift-heading-level-by=1"]
|
|
57
|
+
|
|
58
|
+
build_index = true
|
|
59
|
+
index_title = "All Posts"
|
|
60
|
+
build_rss = true
|
|
61
|
+
home_md = "markdown/index.md"
|
|
62
|
+
home_output = "public/index.html"
|
|
63
|
+
style_css = "style-note.css"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Build
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
essayist build
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Output will be written to `public/`. Open `public/index.html` in a browser.
|
|
73
|
+
|
|
74
|
+
## CLI usage
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
essayist build [--config essayist.toml] [OPTIONS]
|
|
78
|
+
essayist version
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
CLI flags override the corresponding config-file values:
|
|
82
|
+
|
|
83
|
+
| Flag | Description |
|
|
84
|
+
|------------------|------------------------------------|
|
|
85
|
+
| `-c, --config` | Path to TOML config (default: `essayist.toml`) |
|
|
86
|
+
| `--markdown-dir` | Directory with Markdown posts |
|
|
87
|
+
| `--post-dir` | Output directory for rendered HTML |
|
|
88
|
+
| `--template-dir` | Custom Jinja2 template directory |
|
|
89
|
+
| `--blogname` | Blog name for page titles |
|
|
90
|
+
| `--site-url` | Base URL for RSS feeds |
|
|
91
|
+
| `--gallery` | Enable the gallery Lua filter |
|
|
92
|
+
|
|
93
|
+
## Python API
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from essayist import Blog, Config, build_site
|
|
97
|
+
|
|
98
|
+
# High-level: load config and build everything
|
|
99
|
+
cfg = Config(
|
|
100
|
+
markdown_dir="markdown/posts",
|
|
101
|
+
post_dir="public/posts",
|
|
102
|
+
blogname="My Blog",
|
|
103
|
+
site_url="https://example.com",
|
|
104
|
+
panargs=["--mathml", "--toc"],
|
|
105
|
+
)
|
|
106
|
+
build_site(cfg)
|
|
107
|
+
|
|
108
|
+
# Or use the Blog class directly
|
|
109
|
+
blog = Blog(
|
|
110
|
+
markdown_dir="markdown/posts",
|
|
111
|
+
post_dir="public/posts",
|
|
112
|
+
template_dir="path/to/custom/templates", # None → use bundled defaults
|
|
113
|
+
)
|
|
114
|
+
blog.update_data()
|
|
115
|
+
blog.build_posts()
|
|
116
|
+
blog.build_index()
|
|
117
|
+
blog.build_rss("public/posts/rss.xml")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Config reference
|
|
121
|
+
|
|
122
|
+
All keys in `essayist.toml`:
|
|
123
|
+
|
|
124
|
+
| Key | Type | Default | Description |
|
|
125
|
+
|-------------------|-------------|-------------------|----------------------------------------------------|
|
|
126
|
+
| `markdown_dir` | string | `markdown/posts` | Directory with `.md` post files |
|
|
127
|
+
| `post_dir` | string | `public/posts` | Output directory for rendered HTML |
|
|
128
|
+
| `template_dir` | string/null | `null` (bundled) | Jinja2 template directory (`null` = use defaults) |
|
|
129
|
+
| `blogname` | string | `""` | Blog name appended to page titles |
|
|
130
|
+
| `google_group_id` | string | `""` | Enables the email-comment block in posts |
|
|
131
|
+
| `site_url` | string | `https://example.com` | Base URL used in RSS `<link>` tags |
|
|
132
|
+
| `panargs` | array | `[]` | Extra flags passed to Pandoc |
|
|
133
|
+
| `gallery` | bool | `false` | Enable the bundled image-gallery Lua filter |
|
|
134
|
+
| `build_index` | bool | `true` | Generate the post-list index page |
|
|
135
|
+
| `index_title` | string | `Index` | Title for the index page |
|
|
136
|
+
| `build_rss` | bool | `true` | Generate an RSS 2.0 feed |
|
|
137
|
+
| `rss_path` | string/null | `<post_dir>/rss.xml` | Where to write the RSS feed |
|
|
138
|
+
| `home_md` | string/null | `null` | Markdown file for the home page (if any) |
|
|
139
|
+
| `home_template` | string | `home.html` | Template used to render the home page |
|
|
140
|
+
| `home_output` | string | `public/index.html` | Output path for the home page |
|
|
141
|
+
| `style_css` | string/null | `null` | CSS file copied next to rendered posts |
|
|
142
|
+
| `data_path` | string | `data.json` | Path for the auto-generated post index |
|
|
143
|
+
|
|
144
|
+
## Post front matter
|
|
145
|
+
|
|
146
|
+
Every Markdown post should start with a YAML front matter block:
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
---
|
|
150
|
+
title: Post Title # required
|
|
151
|
+
date: 2025-01-15 # used for ordering in index and RSS
|
|
152
|
+
tags: [tag1, tag2] # optional, passed to templates
|
|
153
|
+
publish: public # public | draft | unlisted
|
|
154
|
+
maillist_title: ... # optional, email comment link
|
|
155
|
+
google_group_link: ... # optional, link to mail thread
|
|
156
|
+
---
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Visibility rules:**
|
|
160
|
+
|
|
161
|
+
- `public` — appears in index and RSS
|
|
162
|
+
- `draft` — skipped entirely (existing output is cleaned up)
|
|
163
|
+
- `unlisted` — appears in RSS but not in the index
|
|
164
|
+
|
|
165
|
+
## Templates
|
|
166
|
+
|
|
167
|
+
The package ships with five default templates:
|
|
168
|
+
|
|
169
|
+
| Template | Purpose |
|
|
170
|
+
|-------------|---------------------------------|
|
|
171
|
+
| `header.html` | `<head>` block with CSS and RSS link |
|
|
172
|
+
| `footer.html` | Footer with RSS link |
|
|
173
|
+
| `post.html` | Single blog post page |
|
|
174
|
+
| `index.html` | Post listing (all public posts)|
|
|
175
|
+
| `home.html` | Home / landing page |
|
|
176
|
+
|
|
177
|
+
Supply a `template_dir` in your config to override any of these. The templates
|
|
178
|
+
use [Jinja2](https://jinja.palletsprojects.com/) syntax and receive variables
|
|
179
|
+
like `heading`, `paragraphs`, `title`, `prev_post`, `next_post`, etc.
|
|
180
|
+
|
|
181
|
+
## Bundled Lua filters
|
|
182
|
+
|
|
183
|
+
| Filter | Description |
|
|
184
|
+
|-------------|------------------------------------------|
|
|
185
|
+
| `gallery.lua` | Groups images in a paragraph into a responsive flex gallery |
|
|
186
|
+
|
|
187
|
+
Enable with `gallery = true` in config, or pass `--gallery` on the CLI.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pip install -e ".[test]"
|
|
193
|
+
pytest
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "essayist"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A Pandoc + Jinja2 static site generator for Markdown blogs."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "ayx-dg" }]
|
|
13
|
+
keywords = ["static-site-generator", "blog", "markdown", "pandoc", "jinja2"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Topic :: Internet :: WWW/HTTP :: Site Management",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"jinja2",
|
|
21
|
+
"pyyaml",
|
|
22
|
+
'tomli; python_version < "3.11"',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
test = ["pytest"]
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
essayist = "essayist.cli:main"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/ayx-dg/essayist"
|
|
33
|
+
Repository = "https://github.com/ayx-dg/essayist"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["src"]
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
essayist = ["templates/*.html", "filters/*.lua", "style-note.css", "py.typed"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
essayist-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""essayist: a Pandoc + Jinja2 static site generator.
|
|
2
|
+
|
|
3
|
+
This package turns a directory of Markdown posts (with YAML front matter) into
|
|
4
|
+
a static HTML site, an index page and an RSS feed.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from .builder import build_site
|
|
10
|
+
from .config import Config
|
|
11
|
+
from .core import Blog, pandoc, text_file_to_string
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"Blog",
|
|
17
|
+
"Config",
|
|
18
|
+
"build_site",
|
|
19
|
+
"pandoc",
|
|
20
|
+
"text_file_to_string",
|
|
21
|
+
"__version__",
|
|
22
|
+
]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""High level build orchestration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
|
|
8
|
+
from .config import Config
|
|
9
|
+
from .core import Blog, text_file_to_string
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_site(config: Config) -> Blog:
|
|
13
|
+
"""Run a full site build described by ``config`` and return the Blog."""
|
|
14
|
+
meta = {}
|
|
15
|
+
if config.blogname:
|
|
16
|
+
meta["blogname"] = config.blogname
|
|
17
|
+
if config.google_group_id:
|
|
18
|
+
meta["google_group_id"] = config.google_group_id
|
|
19
|
+
|
|
20
|
+
blog = Blog(
|
|
21
|
+
markdown_dir=config.markdown_dir,
|
|
22
|
+
post_dir=config.post_dir,
|
|
23
|
+
template_dir=config.template_dir,
|
|
24
|
+
meta=meta,
|
|
25
|
+
data_path=config.data_path,
|
|
26
|
+
site_url=config.site_url,
|
|
27
|
+
)
|
|
28
|
+
# set effective panargs (with bundled gallery filter if requested)
|
|
29
|
+
blog.default_panargs = config.effective_panargs(blog)
|
|
30
|
+
|
|
31
|
+
blog.update_data()
|
|
32
|
+
blog.build_posts()
|
|
33
|
+
|
|
34
|
+
if config.style_css:
|
|
35
|
+
dst_dir = os.path.dirname(os.path.join(config.post_dir, "style-note.css"))
|
|
36
|
+
os.makedirs(dst_dir, exist_ok=True)
|
|
37
|
+
shutil.copy2(config.style_css, os.path.join(config.post_dir, "style-note.css"))
|
|
38
|
+
|
|
39
|
+
if config.build_index:
|
|
40
|
+
blog.build_index(index_path=config.post_dir, index_title=config.index_title)
|
|
41
|
+
|
|
42
|
+
if config.build_rss:
|
|
43
|
+
rss_path = config.rss_path or os.path.join(config.post_dir, "rss.xml")
|
|
44
|
+
blog.build_rss(rss_path=rss_path)
|
|
45
|
+
|
|
46
|
+
if config.home_md:
|
|
47
|
+
home_html = blog.render_page(
|
|
48
|
+
content=text_file_to_string(config.home_md),
|
|
49
|
+
template_name=config.home_template,
|
|
50
|
+
meta={},
|
|
51
|
+
panargs=["--mathml"],
|
|
52
|
+
)
|
|
53
|
+
home_dir = os.path.dirname(config.home_output)
|
|
54
|
+
os.makedirs(home_dir, exist_ok=True)
|
|
55
|
+
with open(config.home_output, "w", encoding="utf-8") as f:
|
|
56
|
+
f.write(home_html)
|
|
57
|
+
|
|
58
|
+
return blog
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Command line interface for the static site generator."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from dataclasses import fields
|
|
9
|
+
|
|
10
|
+
try: # Python >= 3.11
|
|
11
|
+
import tomllib
|
|
12
|
+
except ModuleNotFoundError: # Python 3.10
|
|
13
|
+
import tomli as tomllib
|
|
14
|
+
|
|
15
|
+
from .builder import build_site
|
|
16
|
+
from .config import Config
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_config(path: str | None) -> Config:
|
|
20
|
+
"""Load a :class:`Config` from a TOML file, if given."""
|
|
21
|
+
if not path:
|
|
22
|
+
return Config()
|
|
23
|
+
with open(path, "rb") as f:
|
|
24
|
+
data = tomllib.load(f)
|
|
25
|
+
# Accept either a top-level table or a [tool.essayist] table.
|
|
26
|
+
cfg = data.get("essayist", data)
|
|
27
|
+
known = {f.name for f in fields(Config)}
|
|
28
|
+
kwargs = {k: v for k, v in cfg.items() if k in known}
|
|
29
|
+
base = os.path.dirname(os.path.abspath(path))
|
|
30
|
+
config = Config(**kwargs)
|
|
31
|
+
config.resolve(base)
|
|
32
|
+
return config
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
36
|
+
parser = argparse.ArgumentParser(
|
|
37
|
+
prog="essayist",
|
|
38
|
+
description="A Pandoc + Jinja2 static site generator.",
|
|
39
|
+
)
|
|
40
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
41
|
+
|
|
42
|
+
p_build = sub.add_parser("build", help="Build the static site.")
|
|
43
|
+
p_build.add_argument(
|
|
44
|
+
"-c", "--config", default="essayist.toml", help="Path to TOML config file."
|
|
45
|
+
)
|
|
46
|
+
p_build.add_argument("--markdown-dir", help="Directory with Markdown posts.")
|
|
47
|
+
p_build.add_argument("--post-dir", help="Output directory for posts.")
|
|
48
|
+
p_build.add_argument("--template-dir", help="Directory with Jinja2 templates.")
|
|
49
|
+
p_build.add_argument("--blogname", help="Blog name shown in page titles.")
|
|
50
|
+
p_build.add_argument("--site-url", help="Base URL used in RSS feeds.")
|
|
51
|
+
p_build.add_argument(
|
|
52
|
+
"--gallery", action="store_true", help="Enable the gallery lua filter."
|
|
53
|
+
)
|
|
54
|
+
p_build.set_defaults(func=_cmd_build)
|
|
55
|
+
|
|
56
|
+
sub.add_parser("version", help="Print the package version.").set_defaults(
|
|
57
|
+
func=_cmd_version
|
|
58
|
+
)
|
|
59
|
+
return parser
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _cmd_build(args: argparse.Namespace) -> int:
|
|
63
|
+
config = _load_config(args.config)
|
|
64
|
+
# CLI flags override the config file.
|
|
65
|
+
for key in ("markdown_dir", "post_dir", "template_dir", "blogname", "site_url"):
|
|
66
|
+
value = getattr(args, key, None)
|
|
67
|
+
if value:
|
|
68
|
+
setattr(config, key, value)
|
|
69
|
+
if args.gallery:
|
|
70
|
+
config.gallery = True
|
|
71
|
+
build_site(config)
|
|
72
|
+
print("Build complete")
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _cmd_version(args: argparse.Namespace) -> int:
|
|
77
|
+
from . import __version__
|
|
78
|
+
|
|
79
|
+
print(__version__)
|
|
80
|
+
return 0
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def main(argv: list[str] | None = None) -> int:
|
|
84
|
+
parser = build_parser()
|
|
85
|
+
args = parser.parse_args(argv)
|
|
86
|
+
return args.func(args)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
sys.exit(main())
|