nargo_document/templates/
mod.rs1use std::{fs, path::Path};
7use toml::Value;
8
9#[derive(Debug, Clone)]
11pub struct TemplateConfig {
12 pub name: String,
14 pub colors: TemplateColors,
16 pub fonts: TemplateFonts,
18 pub features: TemplateFeatures,
20 pub i18n: TemplateI18n,
22}
23
24#[derive(Debug, Clone)]
26pub struct TemplateColors {
27 pub primary_color: String,
29 pub secondary_color: String,
31 pub background_color: String,
33 pub text_color: String,
35 pub code_background: String,
37 pub border_color: String,
39 pub primary_color_dark: String,
41 pub secondary_color_dark: String,
43 pub background_color_dark: String,
45 pub text_color_dark: String,
47 pub code_background_dark: String,
49 pub border_color_dark: String,
51}
52
53#[derive(Debug, Clone)]
55pub struct TemplateFonts {
56 pub font_family: String,
58 pub code_font_family: String,
60}
61
62#[derive(Debug, Clone)]
64pub struct TemplateFeatures {
65 pub enable_mermaid: bool,
67 pub enable_highlight: bool,
69 pub highlight_theme: String,
71}
72
73#[derive(Debug, Clone)]
75pub struct TemplateI18n {
76 pub default_lang: String,
78}
79
80#[derive(Debug, Clone)]
82pub struct Template {
83 pub name: String,
85 pub config: TemplateConfig,
87 pub content: String,
89}
90
91impl Template {
92 pub fn load_from_dir(template_dir: &str) -> Result<Self, Box<dyn std::error::Error>> {
100 let template_path = Path::new(template_dir).join("template.html");
101 let content = fs::read_to_string(template_path)?;
102
103 let config_path = Path::new(template_dir).join("config.toml");
104 let config_content = fs::read_to_string(config_path)?;
105 let config_value: Value = toml::from_str(&config_content)?;
106
107 let config = Self::parse_config(&config_value)?;
108
109 Ok(Self { name: config.name.clone(), config, content })
110 }
111
112 fn parse_config(config_value: &Value) -> Result<TemplateConfig, Box<dyn std::error::Error>> {
120 let theme = config_value.get("theme").ok_or("Missing theme config")?;
121
122 let name = theme.get("name").and_then(|v| v.as_str()).unwrap_or("default").to_string();
123
124 let colors = theme.get("colors").ok_or("Missing colors config")?;
125 let colors = TemplateColors {
126 primary_color: colors.get("primary_color").and_then(|v| v.as_str()).unwrap_or("#3498db").to_string(),
127 secondary_color: colors.get("secondary_color").and_then(|v| v.as_str()).unwrap_or("#2c3e50").to_string(),
128 background_color: colors.get("background_color").and_then(|v| v.as_str()).unwrap_or("#ffffff").to_string(),
129 text_color: colors.get("text_color").and_then(|v| v.as_str()).unwrap_or("#333333").to_string(),
130 code_background: colors.get("code_background").and_then(|v| v.as_str()).unwrap_or("#f4f4f4").to_string(),
131 border_color: colors.get("border_color").and_then(|v| v.as_str()).unwrap_or("#e0e0e0").to_string(),
132 primary_color_dark: colors.get("primary_color_dark").and_then(|v| v.as_str()).unwrap_or("#3498db").to_string(),
133 secondary_color_dark: colors.get("secondary_color_dark").and_then(|v| v.as_str()).unwrap_or("#ecf0f1").to_string(),
134 background_color_dark: colors.get("background_color_dark").and_then(|v| v.as_str()).unwrap_or("#1a1a1a").to_string(),
135 text_color_dark: colors.get("text_color_dark").and_then(|v| v.as_str()).unwrap_or("#e0e0e0").to_string(),
136 code_background_dark: colors.get("code_background_dark").and_then(|v| v.as_str()).unwrap_or("#2d2d2d").to_string(),
137 border_color_dark: colors.get("border_color_dark").and_then(|v| v.as_str()).unwrap_or("#3d3d3d").to_string(),
138 };
139
140 let fonts = theme.get("fonts").ok_or("Missing fonts config")?;
141 let fonts = TemplateFonts { font_family: fonts.get("font_family").and_then(|v| v.as_str()).unwrap_or("-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif").to_string(), code_font_family: fonts.get("code_font_family").and_then(|v| v.as_str()).unwrap_or("'Courier New', Courier, monospace").to_string() };
142
143 let features = theme.get("features").ok_or("Missing features config")?;
144 let features = TemplateFeatures { enable_mermaid: features.get("enable_mermaid").and_then(|v| v.as_bool()).unwrap_or(true), enable_highlight: features.get("enable_highlight").and_then(|v| v.as_bool()).unwrap_or(true), highlight_theme: features.get("highlight_theme").and_then(|v| v.as_str()).unwrap_or("github").to_string() };
145
146 let i18n = theme.get("i18n").ok_or("Missing i18n config")?;
147 let i18n = TemplateI18n { default_lang: i18n.get("default_lang").and_then(|v| v.as_str()).unwrap_or("zh-CN").to_string() };
148
149 Ok(TemplateConfig { name, colors, fonts, features, i18n })
150 }
151
152 pub fn render(&self, title: &str, content: &str, sidebar: &str) -> String {
162 let mut rendered = self.content.clone();
163
164 rendered = rendered.replace("{{ title }}", title);
165 rendered = rendered.replace("{{ content }}", content);
166 rendered = rendered.replace("{{ sidebar }}", sidebar);
167 rendered = rendered.replace("{{ lang }}", &self.config.i18n.default_lang);
168
169 rendered = rendered.replace("{{ primary_color }}", &self.config.colors.primary_color);
170 rendered = rendered.replace("{{ secondary_color }}", &self.config.colors.secondary_color);
171 rendered = rendered.replace("{{ background_color }}", &self.config.colors.background_color);
172 rendered = rendered.replace("{{ text_color }}", &self.config.colors.text_color);
173 rendered = rendered.replace("{{ code_background }}", &self.config.colors.code_background);
174 rendered = rendered.replace("{{ border_color }}", &self.config.colors.border_color);
175 rendered = rendered.replace("{{ primary_color_dark }}", &self.config.colors.primary_color_dark);
176 rendered = rendered.replace("{{ secondary_color_dark }}", &self.config.colors.secondary_color_dark);
177 rendered = rendered.replace("{{ background_color_dark }}", &self.config.colors.background_color_dark);
178 rendered = rendered.replace("{{ text_color_dark }}", &self.config.colors.text_color_dark);
179 rendered = rendered.replace("{{ code_background_dark }}", &self.config.colors.code_background_dark);
180 rendered = rendered.replace("{{ border_color_dark }}", &self.config.colors.border_color_dark);
181
182 rendered = rendered.replace("{{ font_family }}", &self.config.fonts.font_family);
183 rendered = rendered.replace("{{ code_font_family }}", &self.config.fonts.code_font_family);
184
185 rendered = rendered.replace("{{ enable_mermaid }}", &self.config.features.enable_mermaid.to_string());
186 rendered = rendered.replace("{{ enable_highlight }}", &self.config.features.enable_highlight.to_string());
187 rendered = rendered.replace("{{ highlight_theme }}", &self.config.features.highlight_theme);
188
189 if !self.config.features.enable_mermaid {
190 rendered = rendered.replace("{% if enable_mermaid %}", "");
191 rendered = rendered.replace("{% endif %}", "");
192 }
193 else {
194 rendered = rendered.replace("{% if enable_mermaid %}", "");
195 rendered = rendered.replace("{% endif %}", "");
196 }
197
198 if !self.config.features.enable_highlight {
199 rendered = rendered.replace("{% if enable_highlight %}", "");
200 rendered = rendered.replace("{% endif %}", "");
201 }
202 else {
203 rendered = rendered.replace("{% if enable_highlight %}", "");
204 rendered = rendered.replace("{% endif %}", "");
205 }
206
207 rendered
208 }
209}