research 0.1.22

Manage your reading lists and generate a static site with your saved articles.
use crate::db::{ResearchItem, Tags};
use chrono_tz::Tz;
use sailfish::TemplateOnce;
use serde::Serialize;
use std::sync::RwLock;

pub struct Site {
    pub index_html: String,
    pub search_html: String,
}

#[derive(TemplateOnce, Serialize)]
#[template(path = "index.stpl")]
#[template(rm_whitespace = true)]
struct IndexTemplate<'a> {
    title: &'a str,
    assets_dir: &'a str,
    tags: Vec<&'a str>,
    item_tags: &'a [(Vec<Tags>, ResearchItem)],
}

#[derive(TemplateOnce, Serialize)]
#[template(path = "search.stpl")]
#[template(rm_whitespace = true)]
struct SearchTemplate<'a> {
    title: &'a str,
    assets_dir: &'a str,
    item_tags: Vec<ItemTag<'a>>,
    tags: Vec<&'a str>,
}

#[derive(Serialize)]
struct ItemTag<'a> {
    pub tags: Vec<&'a str>,
    #[serde(flatten)]
    pub item: &'a ResearchItem,
}

static TIMEZONE: RwLock<Option<Tz>> = RwLock::new(None);

const TITLE: &str = "Pocket Research";

impl Site {
    pub fn build(
        tags: &[Tags],
        item_tags: &[(Vec<Tags>, ResearchItem)],
        assets_dir: &str,
        timezone: Option<Tz>,
    ) -> Result<Self, Box<dyn std::error::Error>> {
        {
            let mut timezone_lock = TIMEZONE.write().unwrap();
            *timezone_lock = timezone;
        }
        let tags = tags.iter().map(|t| t.tag_name.as_str()).collect::<Vec<_>>();
        let ctx = IndexTemplate {
            title: TITLE,
            item_tags,
            assets_dir,
            tags: tags.clone(),
        };

        let index_html = ctx.render_once()?;

        let item_tags = item_tags
            .iter()
            .map(|(tags, item)| ItemTag {
                tags: tags.iter().map(|t| t.tag_name.as_str()).collect(),
                item,
            })
            .collect::<Vec<_>>();

        let ctx = SearchTemplate {
            item_tags,
            assets_dir,
            title: "Search",
            tags: tags.clone(),
        };
        let search_html = ctx.render_once()?;
        Ok(Self {
            index_html,
            search_html,
        })
    }
}