Skip to main content

track/webui/
templates.rs

1//! MiniJinja template engine setup.
2
3use minijinja::{path_loader, AutoEscape, Environment};
4use std::path::PathBuf;
5use std::sync::Arc;
6
7/// Template engine wrapper
8pub struct Templates {
9    env: Environment<'static>,
10}
11
12impl Templates {
13    /// Create new template engine with templates from the given directory
14    #[allow(dead_code)]
15    pub fn new(template_dir: PathBuf) -> Self {
16        let mut env = Environment::new();
17        env.set_loader(path_loader(template_dir));
18        env.set_auto_escape_callback(|name| {
19            if name.ends_with(".html") {
20                AutoEscape::Html
21            } else {
22                AutoEscape::None
23            }
24        });
25
26        Self { env }
27    }
28
29    /// Create template engine with embedded templates (for distribution)
30    pub fn embedded() -> Self {
31        let mut env = Environment::new();
32        env.set_auto_escape_callback(|name| {
33            if name.ends_with(".html") {
34                AutoEscape::Html
35            } else {
36                AutoEscape::None
37            }
38        });
39
40        // Embed templates at compile time
41        env.add_template("base.html", include_str!("../../templates/base.html"))
42            .expect("Failed to add base.html template");
43        env.add_template("index.html", include_str!("../../templates/index.html"))
44            .expect("Failed to add index.html template");
45        env.add_template(
46            "partials/todo_list.html",
47            include_str!("../../templates/partials/todo_list.html"),
48        )
49        .expect("Failed to add todo_list.html template");
50        env.add_template(
51            "partials/scrap_list.html",
52            include_str!("../../templates/partials/scrap_list.html"),
53        )
54        .expect("Failed to add scrap_list.html template");
55        env.add_template(
56            "partials/description.html",
57            include_str!("../../templates/partials/description.html"),
58        )
59        .expect("Failed to add description.html template");
60        env.add_template(
61            "partials/ticket.html",
62            include_str!("../../templates/partials/ticket.html"),
63        )
64        .expect("Failed to add ticket.html template");
65        env.add_template(
66            "partials/links.html",
67            include_str!("../../templates/partials/links.html"),
68        )
69        .expect("Failed to add links.html template");
70        env.add_template(
71            "partials/repos.html",
72            include_str!("../../templates/partials/repos.html"),
73        )
74        .expect("Failed to add repos.html template");
75        env.add_template(
76            "partials/calendar.html",
77            include_str!("../../templates/partials/calendar.html"),
78        )
79        .expect("Failed to add calendar.html template");
80
81        Self { env }
82    }
83
84    /// Render a template with the given context
85    pub fn render<S: serde::Serialize>(&self, name: &str, ctx: S) -> anyhow::Result<String> {
86        let tmpl = self.env.get_template(name)?;
87        Ok(tmpl.render(ctx)?)
88    }
89}
90
91/// Thread-safe template engine
92pub type SharedTemplates = Arc<Templates>;