site_footer and post listing order
This commit is contained in:
parent
e0ad3f29ae
commit
c9704a20f6
1
axum_server/src/components/mod.rs
Normal file
1
axum_server/src/components/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod site_footer;
|
21
axum_server/src/components/site_footer.rs
Normal file
21
axum_server/src/components/site_footer.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use askama::Template;
|
||||
|
||||
use crate::{pages::post::PostMetadata, post_list::get_post_list, post_parser::ParseResult};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "site_footer.html")]
|
||||
pub struct SiteFooter {
|
||||
pub latest_posts: Vec<ParseResult<PostMetadata>>,
|
||||
}
|
||||
|
||||
pub async fn render_site_footer() -> SiteFooter {
|
||||
let mut post_list = get_post_list::<PostMetadata>().await.unwrap_or(vec![]);
|
||||
post_list.sort_by_key(|post| post.metadata.date);
|
||||
post_list.reverse();
|
||||
|
||||
let latest_posts = post_list
|
||||
.into_iter()
|
||||
.take(6)
|
||||
.collect::<Vec<ParseResult<PostMetadata>>>();
|
||||
SiteFooter { latest_posts }
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
use askama::filters::format;
|
||||
use axum;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
mod components;
|
||||
mod pages;
|
||||
mod post_list;
|
||||
mod post_parser;
|
||||
mod router;
|
||||
// mod template;
|
||||
|
@ -1,9 +1,14 @@
|
||||
use askama::Template;
|
||||
|
||||
use crate::components::site_footer::{render_site_footer, SiteFooter};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "index.html")]
|
||||
pub struct IndexTemplate {}
|
||||
pub struct IndexTemplate {
|
||||
site_footer: SiteFooter,
|
||||
}
|
||||
|
||||
pub async fn render_index() -> IndexTemplate {
|
||||
IndexTemplate {}
|
||||
let site_footer = render_site_footer().await;
|
||||
IndexTemplate { site_footer }
|
||||
}
|
||||
|
@ -3,7 +3,10 @@ use axum::{extract::Path, http::StatusCode};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::post_parser::{deserialize_date, parse_post};
|
||||
use crate::{
|
||||
components::site_footer::{render_site_footer, SiteFooter},
|
||||
post_parser::{deserialize_date, parse_post},
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct PostMetadata {
|
||||
@ -22,13 +25,20 @@ pub struct PostMetadata {
|
||||
pub struct PostTemplate {
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub site_footer: SiteFooter,
|
||||
}
|
||||
|
||||
pub async fn render_post(Path(post_id): Path<String>) -> Result<PostTemplate, StatusCode> {
|
||||
let site_footer = tokio::spawn(render_site_footer());
|
||||
let path = format!("../_posts/blog/{}.md", post_id);
|
||||
let parsed = parse_post::<PostMetadata>(&path).await?;
|
||||
|
||||
let site_footer = site_footer
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
Ok(PostTemplate {
|
||||
title: parsed.metadata.title,
|
||||
body: parsed.body,
|
||||
site_footer,
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
use askama::Template;
|
||||
use axum::{extract::Path, http::StatusCode};
|
||||
use tokio::fs::read_dir;
|
||||
use tracing::info;
|
||||
|
||||
use crate::post_parser::{parse_post, ParseResult};
|
||||
use crate::{
|
||||
components::site_footer::{render_site_footer, SiteFooter},
|
||||
post_list::get_post_list,
|
||||
post_parser::ParseResult,
|
||||
};
|
||||
|
||||
use super::post::PostMetadata;
|
||||
|
||||
@ -13,32 +15,20 @@ pub struct PostListTemplate {
|
||||
pub title: String,
|
||||
pub posts: Vec<ParseResult<PostMetadata>>,
|
||||
pub tag: Option<String>,
|
||||
pub site_footer: SiteFooter,
|
||||
}
|
||||
|
||||
pub async fn render_post_list(tag: Option<Path<String>>) -> Result<PostListTemplate, StatusCode> {
|
||||
// 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 path = "../_posts/blog/";
|
||||
let mut dir = read_dir(path)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let mut posts: Vec<ParseResult<PostMetadata>> = Vec::new();
|
||||
let site_footer = tokio::spawn(render_site_footer());
|
||||
let mut post_list = get_post_list::<PostMetadata>().await?;
|
||||
post_list.sort_by_key(|post| post.metadata.date);
|
||||
post_list.reverse();
|
||||
|
||||
while let Some(file) = dir
|
||||
.next_entry()
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
{
|
||||
let file_path = file.path();
|
||||
let file_path_str = file_path.to_str().unwrap();
|
||||
info!(":{}", file_path_str);
|
||||
let post = parse_post::<PostMetadata>(file_path_str).await?;
|
||||
posts.push(post);
|
||||
}
|
||||
|
||||
let mut posts = match &tag {
|
||||
Some(tag) => posts
|
||||
let posts = match &tag {
|
||||
Some(tag) => post_list
|
||||
.into_iter()
|
||||
.filter(|post| {
|
||||
post.metadata
|
||||
@ -49,23 +39,18 @@ pub async fn render_post_list(tag: Option<Path<String>>) -> Result<PostListTempl
|
||||
.contains(&tag.to_lowercase())
|
||||
})
|
||||
.collect(),
|
||||
None => posts,
|
||||
None => post_list,
|
||||
};
|
||||
|
||||
if std::env::var("TARGET")
|
||||
.unwrap_or_else(|_| "DEV".to_owned())
|
||||
.eq("PROD")
|
||||
{
|
||||
posts = posts
|
||||
.into_iter()
|
||||
.filter(|post| !post.slug.starts_with("dev"))
|
||||
.collect()
|
||||
}
|
||||
let site_footer = site_footer
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(PostListTemplate {
|
||||
title: "Posts".to_owned(),
|
||||
posts,
|
||||
tag,
|
||||
site_footer,
|
||||
})
|
||||
}
|
||||
|
||||
|
39
axum_server/src/post_list.rs
Normal file
39
axum_server/src/post_list.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use axum::http::StatusCode;
|
||||
use serde::de::DeserializeOwned;
|
||||
use tokio::fs::read_dir;
|
||||
use tracing::info;
|
||||
|
||||
use crate::post_parser::{parse_post, ParseResult};
|
||||
|
||||
pub async fn get_post_list<'de, Metadata: DeserializeOwned>(
|
||||
) -> Result<Vec<ParseResult<Metadata>>, StatusCode> {
|
||||
let path = "../_posts/blog/";
|
||||
let mut dir = read_dir(path)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let mut posts: Vec<ParseResult<Metadata>> = Vec::new();
|
||||
|
||||
while let Some(file) = dir
|
||||
.next_entry()
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
{
|
||||
let file_path = file.path();
|
||||
let file_path_str = file_path.to_str().unwrap();
|
||||
info!(":{}", file_path_str);
|
||||
let post = parse_post::<Metadata>(file_path_str).await?;
|
||||
posts.push(post);
|
||||
}
|
||||
|
||||
if std::env::var("TARGET")
|
||||
.unwrap_or_else(|_| "DEV".to_owned())
|
||||
.eq("PROD")
|
||||
{
|
||||
posts = posts
|
||||
.into_iter()
|
||||
.filter(|post| !post.slug.starts_with("dev"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
return Ok(posts);
|
||||
}
|
@ -31,7 +31,8 @@
|
||||
<link rel="icon" type="image/png" href="/m-logo-192.png" />
|
||||
</head>
|
||||
<body>
|
||||
{% block content %} Placeholder {% endblock %}
|
||||
{# footer, should be not dependant on the each individual handler but it should have it's own handler #}
|
||||
{% block content %} Placeholder {% endblock %} {# footer, should be not
|
||||
dependant on the each individual handler but it should have it's own handler
|
||||
#} {{ site_footer|safe }}
|
||||
</body>
|
||||
</html>
|
||||
|
7
axum_server/templates/site_footer.html
Normal file
7
axum_server/templates/site_footer.html
Normal file
@ -0,0 +1,7 @@
|
||||
<footer>
|
||||
{% for post in latest_posts %}
|
||||
|
||||
<article>{{post.metadata.title}}</article>
|
||||
|
||||
{% endfor %}
|
||||
</footer>
|
Loading…
Reference in New Issue
Block a user