mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
✨ feat: use if component
This commit is contained in:
parent
4e0b338a65
commit
933a9c7316
13 changed files with 105 additions and 111 deletions
|
@ -43,6 +43,9 @@ pub fn App(cx: Scope) -> impl IntoView {
|
||||||
<Route path="/button" view=move |cx| view! {cx,
|
<Route path="/button" view=move |cx| view! {cx,
|
||||||
<ButtonPage />
|
<ButtonPage />
|
||||||
} />
|
} />
|
||||||
|
<Route path="/checkbox" view=move |cx| view! {cx,
|
||||||
|
<CheckboxPage />
|
||||||
|
} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
<Routes base="/mobile".to_string()>
|
<Routes base="/mobile".to_string()>
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
use leptos::*;
|
|
||||||
use melt_ui::*;
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn DemoCheckout(cx: Scope) -> impl IntoView {
|
|
||||||
let (checked, set_checked) = create_signal(cx, false);
|
|
||||||
view! {cx,
|
|
||||||
<div>
|
|
||||||
<Checkbox>
|
|
||||||
"A"
|
|
||||||
</Checkbox>
|
|
||||||
<Checkbox checked=true>
|
|
||||||
"B"
|
|
||||||
</Checkbox>
|
|
||||||
<Checkbox checked=checked on_checked=set_checked>
|
|
||||||
"Click"
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
use leptos::*;
|
|
||||||
use melt_ui::*;
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn DemoSlider(cx: Scope) -> impl IntoView {
|
|
||||||
let (value, set_value) = create_signal(cx, 0.0);
|
|
||||||
let on_value = SignalSetter::map(cx, move |value| {
|
|
||||||
set_value.set(value);
|
|
||||||
});
|
|
||||||
view! { cx,
|
|
||||||
<Slider value=value on_value=on_value/>
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,4 @@
|
||||||
mod app;
|
mod app;
|
||||||
mod demo_checkbox;
|
|
||||||
mod demo_slider;
|
|
||||||
mod pages;
|
mod pages;
|
||||||
|
|
||||||
use app::*;
|
use app::*;
|
||||||
|
|
14
examples/basic/src/pages/checkbox/mod.rs
Normal file
14
examples/basic/src/pages/checkbox/mod.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
use leptos::*;
|
||||||
|
use melt_ui::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn CheckboxPage(cx: Scope) -> impl IntoView {
|
||||||
|
let checked = create_rw_signal(cx, false);
|
||||||
|
view! {cx,
|
||||||
|
<div>
|
||||||
|
<Checkbox checked>
|
||||||
|
"Click"
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,7 @@ pub fn ComponentsPage(cx: Scope) -> impl IntoView {
|
||||||
<MenuItem key="modal" label="madal" />
|
<MenuItem key="modal" label="madal" />
|
||||||
<MenuItem key="nav-bar" label="nav-bar" />
|
<MenuItem key="nav-bar" label="nav-bar" />
|
||||||
<MenuItem key="button" label="button" />
|
<MenuItem key="button" label="button" />
|
||||||
|
<MenuItem key="checkbox" label="checkbox" />
|
||||||
</Menu>
|
</Menu>
|
||||||
</aside>
|
</aside>
|
||||||
<main>
|
<main>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::demo_checkbox::*;
|
|
||||||
use crate::demo_slider::*;
|
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_router::use_navigate;
|
use leptos_router::use_navigate;
|
||||||
use melt_ui::*;
|
use melt_ui::*;
|
||||||
|
@ -38,9 +36,5 @@ pub fn Home(cx: Scope) -> impl IntoView {
|
||||||
|
|
||||||
<Progress percentage=count/>
|
<Progress percentage=count/>
|
||||||
</Space>
|
</Space>
|
||||||
<hr />
|
|
||||||
<DemoCheckout />
|
|
||||||
<hr />
|
|
||||||
<DemoSlider />
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod button;
|
mod button;
|
||||||
|
mod checkbox;
|
||||||
mod components;
|
mod components;
|
||||||
mod home;
|
mod home;
|
||||||
mod image;
|
mod image;
|
||||||
|
@ -11,6 +12,7 @@ mod slider;
|
||||||
mod tabbar;
|
mod tabbar;
|
||||||
|
|
||||||
pub use button::*;
|
pub use button::*;
|
||||||
|
pub use checkbox::*;
|
||||||
pub use components::*;
|
pub use components::*;
|
||||||
pub use home::*;
|
pub use home::*;
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
|
|
|
@ -1,51 +1,75 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{components::*, utils::mount_style::mount_style};
|
use crate::{components::*, utils::mount_style::mount_style};
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use stylers::style_sheet_str;
|
use stylers::style_sheet_str;
|
||||||
|
|
||||||
|
#[slot]
|
||||||
|
pub struct CardHeader {
|
||||||
|
children: ChildrenFn,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[slot]
|
||||||
|
pub struct CardHeaderExtra {
|
||||||
|
children: ChildrenFn,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[slot]
|
||||||
|
pub struct CardFooter {
|
||||||
|
#[prop(default = leptos::MaybeSignal::Static(true), into)]
|
||||||
|
if_: MaybeSignal<bool>,
|
||||||
|
children: ChildrenFn,
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Card(
|
pub fn Card(
|
||||||
cx: Scope,
|
cx: Scope,
|
||||||
#[prop(optional)] title: MaybeSignal<String>,
|
#[prop(optional, into)] title: MaybeSignal<&'static str>,
|
||||||
#[prop(default = None)] header: Option<Children>,
|
#[prop(optional)] card_header: Option<CardHeader>,
|
||||||
#[prop(default = None)] header_extra: Option<Children>,
|
#[prop(optional)] card_header_extra: Option<CardHeaderExtra>,
|
||||||
children: Children,
|
children: Children,
|
||||||
#[prop(default = None)] footer: Option<Children>,
|
#[prop(optional)] card_footer: Option<CardFooter>,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
let class_name = mount_style("card", || style_sheet_str!("./src/card/card.css"));
|
let class_name = mount_style("card", || style_sheet_str!("./src/card/card.css"));
|
||||||
|
|
||||||
|
let is_header = card_header.is_some();
|
||||||
|
let header = card_header.map_or(None, |v| Some(Rc::new(v)));
|
||||||
|
let header_extra = card_header_extra.map_or(None, |v| Some(Rc::new(v)));
|
||||||
|
// let footer = card_footer.map_or(None, |v| Some(Rc::new(v)));
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
cx, class=class_name,
|
cx, class=class_name,
|
||||||
<div class="melt-card">
|
<div class="melt-card">
|
||||||
{
|
<If cond=MaybeSignal::derive(cx, move || is_header || title.get().is_empty()) >
|
||||||
if header.is_some() || title.get().is_empty() {
|
<Then slot>
|
||||||
view! {
|
|
||||||
cx, class=class_name,
|
|
||||||
<div class="melt-card__header">
|
<div class="melt-card__header">
|
||||||
<div class="melt-card__header-content">
|
<div class="melt-card__header-content">
|
||||||
<OptionComp value=header bind:header>
|
<OptionComp value=header.clone() bind:header>
|
||||||
<Fallback slot>
|
<Fallback slot>
|
||||||
{ title.get() }
|
{ title.get() }
|
||||||
</Fallback>
|
</Fallback>
|
||||||
{ header(cx) }
|
{ (header.children)(cx) }
|
||||||
</OptionComp>
|
</OptionComp>
|
||||||
</div>
|
</div>
|
||||||
<OptionComp value=header_extra bind:header_extra>
|
<OptionComp value=header_extra.clone() bind:header_extra>
|
||||||
<div class="melt-card__header-extra">
|
<div class="melt-card__header-extra">
|
||||||
{ header_extra(cx) }
|
{ (header_extra.children)(cx) }
|
||||||
</div>
|
</div>
|
||||||
</OptionComp>
|
</OptionComp>
|
||||||
</div>
|
</div>
|
||||||
}.into()
|
</Then>
|
||||||
} else {
|
</If>
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<div class="melt-card__content">
|
<div class="melt-card__content">
|
||||||
{ children(cx) }
|
{ children(cx) }
|
||||||
</div>
|
</div>
|
||||||
<OptionComp value=footer bind:footer>
|
<OptionComp value=card_footer bind:footer>
|
||||||
<div class="melt-card__footer">
|
<If cond=footer.if_ >
|
||||||
{ footer(cx) }
|
<Then slot>
|
||||||
</div>
|
<div class="melt-card__footer">
|
||||||
|
{ (footer.children)(cx) }
|
||||||
|
</div>
|
||||||
|
</Then>
|
||||||
|
</If>
|
||||||
</OptionComp>
|
</OptionComp>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use crate::{theme::use_theme, utils::mount_style::mount_style, Theme};
|
use crate::{theme::use_theme, utils::mount_style::mount_style, Theme, components::*};
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use stylers::style_sheet_str;
|
|
||||||
use leptos_icons::*;
|
use leptos_icons::*;
|
||||||
|
use stylers::style_sheet_str;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Checkbox(
|
pub fn Checkbox(
|
||||||
cx: Scope,
|
cx: Scope,
|
||||||
#[prop(optional, into)] checked: MaybeSignal<bool>,
|
#[prop(into)] checked: RwSignal<bool>,
|
||||||
#[prop(optional, into)] on_checked: Option<SignalSetter<bool>>,
|
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
let theme = use_theme(cx, Theme::light);
|
let theme = use_theme(cx, Theme::light);
|
||||||
|
@ -22,29 +21,20 @@ pub fn Checkbox(
|
||||||
css_vars.push_str(&format!("--background-color-checked: {bg_color};"));
|
css_vars.push_str(&format!("--background-color-checked: {bg_color};"));
|
||||||
css_vars
|
css_vars
|
||||||
});
|
});
|
||||||
let on_click = move |_| {
|
|
||||||
if let Some(on_checked) = on_checked {
|
|
||||||
on_checked.set(!checked.get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
view! {cx, class=class_name,
|
view! {cx, class=class_name,
|
||||||
<div class:melt-checkbox=true class=("melt-checkbox--checked", move || checked.get()) style=move || css_vars.get() on:click=on_click>
|
<div class:melt-checkbox=true class=("melt-checkbox--checked", move || checked.get()) style=move || css_vars.get()
|
||||||
|
on:click=move |_| checked.set(!checked.get_untracked())>
|
||||||
<input class="melt-checkbox__input" type="checkbox" />
|
<input class="melt-checkbox__input" type="checkbox" />
|
||||||
<div class="melt-checkbox__dot">
|
<div class="melt-checkbox__dot">
|
||||||
{
|
<If cond=checked>
|
||||||
move || {
|
<Then slot>
|
||||||
if checked.get() {
|
<Icon icon=AiIcon::AiCheckOutlined style="color: white"/>
|
||||||
view! {cx,
|
</Then>
|
||||||
<Icon icon=AiIcon::AiCheckOutlined style="color: white"/>
|
</If>
|
||||||
}.into()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="melt-checkbox__label">
|
<div class="melt-checkbox__label">
|
||||||
{children(cx)}
|
{ children(cx) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub struct ElseIf {
|
||||||
#[component]
|
#[component]
|
||||||
pub fn If(
|
pub fn If(
|
||||||
cx: Scope,
|
cx: Scope,
|
||||||
cond: MaybeSignal<bool>,
|
#[prop(into)] cond: MaybeSignal<bool>,
|
||||||
then: Then,
|
then: Then,
|
||||||
#[prop(default=vec![])] else_if: Vec<ElseIf>,
|
#[prop(default=vec![])] else_if: Vec<ElseIf>,
|
||||||
#[prop(optional)] fallback: Option<Fallback>,
|
#[prop(optional)] fallback: Option<Fallback>,
|
||||||
|
|
|
@ -2,8 +2,8 @@ mod if_comp;
|
||||||
mod option_comp;
|
mod option_comp;
|
||||||
|
|
||||||
pub use if_comp::*;
|
pub use if_comp::*;
|
||||||
use leptos::*;
|
|
||||||
pub use option_comp::*;
|
pub use option_comp::*;
|
||||||
|
use leptos::*;
|
||||||
|
|
||||||
#[slot]
|
#[slot]
|
||||||
pub struct Fallback {
|
pub struct Fallback {
|
||||||
|
|
|
@ -1,48 +1,49 @@
|
||||||
use crate::card::*;
|
use crate::card::*;
|
||||||
|
use crate::components::OptionComp;
|
||||||
use crate::teleport::*;
|
use crate::teleport::*;
|
||||||
use crate::utils::mount_style::mount_style;
|
use crate::utils::mount_style::mount_style;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use stylers::style_sheet_str;
|
use stylers::style_sheet_str;
|
||||||
use leptos_icons::*;
|
use leptos_icons::*;
|
||||||
|
|
||||||
|
#[slot]
|
||||||
|
pub struct ModalFooter {
|
||||||
|
children: ChildrenFn,
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Modal(
|
pub fn Modal(
|
||||||
cx: Scope,
|
cx: Scope,
|
||||||
#[prop(optional, into)] title: Option<MaybeSignal<String>>,
|
|
||||||
children: Children,
|
|
||||||
#[prop(optional)] footer: Option<Children>,
|
|
||||||
#[prop(into)] show: RwSignal<bool>,
|
#[prop(into)] show: RwSignal<bool>,
|
||||||
|
#[prop(optional, into)] title: MaybeSignal<&'static str>,
|
||||||
|
children: Children,
|
||||||
|
#[prop(optional)] modal_footer: Option<ModalFooter>,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
let class_name = mount_style("modal", || style_sheet_str!("./src/modal/modal.css"));
|
let class_name = mount_style("modal", || style_sheet_str!("./src/modal/modal.css"));
|
||||||
let header = move |cx| {
|
|
||||||
view! {
|
|
||||||
cx, class=class_name,
|
|
||||||
<>
|
|
||||||
<span class="melt-model-title">
|
|
||||||
{title}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let header_extra = move |cx| {
|
|
||||||
view! {
|
|
||||||
cx,
|
|
||||||
<>
|
|
||||||
<span style="cursor: pointer;" on:click=move |_| show.set(false)>
|
|
||||||
<Icon icon=AiIcon::AiCloseOutlined/>
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
};
|
|
||||||
view! {
|
view! {
|
||||||
cx, class=class_name,
|
cx, class=class_name,
|
||||||
<Teleport>
|
<Teleport>
|
||||||
<div class="melt-modal-container" style=move || if show.get() { "" } else { "display: none" }>
|
<div class="melt-modal-container" style=move || if show.get() { "" } else { "display: none" }>
|
||||||
<div class="melt-modal-mask"></div>
|
<div class="melt-modal-mask"></div>
|
||||||
<div class="melt-modal-body">
|
<div class="melt-modal-body">
|
||||||
<Card header=Some(Box::new(header)) header_extra=Some(Box::new(header_extra)) footer=footer>
|
<Card>
|
||||||
{children(cx)}
|
<CardHeader slot>
|
||||||
|
<span class="melt-model-title">
|
||||||
|
{ title.get() }
|
||||||
|
</span>
|
||||||
|
</CardHeader>
|
||||||
|
<CardHeaderExtra slot>
|
||||||
|
<span style="cursor: pointer;" on:click=move |_| show.set(false)>
|
||||||
|
<Icon icon=AiIcon::AiCloseOutlined/>
|
||||||
|
</span>
|
||||||
|
</CardHeaderExtra>
|
||||||
|
{ children(cx) }
|
||||||
|
<CardFooter slot if_=modal_footer.is_some()>
|
||||||
|
<OptionComp value=modal_footer.as_ref() bind:footer>
|
||||||
|
{ (footer.children)(cx) }
|
||||||
|
</OptionComp>
|
||||||
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue