Skip to main content

nargo_document/generator/
html.rs

1//! HTML 生成器
2//! 使用主题系统生成完整的 HTML 文档页面
3
4use crate::{
5    config::Config,
6    theme::{LocaleInfo, NavItem, PageContext, SidebarGroup, Theme, ThemeFactory},
7};
8use std::sync::Arc;
9
10/// HTML 生成器
11pub struct HtmlGenerator {
12    /// 主题实例
13    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    /// 创建新的 HtmlGenerator
24    ///
25    /// 使用默认配置创建 HTML 生成器
26    pub fn new() -> Self {
27        let config = Config::default();
28        Self::with_config_and_theme(config, "default")
29    }
30
31    /// 使用指定配置和主题名称创建 HtmlGenerator
32    ///
33    /// # 参数
34    /// * `config` - 文档配置
35    /// * `theme_name` - 主题名称
36    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    /// 使用指定配置创建 HtmlGenerator(使用默认主题)
42    ///
43    /// # 参数
44    /// * `config` - 文档配置
45    pub fn with_config(config: Config) -> Self {
46        Self::with_config_and_theme(config, "default")
47    }
48
49    /// 切换主题
50    ///
51    /// # 参数
52    /// * `theme_name` - 新的主题名称
53    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    /// 获取当前主题名称
60    pub fn current_theme_name(&self) -> &str {
61        self.theme.name()
62    }
63
64    /// 获取可用主题列表
65    pub fn available_themes() -> Vec<&'static str> {
66        ThemeFactory::available_themes()
67    }
68
69    /// 生成 HTML 文档
70    ///
71    /// # 参数
72    /// * `content` - Markdown 渲染后的 HTML 内容
73    /// * `title` - 页面标题
74    ///
75    /// # 返回值
76    /// 返回完整的 HTML 页面字符串
77    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    /// 使用完整上下文生成 HTML 文档
97    ///
98    /// # 参数
99    /// * `context` - 页面上下文
100    ///
101    /// # 返回值
102    /// 返回完整的 HTML 页面字符串
103    pub fn generate_with_context(&self, context: &PageContext) -> Result<String, Box<dyn std::error::Error>> {
104        self.theme.render_page(context)
105    }
106
107    /// 获取主题的静态资源
108    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}