feat: color_picker component

This commit is contained in:
luoxiao 2023-10-09 17:34:46 +08:00
parent 95dcd6f992
commit 81a3c36886
2 changed files with 100 additions and 4 deletions

View file

@ -32,6 +32,52 @@
z-index: 1000;
}
.melt-color-picker-popover__panel {
position: relative;
height: 180px;
margin-bottom: 8px;
}
.melt-color-picker-popover__layer {
height: 176px;
}
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.melt-color-picker-popover__layer--shadowed {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient(rgba(0, 0, 0, 0), rgb(0, 0, 0));
}
.melt-color-picker-slider {
height: 12px;
padding-right: 12px;
background-image: linear-gradient(
90deg,
red,
rgb(255, 255, 0) 16.66%,
rgb(0, 255, 0) 33.33%,
rgb(0, 255, 255) 50%,
rgb(0, 0, 255) 66.66%,
rgb(255, 0, 255) 83.33%,
red
);
border-radius: 6px;
}
.melt-color-picker-slider__handle {
position: relative;
left: 0;
width: 12px;
height: 12px;
border-radius: 6px;
box-sizing: border-box;
border: 2px solid white;
cursor: pointer;
}

View file

@ -1,5 +1,6 @@
use crate::{mount_style, teleport::Teleport, utils::maybe_rw_signal::MaybeRwSignal};
use leptos::*;
use leptos_dom::helpers::WindowListenerHandle;
use wasm_bindgen::__rt::IntoJsResult;
#[component]
@ -58,6 +59,7 @@ pub fn ColorPicker(#[prop(optional, into)] value: MaybeRwSignal<String>) -> impl
is_show_popover.set(false);
});
on_cleanup(move || timer.remove());
let hue = create_rw_signal(0);
view! {
<div class="melt-color-picker-trigger" on:click=show_popover ref=trigger_ref>
<div class="melt-color-picker-trigger__content" style=move || style.get()>
@ -73,9 +75,57 @@ pub fn ColorPicker(#[prop(optional, into)] value: MaybeRwSignal<String>) -> impl
}
>
<div class="melt-color-picker-popover__layer"></div>
<div></div>
<div class="melt-color-picker-popover__panel">
<div class="melt-color-picker-popover__layer"></div>
<div class="melt-color-picker-popover__layer--shadowed"></div>
<div></div>
</div>
<HueSlider hue/>
</div>
</Teleport>
}
}
#[component]
fn HueSlider(hue: RwSignal<u16>) -> impl IntoView {
let rail_ref = create_node_ref::<html::Div>();
let mouse = store_value(Vec::<WindowListenerHandle>::new());
let on_mouse_down = move |_| {
let on_mouse_move = window_event_listener(ev::mousemove, move |ev| {
if let Some(rail) = rail_ref.get_untracked() {
let rect = rail.get_bounding_client_rect();
let ev_x = f64::from(ev.x());
let value = (ev_x - rect.x()) / (rect.width() - 12.0) * 360.0;
let value = if value < 0.0 {
0
} else if value > 359.0 {
359
} else {
value.round().to_string().parse::<u16>().unwrap()
};
hue.set(value);
}
});
let on_mouse_up = window_event_listener(ev::mouseup, move |_| {
mouse.update_value(|value| {
for handle in value.drain(..).into_iter() {
handle.remove();
}
});
});
mouse.update_value(|value| {
value.push(on_mouse_move);
value.push(on_mouse_up);
});
};
view! {
<div class="melt-color-picker-slider" ref=rail_ref>
<div
class="melt-color-picker-slider__handle"
on:mousedown=on_mouse_down
style=move || format!("left: {}%", f32::from(hue.get()) / 359.0 * 100.0)
></div>
</div>
}
}