diff --git a/demo/src/app.rs b/demo/src/app.rs index 1685d25..15be80f 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -36,6 +36,7 @@ pub fn App() -> impl IntoView { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 1aad13b..85d4a55 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -125,6 +125,10 @@ fn gen_menu_data() -> Vec { value: "input-number".into(), label: "InputNumber".into(), }, + MenuItemOption { + value: "radio".into(), + label: "Radio".into(), + }, MenuItemOption { value: "select".into(), label: "Select".into(), diff --git a/demo/src/pages/mod.rs b/demo/src/pages/mod.rs index 79fba8a..d94c74d 100644 --- a/demo/src/pages/mod.rs +++ b/demo/src/pages/mod.rs @@ -19,6 +19,7 @@ mod message; mod mobile; mod modal; mod nav_bar; +mod radio; mod select; mod slider; mod space; @@ -48,6 +49,7 @@ pub use message::*; pub use mobile::*; pub use modal::*; pub use nav_bar::*; +pub use radio::*; pub use select::*; pub use slider::*; pub use space::*; diff --git a/demo/src/pages/radio/mod.rs b/demo/src/pages/radio/mod.rs new file mode 100644 index 0000000..85668a4 --- /dev/null +++ b/demo/src/pages/radio/mod.rs @@ -0,0 +1,35 @@ +use crate::components::{Demo, DemoCode}; +use leptos::*; +use melt_ui::*; +use prisms::highlight_str; + +#[component] +pub fn RadioPage() -> impl IntoView { + let checked = create_rw_signal(false); + view! { +
+

"Radio"

+ + "Click" + + "Click" + + } + "#, + "rust" + ) + > + + "" + + +
+ } +} diff --git a/src/lib.rs b/src/lib.rs index 0409170..ea09757 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,9 @@ mod message; pub mod mobile; mod modal; mod progress; +mod radio; mod select; +mod skeleton; mod slider; mod space; mod switch; @@ -51,7 +53,9 @@ pub use menu::*; pub use message::*; pub use modal::*; pub use progress::*; +pub use radio::*; pub use select::*; +pub use skeleton::*; pub use slider::*; pub use space::*; pub use switch::*; diff --git a/src/radio/mod.rs b/src/radio/mod.rs new file mode 100644 index 0000000..5e402ba --- /dev/null +++ b/src/radio/mod.rs @@ -0,0 +1,38 @@ +use crate::{ + theme::use_theme, + utils::{maybe_rw_signal::MaybeRwSignal, mount_style::mount_style}, + Theme, +}; +use leptos::*; + +#[component] +pub fn Radio( + #[prop(optional, into)] value: MaybeRwSignal, + children: Children, +) -> impl IntoView { + let theme = use_theme(Theme::light); + mount_style("radio", include_str!("./radio.css")); + + let css_vars = create_memo(move |_| { + let mut css_vars = String::new(); + theme.with(|theme| { + let bg_color = theme.common.color_primary.clone(); + css_vars.push_str(&format!("--background-color-checked: {bg_color};")); + }); + + css_vars + }); + + view! { +
+ +
+
{children()}
+
+ } +} diff --git a/src/radio/radio.css b/src/radio/radio.css new file mode 100644 index 0000000..127bc17 --- /dev/null +++ b/src/radio/radio.css @@ -0,0 +1,42 @@ +.melt-radio { + display: inline-flex; + align-items: center; + cursor: pointer; +} + +.melt-radio__input { + width: 0; + height: 0; + opacity: 0; +} + +.melt-radio__dot { + display: inline-block; + position: relative; + width: 14px; + height: 14px; + border: 1px solid #ddd; + border-radius: 50%; +} + +.melt-radio:hover .melt-radio__dot, +.melt-radio--checked .melt-radio__dot { + border-color: var(--background-color-checked); +} + +.melt-radio--checked .melt-radio__dot::before { + content: ""; + position: absolute; + top: 3px; + bottom: 3px; + left: 3px; + right: 3px; + background-color: var(--background-color-checked); + border-radius: 50%; +} + +.melt-radio__label { + display: inline-block; + padding: 0 6px; + user-select: none; +} diff --git a/src/skeleton/mod.rs b/src/skeleton/mod.rs new file mode 100644 index 0000000..2fc0a03 --- /dev/null +++ b/src/skeleton/mod.rs @@ -0,0 +1,47 @@ +mod theme; + +use crate::{theme::use_theme, Theme}; +use leptos::*; +pub use theme::SkeletionTheme; + +#[component] +pub fn Skeleton( + #[prop(default = MaybeSignal::Static(1), into)] repeat: MaybeSignal, + #[prop(optional, into)] text: MaybeSignal, + #[prop(optional, into)] width: Option>, + #[prop(optional, into)] height: Option>, +) -> impl IntoView { + let theme = use_theme(Theme::light); + let css_vars = create_memo(move |_| { + let mut css_vars = String::new(); + if text.get() { + css_vars.push_str("display: inline-block;"); + } + + if let Some(width) = width.as_ref() { + css_vars.push_str(&format!("width: {};", width.get())); + } + if let Some(height) = height.as_ref() { + css_vars.push_str(&format!("height: {};", height.get())); + } + + theme.with(|theme| { + css_vars.push_str(&format!( + "--background-color-start: {};", + theme.skeletion.background_color_start + )); + css_vars.push_str(&format!( + "--background-color-end: {};", + theme.skeletion.background_color_end + )); + }); + + css_vars + }); + (0..repeat.get()) + .into_iter() + .map(|_| { + view! {
} + }) + .collect_view() +} diff --git a/src/skeleton/skeleton.css b/src/skeleton/skeleton.css new file mode 100644 index 0000000..6effb96 --- /dev/null +++ b/src/skeleton/skeleton.css @@ -0,0 +1,24 @@ +.melt-skeleton { + width: 100%; + height: 1em; + background-color: var(--background-color-start); + + background: linear-gradient( + 90deg, + var(--background-color-start) 25%, + var(--background-color-end) 37%, + var(--background-color-start) 63% + ); + animation: meltSkeletonLoading 1.4s ease infinite; + background-size: 400% 100%; +} + +@keyframes meltSkeletonLoading { + from { + background-position: 100% 50%; + } + + to { + background-position: 0 50%; + } +} diff --git a/src/skeleton/theme.rs b/src/skeleton/theme.rs new file mode 100644 index 0000000..6b9f337 --- /dev/null +++ b/src/skeleton/theme.rs @@ -0,0 +1,23 @@ +use crate::theme::ThemeMethod; + +#[derive(Clone)] +pub struct SkeletionTheme { + pub background_color_start: String, + pub background_color_end: String, +} + +impl ThemeMethod for SkeletionTheme { + fn light() -> Self { + Self { + background_color_start: "#f2f2f2".into(), + background_color_end: "#e6e6e6".into(), + } + } + + fn dark() -> Self { + Self { + background_color_start: "rgba(255, 255, 255, 0.12)".into(), + background_color_end: "rgba(255, 255, 255, 0.18)".into(), + } + } +} diff --git a/src/theme/mod.rs b/src/theme/mod.rs index 8fb730e..cee4e16 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -2,7 +2,7 @@ mod common; use leptos::*; use self::common::CommonTheme; -use crate::{AlertTheme, ButtonTheme, InputTheme, MenuTheme, TableTheme}; +use crate::{AlertTheme, ButtonTheme, InputTheme, MenuTheme, SkeletionTheme, TableTheme}; pub trait ThemeMethod { fn light() -> Self; @@ -17,6 +17,7 @@ pub struct Theme { pub menu: MenuTheme, pub table: TableTheme, pub alert: AlertTheme, + pub skeletion: SkeletionTheme, } impl Theme { @@ -28,6 +29,7 @@ impl Theme { menu: MenuTheme::light(), table: TableTheme::light(), alert: AlertTheme::light(), + skeletion: SkeletionTheme::light(), } } pub fn dark() -> Self { @@ -38,6 +40,7 @@ impl Theme { menu: MenuTheme::dark(), table: TableTheme::dark(), alert: AlertTheme::dark(), + skeletion: SkeletionTheme::dark(), } } } @@ -51,6 +54,7 @@ impl ThemeMethod for Theme { menu: MenuTheme::light(), table: TableTheme::light(), alert: AlertTheme::light(), + skeletion: SkeletionTheme::light(), } } fn dark() -> Self { @@ -61,6 +65,7 @@ impl ThemeMethod for Theme { menu: MenuTheme::dark(), table: TableTheme::dark(), alert: AlertTheme::dark(), + skeletion: SkeletionTheme::dark(), } } }