use serde::Serialize; use super::macros::render; use super::render_context::RenderContext; use crate::context::RenderDocumentElement; use crate::context::RenderRealFootnoteDefinition; use crate::error::CustomError; use crate::intermediate::get_web_path; use crate::intermediate::BlogPost; use super::GlobalSettings; use super::PageHeader; #[derive(Debug)] pub(crate) struct RenderBlogStreamInput<'a, 'b> { original: &'a [&'b BlogPost], older_link: Option, newer_link: Option, } impl<'a, 'b> RenderBlogStreamInput<'a, 'b> { pub(crate) fn new( original: &'a [&'b BlogPost], older_link: Option, newer_link: Option, ) -> RenderBlogStreamInput<'a, 'b> { RenderBlogStreamInput { original, older_link, newer_link, } } } #[derive(Debug, Serialize)] #[serde(tag = "type")] #[serde(rename = "blog_stream")] pub(crate) struct RenderBlogStream { global_settings: GlobalSettings, page_header: Option, children: Vec, stream_pagination: Option, } render!( RenderBlogStream, RenderBlogStreamInput, original, render_context, { let css_files = vec![ // get_web_path( // config, // output_directory, // output_file, // "stylesheet/reset.css", // )?, get_web_path( render_context.config, render_context.output_directory, render_context.output_file, "stylesheet/main.css", )?, ]; let js_files = vec![get_web_path( render_context.config, render_context.output_directory, render_context.output_file, "blog_post.js", )?]; let global_settings = GlobalSettings::new( render_context.config.get_site_title().map(str::to_string), css_files, js_files, ); let page_header = PageHeader::new( render_context.config.get_site_title().map(str::to_string), Some(get_web_path( render_context.config, render_context.output_directory, render_context.output_file, "", )?), ); let children = original .original .into_iter() .map(|blog_post| RenderBlogStreamEntry::new(render_context.clone(), blog_post)) .collect::, _>>()?; let stream_pagination = if original.older_link.is_some() || original.newer_link.is_some() { Some(RenderBlogStreamPagination::new( original.older_link.clone(), original.newer_link.clone(), )?) } else { None }; Ok(RenderBlogStream { global_settings, page_header: Some(page_header), children, stream_pagination, }) } ); #[derive(Debug, Serialize)] pub(crate) struct RenderBlogStreamEntry { /// The title that will be shown visibly on the page. title: Option, self_link: Option, children: Vec, footnotes: Vec, } render!(RenderBlogStreamEntry, BlogPost, original, render_context, { let link_to_blog_post = get_web_path( render_context.config, render_context.output_directory, render_context.output_file, render_context .config .get_relative_path_to_post(&original.id), )?; // TODO: Should I guess an index page instead of erroring out? let index_page = original .get_index_page() .ok_or_else(|| format!("Blog post {} needs an index page.", original.id))?; let title = index_page.title.clone(); // TODO: Handle footnotes. let children = index_page .children .iter() .map(|child| RenderDocumentElement::new(render_context.clone(), child)) .collect::, _>>()?; Ok(RenderBlogStreamEntry { title, self_link: Some(link_to_blog_post), children, footnotes: Vec::new(), }) }); #[derive(Debug, Serialize)] pub(crate) struct RenderBlogStreamPagination { older_link: Option, newer_link: Option, } impl RenderBlogStreamPagination { fn new( older_link: Option, newer_link: Option, ) -> Result { Ok(RenderBlogStreamPagination { older_link, newer_link, }) } }