Add tags in post

This commit is contained in:
Florian RICHER 2024-01-07 00:23:25 +01:00
parent cf65d5b8e9
commit d353161c92
3 changed files with 74 additions and 30 deletions

View file

@ -1,4 +1,5 @@
use leptos::*; use leptos::*;
use leptos_router::A;
#[component] #[component]
pub fn Title( pub fn Title(
@ -8,7 +9,7 @@ pub fn Title(
) -> impl IntoView { ) -> impl IntoView {
view! { view! {
<header> <header>
<a href=href>r"< Retour"</a> <A href=href>r"< Retour"</A>
<h1>{title}</h1> <h1>{title}</h1>
<span></span> <span></span>
</header> </header>

View file

@ -9,12 +9,18 @@ use crate::app::{
}; };
#[server] #[server]
pub async fn get_posts() -> Result<Vec<Post>, ServerFnError> { pub async fn get_posts(
tag: Option<String>
) -> Result<Vec<Post>, ServerFnError> {
leptos_actix::extract( leptos_actix::extract(
|data: actix_web::web::Data<crate::app::models::Data>| async move { |data: actix_web::web::Data<crate::app::models::Data>| async move {
let data = data.into_inner(); let data = data.into_inner();
data.posts let default = vec![];
.iter() let posts = match tag {
Some(tag) => data.posts_by_tag.get(&tag).unwrap_or(&default),
None => &data.posts
};
posts.iter()
.map(|post| { .map(|post| {
Post { Post {
metadata: post.metadata.clone(), metadata: post.metadata.clone(),
@ -44,44 +50,72 @@ pub async fn get_post(
.and_then(|post| post.ok_or_else(|| ServerFnError::ServerError("Post not found".to_string()))) .and_then(|post| post.ok_or_else(|| ServerFnError::ServerError("Post not found".to_string())))
} }
#[component]
pub fn PostTags(
tags: Vec<String>
) -> impl IntoView {
view! {
<div class="tags_list">
{
tags.into_iter().map(|tag| view! { <A class="tag" href=format!("/posts?tag={}", tag)>{tag}</A>}).collect_view()
}
</div>
}
}
#[component]
pub fn PostListCard(
post: Post
) -> impl IntoView {
view! {
<div>
<img src={post.metadata.image_path.clone()} alt=format!("Image {}", post.metadata.title)/>
{
if post.metadata.draft {
Some(view!{
<div class="warning">
<Icon icon=Icon::from(IoIcon::IoConstruct)/>
</div>
})
} else {
None
}
}
<div>
<PostTags tags=post.metadata.tags.clone()/>
<h2>{post.metadata.title.clone()}</h2>
<p>{post.metadata.description.clone()}</p>
<span>{post.metadata.date.clone()}</span>
</div>
</div>
}
}
#[component] #[component]
pub fn PostList() -> impl IntoView { pub fn PostList() -> impl IntoView {
let posts = create_resource(|| (), |_| get_posts()); let query = use_query_map();
let tag = move || query.with(|query| query.get("tag").cloned());
let posts = create_resource(move || tag(), move |_| get_posts(tag()));
let posts_view = move || { let posts_view = move || {
posts.and_then(|posts| { posts.and_then(|posts| {
posts.iter() posts.iter()
.map(|post| view! { .map(|post| view! { <PostListCard post=post.clone() /> })
<a href=format!("posts/{}", post.metadata.slug.clone())>
<img src={post.metadata.image_path.clone()} alt=format!("Image {}", post.metadata.title)/>
{
if post.metadata.draft {
Some(view!{
<div class="warning">
<Icon icon=Icon::from(IoIcon::IoConstruct)/>
</div>
})
} else {
None
}
}
<div>
<h2>{post.metadata.title.clone()}</h2>
<p>{post.metadata.description.clone()}</p>
<span>{post.metadata.date.clone()}</span>
</div>
</a>
})
.collect_view() .collect_view()
}) })
}; };
let title = move || match tag() {
Some(tag) => view! { <Title href="/posts".to_string() title=format!("Posts for {}", tag)/> },
None => view! { <Title href="/".to_string() title="Posts".to_string()/> }
};
view! { view! {
<Suspense fallback=move || view! { <Loading title="Chargement des posts...".to_string() /> }> <Suspense fallback=move || view! { <Loading title="Chargement des posts...".to_string() /> }>
<main class="posts"> <main class="posts">
<Title href="/".to_string() title="Posts".to_string()/> { title }
<div class="posts__cards">{posts_view}</div> <div class="posts__cards">{posts_view}</div>
</main> </main>
@ -101,6 +135,7 @@ pub fn PostElement() -> impl IntoView {
view! { view! {
<> <>
<Title href="/posts".to_string() title=post.metadata.title.clone()/> <Title href="/posts".to_string() title=post.metadata.title.clone()/>
<PostTags tags=post.metadata.tags.clone()/>
{ {
if post.metadata.draft { if post.metadata.draft {
Some(view!{ Some(view!{

View file

@ -42,13 +42,21 @@
& ol li { & ol li {
@apply list-decimal list-inside; @apply list-decimal list-inside;
} }
& blockquote {
@apply border-l-4 border-primary/50 dark:border-dark_primary/50 pl-3 my-3;
}
& .tags_list {
@apply flex flex-row flex-wrap gap-2;
}
} }
.posts { .posts {
& > .posts__cards { & > .posts__cards {
@apply grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 m-5; @apply grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 m-5;
& > a { & > div {
@apply rounded-xl overflow-hidden relative; @apply rounded-xl overflow-hidden relative;
@apply bg-primary/10 dark:bg-dark_primary/10; @apply bg-primary/10 dark:bg-dark_primary/10;
@apply shadow-md shadow-primary/5 dark:shadow-dark_primary/5; @apply shadow-md shadow-primary/5 dark:shadow-dark_primary/5;