diff --git a/src/components/ui.rs b/src/components/ui.rs index b43ca5d..fd60bde 100644 --- a/src/components/ui.rs +++ b/src/components/ui.rs @@ -274,3 +274,48 @@ pub fn FilterTabs( } } } + +/// 页面级导航 Tab 组件。 +/// +/// 与 [`FilterTabs`] 的区别: +/// - [`FilterTabs`]:**列表筛选**语义,带平滑滑动底部指示条动画(靠 WASM 端测量 +/// `offsetLeft/offsetWidth`)。适合「全部 / 待审核 / 已通过」这类同质数据过滤。 +/// - `Tabs`:**页面导航**语义,选中态用按钮自身 `border-b-2` 下划线(无动画)。 +/// 适合「数据库状态 / 服务器状态 / SQL 控制台」这类切换到结构完全不同的面板。 +/// +/// 因 Dioxus 0.7 `#[component]` 宏不支持泛型类型参数,value 用 `String`(与 +/// `FilterTabs` 一致);调用方负责枚举 ↔ String 的桥接(见 `SystemTab::as_str`)。 +/// +/// Props: +/// - `items`:`(value, label)` 列表,`value` 是稳定字符串 key,`label` 是展示文案 +/// - `active_value`:当前选中项的 value +/// - `on_change`:切换时回调,传入新选中项的 value +// Task 3 起由 /admin/system 页面消费;在此之前无调用方,加 allow 抑制 dead_code(参考 src/api/auth.rs:427)。 +#[allow(dead_code)] +#[component] +pub fn Tabs( + items: Vec<(&'static str, &'static str)>, + active_value: String, + on_change: EventHandler, +) -> Element { + rsx! { + div { class: "flex flex-wrap gap-1 border-b border-paper-border", + for (value, label) in items { + button { + key: "{value}", + class: "px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors", + class: if active_value == *value { + "border-paper-accent text-paper-accent" + } else { + "border-transparent text-paper-secondary hover:text-paper-primary" + }, + onclick: { + let v = value.to_string(); + move |_| on_change.call(v.clone()) + }, + {label} + } + } + } + } +}