Skip to content

Commit 602498c

Browse files
committed
add simple demo site w/ placeholder intergration
1 parent 1799b7c commit 602498c

9 files changed

Lines changed: 420 additions & 0 deletions

File tree

.github/workflows/deploy.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Deploy Demo Site
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: "pages"
15+
cancel-in-progress: false
16+
17+
jobs:
18+
deploy:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- uses: actions/setup-python@v5
24+
with:
25+
python-version: "3.12"
26+
27+
- name: Install dependencies
28+
run: |
29+
pip install mkdocs-material mkdocs-placeholder-plugin
30+
pip install -e .
31+
32+
- name: Build site
33+
run: mkdocs build
34+
35+
- name: Deploy to GitHub Pages
36+
uses: peaceiris/actions-gh-pages@v4
37+
with:
38+
github_token: ${{ secrets.GITHUB_TOKEN }}
39+
publish_dir: ./site
40+
cname: mkdocs-zip-bundle-plugin.daemonless.io

Makefile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
PYTHON = python3
2+
MKDOCS = NO_MKDOCS_2_WARNING=1 mkdocs
3+
4+
.PHONY: all build serve clean status help
5+
6+
all: build
7+
8+
help:
9+
@echo "Usage: make [target]"
10+
@echo ""
11+
@echo "Targets:"
12+
@echo " build Build the static site using mkdocs"
13+
@echo " serve Run local mkdocs development server"
14+
@echo " clean Remove build artifacts"
15+
@echo " status Show git status"
16+
17+
build:
18+
@echo "==> Building site with mkdocs..."
19+
$(MKDOCS) build
20+
21+
serve:
22+
$(MKDOCS) serve -a 0.0.0.0:8888
23+
24+
clean:
25+
@echo "==> Cleaning up..."
26+
rm -rf site/
27+
28+
status:
29+
git status

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ A MkDocs plugin that turns code blocks into downloadable files. Tag any code blo
44

