use crate::service::error::Error; use axum::response::Html; use minijinja::{path_loader, Environment, Value}; use minijinja_autoreload::AutoReloader; use pulldown_cmark::Event; use std::sync::Arc; #[derive(Clone)] pub struct Templates { pub reloader: Arc, } impl Templates { pub fn initialize() -> Result { let reloader = AutoReloader::new(move |notifier| { let mut environment = Environment::new(); let template_path = "templates"; environment.set_loader(path_loader(&template_path)); environment.add_filter("none", none); environment.add_filter("markdown", markdown); environment.add_filter("yesno", filter_yesno); environment.add_filter("table_keys", collect_unique_keys); environment.add_function("static", tpl_static); environment.add_function("url", tpl_url); environment.add_function("csrf_token", tpl_to_be_implemented); environment.add_function("translate", tpl_translate); notifier.watch_path(template_path, true); Ok(environment) }); Ok(Self { reloader: Arc::new(reloader), }) } pub fn render_template( &self, key: &str, data: D, ) -> Result { let env = self.reloader.acquire_env()?; let template = env.get_template(key)?; let rendered = template.render(&data)?; Ok(rendered) } pub fn render_html( &self, key: &str, data: D, ) -> Result, Error> { let result = self.render_template(key, data)?; Ok(Html(result)) } } fn markdown(value: String) -> Value { let mut options = pulldown_cmark::Options::empty(); options.insert(pulldown_cmark::Options::ENABLE_STRIKETHROUGH); options.insert(pulldown_cmark::Options::ENABLE_TABLES); options.insert(pulldown_cmark::Options::ENABLE_TASKLISTS); options.insert(pulldown_cmark::Options::ENABLE_SMART_PUNCTUATION); let parser = pulldown_cmark::Parser::new_ext(&value, options); let parser: Box> = Box::new(parser.into_iter()); let mut html = String::new(); pulldown_cmark::html::push_html(&mut html, parser); Value::from_safe_string(html) } fn filter_yesno(value: String, yesno: String) -> String { "".into() } fn tpl_url(value: String) -> Value { Value::from_safe_string(value.into()) } fn tpl_translate(value: String) -> Value { Value::from_safe_string(value.into()) } fn tpl_to_be_implemented(value: String) -> Value { Value::from_safe_string("