mirror of
https://github.com/adoyle0/thaw.git
synced 2025-02-02 08:34:15 -05:00
✨ feat: add tabbar component
This commit is contained in:
parent
d61fa318c5
commit
90c9856469
12 changed files with 176 additions and 2 deletions
|
@ -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>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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>
|
10
examples/basic/src/pages/mobile.rs
Normal file
10
examples/basic/src/pages/mobile.rs
Normal 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>
|
||||||
|
}
|
||||||
|
}
|
|
@ -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::*;
|
||||||
|
|
23
examples/basic/src/pages/tabbar/mod.rs
Normal file
23
examples/basic/src/pages/tabbar/mod.rs
Normal 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>
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
3
src/mobile/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mod tabbar;
|
||||||
|
|
||||||
|
pub use tabbar::*;
|
55
src/mobile/tabbar/mod.rs
Normal file
55
src/mobile/tabbar/mod.rs
Normal 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")
|
||||||
|
}
|
17
src/mobile/tabbar/tabbar-item.css
Normal file
17
src/mobile/tabbar/tabbar-item.css
Normal 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;
|
||||||
|
}
|
10
src/mobile/tabbar/tabbar.css
Normal file
10
src/mobile/tabbar/tabbar.css
Normal 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;
|
||||||
|
}
|
42
src/mobile/tabbar/tabbar_item.rs
Normal file
42
src/mobile/tabbar/tabbar_item.rs
Normal 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>
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue