86 lines
2.3 KiB
Rust
86 lines
2.3 KiB
Rust
|
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<super::GraphOutput, Asynchronous>,
|
||
|
posts: &[Input<Post<HtmlContent>>],
|
||
|
) -> 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<Input<Post<HtmlContent>>>);
|
||
|
|
||
|
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<i32, Vec<ArchivePost>>;
|
||
|
|
||
|
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<ArchivePost> =
|
||
|
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<<PostsByYear as Rule>::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::<Vec<_>>();
|
||
|
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<ArchivePost>)],
|
||
|
}
|
||
|
|
||
|
impl<'a> ArchiveTemplate<'a> {
|
||
|
fn permalink(&self) -> &'static str {
|
||
|
"/archive/"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a> TemplateCommon for ArchiveTemplate<'a> {}
|