111 lines
3.3 KiB
Rust
111 lines
3.3 KiB
Rust
use dioxus::prelude::*;
|
|
use dioxus::router::components::Link;
|
|
|
|
use crate::api::posts::{list_published_posts, PostListResponse};
|
|
use crate::components::post_card::PostCard;
|
|
use crate::components::skeletons::delayed_skeleton::DelayedSkeleton;
|
|
use crate::components::skeletons::home_skeleton::HomeSkeleton;
|
|
use crate::router::Route;
|
|
|
|
const POSTS_PER_PAGE: i32 = 10;
|
|
|
|
#[component]
|
|
pub fn Home() -> Element {
|
|
rsx! { HomePage { page: 1 } }
|
|
}
|
|
|
|
#[component]
|
|
pub fn HomePage(page: i32) -> Element {
|
|
let current_page = page.max(1);
|
|
|
|
rsx! {
|
|
HomeInfo {}
|
|
HomePosts { current_page }
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
fn HomePosts(current_page: i32) -> Element {
|
|
let posts_res = use_server_future(move || list_published_posts(current_page, POSTS_PER_PAGE))?;
|
|
|
|
let posts_data = posts_res.read().as_ref().map(|r| match r {
|
|
Ok(PostListResponse { posts }) => Ok(posts.clone()),
|
|
Err(e) => Err(e.to_string()),
|
|
});
|
|
|
|
match posts_data {
|
|
Some(Ok(posts)) => {
|
|
rsx! {
|
|
for post in posts.iter() {
|
|
PostCard { post: post.clone() }
|
|
}
|
|
if posts.is_empty() {
|
|
div { class: "text-center text-gray-500 dark:text-[#9b9c9d] py-20",
|
|
"暂无文章"
|
|
}
|
|
}
|
|
Pagination { current_page, posts: posts.clone() }
|
|
}
|
|
}
|
|
Some(Err(e)) => {
|
|
rsx! {
|
|
div { class: "text-center text-red-500 dark:text-red-400 py-20",
|
|
"加载失败: {e}"
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
rsx! {
|
|
DelayedSkeleton { HomeSkeleton {} }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
fn HomeInfo() -> Element {
|
|
rsx! {
|
|
div { class: "mb-10 text-center",
|
|
h1 { class: "text-[34px] font-bold leading-tight text-gray-900 dark:text-[#dadadb]",
|
|
"Yggdrasil"
|
|
}
|
|
p { class: "mt-3 text-base text-gray-500 dark:text-[#9b9c9d] leading-relaxed",
|
|
"以文字为主的简约博客系统"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
fn Pagination(current_page: i32, posts: Vec<crate::models::post::Post>) -> Element {
|
|
let has_prev = current_page > 1;
|
|
let has_next = posts.len() >= POSTS_PER_PAGE as usize;
|
|
let prev = current_page - 1;
|
|
let prev_route = if prev <= 1 {
|
|
Route::Home {}
|
|
} else {
|
|
Route::HomePage { page: prev }
|
|
};
|
|
|
|
rsx! {
|
|
nav { class: "flex mt-10 mb-6 justify-between",
|
|
if has_prev {
|
|
Link {
|
|
class: "inline-flex items-center px-4 py-2 text-sm text-white bg-gray-900 dark:bg-[#dadadb] dark:text-gray-900 rounded-full hover:opacity-80 transition-opacity cursor-pointer",
|
|
to: prev_route,
|
|
span { class: "mr-1", "«" }
|
|
"上一页"
|
|
}
|
|
}
|
|
if has_next {
|
|
Link {
|
|
class: "ml-auto inline-flex items-center px-4 py-2 text-sm text-white bg-gray-900 dark:bg-[#dadadb] dark:text-gray-900 rounded-full hover:opacity-80 transition-opacity cursor-pointer",
|
|
to: Route::HomePage { page: current_page + 1 },
|
|
"下一页"
|
|
span { class: "ml-1", "»" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|