refactor(admin): extract comments filter tabs into FilterTabs component

This commit is contained in:
xfy 2026-06-29 13:15:50 +08:00
parent 79af7d345e
commit d91a56f8b2
2 changed files with 41 additions and 11 deletions

View File

@ -185,3 +185,38 @@ pub fn EmptyState(message: &'static str, variant: &'static str) -> Element {
div { class: "{class}", "{message}" }
}
}
/// 筛选选项卡组件。
///
/// 用于切换不同的视图或筛选条件(例如:全部、待审核、已通过等)。
///
/// Props
/// - `items`:选项卡列表,每一项为 `(value, label)`
/// - `active_value`:当前选中的值
/// - `on_change`:选项卡切换时的回调
#[component]
pub fn FilterTabs(
items: Vec<(&'static str, &'static str)>,
active_value: String,
on_change: EventHandler<String>,
) -> Element {
rsx! {
div { class: "flex gap-1 border-b border-paper-border",
for (value, label) in items {
button {
key: "{value}",
class: if active_value == *value {
"cursor-pointer px-4 py-2 text-sm font-medium border-b-2 border-paper-accent text-paper-primary"
} else {
"cursor-pointer px-4 py-2 text-sm font-medium text-paper-secondary hover:text-paper-primary transition-colors"
},
onclick: {
let v = value.to_string();
move |_| on_change.call(v.clone())
},
"{label}"
}
}
}
}
}

View File

@ -18,7 +18,7 @@ use crate::components::skeletons::atoms::SkeletonBox;
use crate::components::skeletons::delayed_skeleton::DelayedSkeleton;
use crate::components::empty_state::EmptyState;
use crate::components::ui::{
Pagination, StatusBadge, ADMIN_CARD_CLASS, ADMIN_ROW_HOVER, ADMIN_TABLE_CLASS,
FilterTabs, Pagination, StatusBadge, ADMIN_CARD_CLASS, ADMIN_ROW_HOVER, ADMIN_TABLE_CLASS,
BTN_TEXT_AMBER, BTN_TEXT_GREEN, BTN_TEXT_RED, BTN_SOLID_AMBER, BTN_SOLID_GREEN, BTN_SOLID_RED,
CHECKBOX_CLASS,
};
@ -129,20 +129,15 @@ pub fn AdminCommentsPage(page: i32) -> Element {
div { class: "space-y-6",
h1 { class: "text-2xl font-bold text-paper-primary", "评论管理" }
div { class: "flex gap-1 border-b border-paper-border",
for (status, label) in [
FilterTabs {
items: vec![
("", "全部"),
("pending", "待审核"),
("approved", "已通过"),
("spam", "垃圾箱"),
]
{
button {
class: if active_filter() == status { "cursor-pointer px-4 py-2 text-sm font-medium border-b-2 border-paper-accent text-paper-primary" } else { "cursor-pointer px-4 py-2 text-sm font-medium text-paper-secondary hover:text-paper-primary transition-colors" },
onclick: move |_| active_filter.set(status.to_string()),
"{label}"
}
}
],
active_value: active_filter(),
on_change: move |v| active_filter.set(v),
}
if !selected_ids().is_empty() {