use rust_embed::RustEmbed; use sailfish::TemplateOnce; use chrono::NaiveDate; use regex::{Regex}; use std::str; use std::cmp::{PartialOrd, Ord, PartialEq, Eq}; const BLOG_REGEX: &str = r"(?P[\d]{4}-[\d]{2}-[\d]{2})(?P[a-zA-Z0-9-_]*)"; #[derive(RustEmbed)] #[folder = "content/posts/"] struct PostAsset; #[derive(TemplateOnce)] #[template(path = "index.html")] struct IndexTemplate { posts: Vec<BlogEntry>, } #[derive(TemplateOnce)] #[template(path = "post.html")] struct PostTemplate { content: String, title: String, date: String } #[derive(PartialEq, Eq, PartialOrd, Ord)] pub struct BlogEntry { pub title: String, pub datetime: NaiveDate, pub file: String, } impl BlogEntry { pub fn new(path: &String) -> BlogEntry { let re = Regex::new(BLOG_REGEX).unwrap(); let caps = re.captures(path).unwrap(); let date = &caps["date"]; let title = str::replace(&caps["title"], "_", " "); BlogEntry { title: String::from(title), file: String::from(path), datetime: NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap() } } pub fn read_assets() -> Vec<BlogEntry> { let mut entries: Vec<BlogEntry> = PostAsset::iter() .map(|e| format!("{}", e)) .map(|e| BlogEntry::new(&e)) .collect(); entries.sort_by(|a, b| b.datetime.cmp(&a.datetime)); entries } } fn get_file_content(path: &str) -> String { let buffer = PostAsset::get(path) .unwrap() .data .into_owned(); return String::from_utf8(buffer).unwrap(); } pub fn render_post_page(path: &String) -> String { let blog = BlogEntry::new(path); PostTemplate { content: get_file_content(path), title: blog.title, date: blog.datetime.format("%Y-%m-%d").to_string() } .render_once() .unwrap() } pub fn render_index_page() -> String { IndexTemplate { posts: BlogEntry::read_assets() } .render_once() .unwrap() }