Replace hand-rolled YAML parser (70 lines) with serde-backed
toml::from_str<Frontmatter> (6 lines). Frontmatter delimiter
changes from --- to +++ (Hugo TOML convention).
New Frontmatter fields:
- draft: bool (#[serde(default)]) for draft filtering
- aliases: Vec<String> (#[serde(default)]) for URL redirects
Date field upgraded from Option<String> to Option<NaiveDate>
with custom deserializer for TOML native dates. Parse, don't
validate: invalid dates now fail at deserialization time.
Add chrono dependency with serde feature. Update cascade in
sitemap.rs (NaiveDate→String at boundary), template_engine.rs
(FrontmatterContext gains draft/aliases), and all 14 tests.
BREAKING CHANGE: Content files must use +++ TOML frontmatter
instead of --- YAML frontmatter.
- content: DEFAULT_WEIGHT, DEFAULT_WEIGHT_HIGH → pub(crate)
- sitemap: SitemapEntry → pub(crate)
These items are implementation details not exposed to consumers.
- Create escape.rs with shared html_escape, html_escape_into, xml_escape
- Remove duplicate implementations from render.rs, highlight.rs, feed.rs, sitemap.rs
- Add DEFAULT_WEIGHT (50) and DEFAULT_WEIGHT_HIGH (99) constants to content.rs
- Replace all magic number weight defaults with named constants
No functional changes; all 67 tests pass.
- Add Anchor struct with id, label, level fields
- markdown_to_html() now returns (String, Vec<Anchor>) tuple
- Headings h2-h6 are extracted with slugified IDs
- Add toc: bool frontmatter field for per-page TOC opt-in
- All heading tags now include id attributes for anchor links
Extend NavItem struct with children field to support nested navigation.
discover_nav() now populates children for section items by collecting
section pages via Section::collect_items() and mapping them to child
NavItem entries. Children are sorted by weight then alphabetically.
Introduce SiteManifest struct that aggregates all site content from a
single discovery pass:
- homepage: content/_index.md
- sections: directories with _index.md
- pages: top-level standalone .md files
- posts: blog section items (sorted by date for feed)
- nav: navigation menu items
Add discover_pages() helper and 5 unit tests covering homepage,
sections, pages, posts, and nav discovery.
Not yet integrated into main.rs pipeline.
Fully migrate from compile-time maud templates to runtime Tera:
- Rewrote main.rs to use TemplateEngine and discover_sections()
- Replaced hardcoded blog/projects with generic section loop
- Added Clone derive to Frontmatter and Content
- Fixed section_type dispatch via Section struct
- Deleted src/templates.rs, removed maud dependency
Users can now add sections without code changes.
Enable generic section processing by adding:
- Section struct with index, name, section_type, path
- Section::collect_items() to gather content in a section
- discover_sections() to find all directories with _index.md
Section type is determined from frontmatter `section_type` field,
falling back to directory name. Includes 5 unit tests.
Lay groundwork for user-editable templates by adding Tera as a
runtime template engine alongside the existing maud templates.
Changes:
- Add tera dependency
- Create TemplateEngine struct with render methods
- Add TemplateLoad/TemplateRender error variants
- Add section_type/template fields to Frontmatter
- Create templates/ directory with base, page, section, and content templates
Dead code warnings are expected; TemplateEngine will be wired
in to replace maud in subsequent commits.
Add NavItem struct and discover_nav() function to scan content
directory and automatically build navigation from:
- Top-level .md files (pages)
- Directories with _index.md (sections)
Navigation is sorted by frontmatter weight, then alphabetically.
Custom nav_label field allows overriding title in nav menu.
Includes 5 unit tests covering page/section discovery, weight
ordering, and nav_label support.
- src/content.rs: output_path() now returns slug.html instead of
slug/index.html for regular content.
- src/templates.rs: All hrefs use explicit .html extension.
Nav links point to index.html, blog.index.html, about.html.
Blog post links use ./slug.html format.
- src/main.rs: Adjust depth values (root=0, blog posts=1).
No more directory-per-page overhead. file:// navigation works
without directory listings. True suckless structure.
Add minimal e2e pipeline to transform content → HTML:
- src/error.rs: Custom error types with thiserror
- src/content.rs: YAML frontmatter parsing via gray_matter
- src/render.rs: Markdown → HTML via pulldown-cmark
- src/templates.rs: Maud templates for base layout and posts
- src/main.rs: Pipeline orchestrator
All 15 blog posts successfully rendered to public/blog/*/index.html.
Added thiserror and walkdir dependencies.
Added public/ and DepMap fragment to .gitignore and AGENTS.md.