use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::fs;
use std::io::Error;
use tera::{Context, Tera};
use tracing::error;
static TEMPLATES: Lazy<Tera> = Lazy::new(|| {
let patterns = vec![
"crates/arc-app/src/resources/views/**/*", "src/resources/views/**/*", ];
for pattern in patterns {
match Tera::new(pattern) {
Ok(t) if t.get_template_names().next().is_some() => return t,
_ => continue,
}
}
error!("Fatal error: Could not find templates in any expected location");
::std::process::exit(1);
});
static MANIFEST_ASSETS: Lazy<HashMap<String, String>> = Lazy::new(parse_manifest_assets);
pub fn load_template(
template: &str,
params: Vec<(&str, &str)>,
assets: Option<Vec<&str>>,
) -> String {
let mut context: Context = Context::new();
for (key, value) in params.into_iter() {
context.insert(key, value);
}
if !context.contains_key("session_message") {
context.insert("session_message", "");
}
context.insert("assets", &get_assets_string(assets));
TEMPLATES
.render(template, &context)
.expect("Failed to render template")
}
fn get_assets_string(assets: Option<Vec<&str>>) -> String {
let mut assets_string: String = String::new();
if let Some(assets) = assets {
for value in assets.into_iter() {
let asset_type = value.split('.').next_back().unwrap();
if let Some(asset) = MANIFEST_ASSETS.get(value) {
if asset_type == "css" {
assets_string.push_str(&format!(
"<link rel=\"stylesheet\" href=\"/public/{}\">",
asset
));
} else if asset_type == "js" {
assets_string.push_str(&format!(
"<script src=\"/public/{}\" defer></script>",
asset
));
}
}
}
} else {
for value in MANIFEST_ASSETS.values() {
let asset_type = value.split('.').next_back().unwrap();
if asset_type == "css" {
assets_string.push_str(&format!(
"<link rel=\"stylesheet\" href=\"/public/{}\">",
value
));
} else if asset_type == "js" {
assets_string.push_str(&format!(
"<script src=\"/public/{}\" defer></script>",
value
));
}
}
}
assets_string
}
fn parse_manifest_assets() -> HashMap<String, String> {
let mut assets: HashMap<String, String> = HashMap::new();
let manifest: Result<String, Error> = fs::read_to_string("dist/.vite/manifest.json");
if let Ok(manifest) = manifest {
let manifest_json: serde_json::Value =
serde_json::from_str(&manifest).expect("Failed to parse manifest.json");
for (key, value) in manifest_json.as_object().unwrap().iter() {
if let Some(asset) = value.get("file") {
assets.insert(key.to_string(), asset.as_str().unwrap().parse().unwrap());
let asset_type = asset.as_str().unwrap().split('.').next_back().unwrap();
if asset_type == "js" {
if let Some(css_array) = value.get("css").and_then(|v| v.as_array()) {
for css_file in css_array {
let css_file_name =
css_file.as_str().unwrap().split('/').next_back().unwrap();
assets.insert(css_file_name.to_string(), css_file_name.to_string());
}
}
}
}
}
}
assets
}