stapler-ssg 0.1.2__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.
@@ -0,0 +1,24 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.11"
19
+
20
+ - run: pip install build
21
+
22
+ - run: python -m build
23
+
24
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,2 @@
1
+ __pycache__/
2
+ .ruff_cache
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ serve() {
4
+ .venv/bin/python -m stapler serve
5
+ }
6
+
7
+ build() {
8
+ .venv/bin/python -m stapler build
9
+ }
10
+
11
+ format() {
12
+ ruff format .
13
+ }
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
@@ -0,0 +1,284 @@
1
+ Metadata-Version: 2.4
2
+ Name: stapler-ssg
3
+ Version: 0.1.2
4
+ Summary: Simple Jinja-based static site generator
5
+ Project-URL: Homepage, https://github.com/gijs6/stapler
6
+ Project-URL: Repository, https://github.com/gijs6/stapler
7
+ Author-email: Gijs6 <me@gijs6.nl>
8
+ License: Unlicense
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: colorama>=0.4.6
12
+ Requires-Dist: feedgen>=1.0.0
13
+ Requires-Dist: jinja2>=3.1.0
14
+ Requires-Dist: markdown>=3.5.0
15
+ Requires-Dist: pyyaml>=6.0
16
+ Requires-Dist: watchdog>=3.0.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Stapler
22
+
23
+ A simple static site generator built with Jinja and Markdown.
24
+
25
+ ## Installation
26
+
27
+ Clone the repo:
28
+
29
+ ```bash
30
+ git clone https://github.com/gijs6/stapler.git
31
+ cd stapler
32
+ ```
33
+
34
+ Create a virtual environment (recommended):
35
+
36
+ ```bash
37
+ python -m venv .venv
38
+ source .venv/bin/activate
39
+ ```
40
+
41
+ Install:
42
+
43
+ ```bash
44
+ pip install -e .
45
+ ```
46
+
47
+ Or with dev dependencies:
48
+
49
+ ```bash
50
+ pip install -e ".[dev]"
51
+ ```
52
+
53
+ ## Quick start
54
+
55
+ 1. Create a `stapler.toml` in your project root:
56
+
57
+ ```toml
58
+ [site]
59
+ url = "https://yoursite.com"
60
+ title = "Your site"
61
+ ```
62
+
63
+ 2. Put your content in a `site/` directory (the default). Templates go in `site/templates/`.
64
+
65
+ 3. Run:
66
+
67
+ ```bash
68
+ stapler serve # local dev server on port 8000
69
+ stapler build # production build
70
+ ```
71
+
72
+ ## Configuration
73
+
74
+ ### Required
75
+
76
+ ```toml
77
+ [site]
78
+ url = "https://yoursite.com"
79
+ title = "Your site"
80
+ ```
81
+
82
+ ### Optional
83
+
84
+ #### Site metadata
85
+
86
+ ```toml
87
+ [site]
88
+ description = "About your site"
89
+ base_path = "/blog" # Deploy to example.com/blog instead of the root
90
+ ```
91
+
92
+ #### Author info
93
+
94
+ Used in RSS/Atom feeds.
95
+
96
+ ```toml
97
+ [site.author]
98
+ name = "Your name"
99
+ email = "you@example.com"
100
+ ```
101
+
102
+ #### Directories
103
+
104
+ All paths are relative to where you run `stapler`.
105
+
106
+ ```toml
107
+ [directories]
108
+ site = "site" # Content directory (default: "site")
109
+ build = "build" # Production output (default: "build")
110
+ build_dev = "build-dev" # Dev server output (default: "build-dev")
111
+ templates = "templates" # Templates folder inside the site directory (default: "templates")
112
+ blog = "blog" # Blog posts folder inside the site directory (default: "blog")
113
+ ```
114
+
115
+ #### Default template
116
+
117
+ The template used for HTML pages that have front matter but no `template` field.
118
+
119
+ ```toml
120
+ [templates]
121
+ default = "base.html"
122
+ ```
123
+
124
+ #### Blog
125
+
126
+ ```toml
127
+ [features.blog]
128
+ enabled = true # Enable blog functionality (default: false)
129
+ template = "blog_post.html" # Template for individual posts
130
+ index_template = "blog_index.html" # Template for the blog index page
131
+ ```
132
+
133
+ #### Sitemap and feeds
134
+
135
+ ```toml
136
+ [features]
137
+ sitemap = true # Generate sitemap.xml (default: true)
138
+
139
+ [features.feeds]
140
+ rss = true # Generate rss.xml (default: true)
141
+ atom = true # Generate atom.xml (default: true)
142
+ ```
143
+
144
+ Feeds are only generated when the blog feature is enabled.
145
+
146
+ #### Markdown extensions
147
+
148
+ ```toml
149
+ [markdown]
150
+ extensions = ["meta", "tables", "fenced_code"] # Python-Markdown extensions
151
+ ```
152
+
153
+ ## How it works
154
+
155
+ ### Pages
156
+
157
+ Any `.html` or `.md` file in your site directory (excluding the templates and blog folders) becomes a page.
158
+
159
+ #### Markdown files
160
+
161
+ Markdown files are always rendered to HTML. If the front matter includes a `template` field, the result is passed to that template as `page.content`. Without a `template` field (or without front matter entirely), the raw HTML is written directly.
162
+
163
+ ```markdown
164
+ ---
165
+ template: base.html
166
+ title: My page
167
+ ---
168
+
169
+ # Content
170
+
171
+ Regular markdown here
172
+ ```
173
+
174
+ #### HTML files
175
+
176
+ HTML files with front matter are rendered through a template. The `template` field in front matter takes precedence; if omitted, the default template from `[templates].default` is used.
177
+
178
+ ```html
179
+ ---
180
+ title: My page
181
+ ---
182
+ <h1>Content here</h1>
183
+ ```
184
+
185
+ HTML files without front matter are treated as Jinja templates directly:
186
+
187
+ ```html
188
+ {% extends "base.html" %}
189
+ {% block content %}
190
+ <h1>Hello</h1>
191
+ {% endblock %}
192
+ ```
193
+
194
+ Front matter is YAML. All fields are available as `page.metadata.<field>` in your templates.
195
+
196
+ #### Static files
197
+
198
+ Anything that's not a `.html` or `.md` file (and not in your templates or blog folder) is copied as-is to the output directory.
199
+
200
+ ### Blog
201
+
202
+ Enable the blog feature in your config, then put `.md` files in your blog directory.
203
+
204
+ ```markdown
205
+ ---
206
+ title: My post
207
+ date: 2025-01-15
208
+ ---
209
+
210
+ Post content here
211
+ ```
212
+
213
+ The `date` field is optional. If omitted, stapler tries to infer it from the file's git history.
214
+
215
+ ### Templates
216
+
217
+ Templates live in the directory you configured (default: `site/templates/`).
218
+
219
+ #### Available in all templates
220
+
221
+ - `data`: build info
222
+ - `data.now`: current build time
223
+ - `data.now.date.long`: date as `%B %d, %Y` (e.g. `April 12, 2026`)
224
+ - `data.now.date.short`: date as `%Y-%m-%d` (e.g. `2026-04-12`)
225
+ - `data.now.time`: time as `%H:%M:%S`
226
+ - `data.now.iso`: datetime as ISO 8601
227
+ - `data.last_commit`: last git commit info (`None` if not in a git repo)
228
+ - `data.last_commit.hash.short`: short 7-character commit hash
229
+ - `data.last_commit.hash.long`: full commit hash
230
+ - `data.last_commit.dt.date.long`: date as `%B %d, %Y` (e.g. `April 12, 2026`)
231
+ - `data.last_commit.dt.date.short`: date as `%Y-%m-%d` (e.g. `2026-04-12`)
232
+ - `data.last_commit.dt.time`: time as `%H:%M:%S`
233
+ - `data.last_commit.dt.iso`: datetime as ISO 8601
234
+
235
+ #### Regular page templates
236
+
237
+ - `page`: the current page
238
+ - `page.active_page`: identifier derived from the filename (e.g. `about` for `about.html`, `home` for `index.html`), useful for highlighting the active nav item
239
+ - `page.canonical_path`: URL path of the page (e.g. `/about`)
240
+ - `page.content`: page content as HTML (only present if the page has front matter)
241
+ - `page.metadata.<field>`: any front matter field (e.g. `page.metadata.title`)
242
+
243
+ #### Blog post template
244
+
245
+ - `page`: navigation info
246
+ - `page.active_page`: name of the blog directory (e.g. `blog`)
247
+ - `page.canonical_path`: URL path of the post (e.g. `/blog/my-post`)
248
+ - `post`: the current blog post
249
+ - `post.title`: post title (from front matter, or derived from the filename)
250
+ - `post.slug`: URL slug (filename without `.md`)
251
+ - `post.content`: post content as HTML
252
+ - `post.date`: date as `%Y-%m-%d` (e.g. `2026-04-12`), only set if a date is available
253
+ - `post.date_iso`: date as ISO 8601, only set if a date is available
254
+ - `data`: same as above
255
+
256
+ #### Blog index template
257
+
258
+ - `page`: navigation info
259
+ - `page.active_page`: name of the blog directory (e.g. `blog`)
260
+ - `page.canonical_path`: URL path of the blog index (e.g. `/blog`)
261
+ - `posts`: list of all blog posts sorted newest first; each item has the same fields as `post` above
262
+ - `data`: same as above
263
+
264
+ ## CLI
265
+
266
+ ```bash
267
+ # Build with default config (stapler.toml)
268
+ stapler build
269
+
270
+ # Build with custom config
271
+ stapler build -c myconfig.toml
272
+
273
+ # Serve on default port (8000)
274
+ stapler serve
275
+
276
+ # Serve on custom port
277
+ stapler serve -p 3000
278
+
279
+ # Serve with custom config and port
280
+ stapler serve -c myconfig.toml -p 3000
281
+
282
+ # Show version
283
+ stapler --version
284
+ ```
@@ -0,0 +1,264 @@
1
+ # Stapler
2
+
3
+ A simple static site generator built with Jinja and Markdown.
4
+
5
+ ## Installation
6
+
7
+ Clone the repo:
8
+
9
+ ```bash
10
+ git clone https://github.com/gijs6/stapler.git
11
+ cd stapler
12
+ ```
13
+
14
+ Create a virtual environment (recommended):
15
+
16
+ ```bash
17
+ python -m venv .venv
18
+ source .venv/bin/activate
19
+ ```
20
+
21
+ Install:
22
+
23
+ ```bash
24
+ pip install -e .
25
+ ```
26
+
27
+ Or with dev dependencies:
28
+
29
+ ```bash
30
+ pip install -e ".[dev]"
31
+ ```
32
+
33
+ ## Quick start
34
+
35
+ 1. Create a `stapler.toml` in your project root:
36
+
37
+ ```toml
38
+ [site]
39
+ url = "https://yoursite.com"
40
+ title = "Your site"
41
+ ```
42
+
43
+ 2. Put your content in a `site/` directory (the default). Templates go in `site/templates/`.
44
+
45
+ 3. Run:
46
+
47
+ ```bash
48
+ stapler serve # local dev server on port 8000
49
+ stapler build # production build
50
+ ```
51
+
52
+ ## Configuration
53
+
54
+ ### Required
55
+
56
+ ```toml
57
+ [site]
58
+ url = "https://yoursite.com"
59
+ title = "Your site"
60
+ ```
61
+
62
+ ### Optional
63
+
64
+ #### Site metadata
65
+
66
+ ```toml
67
+ [site]
68
+ description = "About your site"
69
+ base_path = "/blog" # Deploy to example.com/blog instead of the root
70
+ ```
71
+
72
+ #### Author info
73
+
74
+ Used in RSS/Atom feeds.
75
+
76
+ ```toml
77
+ [site.author]
78
+ name = "Your name"
79
+ email = "you@example.com"
80
+ ```
81
+
82
+ #### Directories
83
+
84
+ All paths are relative to where you run `stapler`.
85
+
86
+ ```toml
87
+ [directories]
88
+ site = "site" # Content directory (default: "site")
89
+ build = "build" # Production output (default: "build")
90
+ build_dev = "build-dev" # Dev server output (default: "build-dev")
91
+ templates = "templates" # Templates folder inside the site directory (default: "templates")
92
+ blog = "blog" # Blog posts folder inside the site directory (default: "blog")
93
+ ```
94
+
95
+ #### Default template
96
+
97
+ The template used for HTML pages that have front matter but no `template` field.
98
+
99
+ ```toml
100
+ [templates]
101
+ default = "base.html"
102
+ ```
103
+
104
+ #### Blog
105
+
106
+ ```toml
107
+ [features.blog]
108
+ enabled = true # Enable blog functionality (default: false)
109
+ template = "blog_post.html" # Template for individual posts
110
+ index_template = "blog_index.html" # Template for the blog index page
111
+ ```
112
+
113
+ #### Sitemap and feeds
114
+
115
+ ```toml
116
+ [features]
117
+ sitemap = true # Generate sitemap.xml (default: true)
118
+
119
+ [features.feeds]
120
+ rss = true # Generate rss.xml (default: true)
121
+ atom = true # Generate atom.xml (default: true)
122
+ ```
123
+
124
+ Feeds are only generated when the blog feature is enabled.
125
+
126
+ #### Markdown extensions
127
+
128
+ ```toml
129
+ [markdown]
130
+ extensions = ["meta", "tables", "fenced_code"] # Python-Markdown extensions
131
+ ```
132
+
133
+ ## How it works
134
+
135
+ ### Pages
136
+
137
+ Any `.html` or `.md` file in your site directory (excluding the templates and blog folders) becomes a page.
138
+
139
+ #### Markdown files
140
+
141
+ Markdown files are always rendered to HTML. If the front matter includes a `template` field, the result is passed to that template as `page.content`. Without a `template` field (or without front matter entirely), the raw HTML is written directly.
142
+
143
+ ```markdown
144
+ ---
145
+ template: base.html
146
+ title: My page
147
+ ---
148
+
149
+ # Content
150
+
151
+ Regular markdown here
152
+ ```
153
+
154
+ #### HTML files
155
+
156
+ HTML files with front matter are rendered through a template. The `template` field in front matter takes precedence; if omitted, the default template from `[templates].default` is used.
157
+
158
+ ```html
159
+ ---
160
+ title: My page
161
+ ---
162
+ <h1>Content here</h1>
163
+ ```
164
+
165
+ HTML files without front matter are treated as Jinja templates directly:
166
+
167
+ ```html
168
+ {% extends "base.html" %}
169
+ {% block content %}
170
+ <h1>Hello</h1>
171
+ {% endblock %}
172
+ ```
173
+
174
+ Front matter is YAML. All fields are available as `page.metadata.<field>` in your templates.
175
+
176
+ #### Static files
177
+
178
+ Anything that's not a `.html` or `.md` file (and not in your templates or blog folder) is copied as-is to the output directory.
179
+
180
+ ### Blog
181
+
182
+ Enable the blog feature in your config, then put `.md` files in your blog directory.
183
+
184
+ ```markdown
185
+ ---
186
+ title: My post
187
+ date: 2025-01-15
188
+ ---
189
+
190
+ Post content here
191
+ ```
192
+
193
+ The `date` field is optional. If omitted, stapler tries to infer it from the file's git history.
194
+
195
+ ### Templates
196
+
197
+ Templates live in the directory you configured (default: `site/templates/`).
198
+
199
+ #### Available in all templates
200
+
201
+ - `data`: build info
202
+ - `data.now`: current build time
203
+ - `data.now.date.long`: date as `%B %d, %Y` (e.g. `April 12, 2026`)
204
+ - `data.now.date.short`: date as `%Y-%m-%d` (e.g. `2026-04-12`)
205
+ - `data.now.time`: time as `%H:%M:%S`
206
+ - `data.now.iso`: datetime as ISO 8601
207
+ - `data.last_commit`: last git commit info (`None` if not in a git repo)
208
+ - `data.last_commit.hash.short`: short 7-character commit hash
209
+ - `data.last_commit.hash.long`: full commit hash
210
+ - `data.last_commit.dt.date.long`: date as `%B %d, %Y` (e.g. `April 12, 2026`)
211
+ - `data.last_commit.dt.date.short`: date as `%Y-%m-%d` (e.g. `2026-04-12`)
212
+ - `data.last_commit.dt.time`: time as `%H:%M:%S`
213
+ - `data.last_commit.dt.iso`: datetime as ISO 8601
214
+
215
+ #### Regular page templates
216
+
217
+ - `page`: the current page
218
+ - `page.active_page`: identifier derived from the filename (e.g. `about` for `about.html`, `home` for `index.html`), useful for highlighting the active nav item
219
+ - `page.canonical_path`: URL path of the page (e.g. `/about`)
220
+ - `page.content`: page content as HTML (only present if the page has front matter)
221
+ - `page.metadata.<field>`: any front matter field (e.g. `page.metadata.title`)
222
+
223
+ #### Blog post template
224
+
225
+ - `page`: navigation info
226
+ - `page.active_page`: name of the blog directory (e.g. `blog`)
227
+ - `page.canonical_path`: URL path of the post (e.g. `/blog/my-post`)
228
+ - `post`: the current blog post
229
+ - `post.title`: post title (from front matter, or derived from the filename)
230
+ - `post.slug`: URL slug (filename without `.md`)
231
+ - `post.content`: post content as HTML
232
+ - `post.date`: date as `%Y-%m-%d` (e.g. `2026-04-12`), only set if a date is available
233
+ - `post.date_iso`: date as ISO 8601, only set if a date is available
234
+ - `data`: same as above
235
+
236
+ #### Blog index template
237
+
238
+ - `page`: navigation info
239
+ - `page.active_page`: name of the blog directory (e.g. `blog`)
240
+ - `page.canonical_path`: URL path of the blog index (e.g. `/blog`)
241
+ - `posts`: list of all blog posts sorted newest first; each item has the same fields as `post` above
242
+ - `data`: same as above
243
+
244
+ ## CLI
245
+
246
+ ```bash
247
+ # Build with default config (stapler.toml)
248
+ stapler build
249
+
250
+ # Build with custom config
251
+ stapler build -c myconfig.toml
252
+
253
+ # Serve on default port (8000)
254
+ stapler serve
255
+
256
+ # Serve on custom port
257
+ stapler serve -p 3000
258
+
259
+ # Serve with custom config and port
260
+ stapler serve -c myconfig.toml -p 3000
261
+
262
+ # Show version
263
+ stapler --version
264
+ ```
@@ -0,0 +1,2 @@
1
+ build/
2
+ build-dev/
@@ -0,0 +1,6 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <h1>about</h1>
5
+ <p>this is the about page</p>
6
+ {% endblock %}
@@ -0,0 +1,25 @@
1
+ body {
2
+ font-family: system-ui, sans-serif;
3
+ line-height: 1.6;
4
+ max-width: 800px;
5
+ margin: 0 auto;
6
+ padding: 20px;
7
+ }
8
+
9
+ nav {
10
+ margin-bottom: 40px;
11
+ }
12
+
13
+ nav a {
14
+ margin-right: 20px;
15
+ }
16
+
17
+ article {
18
+ margin-bottom: 40px;
19
+ }
20
+
21
+ footer {
22
+ margin-top: 80px;
23
+ padding-top: 20px;
24
+ border-top: 1px solid #ccc;
25
+ }
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: getting started
3
+ date: 2025-01-16
4
+ ---
5
+
6
+ # getting started with stapler
7
+
8
+ here's how to get started with your own stapler site.
9
+
10
+ ## create a config
11
+
12
+ create `stapler.toml`:
13
+
14
+ ```toml
15
+ [site]
16
+ url = "https://yoursite.com"
17
+ title = "your site"
18
+ ```
19
+
20
+ ## add content
21
+
22
+ create a `site/` folder and put your content there. that's it!
23
+
24
+ ## build
25
+
26
+ run `stapler build` to build your site, or `stapler serve` for a dev server.
@@ -0,0 +1,19 @@
1
+ ---
2
+ title: welcome to stapler
3
+ date: 2025-01-15
4
+ ---
5
+
6
+ # welcome to stapler
7
+
8
+ this is the first example blog post. stapler is a simple static site generator built with python.
9
+
10
+ ## features
11
+
12
+ - jinja2 templating
13
+ - markdown support
14
+ - blog with rss/atom feeds
15
+ - dev server with live reload
16
+
17
+ ## getting started
18
+
19
+ check out the [README](https://github.com/gijs6/stapler) for installation instructions.
@@ -0,0 +1,6 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <h1>welcome to stapler</h1>
5
+ <p>this is an example site built with stapler</p>
6
+ {% endblock %}