feat: add tabbar component

This commit is contained in:
luoxiao 2023-05-27 23:55:27 +08:00
parent d61fa318c5
commit 90c9856469
12 changed files with 176 additions and 2 deletions

View file

@ -1,4 +1,3 @@
use crate::components::*;
use crate::pages::*; use crate::pages::*;
use leptos::*; use leptos::*;
use leptos_router::*; use leptos_router::*;
@ -26,8 +25,16 @@ pub fn App(cx: Scope) -> impl IntoView {
<Route path="/slider" view=move |cx| view! {cx, <Route path="/slider" view=move |cx| view! {cx,
<SliderPage /> <SliderPage />
} /> } />
<Route path="/tabbar" view=move |cx| view! {cx,
<MobilePage path="/mobile/tabbar" />
} />
</Route> </Route>
</Routes> </Routes>
<Routes base="/mobile".to_string()>
<Route path="/tabbar" view=move |cx| view! {cx,
<TabbarPage />
} />
</Routes>
</Router> </Router>
} }
} }

View file

@ -4,7 +4,6 @@ mod demo_checkbox;
mod demo_modal; mod demo_modal;
mod demo_slider; mod demo_slider;
mod pages; mod pages;
mod components;
use app::*; use app::*;
use leptos::*; use leptos::*;

View file

@ -35,6 +35,7 @@ pub fn ComponentsPage(cx: Scope) -> impl IntoView {
<Menu selected> <Menu selected>
<MenuItem key="menu" label="menu" /> <MenuItem key="menu" label="menu" />
<MenuItem key="slider" label="slider" /> <MenuItem key="slider" label="slider" />
<MenuItem key="tabbar" label="tabbar" />
</Menu> </Menu>
</aside> </aside>
<main> <main>

View file

@ -0,0 +1,10 @@
use leptos::*;
#[component]
pub fn MobilePage(cx: Scope, path: &'static str) -> impl IntoView {
view! { cx,
<div style="height: 100vh; display: flex; align-items: center; justify-content: center; background: #eff2f5">
<iframe src=path style="width: 360px; height: 640px; background-color: #fff; border: none; border-radius: 16px; border: 1px solid #e1e1e1"/>
</div>
}
}

View file

@ -1,7 +1,13 @@
mod components;
mod home; mod home;
mod menu; mod menu;
mod mobile;
mod slider; mod slider;
mod tabbar;
pub use components::*;
pub use home::*; pub use home::*;
pub use menu::*; pub use menu::*;
pub use mobile::*;
pub use slider::*; pub use slider::*;
pub use tabbar::*;

View file

@ -0,0 +1,23 @@
use leptos::*;
use melt_ui::mobile::*;
#[component]
pub fn TabbarPage(cx: Scope) -> impl IntoView {
let selected = create_rw_signal(cx, String::from("o"));
view! { cx,
<div style="height: 100vh; background: #f5f5f5">
{ move || selected.get() }
<Tabbar selected>
<TabbarItem name="a">
"and"
</TabbarItem>
<TabbarItem name="i">
"if"
</TabbarItem>
<TabbarItem name="o" icon=leptos_icons::AiIcon::AiCloseOutlined>
"or"
</TabbarItem>
</Tabbar>
</div>
}
}

View file

@ -4,6 +4,7 @@ mod checkbox;
mod components; mod components;
mod input; mod input;
mod menu; mod menu;
pub mod mobile;
mod modal; mod modal;
mod progress; mod progress;
mod slider; mod slider;

3
src/mobile/mod.rs Normal file
View file

@ -0,0 +1,3 @@
mod tabbar;
pub use tabbar::*;

55
src/mobile/tabbar/mod.rs Normal file
View file

@ -0,0 +1,55 @@
mod tabbar_item;
use crate::utils::mount_style::mount_style;
use leptos::*;
use stylers::style_sheet_str;
pub use tabbar_item::*;
#[component]
pub fn Tabbar(
cx: Scope,
#[prop(into)] selected: RwSignal<String>,
children: Children,
) -> impl IntoView {
let class_name = mount_style("tabbar", || {
style_sheet_str!("./src/mobile/tabbar/tabbar.css")
});
let tabbar_injection_key = create_rw_signal(cx, TabbarInjectionKey::new(selected.get()));
create_effect(cx, move |_| {
let selected_key = selected.get();
let key = tabbar_injection_key.get_untracked();
if selected_key != key.value {
tabbar_injection_key.set(TabbarInjectionKey::new(selected_key));
}
});
create_effect(cx, move |_| {
let selected_key = selected.get_untracked();
let key = tabbar_injection_key.get();
if selected_key != key.value {
selected.set(key.value);
}
});
provide_context(cx, tabbar_injection_key);
view! {cx, class=class_name,
<div class="melt-tabbar">
{ children(cx) }
</div>
}
}
#[derive(Clone)]
pub struct TabbarInjectionKey {
value: String,
}
impl TabbarInjectionKey {
pub fn new(value: String) -> Self {
Self { value }
}
}
pub fn use_tabbar(cx: Scope) -> RwSignal<TabbarInjectionKey> {
use_context::<RwSignal<TabbarInjectionKey>>(cx).expect("TabbarInjectionKey not exist")
}

View file

@ -0,0 +1,17 @@
.melt-tabbar-item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
}
.melt-tabbar-item--selected {
color: var(--font-color-selected)
}
.melt-tabbar-item__content {
font-size: 14px;
line-height: 14px;
}

View file

@ -0,0 +1,10 @@
.melt-tabbar {
background-color: #fff;
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 50px;
display: flex;
justify-content: space-around;
}

View file

@ -0,0 +1,42 @@
use super::{use_tabbar, TabbarInjectionKey};
use crate::{theme::use_theme, utils::mount_style::mount_style, Theme};
use leptos::*;
use stylers::style_sheet_str;
use crate::components::*;
use leptos_icons::*;
#[component]
pub fn TabbarItem(
cx: Scope,
#[prop(into)] name: MaybeSignal<&'static str>,
#[prop(optional, into)] icon: Option<IconData>,
children: Children,
) -> impl IntoView {
let class_name = mount_style("tabbar-item", || style_sheet_str!("./src/mobile/tabbar/tabbar-item.css"));
let theme = use_theme(cx, Theme::light);
let tabbar = use_tabbar(cx);
let onclick_select = move |_| {
tabbar.set(TabbarInjectionKey::new(name.get().to_string()));
};
let css_vars = create_memo(cx, move |_| {
let mut css_vars = String::new();
let theme = theme.get();
let font_color = theme.common.color_primary.clone();
css_vars.push_str(&format!("--font-color-selected: {font_color};"));
css_vars
});
view! {cx, class=class_name,
<div class="melt-tabbar-item" class=("melt-tabbar-item--selected", move || tabbar.get().value == name.get()) on:click=onclick_select style=move || css_vars.get()>
<OptionComp value=icon view=move |cx, icon| {
view!{cx,
<Icon icon=icon width="22px" height="22px" class="melt-tabbar-item__icon"/>
}
}/>
<div class="melt-tabbar-item__content">
{ children(cx) }
</div>
</div>
}
}