feat: add tabs component

This commit is contained in:
luoxiao 2023-06-15 18:02:21 +08:00
parent b50acd1e55
commit de88ddb7e3
5 changed files with 111 additions and 0 deletions

View file

@ -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::*;

64
src/tabs/mod.rs Normal file
View file

@ -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,
<div class="melt-tabs" style=move || css_vars.get()>
<div class="melt-tabs__label-list">
<For each=move || tab_options_vec.get() key=move |v| v.key.clone() view=move |cx, options| view! {cx, class=class_name,
<span class="melt-tabs__label" class=("melt-tabs__label--active", move || options.key == active_key.get()) on:click=move |_| active_key.set(options.key)>
{ options.label }
</span>
}>
</For>
<span class="melt-tabs-label__active"></span>
</div>
<div>
{ children(cx) }
</div>
</div>
}
}
#[derive(Clone)]
pub struct TabsInjectionKey {
active_key: RwSignal<&'static str>,
tab_options_vec: RwSignal<Vec<TabOptions>>,
}
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::<TabsInjectionKey>(cx).expect("TabsInjectionKey not exist")
}

3
src/tabs/tab.css Normal file
View file

@ -0,0 +1,3 @@
.melt-tab--hidden {
display: none;
}

22
src/tabs/tab.rs Normal file
View file

@ -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,
<div class="melt-tab" class=("melt-tab--hidden", move || key != tabs.get_key()) >
{ children(cx) }
</div>
}
}

20
src/tabs/tabs.css Normal file
View file

@ -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;
}