From de88ddb7e35c6943560129f99f2e9604fdf21d7d Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 15 Jun 2023 18:02:21 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20tabs=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 2 ++ src/tabs/mod.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++ src/tabs/tab.css | 3 +++ src/tabs/tab.rs | 22 ++++++++++++++++ src/tabs/tabs.css | 20 +++++++++++++++ 5 files changed, 111 insertions(+) create mode 100644 src/tabs/mod.rs create mode 100644 src/tabs/tab.css create mode 100644 src/tabs/tab.rs create mode 100644 src/tabs/tabs.css diff --git a/src/lib.rs b/src/lib.rs index 620cc65..424a328 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ mod progress; mod slider; mod space; mod table; +mod tabs; mod teleport; mod theme; mod utils; @@ -25,6 +26,7 @@ pub use modal::*; pub use progress::*; pub use slider::*; pub use space::*; +pub use tabs::*; pub use table::*; pub use theme::Theme; pub use wave::*; diff --git a/src/tabs/mod.rs b/src/tabs/mod.rs new file mode 100644 index 0000000..2953299 --- /dev/null +++ b/src/tabs/mod.rs @@ -0,0 +1,64 @@ +mod tab; +use crate::{utils::mount_style::mount_style, theme::use_theme, Theme}; +use leptos::*; +use stylers::style_sheet_str; +pub use tab::*; + +#[component] +pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -> impl IntoView { + let class_name = mount_style("tabs", || style_sheet_str!("./src/tabs/tabs.css")); + let tab_options_vec = create_rw_signal(cx, vec![]); + provide_context( + cx, + TabsInjectionKey { + active_key: active_key.clone(), + tab_options_vec: tab_options_vec.clone(), + }, + ); + let theme = use_theme(cx, Theme::light); + let css_vars = create_memo(cx, move |_| { + let mut css_vars = String::new(); + let theme = theme.get(); + let color_primary = theme.common.color_primary.clone(); + css_vars.push_str(&format!("--label-active-background-color: {color_primary};")); + css_vars + }); + view! { cx, class=class_name, +
+
+ + { options.label } + + }> + + +
+
+ { children(cx) } +
+
+ } +} + +#[derive(Clone)] +pub struct TabsInjectionKey { + active_key: RwSignal<&'static str>, + tab_options_vec: RwSignal>, +} + +impl TabsInjectionKey { + pub fn get_key(&self) -> &str { + self.active_key.get() + } + + pub(crate) fn push_tab_options(&self, options: TabOptions) { + self.tab_options_vec.update(|v| { + v.push(options); + }); + } +} + +pub fn use_tabs(cx: Scope) -> TabsInjectionKey { + use_context::(cx).expect("TabsInjectionKey not exist") +} diff --git a/src/tabs/tab.css b/src/tabs/tab.css new file mode 100644 index 0000000..d28c3f8 --- /dev/null +++ b/src/tabs/tab.css @@ -0,0 +1,3 @@ +.melt-tab--hidden { + display: none; +} diff --git a/src/tabs/tab.rs b/src/tabs/tab.rs new file mode 100644 index 0000000..be4fedf --- /dev/null +++ b/src/tabs/tab.rs @@ -0,0 +1,22 @@ +use super::use_tabs; +use crate::utils::mount_style::mount_style; +use leptos::*; +use stylers::style_sheet_str; + +#[derive(Clone)] +pub(crate) struct TabOptions { + pub key: &'static str, + pub label: &'static str, +} + +#[component] +pub fn Tab(cx: Scope, key: &'static str, label: &'static str, children: Children) -> impl IntoView { + let class_name = mount_style("tab", || style_sheet_str!("./src/tabs/tab.css")); + let tabs = use_tabs(cx); + tabs.push_tab_options(TabOptions { key, label }); + view! { cx, class=class_name, +
+ { children(cx) } +
+ } +} diff --git a/src/tabs/tabs.css b/src/tabs/tabs.css new file mode 100644 index 0000000..59e62ca --- /dev/null +++ b/src/tabs/tabs.css @@ -0,0 +1,20 @@ +.melt-tabs__label-list { + position: relative; +} + +.melt-tabs__label { + padding: 0 20px; + display: inline-block; + height: 40px; + line-height: 40px; + cursor: pointer; +} + +.melt-tabs-label__active { + position: absolute; + height: 3px; + background-color: var(--label-active-background-color); + border-radius: 3px; + bottom: 0; + left: 0; +} \ No newline at end of file