laterite_web/theme/
build.rs1use super::engine::Engine;
6use super::router::Params;
7use super::{site, store, Kind, ThemeError};
8use crate::StaticSite;
9use laterite_core::Db;
10use std::path::Path;
11
12#[derive(Debug, Default, Clone, PartialEq, Eq)]
14pub struct BuildReport {
15 pub pages: Vec<String>,
17 pub assets: Vec<String>,
19 pub skipped: Vec<String>,
21}
22
23pub async fn build(
27 db: &Db,
28 code: &str,
29 out_dir: &Path,
30 base_url: &str,
31) -> Result<BuildReport, ThemeError> {
32 build_with(db, code, out_dir, base_url, &[], &[]).await
33}
34
35pub async fn build_with(
38 db: &Db,
39 code: &str,
40 out_dir: &Path,
41 base_url: &str,
42 markup: &[std::sync::Arc<dyn super::markup::Markup>],
43 components: &[&super::component::ComponentReg],
44) -> Result<BuildReport, ThemeError> {
45 let theme = store::find_theme(db, code)
46 .await?
47 .ok_or_else(|| ThemeError::NotFound(code.to_string()))?;
48 let origin = base_url.trim_end_matches('/').to_string();
49 let engine = Engine::build_with(db, code, {
50 let origin = origin.clone();
51 move |env| {
52 super::markup::install_all(markup, env);
53 super::component::install_markup(components, env);
54 site::add_url(env, origin);
55 }
56 })
57 .await?;
58 let mut out = StaticSite::new(out_dir, &origin)?;
59 let mut report = BuildReport::default();
60 let mut names: Vec<&str> = engine.routes().names();
61 names.sort_unstable();
62 for name in names {
63 let settings = engine.page(name).cloned().unwrap_or_default();
64 let pattern = match settings.pattern() {
65 Ok(p) => p,
66 Err(_) => continue,
67 };
68 if !pattern.is_static() || settings.hidden {
69 report.skipped.push(name.to_string());
70 continue;
71 }
72 let url = pattern.source().to_string();
73 let extras = site::run_components(
74 &engine,
75 components,
76 db,
77 &theme,
78 name,
79 &Params::new(),
80 &url,
81 false,
82 )
83 .await?;
84 let html = site::render_page_with(
85 &engine,
86 &theme,
87 name,
88 &Params::new(),
89 &url,
90 false,
91 &origin,
92 extras,
93 )
94 .map_err(ThemeError::Template)?;
95 out.page(&url, &html)?;
96 if url == "/404" {
97 out.file("404.html", &html)?;
98 }
99 report.pages.push(url);
100 }
101 report.pages.sort();
102 report.skipped.sort();
103 for template in engine.names() {
104 let Some(path) = template.strip_prefix("assets/") else {
105 continue;
106 };
107 let body = engine
108 .render(Kind::Asset, path, ())
109 .map_err(ThemeError::Template)?;
110 let target = format!("themes/{code}/assets/{path}");
111 out.file(&target, &body)?;
112 report.assets.push(target);
113 }
114 Ok(report)
115}