use anyhow::{Context, Result}; use maud::{html, Markup}; use serde::Deserialize; use toml::value::Date; use self::page::Page; mod page; #[derive(Deserialize)] struct Data { stories: Vec, } impl page::Page for Vec { fn page_title() -> String { String::from("Stories") } fn render_content(self) -> Markup { html!( @for story in self { (story.render_as_card()) } ) } fn prepare_content(&self) -> Result<()> { for story in self { std::fs::copy(&story.path, story.format_local_pdf_path())?; } Ok(()) } } #[derive(Deserialize, Debug)] enum StoryLanguage { German, English, } impl std::fmt::Display for StoryLanguage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } #[derive(Deserialize)] struct Story { name: String, description: String, language: StoryLanguage, upload_date: Date, update_date: Option, path: String, } impl Story { fn render_as_card(self) -> Markup { html!(div class="story-card" { card { h2 { (self.name) } p { (self.description) } hr {} ul { li { "Language: " (self.language) } li { "Uploaded on: " (self.upload_date) } @if let Some(update_date) = self.update_date { li { "Updated on: " (update_date) } } li { a href=(&self.format_pdf_path()) download { "PDF" } } } } }) } fn format_pdf_path(&self) -> String { let snake_case_name = self.name.to_lowercase().replace(" ", "_"); format!("stories/{}.pdf", snake_case_name) } fn format_local_pdf_path(&self) -> String { format!("dist/{}", self.format_pdf_path()) } } fn main() -> Result<()> { let data_file_content = std::fs::read_to_string("data.toml").with_context(|| "Failed to read data.toml")?; let data: Data = toml::from_str(&data_file_content)?; data.stories.write_page()?; Ok(()) }