Markdown-based static site publishing — no server, no database required. Write in markdown, build with Python, deploy anywhere.
Find a file
Claude 71bda790ef
Overhaul topbar navigation with grouped dropdowns
Topbar now shows two item types intermixed by sort order:
- Unsectioned pages grouped by sort century: lowest sort = top-level
  link, others fold out in a dropdown beneath it
- Sections: appear as named triggers; pages fold out on hover/click;
  hidden sections require click to expand, visible sections also open
  on hover; draft sections excluded entirely

Desktop: hover or click to open dropdown, small ▾ caret indicates
nested items, parent link highlighted when a child page is active.
Mobile: slide-in panel with accordion expand/collapse per group,
+ / − toggle button on each group that has children.

https://claude.ai/code/session_013A4egzphocyto9bvZ76dxf
2026-05-09 14:03:11 +00:00
.github/workflows Opt into Node.js 24 for GitHub Actions 2026-05-08 17:10:02 +00:00
app Overhaul topbar navigation with grouped dropdowns 2026-05-09 14:03:11 +00:00
docs Fix install.md: install from GitHub until mdcms is on PyPI 2026-05-09 01:19:53 +07:00
samplesite Update post listing tags to use created field throughout 2026-05-09 13:41:00 +00:00
.gitignore v0.2.2 migrated to GitHub 2026-04-20 00:02:43 +07:00
CLAUDE.md Update post listing tags to use created field throughout 2026-05-09 13:41:00 +00:00
CONTRIBUTING.md Add LICENSE, CONTRIBUTING.md, and SECURITY.md 2026-05-09 02:55:19 +00:00
LICENSE Add LICENSE, CONTRIBUTING.md, and SECURITY.md 2026-05-09 02:55:19 +00:00
mdcms.py Remove date and datetime frontmatter fields, consolidate to created 2026-05-09 13:37:36 +00:00
pyproject.toml Fix build backend: use setuptools.build_meta instead of legacy 2026-05-09 01:26:10 +07:00
README.md Update README.md 2026-05-09 12:29:43 +07:00
SECURITY.md Add LICENSE, CONTRIBUTING.md, and SECURITY.md 2026-05-09 02:55:19 +00:00

MD-CMS

Markdown-based static site publishing

MD-CMS lets you write and publish a website entirely in markdown. Drop your .md files in a folder, run the build tool, upload the output to any static host, and you're done. All rendering happens in the browser.


Installation

  1. Download the latest release for your

How it works

MD-CMS has two parts:

index.html — a single-file browser renderer. It reads your markdown files, config, and navigation at runtime and renders everything client-side. No build pipeline, no framework, no compilation step.

mdcms.py — a zero-dependency Python CLI tool. It scans your content, generates nav.yml and search.json, validates your config, and packages everything into a zip file ready for upload.


Features

  • Write in markdown — pages and posts with YAML frontmatter
  • Categories — serve multiple versions of the same page (e.g. languages, destinations, variants) via ?cat= URL parameter and a dropdown UI
  • Sections — nested navigation defined in nav.yml; pages declare their section via frontmatter
  • Full-text search — category-aware, generated at build time
  • Dynamic content tags — embed post lists with date sorting, pagination, and year grouping using fenced mdcms code blocks
  • RTL support — per-category text direction
  • Custom fonts per category — load a font file from assets/fonts/ when a category is selected
  • Light and dark mode — fully themeable via config.yml
  • No server required — everything is static; deploy to GitHub Pages, Codeberg Pages, Cloudflare Pages, Netlify, or any file host
  • Zero dependenciesmdcms.py uses only the Python standard library

File structure

mdcms.py          ← build tool, run this
quickstart.md     ← getting started guide
website/          ← everything in here gets deployed
  index.html
  config.yml
  nav.yml
  search.json
  pages/
    home.md
    about.md
    about.nb.md   ← Norwegian variant of about.md
  posts/
    2025-01-01-my-first-post.md
  assets/
    images/
    fonts/

The website/ folder is your deployable site. mdcms.py lives outside it.


Getting started

Requirements: Python 3 (standard library only). A modern browser.

  1. Clone or download this repository.
  2. Run python3 mdcms.py and choose option 2 to build your config and folder structure from scratch.
  3. Write your pages in website/pages/ and posts in website/posts/.
  4. Run mdcms.py again and choose option 3 to generate nav.yml and search.json.
  5. Choose option 8 to start a local webserver and preview your site.
  6. When ready to publish, choose option 1 to validate, build, and export website.zip.
  7. Upload the contents of website.zip to your static host.

Local preview note: Open index.html via the built-in webserver (option 8), not by double-clicking the file. Browsers block local file access due to CORS restrictions.


Configuration

Site behaviour is controlled by two YAML files in website/:

config.yml — site title, logo, default page, search settings, typography, layout dimensions, light/dark theme colours, and category definitions.

nav.yml — navigation structure. Sections are defined here; pages declare their section via section-id in frontmatter. Sections can be nested.

Both files are human-readable and comment-supported. The mdcms.py wizard generates them for you and can fill in missing values interactively.


Categories

Categories let you publish multiple versions of the same page — different languages, regions, or product variants — under a single URL with a ?cat= parameter.

Each variant is a separate file:

about.md          ← default
about.en-gb.md    ← British English variant
about.nb.md       ← Norwegian variant

The category dropdown shows only categories for which a variant exists (or where a "not available" message is configured). All internal links preserve the active category.


Tag system

Embed dynamic post lists in any page using fenced mdcms code blocks:

```mdcms
posts-date-reversechronological
limit: 10
paginate: yes
```

Available tags cover chronological and reverse-chronological post lists, grouped by year, with date or datetime display, and configurable pagination.


Licence

Apache 2.0 — see LICENCE.

© Kristian Benestad