portfolio_leptos/src/app/models/post.rs

60 lines
1.8 KiB
Rust

use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PostMetadata {
pub slug: String,
pub image_path: String,
pub title: String,
pub date: String,
pub description: String,
pub project_link: String,
pub draft: bool,
pub tags: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Post {
pub metadata: PostMetadata,
pub content: String,
}
cfg_if::cfg_if! {
if #[cfg(feature = "ssr")] {
#[derive(Debug, thiserror::Error)]
pub enum PostDeserializationError {
#[error("Invalid front matter")]
InvalidFrontMatter,
#[error("Invalid markdown")]
InvalidMarkdown,
}
impl TryFrom<String> for Post {
type Error = PostDeserializationError;
fn try_from(content: String) -> Result<Self, Self::Error> {
use gray_matter::{Matter, engine::YAML};
let matter = Matter::<YAML>::new();
let post_data = matter
.parse_with_struct::<PostMetadata>(&content)
.ok_or_else(|| PostDeserializationError::InvalidFrontMatter)?;
let content = post_data.content;
use pulldown_cmark::{Parser, Options, html};
let parser = Parser::new_ext(&content, Options::all());
let mut html_output = String::new();
html::push_html(&mut html_output, parser);
if html_output.is_empty() {
return Err(PostDeserializationError::InvalidMarkdown);
}
Ok(Self {
metadata: post_data.data,
content: html_output,
})
}
}
}
}