nargo_document/generator/
html.rs1use crate::{
5 config::Config,
6 theme::{LocaleInfo, NavItem, PageContext, SidebarGroup, Theme, ThemeFactory},
7};
8use std::sync::Arc;
9
10pub struct HtmlGenerator {
12 theme: Arc<dyn Theme>,
14}
15
16impl Clone for HtmlGenerator {
17 fn clone(&self) -> Self {
18 Self { theme: Arc::clone(&self.theme) }
19 }
20}
21
22impl HtmlGenerator {
23 pub fn new() -> Self {
27 let config = Config::default();
28 Self::with_config_and_theme(config, "default")
29 }
30
31 pub fn with_config_and_theme(config: Config, theme_name: &str) -> Self {
37 let theme = ThemeFactory::create(theme_name, config.clone()).unwrap_or_else(|_| ThemeFactory::create("default", config).expect("Failed to create default theme"));
38 Self { theme }
39 }
40
41 pub fn with_config(config: Config) -> Self {
46 Self::with_config_and_theme(config, "default")
47 }
48
49 pub fn switch_theme(&mut self, theme_name: &str) -> Result<(), Box<dyn std::error::Error>> {
54 let config = self.theme.config().clone();
55 self.theme = ThemeFactory::create(theme_name, config)?;
56 Ok(())
57 }
58
59 pub fn current_theme_name(&self) -> &str {
61 self.theme.name()
62 }
63
64 pub fn available_themes() -> Vec<&'static str> {
66 ThemeFactory::available_themes()
67 }
68
69 pub fn generate(&self, content: &str, title: &str) -> String {
78 let site_title = self.theme.config().title.clone().unwrap_or_default();
79
80 let site_title_str = site_title.to_string();
81 let page_title = if !title.is_empty() && title != site_title_str { format!("{} | {}", title, site_title_str) } else { site_title_str.clone() };
82
83 let nav_items: Vec<NavItem> = Vec::new();
84 let sidebar_group = SidebarGroup { text: "文档".to_string(), items: Vec::new() };
85 let sidebar_groups = vec![sidebar_group];
86
87 let (has_footer, has_footer_message, footer_message, has_footer_copyright, footer_copyright) = if let Some(footer) = &self.theme.config().theme.footer { (true, footer.message.is_some(), footer.message.clone().unwrap_or_default(), footer.copyright.is_some(), footer.copyright.clone().unwrap_or_default()) } else { (false, false, String::new(), false, String::new()) };
88
89 let locale_infos: Vec<LocaleInfo> = Vec::new();
90
91 let context = PageContext { page_title, site_title: site_title_str, content: content.to_string(), nav_items, sidebar_groups, current_path: "".to_string(), has_footer, has_footer_message, footer_message, has_footer_copyright, footer_copyright, current_lang: "zh-CN".to_string(), available_locales: locale_infos, root_path: "./".to_string() };
92
93 self.theme.render_page(&context).unwrap_or_else(|_| format!("<html><head><title>{}</title></head><body><h1>{}</h1>{}</body></html>", title, title, content))
94 }
95
96 pub fn generate_with_context(&self, context: &PageContext) -> Result<String, Box<dyn std::error::Error>> {
104 self.theme.render_page(context)
105 }
106
107 pub fn static_resources(&self) -> Vec<(String, String)> {
109 self.theme.static_resources()
110 }
111}
112
113impl Default for HtmlGenerator {
114 fn default() -> Self {
115 Self::new()
116 }
117}