diff --git a/Cargo.toml b/Cargo.toml index 6d25fa0..f745f41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ features = [ "IntersectionObserver", "IntersectionObserverInit", "IntersectionObserverEntry", + "Location", "MediaDevices", "MediaQueryList", "MediaStream", @@ -112,6 +113,8 @@ features = [ "Touch", "TouchEvent", "TouchList", + "Url", + "UrlSearchParams", "VisibilityState", "WebSocket", "WebTransport", diff --git a/src/core/mod.rs b/src/core/mod.rs index 9abe354..577cf7f 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -9,6 +9,7 @@ mod position; mod size; mod ssr_safe_method; mod storage; +pub(crate) mod url; pub use connection_ready_state::*; pub(crate) use datetime::*; diff --git a/src/core/url.rs b/src/core/url.rs new file mode 100644 index 0000000..bddd7a9 --- /dev/null +++ b/src/core/url.rs @@ -0,0 +1,20 @@ +use leptos::window; + +fn get() -> web_sys::Url { + web_sys::Url::new( + &window() + .location() + .href() + .expect("Failed to get location.href from the browser"), + ) + .expect("Failed to parse location.href from the browser") +} + +pub mod params { + use super::get as current_url; + + /// Get a URL param value from the URL of the browser + pub fn get(k: &str) -> Option { + current_url().search_params().get(k) + } +} diff --git a/src/storage/use_storage.rs b/src/storage/use_storage.rs index 5b5f3d1..20f14d5 100644 --- a/src/storage/use_storage.rs +++ b/src/storage/use_storage.rs @@ -67,7 +67,7 @@ const INTERNAL_STORAGE_EVENT: &str = "leptos-use-storage"; /// pub greeting: String, /// } /// -/// // Default can be used to implement intial or deleted values. +/// // Default can be used to implement initial or deleted values. /// // You can also use a signal via UseStorageOptions::default_value` /// impl Default for MyState { /// fn default() -> Self { diff --git a/src/use_color_mode.rs b/src/use_color_mode.rs index 919efde..aabf8f1 100644 --- a/src/use_color_mode.rs +++ b/src/use_color_mode.rs @@ -1,3 +1,4 @@ +use crate::core::url; use crate::core::StorageType; use crate::core::{ElementMaybeSignal, MaybeRwSignal}; use crate::storage::{use_storage_with_options, UseStorageOptions}; @@ -106,6 +107,8 @@ where target, attribute, initial_value, + initial_value_from_url_param, + initial_value_from_url_param_to_storage, on_changed, storage_signal, custom_modes, @@ -136,8 +139,15 @@ where } }); + let mut initial_value_from_url = None; + if let Some(param) = initial_value_from_url_param.as_ref() { + if let Some(value) = url::params::get(param) { + initial_value_from_url = ColorMode::from_str(&value).map(MaybeRwSignal::Static).ok() + } + } + let (store, set_store) = get_store_signal( - initial_value, + initial_value_from_url.clone().unwrap_or(initial_value), storage_signal, &storage_key, storage_enabled, @@ -145,6 +155,15 @@ where listen_to_storage_changes, ); + if let Some(initial_value_from_url) = initial_value_from_url { + let value = initial_value_from_url.into_signal().0.get_untracked(); + if initial_value_from_url_param_to_storage { + set_store.set(value); + } else { + set_store.set_untracked(value); + } + } + let state = Signal::derive(move || { let value = store.get(); if value == ColorMode::Auto { @@ -330,6 +349,14 @@ where #[builder(into)] initial_value: MaybeRwSignal, + /// Discover the initial value of the color mode from an URL parameter. Defaults to `None`. + #[builder(into)] + initial_value_from_url_param: Option, + + /// Update the initial value of the discovered color mode from URL parameter into storage. + /// Defaults to `false`. + initial_value_from_url_param_to_storage: bool, + /// Custom modes that you plan to use as `ColorMode::Custom(x)`. Defaults to `vec![]`. custom_modes: Vec, @@ -386,6 +413,8 @@ impl Default for UseColorModeOptions<&'static str, web_sys::Element> { target: "html", attribute: "class".into(), initial_value: ColorMode::Auto.into(), + initial_value_from_url_param: None, + initial_value_from_url_param_to_storage: false, custom_modes: vec![], on_changed: Rc::new(move |mode, default_handler| (default_handler)(mode)), storage_signal: None,