1use rust_embed::RustEmbed;
2use sailfish::TemplateOnce;
3use chrono::NaiveDate;
4use regex::{Regex};
5use std::str;
6use std::cmp::{PartialOrd, Ord, PartialEq, Eq};
7
8const BLOG_REGEX: &str = r"(?P<date>[\d]{4}-[\d]{2}-[\d]{2})(?P<title>[a-zA-Z0-9-_]*)";
9
10#[derive(RustEmbed)]
11#[folder = "content/posts/"]
12struct PostAsset;
13
14
15#[derive(TemplateOnce)]
16#[template(path = "index.html")]
17struct IndexTemplate {
18 posts: Vec<BlogEntry>,
19}
20
21#[derive(TemplateOnce)]
22#[template(path = "post.html")]
23struct PostTemplate {
24 content: String,
25 title: String,
26 date: String
27}
28
29#[derive(PartialEq, Eq, PartialOrd, Ord)]
30pub struct BlogEntry {
31 pub title: String,
32 pub datetime: NaiveDate,
33 pub file: String,
34}
35
36impl BlogEntry {
37 pub fn new(path: &String) -> BlogEntry {
38 let re = Regex::new(BLOG_REGEX).unwrap();
39 let caps = re.captures(path).unwrap();
40 let date = &caps["date"];
41 let title = str::replace(&caps["title"], "_", " ");
42
43 BlogEntry {
44 title: String::from(title),
45 file: String::from(path),
46 datetime: NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap()
47 }
48 }
49
50 pub fn read_assets() -> Vec<BlogEntry> {
51
52 let mut entries: Vec<BlogEntry> = PostAsset::iter()
53 .map(|e| format!("{}", e))
54 .map(|e| BlogEntry::new(&e))
55 .collect();
56
57 entries.sort_by(|a, b| b.datetime.cmp(&a.datetime));
58
59 entries
60 }
61}
62
63fn get_file_content(path: &str) -> String {
64 let buffer = PostAsset::get(path)
65 .unwrap()
66 .data
67 .into_owned();
68
69 return String::from_utf8(buffer).unwrap();
70}
71
72
73pub fn render_post_page(path: &String) -> String {
74 let blog = BlogEntry::new(path);
75
76 PostTemplate {
77 content: get_file_content(path),
78 title: blog.title,
79 date: blog.datetime.format("%Y-%m-%d").to_string()
80 }
81 .render_once()
82 .unwrap()
83}
84
85pub fn render_index_page() -> String {
86 IndexTemplate { posts: BlogEntry::read_assets() }
87 .render_once()
88 .unwrap()
89}