feat: perfect tabs component

This commit is contained in:
luoxiao 2023-06-18 22:13:32 +08:00
parent 0296c4a00b
commit c1537409a7
7 changed files with 81 additions and 11 deletions

View file

@ -49,6 +49,9 @@ pub fn App(cx: Scope) -> impl IntoView {
<Route path="/toast" view=move |cx| view! {cx,
<MobilePage path="/melt-ui?path=/mobile/toast" />
} />
<Route path="/tabs" view=move |cx| view! {cx,
<TabsPage />
} />
</Route>
</Routes>
<Routes base="/melt-ui/mobile".to_string()>

View file

@ -12,7 +12,7 @@ pub fn ComponentsPage(cx: Scope) -> impl IntoView {
create_effect(cx, move |_| {
let pathname = loaction.pathname.get();
let re = Regex::new(r"^/components/(.+)$").unwrap();
let re = Regex::new(r"^/melt-ui/components/(.+)$").unwrap();
let Some(caps) = re.captures(&pathname) else {
return;
};
@ -46,6 +46,7 @@ pub fn ComponentsPage(cx: Scope) -> impl IntoView {
<MenuItem key="button" label="button" />
<MenuItem key="checkbox" label="checkbox" />
<MenuItem key="toast" label="toast" />
<MenuItem key="tabs" label="tabs" />
</Menu>
</LayoutSider>
<Layout>

View file

@ -10,6 +10,7 @@ mod modal;
mod nav_bar;
mod slider;
mod tabbar;
mod tabs;
mod toast;
pub use button::*;
@ -24,4 +25,5 @@ pub use modal::*;
pub use nav_bar::*;
pub use slider::*;
pub use tabbar::*;
pub use tabs::*;
pub use toast::*;

View file

@ -0,0 +1,17 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn TabsPage(cx: Scope) -> impl IntoView {
let active_key = create_rw_signal(cx, "apple");
view! { cx,
<Tabs active_key>
<Tab key="apple" label="Apple">
"apple"
</Tab>
<Tab key="pear" label="Pear">
"pear"
</Tab>
</Tabs>
}
}

View file

@ -1,5 +1,5 @@
mod tab;
use crate::{utils::mount_style::mount_style, theme::use_theme, Theme};
use crate::{theme::use_theme, utils::mount_style::mount_style, Theme};
use leptos::*;
use stylers::style_sheet_str;
pub use tab::*;
@ -20,19 +20,56 @@ pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -
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.push_str(&format!(
"--label-active-background-color: {color_primary};"
));
css_vars
});
let label_line = create_rw_signal::<Option<TabsLabelLine>>(cx, None);
let label_line_style = create_memo(cx, move |_| {
let mut style = String::new();
if let Some(line) = label_line.get() {
style.push_str(&format!("width: {}px; left: {}px", line.width, line.left))
}
style
});
let label_list_ref = create_node_ref::<html::Div>(cx);
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>
<div class="melt-tabs__label-list" ref=label_list_ref>
<For each=move || tab_options_vec.get() key=move |v| v.key.clone() view=move |cx, options| {
let label_ref = create_node_ref::<html::Span>(cx);
create_effect(cx, move |_| {
let Some(label) = label_ref.get() else {
return;
};
let Some(label_list) = label_list_ref.get() else {
return;
};
if options.key == active_key.get() {
request_animation_frame(move || {
let list_rect = label_list.get_bounding_client_rect();
let rect = label.get_bounding_client_rect();
label_line.set(Some(TabsLabelLine {
width: rect.width(),
left: rect.left() - list_rect.left(),
}));
});
}
});
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)
ref=label_ref
>
{ options.label }
</span>
}
}>
</For>
<span class="melt-tabs-label__active"></span>
<span class="melt-tabs-label__line" style=move || label_line_style.get()></span>
</div>
<div>
{ children(cx) }
@ -41,6 +78,12 @@ pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -
}
}
#[derive(Clone)]
pub(crate) struct TabsLabelLine {
width: f64,
left: f64,
}
#[derive(Clone)]
pub struct TabsInjectionKey {
active_key: RwSignal<&'static str>,

View file

@ -1,3 +1,7 @@
.melt-tab {
padding-top: 12px;
}
.melt-tab--hidden {
display: none;
}

View file

@ -10,11 +10,11 @@
cursor: pointer;
}
.melt-tabs-label__active {
.melt-tabs-label__line {
position: absolute;
height: 3px;
background-color: var(--label-active-background-color);
border-radius: 3px;
bottom: 0;
left: 0;
}
}