use crate::parser::Document;
use crate::theme::Theme;
use crate::i18n::I18nManager;
use crate::site::SiteConfig;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct SiteGenerator {
pub source_dir: PathBuf,
pub output_dir: PathBuf,
pub theme: Theme,
pub i18n: I18nManager,
pub site_config: SiteConfig,
pub documents: Vec<Document>,
}
impl SiteGenerator {
pub fn new<P: AsRef<Path>>(
source_dir: P,
output_dir: P,
theme_dir: Option<P>,
) -> Result<Self, Box<dyn std::error::Error>> {
let source_dir = source_dir.as_ref().to_path_buf();
let output_dir = output_dir.as_ref().to_path_buf();
let theme = if let Some(theme_path) = theme_dir {
Theme::load_from_path(theme_path)?
} else {
Theme::load_from_path("themes/default").unwrap_or_else(|_| {
Theme {
config: crate::theme::ThemeConfig {
name: "default".to_string(),
version: "1.0.0".to_string(),
author: None,
description: None,
templates: HashMap::new(),
},
templates: tera::Tera::new("themes/default/templates/**/*").unwrap_or_default(),
theme_path: PathBuf::from("themes/default"),
}
})
};
let i18n = I18nManager::new("en".to_string());
let site_config = SiteConfig::load_from_path(&source_dir);
Ok(Self {
source_dir,
output_dir,
theme,
i18n,
site_config,
documents: Vec::new(),
})
}
pub fn scan_files(&mut self) -> Result<(), Box<dyn std::error::Error>> {
super::markdown::scan_files(&self.source_dir, &mut self.documents)
}
pub fn generate_site(&self) -> Result<(), Box<dyn std::error::Error>> {
if !self.output_dir.exists() {
std::fs::create_dir_all(&self.output_dir)?;
}
super::assets::copy_non_markdown_files(&self.source_dir, &self.output_dir)?;
super::assets::copy_theme_assets(&self.theme, &self.output_dir)?;
super::templates::generate_pages(&self.documents, &self.theme, &self.i18n, &self.site_config, &self.output_dir)?;
super::templates::generate_index(&self.documents, &self.theme, &self.site_config, &self.output_dir)?;
super::feeds::generate_feed(&self.documents, &self.site_config, &self.output_dir)?;
Ok(())
}
}