portfolio_leptos/src/app/pages/posts.rs

103 lines
No EOL
3.3 KiB
Rust

use leptos::*;
use leptos_router::*;
use crate::app::{
models::Post,
components::{
Title, Loading
}
};
#[server]
pub async fn get_posts() -> Result<Vec<Post>, ServerFnError> {
let posts = Post::get_all("posts")
.map_err(|e| ServerFnError::ServerError(e.to_string()))?;
Ok(posts)
}
#[server]
pub async fn get_post(
slug: String
) -> Result<Post, ServerFnError> {
let posts = Post::get_all("posts")
.map_err(|e| ServerFnError::ServerError(e.to_string()))?;
let post = posts.into_iter().find(|post| post.slug == slug)
.ok_or(ServerFnError::ServerError("Post not found".to_string()))?;
Ok(post)
}
#[component]
pub fn PostList() -> impl IntoView {
let posts = create_resource(|| (), |_| get_posts());
let posts_view = move || {
posts.and_then(|posts| {
posts.iter()
.map(|post| view! {
<a href=format!("posts/{}", post.slug.clone())>
<img src={post.metadata.image_path.clone()} alt=format!("Image {}", post.metadata.title)/>
<div>
<h2>{post.metadata.title.clone()}</h2>
<p>{post.metadata.description.clone()}</p>
<span>{post.metadata.date.clone()}</span>
</div>
</a>
})
.collect_view()
})
};
view! {
<Suspense fallback=move || view! { <Loading title="Chargement des posts...".to_string() /> }>
<main class="posts">
<Title href="/".to_string() title="Posts".to_string()/>
<div class="posts__cards">{posts_view}</div>
</main>
</Suspense>
}
}
#[component]
pub fn PostElement() -> impl IntoView {
let params = use_params_map();
let slug = move || params.with(|params| params.get("slug").cloned().unwrap_or_default());
let post = create_resource(|| (), move |_| get_post(slug()));
let post_view = move || {
post.and_then(|post| {
view! {
<>
<Title href="/posts".to_string() title=post.metadata.title.clone()/>
{
if post.metadata.draft {
Some(view!{
<div class="bg-warning text-on_warning dark:bg-dark_warning dark:text-dart_on_warning rounded-md p-5">
r#"
L'article est en cours d'écriture. La formulation peut ne pas être exacte et les phrases peuvent contenir des fautes.
"#
</div>
})
} else {
None
}
}
<div inner_html={post.content.clone()}></div>
</>
}
})
};
view! {
<Suspense fallback=move || view! { <Loading title="Chargement du post...".to_string() /> }>
<main class="post">
{post_view}
<script>load();</script>
</main>
</Suspense>
}
}