55
Built to pair with [`mkdocs-placeholder-plugin`](https://github.com/six-two/mkdocs-placeholder-plugin): if your docs use interactive placeholders like `@PORT@`, the downloaded file will contain the user's actual values, not the defaults.
66

7+
**[Live demo → mkdocs-zip-bundle-plugin.daemonless.io](https://mkdocs-zip-bundle-plugin.daemonless.io)**
8+
79
## Features
810

911
- **Single file downloads** — one code block gets a direct raw file download, no ZIP needed

docs/CNAME

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mkdocs-zip-bundle-plugin.daemonless.io

docs/configuration.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Configuration
2+
3+
## Plugin options
4+
5+
```yaml
6+
plugins:
7+
- zip-bundle:
8+
include_jszip: true # Bundle JSZip — set false if you load it yourself
9+
zip_label_suffix: "(.zip)" # Suffix appended to multi-file bundle button labels
10+
```
11+
12+
| Option | Default | Description |
13+
|--------|---------|-------------|
14+
| `include_jszip` | `true` | Inject the bundled JSZip library. Set to `false` if you already load JSZip via `extra_javascript`. |
15+
| `zip_label_suffix` | `"(.zip)"` | Text appended to the auto-generated label for multi-file bundles. |
16+
17+
## Code block attributes
18+
19+
| Attribute | Required | Description |
20+
|-----------|----------|-------------|
21+
| `data-zip-bundle` | Yes | Bundle ID. Blocks with the same ID are grouped into one download. |
22+
| `data-zip-filename` | Yes | Filename inside the ZIP (or the downloaded filename for single files). Supports paths: `config/app.yaml`. |
23+
| `data-zip-label` | No | Override the auto-generated button label. |
24+
| `data-zip-force` | No | Set to `"true"` to always produce a ZIP even for a single file. |
25+
26+
## Required markdown extensions
27+
28+
```yaml
29+
markdown_extensions:
30+
- attr_list # Required — reads data-zip-* attributes on code blocks
31+
- pymdownx.superfences # Recommended for reliable fenced code block attribute support
32+
```
33+
34+
## Placeholder integration
35+
36+
Pair with [`mkdocs-placeholder-plugin`](https://github.com/six-two/mkdocs-placeholder-plugin) so downloaded files contain the user's live edited values instead of defaults:
37+
38+
```yaml
39+
plugins:
40+
- search
41+
- zip-bundle
42+
- placeholder:
43+
placeholder_file: placeholder-plugin.yaml
44+
```
45+
46+
The download button captures the **current rendered text** of the code block at click time — whatever the user has typed into the placeholder inputs is what ends up in the file.

docs/index.md

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# mkdocs-zip-bundle-plugin
2+
3+
Turn code blocks into **downloadable files** — directly from your MkDocs docs. Tag any fenced code block with a bundle ID and filename and the plugin injects a download button. Group multiple blocks under one ID to produce a **ZIP archive**. Pair with [`mkdocs-placeholder-plugin`](https://github.com/six-two/mkdocs-placeholder-plugin) and the downloaded files contain the reader's own values, not your defaults.
4+
5+
---
6+
7+
## Live demo
8+
9+
Edit the fields below. Every code block on this page updates live. Click any download button — the file you get has **your values** in it, not the defaults.
10+
11+
<div class="auto-input-table" data-columns="description,input"></div>
12+
13+
---
14+
15+
### Single file download
16+
17+
Add `data-zip-bundle` and `data-zip-filename` to a code block. The plugin injects a download button — no ZIP, just the raw file.
18+
19+
~~~markdown
20+
```yaml { data-zip-bundle="compose-only" data-zip-filename="compose.yaml" }
21+
services:
22+
@APP_NAME@:
23+
...
24+
```
25+
~~~
26+
27+
**Result:**
28+
29+
```yaml { data-zip-bundle="compose-only" data-zip-filename="compose.yaml" }
30+
services:
31+
@APP_NAME@:
32+
image: ghcr.io/example/@APP_NAME@:latest
33+
container_name: @APP_NAME@
34+
environment:
35+
- PUID=@PUID@
36+
- PGID=@PGID@
37+
- TZ=@TZ@
38+
ports:
39+
- "@PORT@:8080"
40+
volumes:
41+
- @CONFIG_PATH@:/config
42+
restart: unless-stopped
43+
```
44+
45+
---
46+
47+
### Multi-file ZIP bundle
48+
49+
Use the **same `data-zip-bundle` ID** on multiple blocks. The button appears after the last one and downloads all files as a single ZIP.
50+
51+
~~~markdown
52+
```yaml { data-zip-bundle="full-bundle" data-zip-filename="compose.yaml" }
53+
...
54+
```
55+
56+
```ini { data-zip-bundle="full-bundle" data-zip-filename="app.env" }
57+
...
58+
```
59+
60+
```bash { data-zip-bundle="full-bundle" data-zip-filename="setup.sh" }
61+
...
62+
```
63+
~~~
64+
65+
**Result:**
66+
67+
```yaml { data-zip-bundle="full-bundle" data-zip-filename="compose.yaml" }
68+
services:
69+
@APP_NAME@:
70+
image: ghcr.io/example/@APP_NAME@:latest
71+
container_name: @APP_NAME@
72+
environment:
73+
- PUID=@PUID@
74+
- PGID=@PGID@
75+
- TZ=@TZ@
76+
ports:
77+
- "@PORT@:8080"
78+
volumes:
79+
- @CONFIG_PATH@:/config
80+
restart: unless-stopped
81+
```
82+
83+
```ini { data-zip-bundle="full-bundle" data-zip-filename="app.env" }
84+
APP_NAME=@APP_NAME@
85+
HOST=@HOST_IP@
86+
PORT=@PORT@
87+
CONFIG_PATH=@CONFIG_PATH@
88+
TZ=@TZ@
89+
PUID=@PUID@
90+
PGID=@PGID@
91+
```
92+
93+
```bash { data-zip-bundle="full-bundle" data-zip-filename="setup.sh" }
94+
#!/bin/sh
95+
set -e
96+
97+
mkdir -p @CONFIG_PATH@
98+
chown @PUID@:@PGID@ @CONFIG_PATH@
99+
100+
podman compose up -d
101+
echo "Done. Access at http://@HOST_IP@:@PORT@"
102+
```
103+
104+
---
105+
106+
### Nested directories in the ZIP
107+
108+
Use paths as filenames — the plugin creates the directory structure inside the ZIP automatically.
109+
110+
~~~markdown
111+
```yaml { data-zip-bundle="nested" data-zip-filename="config/app.yaml" }
112+
...
113+
```
114+
115+
```bash { data-zip-bundle="nested" data-zip-filename="scripts/setup.sh" }
116+
...
117+
```
118+
~~~
119+
120+
**Result:**
121+
122+
```yaml { data-zip-bundle="nested" data-zip-filename="config/app.yaml" }
123+
server:
124+
host: @HOST_IP@
125+
port: @PORT@
126+
name: @APP_NAME@
127+
timezone: @TZ@
128+
```
129+
130+
```bash { data-zip-bundle="nested" data-zip-filename="scripts/setup.sh" }
131+
#!/bin/sh
132+
mkdir -p @CONFIG_PATH@/config
133+
cp config/app.yaml @CONFIG_PATH@/config/
134+
podman compose up -d
135+
```
136+
137+
---
138+
139+
### Custom button label
140+
141+
Use `data-zip-label` to override the auto-generated button text.
142+
143+
~~~markdown
144+
```yaml { data-zip-bundle="labeled" data-zip-filename="compose.yaml" data-zip-label="Download my config" }
145+
...
146+
```
147+
~~~
148+
149+
**Result:**
150+
151+
```yaml { data-zip-bundle="labeled" data-zip-filename="compose.yaml" data-zip-label="Download my config" }
152+
services:
153+
@APP_NAME@:
154+
image: ghcr.io/example/@APP_NAME@:latest
155+
ports:
156+
- "@PORT@:8080"
157+
```
158+
159+
---
160+
161+
## Installation
162+
163+
```bash
164+
pip install mkdocs-zip-bundle-plugin mkdocs-placeholder-plugin
165+
```
166+
167+
## Full setup
168+
169+
**`mkdocs.yml`**
170+
171+
```yaml
172+
markdown_extensions:
173+
- attr_list # required — reads data-zip-* attributes
174+
- pymdownx.superfences
175+
176+
plugins:
177+
- search
178+
- zip-bundle:
179+
include_jszip: true
180+
- placeholder:
181+
placeholder_file: placeholder-plugin.yaml
182+
```
183+
184+
**`placeholder-plugin.yaml`**
185+
186+
```yaml
187+
settings:
188+
normal_prefix: "@"
189+
normal_suffix: "@"
190+
auto_placeholder_tables: false # place the table manually where you want it
191+
192+
placeholders:
193+
APP_NAME:
194+
default: myapp
195+
description: Application name
196+
PORT:
197+
default: "8080"
198+
description: Application port
199+
HOST_IP:
200+
default: 192.168.1.100
201+
description: Host IP address
202+
```
203+
204+
**Your page**
205+
206+
Place the input table wherever you want it in your markdown:
207+
208+
```markdown
209+
<div class="auto-input-table" data-columns="description,input"></div>
210+
```
211+
212+
Then tag your code blocks. The download button is injected automatically. At click time, the button reads the **live rendered text** — so whatever the reader typed into the inputs is what ends up in the downloaded file.
213+
214+
[Configuration reference →](configuration.md){ .md-button }

mkdocs.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
site_name: mkdocs-zip-bundle-plugin
2+
site_url: https://mkdocs-zip-bundle-plugin.daemonless.io
3+
site_description: A MkDocs plugin that turns code blocks into downloadable ZIP bundles or raw files — placeholder-aware.
4+
repo_url: https://github.com/daemonless/mkdocs-zip-bundle-plugin
5+
repo_name: daemonless/mkdocs-zip-bundle-plugin
6+
7+
theme:
8+
name: material
9+
features:
10+
- navigation.tabs
11+
- navigation.top
12+
- content.code.copy
13+
- search.suggest
14+
15+
markdown_extensions:
16+
- attr_list
17+
- admonition
18+
- pymdownx.details
19+
- pymdownx.superfences
20+
- pymdownx.highlight:
21+
anchor_linenums: true
22+
- pymdownx.inlinehilite
23+
- tables
24+
- md_in_html
25+
26+
plugins:
27+
- search
28+
- zip-bundle:
29+
include_jszip: true
30+
- placeholder:
31+
placeholder_file: placeholder-plugin.yaml
32+
33+
nav:
34+
- Home: index.md
35+
- Configuration: configuration.md

0 commit comments

Comments
 (0)