feat(templates): add Tera runtime template engine

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.
This commit is contained in:
Timothy DeHerrera
2026-01-31 14:59:49 -07:00
parent 1bf265f14b
commit 3df7fda26a
14 changed files with 647 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
use crate::error::{Error, Result};
use gray_matter::{engine::YAML, Matter};
use serde::Serialize;
use std::fs;
use std::path::{Path, PathBuf};
@@ -19,7 +20,7 @@ pub enum ContentKind {
}
/// A navigation menu item discovered from the filesystem.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize)]
pub struct NavItem {
/// Display label (from nav_label or title)
pub label: String,
@@ -42,6 +43,10 @@ pub struct Frontmatter {
pub link_to: Option<String>,
/// Custom navigation label (defaults to title)
pub nav_label: Option<String>,
/// Section type for template dispatch (e.g., "blog", "projects")
pub section_type: Option<String>,
/// Override template for this content item
pub template: Option<String>,
}
/// A content item ready for rendering.
@@ -134,6 +139,8 @@ fn parse_frontmatter(path: &Path, parsed: &gray_matter::ParsedEntity) -> Result<
let weight = pod.get("weight").and_then(|v| v.as_i64().ok());
let link_to = pod.get("link_to").and_then(|v| v.as_string().ok());
let nav_label = pod.get("nav_label").and_then(|v| v.as_string().ok());
let section_type = pod.get("section_type").and_then(|v| v.as_string().ok());
let template = pod.get("template").and_then(|v| v.as_string().ok());
// Handle nested taxonomies.tags structure
let tags = if let Some(taxonomies) = pod.get("taxonomies") {
@@ -162,6 +169,8 @@ fn parse_frontmatter(path: &Path, parsed: &gray_matter::ParsedEntity) -> Result<
weight,
link_to,
nav_label,
section_type,
template,
})
}