use crate::activitypub::DOMAIN; use chrono::{DateTime, Utc}; use once_cell::sync::Lazy; use std::time::SystemTime; static CB: Lazy = Lazy::new(|| { SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs() }); static GENERATED_AT: Lazy> = Lazy::new(|| Utc::now()); pub trait TemplateCommon { fn domain() -> String { DOMAIN.to_owned() } fn stylesheet_cache_buster() -> u64 { *CB } fn fancy_link(text: &str, href: &str, meta: Option<&str>) -> String { format!( r#" {} "#, href, meta.unwrap_or(""), text ) } fn generated_at() -> &'static DateTime { &*GENERATED_AT } } pub mod filters { use std::fmt::Display; use chrono::{DateTime, Datelike, NaiveDate, TimeZone, Utc}; pub fn iso_date(date: &NaiveDate) -> askama::Result { Ok(DateTime::::from_utc(date.and_hms(12, 0, 0), Utc) .format("%+:0") .to_string()) } pub fn iso_datetime(datetime: &DateTime) -> askama::Result where Tz: TimeZone, Tz::Offset: Display, { Ok(datetime.format("%+:0").to_string()) } const MONTHS: &[&str; 12] = &[ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; pub fn pretty_date(date: &impl Datelike) -> askama::Result { let month = MONTHS[date.month0() as usize]; let suffix = match date.day() { 1 | 21 | 31 => "st", 2 | 22 => "nd", 3 | 23 => "rd", _ => "th", }; Ok(format!( "{} {}{}, {}", month, date.day(), suffix, date.year() )) } pub fn pretty_datetime(datetime: &DateTime) -> askama::Result where Tz: TimeZone, Tz::Offset: Display, { Ok(format!( "{} {}", datetime.format("%-I:%M:%S %p"), pretty_date(datetime)? )) } pub fn reading_time(words: &u32) -> askama::Result { let wpm = 225.0; return Ok((*words as f32 / wpm).max(1.0) as u32); } }