bim 0.1.0

A content-first static site generator for blogs, digital gardens, and knowledge bases
Documentation
use crate::collections::Collection;
use crate::lang::TextDirection;
use crate::links::{Context, InternalLink, Tag};
use chrono::{DateTime, Utc};
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub struct Page {
    pub source_path: PathBuf,
    pub url: String,
    pub title: String,
    pub date: Option<DateTime<Utc>>,
    pub raw_content: String,
    pub html_content: String,
    pub collection: Collection,
    pub is_draft: bool,
    pub lang: String,
    pub dir: TextDirection,
    pub links: Vec<InternalLink>,
    pub tags: Vec<Tag>,
    pub contexts: Vec<Context>,
    pub backlinks: Vec<Backlink>,
    pub is_index: bool,
    pub is_auto_index: bool,
}

#[derive(Debug, Clone)]
pub struct Backlink {
    pub url: String,
    pub title: String,
}

#[derive(Debug, Clone)]
pub struct Snippet {
    pub source_path: PathBuf,
    pub url: String,
    pub title: String,
    pub language: String,
    pub code: String,
    pub html_content: String,
    pub date: Option<DateTime<Utc>>,
    pub backlinks: Vec<Backlink>,
}

#[derive(Debug, Clone)]
pub struct Site {
    pub pages: Vec<Page>,
    pub snippets: Vec<Snippet>,
    pub nav_html: String,
    pub nav_items: Vec<NavItem>,
}

#[derive(Debug, Clone)]
pub struct NavItem {
    pub label: String,
    pub url: String,
}

impl Page {
    pub fn new(source_path: PathBuf, collection: Collection) -> Self {
        Self {
            source_path,
            url: String::new(),
            title: String::new(),
            date: None,
            raw_content: String::new(),
            html_content: String::new(),
            collection,
            is_draft: false,
            lang: "en".to_string(),
            dir: TextDirection::Ltr,
            links: Vec::new(),
            tags: Vec::new(),
            contexts: Vec::new(),
            backlinks: Vec::new(),
            is_index: false,
            is_auto_index: false,
        }
    }
}

impl Snippet {
    pub fn new(source_path: PathBuf) -> Self {
        Self {
            source_path,
            url: String::new(),
            title: String::new(),
            language: String::new(),
            code: String::new(),
            html_content: String::new(),
            date: None,
            backlinks: Vec::new(),
        }
    }
}

impl Site {
    pub fn new() -> Self {
        Self {
            pages: Vec::new(),
            snippets: Vec::new(),
            nav_html: String::new(),
            nav_items: Vec::new(),
        }
    }

    pub fn pages_by_collection(&self, collection: Collection) -> Vec<&Page> {
        self.pages
            .iter()
            .filter(|p| p.collection == collection)
            .collect()
    }

    pub fn recent_pages(&self, collection: Collection, count: usize) -> Vec<&Page> {
        let mut pages: Vec<_> = self.pages_by_collection(collection);
        pages.sort_by(|a, b| b.date.cmp(&a.date));
        pages.into_iter().take(count).collect()
    }

    pub fn find_page_by_url(&self, url: &str) -> Option<&Page> {
        self.pages.iter().find(|p| p.url == url)
    }

    pub fn find_snippet_by_url(&self, url: &str) -> Option<&Snippet> {
        self.snippets.iter().find(|s| s.url == url)
    }
}

impl Default for Site {
    fn default() -> Self {
        Self::new()
    }
}