use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; use crate::error::{Result, WebBuilderError}; /// Site configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SiteConfig { /// Site name pub name: String, /// Site title pub title: String, /// Site description pub description: Option, /// Site keywords pub keywords: Option>, /// Site URL pub url: Option, /// Site favicon pub favicon: Option, /// Site header pub header: Option, /// Site footer pub footer: Option, /// Site collections pub collections: Vec, /// Site pages pub pages: Vec, /// Base path of the site configuration #[serde(skip)] pub base_path: PathBuf, } /// Header configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HeaderConfig { /// Header logo pub logo: Option, /// Header title pub title: Option, /// Header menu pub menu: Option>, /// Login button pub login: Option, } /// Logo configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LogoConfig { /// Logo source pub src: String, /// Logo alt text pub alt: Option, } /// Menu item configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MenuItemConfig { /// Menu item label pub label: String, /// Menu item link pub link: String, /// Menu item children pub children: Option>, } /// Login button configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LoginConfig { /// Whether the login button is visible pub visible: bool, /// Login button label pub label: Option, /// Login button link pub link: Option, } /// Footer configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FooterConfig { /// Footer title pub title: Option, /// Footer sections pub sections: Option>, /// Footer copyright pub copyright: Option, } /// Footer section configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FooterSectionConfig { /// Section title pub title: String, /// Section links pub links: Vec, } /// Link configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LinkConfig { /// Link label pub label: String, /// Link URL pub href: String, } /// Collection configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CollectionConfig { /// Collection name pub name: Option, /// Collection URL pub url: Option, /// Collection description pub description: Option, /// Whether to scan the URL for collections pub scan: Option, } /// Page configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PageConfig { /// Page name pub name: String, /// Page title pub title: String, /// Page description pub description: Option, /// Page navigation path pub navpath: String, /// Page collection pub collection: String, /// Whether the page is a draft pub draft: Option, } impl SiteConfig { /// Load site configuration from a directory /// /// # Arguments /// /// * `path` - Path to the directory containing hjson configuration files /// /// # Returns /// /// A new SiteConfig instance or an error pub fn from_directory>(path: P) -> Result { let path = path.as_ref(); // Check if the directory exists if !path.exists() { return Err(WebBuilderError::MissingDirectory(path.to_path_buf())); } // Check if the directory is a directory if !path.is_dir() { return Err(WebBuilderError::InvalidConfiguration(format!( "{:?} is not a directory", path ))); } // TODO: Implement loading configuration from hjson files // For now, return a placeholder configuration Ok(SiteConfig { name: "demo1".to_string(), title: "Demo Site 1".to_string(), description: Some("This is a demo site for doctree".to_string()), keywords: Some(vec![ "demo".to_string(), "doctree".to_string(), "example".to_string(), ]), url: Some("https://example.com".to_string()), favicon: Some("img/favicon.png".to_string()), header: None, footer: None, collections: Vec::new(), pages: Vec::new(), base_path: path.to_path_buf(), }) } }