Static website for the Förderverein Windmühle Tündern e.V., the association restoring the historic windmill in Tündern.
Not a developer? See HOWTO.md. You describe the change in plain English to an AI assistant (OpenAI Codex in the ChatGPT desktop app, or Claude Code); it edits the files and opens a pull request for you to approve.
Prerequisite: install Zola.
zola build
./start-local.shThe local preview normally runs at http://127.0.0.1:1111. If the port is busy, pass another one through to Zola:
./start-local.sh --port 1112| Area | Path |
|---|---|
| Content, German default | content/ |
| Content, English | content/en/ |
| Content, Spanish | content/es/ |
| Templates | templates/ |
| Styles | sass/main.scss |
| Static images | static/imgs/ |
| Guided tours data | data/fuehrungen.toml |
| Utility scripts | scripts/ |
The site is trilingual: German (/), English (/en/) and Spanish (/es/). Every content or translation change must be made in all three languages.
zola build
./scripts/check-links.py
./start-local.shRun both before committing. zola build checks templates and frontmatter; it
resolves no link and no image path, so a green build says nothing about them.
Posts live in:
content/aktuelles/content/en/aktuelles/content/es/aktuelles/
Use the helper when starting from images or boilerplate:
./scripts/new-post.sh <slug> -s "Kurze Beschreibung."Useful options:
| Option | Meaning |
|---|---|
-d, --dir <path> |
Source image directory, defaults to local/imgs/ |
-t, --title <text> |
Post title |
-s, --summary <text> |
Frontmatter description |
-D, --date <YYYY-MM-DD> |
Post date, defaults to today |
Post filenames must be YYYY-MM-DD-<slug>.md. Zola derives page.date from the filename, so do not add a date field to frontmatter.
After scaffolding:
- Write the German post first.
- Mirror the same structure in English and Spanish.
- Group gallery images with
<div class="post-images">. - Keep
[extra] imageset to an existing image instatic/imgs/. - Ensure
static/imgs/thumbs/<image>.jpgexists for the selected hero image. - Run
zola build, then./scripts/check-links.py.
To swap a post hero image and regenerate thumbnails:
./scripts/make-thumb.sh static/imgs/<image>.jpgSee content/aktuelles/2026-04-17-einweihung-der-windmuehle.md for a structured example.
Tours are stored in data/fuehrungen.toml. Add one [[slots]] table per tour:
[[slots]]
date = "2026-06-14"
time = "14:00"
kind = "public"
status = "free"
guide = "Dirk"Fields:
| Field | Required | Notes |
|---|---|---|
date |
yes | YYYY-MM-DD, Europe/Berlin |
time |
yes | 24-hour HH:MM |
duration_min |
no | integer, defaults to 60 |
kind |
yes | "public", "private" or "event" (non-tour, e.g. a concert) |
status |
yes | "free", "booked" or "cancelled" |
guide |
no | first names only (tours) |
Private slots cannot be "free" and must not include family names, group names or other identifiers. They are rendered anonymously on the site.
Event slots (kind = "event") use title (required) plus optional location (venue when it is not the mill) and free_entry (bool). Add them by editing this file directly; new-tour.sh handles tours only.
After editing:
./scripts/validate-fuehrungen.py
zola build| Script | Purpose |
|---|---|
scripts/setup.sh |
Install the pinned Zola + Python deps (fresh machine, or Codex/CI sandbox) |
scripts/new-post.sh |
Scaffold trilingual Aktuelles posts, optimize images and create thumbnails |
scripts/make-thumb.sh |
Change a post hero image and regenerate its thumbnail |
scripts/optimize-imgs.sh |
Optimize source images |
scripts/new-tour.sh |
Append a guided tour slot |
scripts/validate-fuehrungen.py |
Validate data/fuehrungen.toml |
scripts/check-i18n.py |
Check translation parity |
scripts/check-links.py |
Resolve every link and image in public/ (run after zola build) |
scripts/mark-for-translation.sh |
Mark Markdown files in a directory for translation |
Script tests use bashunit:
./scripts/lib/bashunit scripts/testsAdd or update tests when changing script behavior.
- Keep German, English and Spanish content in sync.
- Preserve matching translation key order in
config.toml. - Use conventional commit messages.
- Edit AI assistant config under
.agents/, never the.claude/or root symlinks. - Run
zola buildand./scripts/check-links.pybefore committing. - One slug per post: recurring events carry the year (
pfingstmontag-2027).
AI instructions, skills and agents live once under .agents/ (plain Markdown). Each tool reads that single source through committed symlinks: Codex via root AGENTS.md, Claude Code via CLAUDE.md and .claude/. No build step.
See CONTRIBUTING.md and .agents/AGENTS.md for the full agent workflow, voice rules and post-writing guidance.