Skip to main content

nargo_document/theme/
default_theme.rs

1//! 默认主题实现
2//! 提供完整的文档站点主题和样式,兼容 VuTeX 配置格式
3
4use super::Theme;
5use crate::config::{Config, FooterConfig, NavItem as ConfigNavItem, SidebarItem as ConfigSidebarItem};
6use askama::Template;
7
8/// 语言信息
9#[derive(Debug, Clone)]
10pub struct LocaleInfo {
11    /// 语言代码
12    pub code: String,
13    /// 语言标签
14    pub label: String,
15    /// 是否为当前语言
16    pub is_current: bool,
17}
18
19/// 侧边栏组
20#[derive(Debug, Clone)]
21pub struct SidebarGroup {
22    /// 组标题
23    pub text: String,
24    /// 组内项目
25    pub items: Vec<SidebarLink>,
26}
27
28/// 侧边栏链接
29#[derive(Debug, Clone)]
30pub struct SidebarLink {
31    /// 链接文本
32    pub text: String,
33    /// 链接地址
34    pub link: String,
35}
36
37/// 导航栏项
38#[derive(Debug, Clone)]
39pub struct NavItem {
40    /// 显示文本
41    pub text: String,
42    /// 链接
43    pub link: String,
44}
45
46/// 页面模板上下文
47#[derive(Debug, Clone, Template)]
48#[template(path = "page.html")]
49pub struct PageContext {
50    /// 页面标题
51    pub page_title: String,
52    /// 站点标题
53    pub site_title: String,
54    /// 页面内容
55    pub content: String,
56    /// 导航栏项目
57    pub nav_items: Vec<NavItem>,
58    /// 侧边栏组
59    pub sidebar_groups: Vec<SidebarGroup>,
60    /// 当前页面路径
61    pub current_path: String,
62    /// 是否有页脚
63    pub has_footer: bool,
64    /// 是否有页脚消息
65    pub has_footer_message: bool,
66    /// 页脚消息
67    pub footer_message: String,
68    /// 是否有页脚版权
69    pub has_footer_copyright: bool,
70    /// 页脚版权
71    pub footer_copyright: String,
72    /// 当前语言
73    pub current_lang: String,
74    /// 可用语言列表
75    pub available_locales: Vec<LocaleInfo>,
76    /// 相对于根目录的路径前缀
77    pub root_path: String,
78}
79
80/// 默认主题
81#[derive(Clone)]
82pub struct DefaultTheme {
83    /// 主题配置
84    pub config: Config,
85}
86
87impl Theme for DefaultTheme {
88    fn name(&self) -> &str {
89        "default"
90    }
91
92    fn render_page(&self, context: &PageContext) -> Result<String, Box<dyn std::error::Error>> {
93        <PageContext as Template>::render(context).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()).into())
94    }
95
96    fn config(&self) -> &Config {
97        &self.config
98    }
99}
100
101impl DefaultTheme {
102    /// 创建新的默认主题实例
103    pub fn new(config: Config) -> Result<Self, Box<dyn std::error::Error>> {
104        Ok(Self { config })
105    }
106
107    /// 获取站点标题
108    pub fn site_title(&self) -> &str {
109        self.config.title.as_deref().unwrap_or("Nargo Documentation")
110    }
111
112    /// 将 ConfigNavItem 转换为主题 NavItem
113    pub fn convert_nav_items(items: &[ConfigNavItem]) -> Vec<NavItem> {
114        items.iter().filter_map(|item| item.link.as_ref().map(|link| NavItem { text: item.text.clone(), link: link.clone() })).collect()
115    }
116
117    /// 将侧边栏配置转换为 SidebarGroup
118    pub fn convert_sidebar_groups(sidebar: &std::collections::HashMap<String, Vec<ConfigSidebarItem>>) -> Vec<SidebarGroup> {
119        sidebar
120            .iter()
121            .map(|(group_text, items)| {
122                let sidebar_links: Vec<SidebarLink> = items.iter().filter_map(|item| item.link.as_ref().map(|link| SidebarLink { text: item.text.clone(), link: link.clone() })).collect();
123
124                SidebarGroup { text: group_text.clone(), items: sidebar_links }
125            })
126            .collect()
127    }
128
129    /// 获取页脚配置
130    pub fn footer_config(&self) -> &Option<FooterConfig> {
131        &self.config.theme.footer
132    }
133}