krik 0.1.27

A fast static site generator written in Rust with internationalization, theming, and modern web features
Documentation
use crate::error::{KrikError, KrikResult, TemplateError, TemplateErrorKind};
use crate::i18n::I18nManager;
use crate::parser::Document;
use crate::site::SiteConfig;
use crate::theme::Theme;
use chrono::{DateTime, Utc};
use std::fs::File;
use std::io::Write;
use std::path::Path;
use tera::Context;

use super::context::{add_page_links_context, add_site_context, create_post_object, is_post};
use super::paths::get_base_path;

pub fn generate_index(
    documents: &[Document],
    theme: &Theme,
    site_config: &SiteConfig,
    output_dir: &Path,
) -> KrikResult<()> {
    let mut context = Context::new();
    add_site_context(
        &mut context,
        site_config,
        I18nManager::default_language(),
        "index.html",
    );

    let site_description = "Latest posts and articles".to_string();
    context.insert("site_description", &site_description);

    // Choose one document per post base path, prefer default language if available
    let default_lang = I18nManager::default_language();
    use std::collections::HashMap;
    let mut chosen: HashMap<String, &Document> = HashMap::new();
    for doc in documents.iter().filter(|d| is_post(d)) {
        let base = get_base_path(Path::new(&doc.file_path));
        match chosen.get(&base) {
            None => {
                chosen.insert(base, doc);
            }
            Some(existing) => {
                // Prefer default language over non-default
                if existing.language != default_lang && doc.language == default_lang {
                    chosen.insert(base, doc);
                }
            }
        }
    }
    let mut post_docs: Vec<&Document> = chosen.values().cloned().collect();
    post_docs.sort_by(|a, b| {
        b.front_matter
            .date
            .unwrap_or(DateTime::<Utc>::MIN_UTC)
            .cmp(&a.front_matter.date.unwrap_or(DateTime::<Utc>::MIN_UTC))
    });

    let posts: Vec<HashMap<String, serde_json::Value>> = post_docs
        .iter()
        .map(|doc| create_post_object(doc, "index.html"))
        .collect();
    context.insert("posts", &posts);

    add_page_links_context(&mut context, documents, "index.html");

    // Rendering can be parallelized if needed, but index is a single template render.
    let rendered = theme
        .templates
        .render("index.html", &context)
        .map_err(|e| {
            KrikError::Template(Box::new(TemplateError {
                kind: TemplateErrorKind::RenderError(e),
                template: "index.html".to_string(),
                context: "Rendering index page".to_string(),
            }))
        })?;
    let index_path = output_dir.join("index.html");
    let mut file = File::create(&index_path)?;
    file.write_all(rendered.as_bytes())?;
    Ok(())
}