v6/src/generator/pagination.rs

75 lines
2.2 KiB
Rust

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<HtmlContent>],
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<String>,
// Relative to path of the file being generated
pub prev_href: Option<String>,
}
const SIZE: usize = 5;
pub fn render_paginated<'a, T: PaginatableTemplate<'a>>(
template: &'a T,
posts: &'a [&'a Post<HtmlContent>],
base_path: impl AsRef<Path>,
) -> 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(())
}