use crate::generator::util::output_rendered_template; use crate::generator::util::templates::{filters, TemplateCommon}; use crate::generator::{archive::ArchivePost, HtmlContent, Post}; use askama::Template; use chrono::Datelike; use compute_graph::{ builder::GraphBuilder, rule::{Input, InputVisitable, Rule}, synchronicity::Asynchronous, }; use std::collections::HashMap; pub fn make_graph( builder: &mut GraphBuilder, posts: &[Input>], ) -> Input<()> { let posts_by_year = builder.add_rule(PostsByYear(posts.into())); let archive = builder.add_rule(GenerateArchive(posts_by_year)); // TODO: paginated year posts indexes archive } struct PostsByYear(Vec>>); impl InputVisitable for PostsByYear { fn visit_inputs(&self, visitor: &mut impl compute_graph::rule::InputVisitor) { for input in &self.0 { visitor.visit(input); } } } impl Rule for PostsByYear { type Output = HashMap>; fn evaluate(&mut self) -> Self::Output { let mut map = HashMap::new(); for input in &self.0 { let post = input.value(); let year_posts: &mut Vec = map.entry(post.metadata.date.year()).or_default(); year_posts.push(ArchivePost { permalink: post.permalink(), title: post.metadata.title.clone(), }); } map } } #[derive(InputVisitable)] struct GenerateArchive(Input<::Output>); impl Rule for GenerateArchive { type Output = (); fn evaluate(&mut self) -> Self::Output { let posts_by_year = self.input_0(); let mut years = posts_by_year .iter() .map(|(y, ps)| (*y, ps)) .collect::>(); years.sort_by_key(|(year, _)| *year); years.reverse(); let template = ArchiveTemplate { years: &years }; output_rendered_template(&template, "archive/index.html").expect("generate archive"); } } #[derive(Template)] #[template(path = "archive.html")] struct ArchiveTemplate<'a> { years: &'a [(i32, &'a Vec)], } impl<'a> ArchiveTemplate<'a> { fn permalink(&self) -> &'static str { "/archive/" } } impl<'a> TemplateCommon for ArchiveTemplate<'a> {}