zino_http/view/
minijinja.rs

1use convert_case::{Case, Casing};
2use minijinja::Environment;
3use std::sync::LazyLock;
4use zino_core::{
5    Map,
6    application::{Agent, Application},
7    error::Error,
8    extension::TomlTableExt,
9};
10
11/// Renders a template with the given data using [`minijinja`](https://crates.io/crates/minijinja).
12pub fn render(template_name: &str, data: Map) -> Result<String, Error> {
13    let template = SHARED_VIEW_ENGINE.get_template(template_name)?;
14    template.render(data).map_err(Error::from)
15}
16
17/// Shared view engine.
18static SHARED_VIEW_ENGINE: LazyLock<Environment> = LazyLock::new(|| {
19    let app_state = Agent::shared_state();
20    let mut template_dir = "templates";
21    if let Some(view) = app_state.get_config("view") {
22        if let Some(dir) = view.get_str("template-dir") {
23            template_dir = dir;
24        }
25    }
26
27    let mut view_engine = Environment::new();
28    let app_env = app_state.env();
29    let template_dir = Agent::parse_path(template_dir);
30    view_engine.set_debug(app_env.is_dev());
31    view_engine.set_loader(minijinja::path_loader(template_dir));
32    view_engine.add_global("APP_ENV", app_env.as_str());
33    for (key, value) in app_state.data() {
34        if let Some(value) = value.as_str() {
35            let key = key.replace('.', "_").to_case(Case::UpperSnake);
36            view_engine.add_global(key, value);
37        }
38    }
39    view_engine
40});