feat: add badge component

This commit is contained in:
luoxiao 2023-10-16 20:56:14 +08:00
parent 826a30dc01
commit 087391f0f7
7 changed files with 175 additions and 0 deletions

View file

@ -28,6 +28,7 @@ pub fn App() -> impl IntoView {
<Route path="/grid" view=GridPage/>
<Route path="/auto-complete" view=AutoCompletePage/>
<Route path="/avatar" view=AvatarPage/>
<Route path="/badge" view=BadgePage/>
</Route>
<Route path="/mobile/tabbar" view=TabbarDemoPage/>
<Route path="/mobile/nav-bar" view=NavBarDemoPage/>

View file

@ -0,0 +1,73 @@
use crate::components::{Demo, DemoCode};
use leptos::*;
use melt_ui::*;
use prisms::highlight_str;
#[component]
pub fn BadgePage() -> impl IntoView {
let value = create_rw_signal(0);
view! {
<div style="width: 896px; margin: 0 auto;">
<h1>"Badge"</h1>
<Demo>
<Space>
<Badge value=value max_value=10>
<Avatar/>
</Badge>
<Badge color=BadgeColor::Success value=value max_value=10>
<Avatar/>
</Badge>
<Badge color=BadgeColor::Warning value=value max_value=10>
<Avatar/>
</Badge>
<Badge color=BadgeColor::Warning dot=true>
<Avatar/>
</Badge>
<Button on_click=move |_| value.update(|v| *v += 1)>"+1"</Button>
<Button on_click=move |_| {
value
.update(|v| {
if *v != 0 {
*v -= 1;
}
})
}>"-1"</Button>
"value:"
{move || value.get()}
</Space>
<DemoCode
slot
html=highlight_str!(
r#"
let value = create_rw_signal(0);
view! {
<Space>
<Badge value=value max_value=10>
<Avatar />
</Badge>
<Badge color=BadgeColor::Success value=value max_value=10>
<Avatar />
</Badge>
<Badge color=BadgeColor::Warning value=value max_value=10>
<Avatar />
</Badge>
<Badge color=BadgeColor::Warning dot=true>
<Avatar />
</Badge>
<Button on_click=move |_| value.update(|v| *v += 1)>"+1"</Button>
<Button on_click=move |_| value.update(|v| if *v != 0 { *v -= 1 })>"-1"</Button>
"value:"
{move || value.get()}
</Space>
}
"#,
"rust"
)
>
""
</DemoCode>
</Demo>
</div>
}
}

View file

@ -152,6 +152,10 @@ fn gen_menu_data() -> Vec<MenuGroupOption> {
value: "alert".into(),
label: "Alert".into(),
},
MenuItemOption {
value: "badge".into(),
label: "Badge".into(),
},
MenuItemOption {
value: "modal".into(),
label: "Modal".into(),

View file

@ -1,6 +1,7 @@
mod alert;
mod auto_complete;
mod avatar;
mod badge;
mod button;
mod checkbox;
mod color_picker;
@ -24,6 +25,7 @@ mod toast;
pub use alert::*;
pub use auto_complete::*;
pub use avatar::*;
pub use badge::*;
pub use button::*;
pub use checkbox::*;
pub use color_picker::*;

27
src/badge/badge.css Normal file
View file

@ -0,0 +1,27 @@
.melt-badge {
position: relative;
display: inline-block;
}
.melt-badge__sup {
position: absolute;
color: var(--font-color);
background-color: var(--background-color);
}
.melt-badge__sup--value {
top: -9px;
right: -9px;
font-size: 12px;
height: 18px;
line-height: 18px;
border-radius: 9px;
padding: 0 6px;
text-align: center;
}
.melt-badge__sup--dot {
top: -5px;
right: -5px;
height: 10px;
width: 10px;
border-radius: 50%;
}

66
src/badge/mod.rs Normal file
View file

@ -0,0 +1,66 @@
use crate::{mount_style, theme::use_theme, Theme};
use leptos::*;
#[derive(Default, Clone)]
pub enum BadgeColor {
Success,
Warning,
#[default]
Error,
}
impl BadgeColor {
pub fn theme_color(&self, theme: &Theme) -> String {
match self {
BadgeColor::Success => theme.common.color_success.clone(),
BadgeColor::Warning => theme.common.color_warning.clone(),
BadgeColor::Error => theme.common.color_error.clone(),
}
}
}
#[component]
pub fn Badge(
#[prop(optional, into)] value: MaybeSignal<u32>,
#[prop(default = MaybeSignal::Static(u32::MAX), into)] max_value: MaybeSignal<u32>,
#[prop(optional, into)] color: MaybeSignal<BadgeColor>,
#[prop(optional, into)] dot: MaybeSignal<bool>,
children: Children,
) -> impl IntoView {
let theme = use_theme(Theme::light);
mount_style("badge", include_str!("./badge.css"));
let css_vars = create_memo(move |_| {
let mut css_vars = String::new();
css_vars.push_str(&format!("--font-color: #fff;"));
theme.with(|theme| {
css_vars.push_str(&format!(
"--background-color: {};",
color.get().theme_color(theme)
));
});
css_vars
});
let value = create_memo(move |_| {
let value = value.get();
let max_value = max_value.get();
if value == 0 {
String::new()
} else if max_value < value {
format!("{max_value}+")
} else {
value.to_string()
}
});
view! {
<div class="melt-badge" style=move || css_vars.get()>
<div
class="melt-badge__sup"
class=("melt-badge__sup--value", move || !dot.get() && !value.get().is_empty())
class=("melt-badge__sup--dot", move || dot.get())
>
{move || value.get()}
</div>
{children()}
</div>
}
}

View file

@ -1,6 +1,7 @@
mod alert;
mod auto_complete;
mod avatar;
mod badge;
mod button;
mod card;
mod checkbox;
@ -29,6 +30,7 @@ mod wave;
pub use alert::*;
pub use auto_complete::*;
pub use avatar::*;
pub use badge::*;
pub use button::*;
pub use card::*;
pub use checkbox::*;