diff --git a/src/components/empty_state.rs b/src/components/empty_state.rs index 809b4e7..e5d5704 100644 --- a/src/components/empty_state.rs +++ b/src/components/empty_state.rs @@ -14,7 +14,8 @@ use dioxus::router::components::Link; #[derive(Props, Clone, PartialEq)] pub struct EmptyStateAction { /// 按钮文案。 - pub label: &'static str, + #[props(into)] + pub label: String, /// 跳转目标路由。 pub to: crate::router::Route, } @@ -28,11 +29,14 @@ pub struct EmptyStateAction { #[component] pub fn EmptyState( /// 主标题(通常为「还没有文章」之类)。 - #[props(default)] title: Option<&'static str>, + #[props(into, default = "还没有文章".to_string())] + title: String, /// 副文案,说明当前状态或引导用户。 - #[props(default)] description: Option<&'static str>, + #[props(into, default = String::new())] + description: String, /// 可选的行动按钮。 - #[props(default)] action: Option, + #[props(default)] + action: Option, ) -> Element { rsx! { div { class: "flex flex-col items-center justify-center text-center py-20 px-4 page-enter", @@ -45,12 +49,12 @@ pub fn EmptyState( } // 主标题:衬线字体,与首页 H1 风格呼应但更轻量。 h2 { class: "mt-8 text-2xl font-bold tracking-tight text-paper-primary", - {title.unwrap_or("还没有文章")} + "{title}" } // 副文案:次要色,限宽保证可读性。 - if let Some(desc) = description { + if !description.is_empty() { p { class: "mt-3 text-sm leading-relaxed text-paper-secondary max-w-md", - {desc} + "{description}" } } // 行动按钮:药丸形,与搜索页主按钮一致。 @@ -58,7 +62,7 @@ pub fn EmptyState( Link { class: "mt-8 inline-flex items-center px-6 py-2 bg-paper-accent text-white rounded-full font-medium text-sm hover:brightness-110 active:scale-[0.98] transition-all duration-200", to: act.to, - {act.label} + "{act.label}" } } } diff --git a/src/pages/archives.rs b/src/pages/archives.rs index 268e770..d55fa29 100644 --- a/src/pages/archives.rs +++ b/src/pages/archives.rs @@ -11,6 +11,7 @@ use dioxus::prelude::*; use dioxus::router::components::Link; use crate::api::posts::{list_published_posts, PostListResponse}; +use crate::components::empty_state::EmptyState; use crate::components::skeletons::archive_skeleton::ArchiveSkeleton; use crate::components::skeletons::delayed_skeleton::DelayedSkeleton; use crate::models::post::PostListItem; @@ -119,17 +120,26 @@ fn ArchivesContent() -> Element { let posts_data = posts_res.read(); match &*posts_data { Some(Ok(PostListResponse { posts, total })) => { - let grouped = group_posts(posts); - rsx! { - div { class: "mt-2 text-base text-paper-secondary", - "共 " - span { class: "font-medium text-paper-primary", "{total}" } - " 篇文章" + if *total == 0 { + rsx! { + EmptyState { + title: "还没有文章归档", + description: "发布文章后,这里会自动按年月进行归档显示。", + } } - for year_group in grouped.iter() { - YearSection { - key: "{year_group.year}", - year_group: year_group.clone(), + } else { + let grouped = group_posts(posts); + rsx! { + div { class: "mt-2 text-base text-paper-secondary", + "共 " + span { class: "font-medium text-paper-primary", "{total}" } + " 篇文章" + } + for year_group in grouped.iter() { + YearSection { + key: "{year_group.year}", + year_group: year_group.clone(), + } } } }