feat(ui): refactor EmptyState to accept dynamic string props and add empty state to archives page
This commit is contained in:
parent
824ad5a3d3
commit
178870427c
@ -14,7 +14,8 @@ use dioxus::router::components::Link;
|
|||||||
#[derive(Props, Clone, PartialEq)]
|
#[derive(Props, Clone, PartialEq)]
|
||||||
pub struct EmptyStateAction {
|
pub struct EmptyStateAction {
|
||||||
/// 按钮文案。
|
/// 按钮文案。
|
||||||
pub label: &'static str,
|
#[props(into)]
|
||||||
|
pub label: String,
|
||||||
/// 跳转目标路由。
|
/// 跳转目标路由。
|
||||||
pub to: crate::router::Route,
|
pub to: crate::router::Route,
|
||||||
}
|
}
|
||||||
@ -28,11 +29,14 @@ pub struct EmptyStateAction {
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn EmptyState(
|
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<EmptyStateAction>,
|
#[props(default)]
|
||||||
|
action: Option<EmptyStateAction>,
|
||||||
) -> Element {
|
) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "flex flex-col items-center justify-center text-center py-20 px-4 page-enter",
|
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 风格呼应但更轻量。
|
// 主标题:衬线字体,与首页 H1 风格呼应但更轻量。
|
||||||
h2 { class: "mt-8 text-2xl font-bold tracking-tight text-paper-primary",
|
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",
|
p { class: "mt-3 text-sm leading-relaxed text-paper-secondary max-w-md",
|
||||||
{desc}
|
"{description}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 行动按钮:药丸形,与搜索页主按钮一致。
|
// 行动按钮:药丸形,与搜索页主按钮一致。
|
||||||
@ -58,7 +62,7 @@ pub fn EmptyState(
|
|||||||
Link {
|
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",
|
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,
|
to: act.to,
|
||||||
{act.label}
|
"{act.label}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use dioxus::prelude::*;
|
|||||||
use dioxus::router::components::Link;
|
use dioxus::router::components::Link;
|
||||||
|
|
||||||
use crate::api::posts::{list_published_posts, PostListResponse};
|
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::archive_skeleton::ArchiveSkeleton;
|
||||||
use crate::components::skeletons::delayed_skeleton::DelayedSkeleton;
|
use crate::components::skeletons::delayed_skeleton::DelayedSkeleton;
|
||||||
use crate::models::post::PostListItem;
|
use crate::models::post::PostListItem;
|
||||||
@ -119,6 +120,14 @@ fn ArchivesContent() -> Element {
|
|||||||
let posts_data = posts_res.read();
|
let posts_data = posts_res.read();
|
||||||
match &*posts_data {
|
match &*posts_data {
|
||||||
Some(Ok(PostListResponse { posts, total })) => {
|
Some(Ok(PostListResponse { posts, total })) => {
|
||||||
|
if *total == 0 {
|
||||||
|
rsx! {
|
||||||
|
EmptyState {
|
||||||
|
title: "还没有文章归档",
|
||||||
|
description: "发布文章后,这里会自动按年月进行归档显示。",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let grouped = group_posts(posts);
|
let grouped = group_posts(posts);
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "mt-2 text-base text-paper-secondary",
|
div { class: "mt-2 text-base text-paper-secondary",
|
||||||
@ -134,6 +143,7 @@ fn ArchivesContent() -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "text-center text-red-500 dark:text-red-400 py-20", "加载失败: {e}" }
|
div { class: "text-center text-red-500 dark:text-red-400 py-20", "加载失败: {e}" }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user