crabmail

Static HTML email archive viewer in Rust
git clone git://git.alexwennerberg.com/crabmail
Log | Files | Refs | README | LICENSE

commit 208951957b47aa884bc886a358d81566abbfd9d9
parent c90e0d426db207011aa7843e4dd17931321fefc7
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sun, 27 Mar 2022 11:05:50 -0700

wip pagination

Diffstat:
MTODO | 11+++++++----
Msrc/main.rs | 4++--
Msrc/templates/gmi.rs | 57++++++++++++++++++++++++++++++++-------------------------
Msrc/templates/html.rs | 107++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/templates/mod.rs | 2+-
5 files changed, 105 insertions(+), 76 deletions(-)

diff --git a/TODO b/TODO @@ -1,12 +1,15 @@ TODO ==== -cleanup atom threads +features +-------- paginate list home -only unformat flowed if we are format flowed in gmi, html, xml + +qa +-- +cleanup atom threads URL encode spaces in links for gemini export reference mblaze command, add examples to readme fix docs check for html escape bugz -Duplicate ID verification: warn on duplicate ID, use first received-date. This -is to prevent someone overwriting old emails secretly +Duplicate ID verification: warn on duplicate ID, use first received-date. This is to prevent someone overwriting old emails secretly Color highlight on anchor select diff --git a/src/main.rs b/src/main.rs @@ -76,7 +76,7 @@ impl List { if n == 0 { index = self.out_dir.join("index"); } else { - index = self.out_dir.join(format!("{}-{}", "index", n)); + index = self.out_dir.join(format!("{}-{}", "index", n + 1)); } write_if_unchanged(&index.with_extension("gmi"), gmi.as_bytes()); } @@ -87,7 +87,7 @@ impl List { if n == 0 { index = self.out_dir.join("index"); } else { - index = self.out_dir.join(format!("{}-{}", "index", n)); + index = self.out_dir.join(format!("{}-{}", "index", n + 1)); } write_if_unchanged(&index.with_extension("html"), html.as_bytes()); } diff --git a/src/templates/gmi.rs b/src/templates/gmi.rs @@ -1,6 +1,7 @@ // WIP // use crate::models::*; +use crate::templates::PAGE_SIZE; use crate::time::Date; use crate::util::*; use nanotemplate::template; @@ -25,40 +26,46 @@ impl Lists { impl List { pub fn to_gmi(&self) -> Vec<String> { // TODO paginate - let mut threads = format!("## {}\n", self.config.name); - for thread in &self.thread_topics { - threads.push_str( - // TODO reuse with html templates? - &template( - r#" + self.thread_topics + .chunks(PAGE_SIZE) + .enumerate() + .map(|(n, thread_topics)| { + let mut threads = format!("## {}\n", self.config.name); + for thread in thread_topics { + threads.push_str( + // TODO reuse with html templates? + &template( + r#" => threads/{path_id}.gmi {subject} {preview} {from} | {replies} replies | {date} "#, - &[ - ( - "path_id", - &h(thread.message.pathescape_msg_id().to_str().unwrap()), - ), - ("subject", &h(&thread.message.subject)), - ("replies", &thread.reply_count.to_string()), - ("preview", &h(&thread.message.preview)), - ("date", &h(&Date::from(thread.last_reply).ymd())), - ( - "from", - &h(&thread. // awkawrd + &[ + ( + "path_id", + &h(thread.message.pathescape_msg_id().to_str().unwrap()), + ), + ("subject", &h(&thread.message.subject)), + ("replies", &thread.reply_count.to_string()), + ("preview", &h(&thread.message.preview)), + ("date", &h(&Date::from(thread.last_reply).ymd())), + ( + "from", + &h(&thread. // awkawrd message.from .name .clone() .unwrap_or(thread.message.from.address.clone()) .clone()), - ), - ], - ) - .unwrap(), - ); - } - vec![threads] + ), + ], + ) + .unwrap(), + ); + } + threads + }) + .collect() } } diff --git a/src/templates/html.rs b/src/templates/html.rs @@ -1,6 +1,7 @@ use super::util::xml_escape; use super::util::xml_safe as x; use crate::models::*; +use crate::templates::PAGE_SIZE; use crate::time::Date; use crate::util::*; use linkify::{LinkFinder, LinkKind}; @@ -53,46 +54,59 @@ impl Lists { impl List { pub fn to_html(&self) -> Vec<String> { // TODO paginate - let mut threads = String::new(); - for thread in &self.thread_topics { - threads.push_str( - &template( - r#" + let page_count = self.thread_topics.len() / PAGE_SIZE + 1; + let mut page_idx = "<b>Pages</b>: ".to_string(); + for n in 0..page_count { + let path = match n { + 0 => "index.html".to_string(), + n => format!("index-{}.html", n + 1), + }; + page_idx.push_str(&format!("<a href='{}'>{}</a> ", path, n + 1)); + } + self.thread_topics + .chunks(PAGE_SIZE) + .enumerate() + .map(|(n, thread_topics)| { + let mut threads = String::new(); + for thread in thread_topics { + threads.push_str( + &template( + r#" <div class='message-sum'> <a class="bigger" href="threads/{path_id}.html">{subject}</a> <br> <div class="monospace">{preview}</div> <b>{from}</b> | {replies} replies | {date}<hr> "#, - &[ - ( - "path_id", - &x(thread.message.pathescape_msg_id().to_str().unwrap()), - ), - ("subject", &x(&thread.message.subject)), - ("replies", &thread.reply_count.to_string()), - ("date", &x(&Date::from(thread.last_reply).ymd())), - ( - "from", - &x(&thread. // awkawrd + &[ + ( + "path_id", + &x(thread.message.pathescape_msg_id().to_str().unwrap()), + ), + ("subject", &x(&thread.message.subject)), + ("replies", &thread.reply_count.to_string()), + ("date", &x(&Date::from(thread.last_reply).ymd())), + ( + "from", + &x(&thread. // awkawrd message.from .name .clone() .unwrap_or(thread.message.from.address.clone()) .clone()), - ), - ("preview", &x(&thread.message.preview)), - ], - ) - .unwrap(), - ); - } - // TODO use summary?? - let page = template( - &format!( - "{}{}{}", - HEADER, - r#" + ), + ("preview", &x(&thread.message.preview)), + ], + ) + .unwrap(), + ); + } + // TODO use summary?? + let page = template( + &format!( + "{}{}{}", + HEADER, + r#" <h1 class="page-title"> {title} <a href="atom.xml"> @@ -103,22 +117,27 @@ impl List { <a href="{mailto:list_email}">{list_email}</a> <hr> {threads} + {page_idx} + <hr> "#, - FOOTER - ), - &[ - ("header", HEADER), - ("description", &self.config.description), - ("title", self.config.title.as_str()), - ("css_path", "../style.css"), - ("threads", &threads), - ("list_email", &self.config.email), - ("rss_svg", RSS_SVG), - ("footer", FOOTER), - ], - ) - .unwrap(); - vec![page] + FOOTER + ), + &[ + ("header", HEADER), + ("description", &self.config.description), + ("title", self.config.title.as_str()), + ("css_path", "../style.css"), + ("threads", &threads), + ("page_idx", &page_idx), + ("list_email", &self.config.email), + ("rss_svg", RSS_SVG), + ("footer", FOOTER), + ], + ) + .unwrap(); + page + }) + .collect() } } diff --git a/src/templates/mod.rs b/src/templates/mod.rs @@ -3,4 +3,4 @@ pub mod html; pub mod util; pub mod xml; -// const PAGE_SIZE: i32 = 100; +const PAGE_SIZE: usize = 10;