From eac590e1632736b11caf93b396b9ba93ac714336 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sun, 8 Oct 2023 22:45:29 +0800 Subject: [PATCH] feat: add color_picker component frame --- gh-pages/src/app.rs | 1 + gh-pages/src/pages/color_picker/mod.rs | 16 +++++ gh-pages/src/pages/components.rs | 1 + gh-pages/src/pages/mod.rs | 2 + src/button/mod.rs | 2 +- src/color_picker/color-picker.css | 37 ++++++++++++ src/color_picker/mod.rs | 81 ++++++++++++++++++++++++++ src/lib.rs | 2 + src/slider/mod.rs | 4 +- src/tabs/mod.rs | 10 ++-- src/teleport/mod.rs | 6 +- 11 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 gh-pages/src/pages/color_picker/mod.rs create mode 100644 src/color_picker/color-picker.css create mode 100644 src/color_picker/mod.rs diff --git a/gh-pages/src/app.rs b/gh-pages/src/app.rs index 0ddcd5f..be05e83 100644 --- a/gh-pages/src/app.rs +++ b/gh-pages/src/app.rs @@ -23,6 +23,7 @@ pub fn App() -> impl IntoView { + diff --git a/gh-pages/src/pages/color_picker/mod.rs b/gh-pages/src/pages/color_picker/mod.rs new file mode 100644 index 0000000..f16ea5b --- /dev/null +++ b/gh-pages/src/pages/color_picker/mod.rs @@ -0,0 +1,16 @@ +use crate::components::{Demo, DemoCode}; +use leptos::*; +use melt_ui::*; + +#[component] +pub fn ColorPickerPage() -> impl IntoView { + view! { +
+

"Color Picker"

+ + + "" + +
+ } +} diff --git a/gh-pages/src/pages/components.rs b/gh-pages/src/pages/components.rs index b719e39..78d4dc4 100644 --- a/gh-pages/src/pages/components.rs +++ b/gh-pages/src/pages/components.rs @@ -48,6 +48,7 @@ pub fn ComponentsPage() -> impl IntoView { + diff --git a/gh-pages/src/pages/mod.rs b/gh-pages/src/pages/mod.rs index 8abd527..f801e1e 100644 --- a/gh-pages/src/pages/mod.rs +++ b/gh-pages/src/pages/mod.rs @@ -1,5 +1,6 @@ mod button; mod checkbox; +mod color_picker; mod components; mod home; mod image; @@ -18,6 +19,7 @@ mod toast; pub use button::*; pub use checkbox::*; +pub use color_picker::*; pub use components::*; pub use home::*; pub use image::*; diff --git a/src/button/mod.rs b/src/button/mod.rs index 3cb1fbb..ae20207 100644 --- a/src/button/mod.rs +++ b/src/button/mod.rs @@ -126,7 +126,7 @@ pub fn Button( } diff --git a/src/color_picker/color-picker.css b/src/color_picker/color-picker.css new file mode 100644 index 0000000..e4a4c3b --- /dev/null +++ b/src/color_picker/color-picker.css @@ -0,0 +1,37 @@ +.melt-color-picker-trigger { + display: inline-block; + padding: 4px; + width: 100%; + height: 34px; + border: 1px solid #e0e0e6; + border-radius: 3px; + box-sizing: border-box; + cursor: pointer; +} + +.melt-color-picker-trigger__content { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + font-size: 14px; +} + +.melt-color-picker-popover { + position: absolute; + top: 0; + left: 0; + right: 0; + width: 240px; + padding: 12px; + background-color: #fff; + border-radius: 3px; + box-sizing: border-box; + box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); + z-index: 1000; +} + +.melt-color-picker-popover__layer { + height: 176px; +} \ No newline at end of file diff --git a/src/color_picker/mod.rs b/src/color_picker/mod.rs new file mode 100644 index 0000000..c74c55b --- /dev/null +++ b/src/color_picker/mod.rs @@ -0,0 +1,81 @@ +use crate::{mount_style, teleport::Teleport, utils::maybe_rw_signal::MaybeRwSignal}; +use leptos::*; +use wasm_bindgen::__rt::IntoJsResult; + +#[component] +pub fn ColorPicker(#[prop(optional, into)] value: MaybeRwSignal) -> impl IntoView { + mount_style("color-picker", include_str!("./color-picker.css")); + let label = create_rw_signal(String::new()); + let style = create_memo(move |_| { + let mut style = String::new(); + + value.with(|value| { + if value.is_empty() { + label.set("Invalid value".into()); + return; + } + + style.push_str(&format!("background-color: {value}")); + label.set(value.clone()); + }); + + style + }); + + let is_show_popover = create_rw_signal(false); + let trigger_ref = create_node_ref::(); + let popover_ref = create_node_ref::(); + let show_popover = move |_| { + let rect = trigger_ref.get().unwrap().get_bounding_client_rect(); + is_show_popover.set(true); + if let Some(popover_ref) = popover_ref.get() { + popover_ref.style( + "transform", + format!( + "translateX({}px) translateY({}px)", + rect.x(), + rect.y() + rect.height() + ), + ); + } + }; + let timer = window_event_listener(ev::click, move |ev| { + let el = ev.target(); + let mut el: Option = + el.into_js_result().map_or(None, |el| Some(el.into())); + let body = document().body().unwrap(); + while let Some(current_el) = el { + if current_el == *body { + break; + }; + if current_el == ***popover_ref.get().unwrap() + || current_el == ***trigger_ref.get().unwrap() + { + return; + } + el = current_el.parent_element(); + } + is_show_popover.set(false); + }); + on_cleanup(move || timer.remove()); + view! { +
+
+ {move || label.get()} +
+
+ +
+ +
+
+
+
+ } +} diff --git a/src/lib.rs b/src/lib.rs index 570e86e..4063edb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ mod button; mod card; mod checkbox; mod code; +mod color_picker; mod components; mod icon; mod image; @@ -25,6 +26,7 @@ pub use button::*; pub use card::*; pub use checkbox::*; pub use code::*; +pub use color_picker::*; pub use icon::*; pub use image::*; pub use input::*; diff --git a/src/slider/mod.rs b/src/slider/mod.rs index 9b1c825..89da2e4 100644 --- a/src/slider/mod.rs +++ b/src/slider/mod.rs @@ -78,7 +78,9 @@ pub fn Slider( class="melt-slider-handle" style=move || { format!( - "left: {}%; transform: translateX(-{}%)", percentage.get(), percentage.get() + "left: {}%; transform: translateX(-{}%)", + percentage.get(), + percentage.get(), ) } > diff --git a/src/tabs/mod.rs b/src/tabs/mod.rs index 2a6af9b..6a7abde 100644 --- a/src/tabs/mod.rs +++ b/src/tabs/mod.rs @@ -42,10 +42,12 @@ pub fn Tabs(active_key: RwSignal<&'static str>, children: Children) -> impl Into children=move |options| { let label_ref = create_node_ref::(); create_effect(move |_| { - let Some(label) = label_ref.get() else { return; - }; - let Some(label_list) = label_list_ref.get() else { return; - }; + let Some(label) = label_ref.get() else { + return; + }; + let Some(label_list) = label_list_ref.get() else { + return; + }; if options.key == active_key.get() { request_animation_frame(move || { let list_rect = label_list.get_bounding_client_rect(); diff --git a/src/teleport/mod.rs b/src/teleport/mod.rs index fe036ec..1ecbb75 100644 --- a/src/teleport/mod.rs +++ b/src/teleport/mod.rs @@ -17,7 +17,11 @@ pub fn Teleport(#[prop(optional)] to: Option<&'static str>, children: Children) { use leptos_dom::Mountable; let node = children().into_view(); - parent.append_child(&node.get_mountable_node()).unwrap(); + let node = node.get_mountable_node(); + parent.append_child(&node).unwrap(); + on_cleanup(move || { + _ = parent.remove_child(&node); + }); } #[cfg(not(target_arch = "wasm32"))]