use super::posts::{HtmlContent, Post}; use super::util::output_rendered_template; use askama::Template; use std::path::{Path, PathBuf}; pub trait PaginatableTemplate<'a>: Template { fn with_posts( &'a self, posts: &'a [&'a Post], pagination_info: PaginationInfo, ) -> Self; } #[derive(Default)] pub struct PaginationInfo { pub page: usize, pub total_pages: usize, // Relative to path of the file being generated pub next_href: Option, // Relative to path of the file being generated pub prev_href: Option, } const SIZE: usize = 5; pub fn render_paginated<'a, T: PaginatableTemplate<'a>>( template: &'a T, posts: &'a [&'a Post], base_path: impl AsRef, ) -> Result<(), std::io::Error> { // div_ceil is unstable, so we do it ourselves let total_pages = (posts.len() as f32 / SIZE as f32).ceil() as usize; let mut buf: PathBuf = base_path.as_ref().into(); for (chunk_idx, chunk) in posts.chunks(SIZE).enumerate() { let page = chunk_idx + 1; let next_page = if page < total_pages { Some(page + 1) } else { None }; let prev_page = if page > 1 { Some(page - 1) } else { None }; if page == 1 { buf.push("index.html"); let chunk_template = template.with_posts( chunk, PaginationInfo { page, total_pages, next_href: next_page.map(|p| format!("./{}/", p)), prev_href: None, }, ); output_rendered_template(&chunk_template, &buf)?; buf.pop(); } let chunk_template = template.with_posts( chunk, PaginationInfo { page, total_pages, next_href: next_page.map(|p| format!("../{}/", p)), prev_href: prev_page.map(|p| format!("../{}/", p)), }, ); buf.push(page.to_string()); buf.push("index.html"); output_rendered_template(&chunk_template, &buf)?; buf.pop(); buf.pop(); } Ok(()) }