Skip to main content

maud_extensions/
init.rs

1// Runtime bootstrap builder for bundled browser-side helper scripts.
2use maud::{Markup, PreEscaped, Render, html};
3
4/// Page-level runtime bootstrap for bundled browser-side helpers.
5#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
6pub struct Init {
7    surrealjs: bool,
8    scoped_css: bool,
9    signals: bool,
10}
11
12impl Init {
13    /// Starts with an empty runtime bootstrap configuration.
14    pub fn new() -> Self {
15        Self::default()
16    }
17
18    /// Includes the bundled Surreal runtime.
19    pub fn surrealjs(mut self) -> Self {
20        self.surrealjs = true;
21        self
22    }
23
24    /// Includes the bundled css-scope-inline runtime.
25    pub fn scoped_css(mut self) -> Self {
26        self.scoped_css = true;
27        self
28    }
29
30    /// Includes the bundled Signals runtime and adapter.
31    pub fn signals(mut self) -> Self {
32        self.signals = true;
33        self
34    }
35
36    /// Builds the runtime bootstrap markup.
37    pub fn build(self) -> Markup {
38        let mut scripts = Vec::new();
39
40        if self.surrealjs {
41            scripts.push(sanitized_script(include_str!("../assets/surreal.js")));
42        }
43        if self.scoped_css {
44            scripts.push(sanitized_script(include_str!("../assets/css-scope-inline.js")));
45        }
46        if self.signals {
47            scripts.push(sanitized_script(include_str!("../assets/signals-core.min.js")));
48            scripts.push(sanitized_script(include_str!("../assets/signals-adapter.js")));
49        }
50
51        html! {
52            @for script_text in scripts {
53                script { (PreEscaped(script_text)) }
54            }
55        }
56    }
57
58    /// Emits the full recommended runtime bundle.
59    pub fn all() -> Markup {
60        Self::new().surrealjs().scoped_css().signals().build()
61    }
62}
63
64impl Render for Init {
65    fn render(&self) -> Markup {
66        (*self).build()
67    }
68}
69
70fn sanitized_script(source: &str) -> String {
71    source
72        .replace("</script>", "<\\/script>")
73        .replace("</SCRIPT>", "<\\/SCRIPT>")
74        .replace("</Script>", "<\\/Script>")
75}