diff --git a/src/blog_posts/blog_post_model.rs b/src/blog_posts/blog_post_model.rs index 60addee..76ad208 100644 --- a/src/blog_posts/blog_post_model.rs +++ b/src/blog_posts/blog_post_model.rs @@ -1,14 +1,23 @@ use chrono::{DateTime, Utc}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use crate::post_utils::post_parser::deserialize_date; pub const BLOG_POST_PATH: &str = "_posts/blog"; -#[derive(Deserialize, Debug, Clone)] +#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] // Optional, this converts enum variants to lowercase +pub enum Segment { + Blog, + Broadcasts, + Featured, + Cookbook, +} + +#[derive(Deserialize, Debug)] pub struct BlogPostMetadata { pub title: String, - pub segments: Vec, + pub segments: Vec, pub published: bool, #[serde(deserialize_with = "deserialize_date")] pub date: DateTime, diff --git a/src/main.rs b/src/main.rs index c79b559..3f21c84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ -use askama_axum::IntoResponse; -use axum::{self, extract::OriginalUri, http::StatusCode}; +use axum::{self}; use tower_http::services::ServeDir; use tower_livereload::LiveReloadLayer; use tracing::info; @@ -57,3 +56,5 @@ async fn main() { // THINK deploy to alula? rather then katelyn? can be change whenever // // TODO 404 page +// TODO view page transitions +// TODO cookbook diff --git a/src/pages/blog_post_list.rs b/src/pages/blog_post_list.rs index c86ed58..643bf4a 100644 --- a/src/pages/blog_post_list.rs +++ b/src/pages/blog_post_list.rs @@ -6,10 +6,11 @@ use tokio::try_join; use tracing::debug; use crate::{ - blog_posts::blog_post_model::{BlogPostMetadata, BLOG_POST_PATH}, + blog_posts::blog_post_model::{BlogPostMetadata, Segment, BLOG_POST_PATH}, components::site_header::{HeaderProps, Link}, post_utils::{ post_listing::get_post_list, + segments::get_posts_by_segment, tags::{get_popular_tags, get_posts_by_tag}, }, projects::featured_projects::get_featured_projects, @@ -17,6 +18,7 @@ use crate::{ use super::post_list::PostListTemplate; +// TODO Refactor to render post list for the same broadcasts, blog and cookbook pub async fn render_blog_post_list( tag: Option>, OriginalUri(original_uri): OriginalUri, @@ -24,18 +26,14 @@ pub async fn render_blog_post_list( // I will forget what happens here in a week. But essentially it's pattern matching and shadowing let tag = tag.map(|Path(tag)| tag); - let (blog_tags, featured_projects, mut post_list) = try_join!( - get_popular_tags(Some("blog".to_string())), + let (blog_tags, featured_projects, post_list) = try_join!( + get_popular_tags(Some(Segment::Blog)), get_featured_projects(), get_post_list::(BLOG_POST_PATH) )?; - post_list.sort_by_key(|post| post.metadata.date); - post_list.retain(|post| post.metadata.published); - post_list.retain(|post| post.metadata.segments.contains(&"blog".to_string())); - post_list.reverse(); - - let posts = get_posts_by_tag(post_list, &tag); + let posts = get_posts_by_segment(post_list, &[Segment::Blog]); + let posts = get_posts_by_tag(posts, &tag); let header_props = match tag { Some(_) => HeaderProps::with_back_link(Link { href: "/blog".to_string(), @@ -55,7 +53,7 @@ pub async fn render_blog_post_list( Ok(PostListTemplate { title, og_title, - segment: "blog".to_string(), + segment: Segment::Blog, posts, header_props, tags: blog_tags, diff --git a/src/pages/broadcast_list.rs b/src/pages/broadcast_list.rs index 8321e91..cb24a82 100644 --- a/src/pages/broadcast_list.rs +++ b/src/pages/broadcast_list.rs @@ -6,10 +6,11 @@ use tokio::try_join; use tracing::debug; use crate::{ - blog_posts::blog_post_model::{BlogPostMetadata, BLOG_POST_PATH}, + blog_posts::blog_post_model::{BlogPostMetadata, Segment, BLOG_POST_PATH}, components::site_header::{HeaderProps, Link}, post_utils::{ post_listing::get_post_list, + segments::get_posts_by_segment, tags::{get_popular_tags, get_posts_by_tag}, }, projects::featured_projects::get_featured_projects, @@ -24,18 +25,14 @@ pub async fn render_broadcast_post_list( // I will forget what happens here in a week. But essentially it's pattern matching and shadowing let tag = tag.map(|Path(tag)| tag); - let (popular_tags, featured_projects, mut post_list) = try_join!( - get_popular_tags(Some("broadcasts".to_string())), + let (popular_tags, featured_projects, post_list) = try_join!( + get_popular_tags(Some(Segment::Broadcasts)), get_featured_projects(), get_post_list::(BLOG_POST_PATH) )?; - post_list.sort_by_key(|post| post.metadata.date); - post_list.retain(|post| post.metadata.published); - post_list.retain(|post| post.metadata.segments.contains(&"broadcasts".to_string())); - post_list.reverse(); - - let posts = get_posts_by_tag(post_list, &tag); + let posts = get_posts_by_segment(post_list, &[Segment::Broadcasts]); + let posts = get_posts_by_tag(posts, &tag); let header_props = match tag { Some(_) => HeaderProps::with_back_link(Link { @@ -56,7 +53,7 @@ pub async fn render_broadcast_post_list( Ok(PostListTemplate { title: title.clone(), og_title: title, - segment: "broadcasts".to_string(), + segment: Segment::Broadcasts, posts, header_props, tags: popular_tags, diff --git a/src/pages/index.rs b/src/pages/index.rs index d151f81..0e2f919 100644 --- a/src/pages/index.rs +++ b/src/pages/index.rs @@ -5,7 +5,7 @@ use axum::http::StatusCode; use tokio::try_join; use crate::{ - blog_posts::blog_post_model::{BlogPostMetadata, BLOG_POST_PATH}, + blog_posts::blog_post_model::{BlogPostMetadata, Segment, BLOG_POST_PATH}, components::site_header::HeaderProps, filters, post_utils::{ @@ -28,8 +28,8 @@ pub struct IndexTemplate { pub async fn render_index() -> Result { let (blog_tags, broadcasts_tags, all_posts, featured_projects) = try_join!( - get_popular_tags(Some("blog".to_string())), - get_popular_tags(Some("broadcasts".to_string())), + get_popular_tags(Some(Segment::Blog)), + get_popular_tags(Some(Segment::Broadcasts)), get_post_list::(BLOG_POST_PATH), get_featured_projects() )?; @@ -39,12 +39,10 @@ pub async fn render_index() -> Result { all_posts.into_iter().map(Rc::new).collect(); let featured_blog_posts = - ref_get_posts_by_segment(&all_posts_rc, &["blog".to_string(), "featured".to_string()]); + ref_get_posts_by_segment(&all_posts_rc, &[Segment::Blog, Segment::Featured]); - let featured_broadcasts = ref_get_posts_by_segment( - &all_posts_rc, - &["broadcasts".to_string(), "featured".to_string()], - ); + let featured_broadcasts = + ref_get_posts_by_segment(&all_posts_rc, &[Segment::Broadcasts, Segment::Featured]); Ok(IndexTemplate { header_props: HeaderProps::default(), diff --git a/src/pages/post_list.rs b/src/pages/post_list.rs index 6ef81d1..d6972e9 100644 --- a/src/pages/post_list.rs +++ b/src/pages/post_list.rs @@ -1,8 +1,11 @@ use askama::Template; use crate::{ - blog_posts::blog_post_model::BlogPostMetadata, components::site_header::HeaderProps, filters, - post_utils::post_parser::ParseResult, projects::project_model::ProjectMetadata, + blog_posts::blog_post_model::{BlogPostMetadata, Segment}, + components::site_header::HeaderProps, + filters, + post_utils::post_parser::ParseResult, + projects::project_model::ProjectMetadata, }; #[derive(Template)] @@ -10,7 +13,7 @@ use crate::{ pub struct PostListTemplate { pub title: String, pub og_title: String, - pub segment: String, + pub segment: Segment, pub posts: Vec>, pub header_props: HeaderProps, pub tags: Vec, diff --git a/src/post_utils/segments.rs b/src/post_utils/segments.rs index b47de68..888b7e6 100644 --- a/src/post_utils/segments.rs +++ b/src/post_utils/segments.rs @@ -1,35 +1,50 @@ -use std::rc::Rc; +use std::{fmt::Display, rc::Rc}; -use crate::blog_posts::blog_post_model::BlogPostMetadata; +use crate::blog_posts::blog_post_model::{BlogPostMetadata, Segment}; use super::post_parser::ParseResult; -// // TODO convert segmetns to enum, find out how to serde to enum vlaue -// pub fn get_posts_by_segment( -// post_list: &Vec>, -// segments: &Vec, -// ) -> Vec> { -// let mut filtered_posts: Vec> = post_list -// .iter() -// .filter(|post| { -// segments -// .iter() -// .all(|segment| post.metadata.segments.contains(segment)) -// }) // Filter by segments -// .filter(|post| post.metadata.published) // Filter only published posts -// .cloned() -// .collect(); +impl Segment { + fn as_str(&self) -> &'static str { + match self { + Segment::Blog => "blog", + Segment::Broadcasts => "broadcasts", + Segment::Featured => "featured", + Segment::Cookbook => "cookbook", + } + } +} -// // Sort by date in descending order -// filtered_posts.sort_by_key(|post| post.metadata.date); -// filtered_posts.reverse(); +impl Display for Segment { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } +} -// filtered_posts -// } +pub fn get_posts_by_segment( + post_list: Vec>, + segments: &[Segment], +) -> Vec> { + let mut filtered_posts: Vec> = post_list + .into_iter() + .filter(|post| { + segments + .iter() + .all(|segment| post.metadata.segments.contains(segment)) + }) // Filter by segments + .filter(|post| post.metadata.published) // Filter only published posts + .collect(); + + // Sort by date in descending order + filtered_posts.sort_by_key(|post| post.metadata.date); + filtered_posts.reverse(); + + filtered_posts +} pub fn ref_get_posts_by_segment( post_list: &[Rc>], - segments: &[String], + segments: &[Segment], ) -> Vec>> { let mut filtered_posts: Vec>> = post_list .iter() // Use iter() to borrow instead of consuming the original vector diff --git a/src/post_utils/tags.rs b/src/post_utils/tags.rs index 8a5b58d..8159f67 100644 --- a/src/post_utils/tags.rs +++ b/src/post_utils/tags.rs @@ -2,11 +2,11 @@ use axum::http::StatusCode; use std::collections::HashMap; use tracing::debug; -use crate::blog_posts::blog_post_model::{BlogPostMetadata, BLOG_POST_PATH}; +use crate::blog_posts::blog_post_model::{BlogPostMetadata, Segment, BLOG_POST_PATH}; use super::{post_listing::get_post_list, post_parser::ParseResult}; -pub async fn get_popular_tags(segment: Option) -> Result, StatusCode> { +pub async fn get_popular_tags(segment: Option) -> Result, StatusCode> { const TAGS_LENGTH: usize = 7; let mut post_list = get_post_list::(BLOG_POST_PATH).await?;