2023-08-29 09:23:53 +08:00
|
|
|
use crate::{theme::use_theme, utils::mount_style::mount_style, Theme};
|
2023-04-18 17:27:39 +08:00
|
|
|
use leptos::*;
|
2023-04-23 15:07:33 +08:00
|
|
|
use wasm_bindgen::JsCast;
|
2023-04-18 17:27:39 +08:00
|
|
|
|
|
|
|
#[component]
|
|
|
|
pub fn Slider(
|
2023-06-10 13:00:41 +08:00
|
|
|
#[prop(into)] value: RwSignal<f64>,
|
2023-04-18 17:27:39 +08:00
|
|
|
#[prop(default = MaybeSignal::Static(100f64), into)] max: MaybeSignal<f64>,
|
|
|
|
) -> impl IntoView {
|
2023-08-29 09:11:22 +08:00
|
|
|
let theme = use_theme(Theme::light);
|
|
|
|
let css_vars = create_memo(move |_| {
|
2023-04-18 17:27:39 +08:00
|
|
|
let mut css_vars = String::new();
|
|
|
|
let theme = theme.get();
|
|
|
|
let bg_color = theme.common.color_primary;
|
|
|
|
css_vars.push_str(&format!("--background-color-fill: {bg_color};"));
|
|
|
|
|
|
|
|
css_vars
|
|
|
|
});
|
|
|
|
|
2023-08-29 09:11:22 +08:00
|
|
|
let percentage = create_memo(move |_| {
|
2023-04-18 17:27:39 +08:00
|
|
|
if value.get() < 0.0 || max.get() <= 0.0 {
|
|
|
|
0f64
|
|
|
|
} else if value.get() >= max.get() {
|
|
|
|
100f64
|
|
|
|
} else {
|
|
|
|
value.get() / max.get() * 100.0
|
|
|
|
}
|
|
|
|
});
|
2023-10-07 21:41:03 +08:00
|
|
|
mount_style("slider", include_str!("./slider.css"));
|
2023-04-18 17:27:39 +08:00
|
|
|
|
2023-06-10 13:00:41 +08:00
|
|
|
let do_update_value = move |val| {
|
|
|
|
value.set(val);
|
2023-04-23 15:07:33 +08:00
|
|
|
};
|
|
|
|
|
2023-08-29 09:11:22 +08:00
|
|
|
let rail_ref = create_node_ref::<html::Div>();
|
|
|
|
let (mouse_move_value, set_mouse_move_value) = create_signal::<Option<f64>>(None);
|
|
|
|
let (is_mouse_move, set_mouse_move) = create_signal(false);
|
2023-04-21 20:35:26 +08:00
|
|
|
let on_mouse_down = move |_| {
|
|
|
|
set_mouse_move.set(true);
|
|
|
|
};
|
2023-06-10 13:00:41 +08:00
|
|
|
|
2023-05-18 10:55:29 +08:00
|
|
|
let on_mouse_up = window_event_listener(ev::mouseup, move |_| {
|
2023-04-23 15:07:33 +08:00
|
|
|
set_mouse_move.set(false);
|
|
|
|
});
|
2023-08-29 09:23:53 +08:00
|
|
|
on_cleanup(move || on_mouse_up.remove());
|
2023-04-23 15:07:33 +08:00
|
|
|
|
2023-05-18 10:55:29 +08:00
|
|
|
let on_mouse_move = window_event_listener(ev::mousemove, move |ev| {
|
2023-05-17 12:56:32 +08:00
|
|
|
if is_mouse_move.get_untracked() {
|
|
|
|
if let Some(rail) = rail_ref.get_untracked() {
|
2023-04-23 15:07:33 +08:00
|
|
|
let ev = ev.unchecked_into::<web_sys::MouseEvent>();
|
|
|
|
let rect = rail.get_bounding_client_rect();
|
|
|
|
let ev_x = f64::from(ev.x());
|
|
|
|
if ev_x <= rect.x() {
|
|
|
|
set_mouse_move_value.set(Some(0.0));
|
|
|
|
} else if ev_x >= rect.x() + rect.width() {
|
|
|
|
set_mouse_move_value.set(Some(max.get()));
|
|
|
|
} else {
|
|
|
|
set_mouse_move_value.set(Some(((ev_x - rect.x()) / rect.width()) * max.get()));
|
|
|
|
}
|
2023-05-17 12:56:32 +08:00
|
|
|
if let Some(value) = mouse_move_value.get_untracked() {
|
2023-04-23 15:07:33 +08:00
|
|
|
do_update_value(value);
|
|
|
|
}
|
|
|
|
};
|
2023-04-21 20:35:26 +08:00
|
|
|
}
|
|
|
|
});
|
2023-08-29 09:23:53 +08:00
|
|
|
on_cleanup(move || on_mouse_move.remove());
|
2023-04-21 20:35:26 +08:00
|
|
|
|
2023-10-07 21:41:03 +08:00
|
|
|
view! {
|
2023-04-18 17:27:39 +08:00
|
|
|
<div class="melt-slider" style=move || css_vars.get()>
|
2023-04-23 15:07:33 +08:00
|
|
|
<div class="melt-slider-rail" ref=rail_ref>
|
2023-10-08 09:28:13 +08:00
|
|
|
<div
|
|
|
|
class="melt-slider-rail__fill"
|
|
|
|
style=move || format!("width: {}%", percentage.get())
|
|
|
|
></div>
|
2023-04-18 17:27:39 +08:00
|
|
|
</div>
|
2023-10-08 09:28:13 +08:00
|
|
|
<div
|
|
|
|
on:mousedown=on_mouse_down
|
|
|
|
class="melt-slider-handle"
|
|
|
|
style=move || {
|
|
|
|
format!(
|
2023-10-09 10:28:22 +08:00
|
|
|
"left: {}%; transform: translateX(-{}%)", percentage.get(), percentage
|
|
|
|
.get(),
|
2023-10-08 09:28:13 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
>
|
2023-04-18 17:27:39 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
}
|