Chunking the blog posts for the stream.

This commit is contained in:
Tom Alexander 2023-12-17 16:57:37 -05:00
parent fdf84e3d0b
commit c3482cf1e4
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
6 changed files with 84 additions and 10 deletions

View File

@ -100,8 +100,30 @@ impl SiteRenderer {
//
// Steps: pass each RenderBlogStream to dust as the context to render index.html and any additional stream pages.
for blog_post in &self.blog_posts {
println!("{:?}", blog_post.get_date()?);
// Sort blog posts by date, newest first.
let sorted_blog_posts = {
let mut sorted_blog_posts: Vec<_> = self.blog_posts.iter().collect();
sorted_blog_posts
.sort_by_key(|blog_post| (blog_post.get_date(), blog_post.id.as_str()));
sorted_blog_posts.reverse();
sorted_blog_posts
};
for blog_post in &sorted_blog_posts {
if blog_post.get_date().is_none() {
return Err(format!("Blog post {} does not have a date.", blog_post.id).into());
}
}
// Group blog posts based on # of posts per page.
let stream_chunks: Vec<_> = sorted_blog_posts
.chunks(config.get_stream_entries_per_page())
.collect();
// For each group, create a RenderBlogStream.
let num_stream_pages = stream_chunks.len();
for chunk in stream_chunks {
// foo
}
Ok(())
}

View File

@ -71,4 +71,13 @@ impl Config {
pub(crate) fn get_site_title(&self) -> Option<&str> {
self.raw.site_title.as_deref()
}
pub(crate) fn get_stream_entries_per_page(&self) -> usize {
self.raw
.stream
.as_ref()
.map(|stream| stream.entries_per_page)
.flatten()
.unwrap_or(5)
}
}

View File

@ -9,6 +9,7 @@ pub(crate) struct RawConfig {
email: Option<String>,
pub(super) use_relative_paths: Option<bool>,
pub(super) web_root: Option<String>,
pub(super) stream: Option<RawConfigStream>,
}
impl Default for RawConfig {
@ -19,6 +20,20 @@ impl Default for RawConfig {
email: None,
use_relative_paths: None,
web_root: None,
stream: None,
}
}
}
#[derive(Deserialize, Serialize)]
pub(crate) struct RawConfigStream {
pub(super) entries_per_page: Option<usize>,
}
impl Default for RawConfigStream {
fn default() -> Self {
RawConfigStream {
entries_per_page: None,
}
}
}

View File

@ -4,6 +4,7 @@ use std::string::FromUtf8Error;
#[derive(Debug)]
pub(crate) enum CustomError {
Static(&'static str),
String(String),
IO(std::io::Error),
TomlSerialize(toml::ser::Error),
TomlDeserialize(toml::de::Error),
@ -29,6 +30,12 @@ impl From<&'static str> for CustomError {
}
}
impl From<String> for CustomError {
fn from(value: String) -> Self {
CustomError::String(value)
}
}
impl From<toml::ser::Error> for CustomError {
fn from(value: toml::ser::Error) -> Self {
CustomError::TomlSerialize(value)

View File

@ -87,19 +87,26 @@ impl BlogPost {
/// all the pages under the blog post looking for any page that
/// contains a date export setting. It will return the first date
/// found.
pub(crate) fn get_date(&self) -> Result<(), CustomError> {
if let Some(index_page) = self.get_index_page()? {
println!("{:?}", index_page);
pub(crate) fn get_date(&self) -> Option<&str> {
let index_page_date = self
.get_index_page()
.map(|index_page| index_page.date.as_ref().map(String::as_str))
.flatten();
if index_page_date.is_some() {
return index_page_date;
}
Ok(())
self.pages
.iter()
.filter_map(|page| page.date.as_ref().map(String::as_str))
.next()
}
/// Get the blog post page for index.org
fn get_index_page(&self) -> Result<Option<&BlogPostPage>, CustomError> {
Ok(self
.pages
fn get_index_page(&self) -> Option<&BlogPostPage> {
self.pages
.iter()
.find(|page| page.path == Path::new("index.org")))
.find(|page| page.path == Path::new("index.org"))
}
}

View File

@ -16,6 +16,8 @@ pub(crate) struct BlogPostPage {
pub(crate) title: Option<String>,
pub(crate) date: Option<String>,
pub(crate) children: Vec<IDocumentElement>,
pub(crate) footnotes: Vec<IRealFootnoteDefinition>,
@ -60,6 +62,7 @@ impl BlogPostPage {
Ok(BlogPostPage {
path,
title: get_title(&document),
date: get_date(&document),
children,
footnotes,
})
@ -85,3 +88,14 @@ fn get_title(document: &organic::types::Document<'_>) -> Option<String> {
.last()
.map(|kw| kw.value.to_owned())
}
fn get_date(document: &organic::types::Document<'_>) -> Option<String> {
organic::types::AstNode::from(document)
.iter_all_ast_nodes()
.filter_map(|node| match node {
organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("date") => Some(kw),
_ => None,
})
.last()
.map(|kw| kw.value.to_owned())
}