diff --git a/Cargo.toml b/Cargo.toml index 6d25fa0..53c9a27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ serde_json = { version = "1", optional = true } thiserror = "1" wasm-bindgen = "0.2.88" wasm-bindgen-futures = "0.4" +log = "0.4" [dependencies.web-sys] version = "0.3" @@ -70,6 +71,7 @@ features = [ "IntersectionObserver", "IntersectionObserverInit", "IntersectionObserverEntry", + "Location", "MediaDevices", "MediaQueryList", "MediaStream", @@ -112,6 +114,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 d773e81..c95343f 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..550c993 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,7 @@ where target, attribute, initial_value, + initial_value_from_url_param, on_changed, storage_signal, custom_modes, @@ -136,13 +138,26 @@ where } }); + let initial_value_from_url = match initial_value_from_url_param { + Some(param) => match url::params::get(¶m) { + Some(value) => match ColorMode::from_str(&value) { + Ok(mode) => Some(MaybeRwSignal::Static(mode)), + Err(_) => None, + }, + None => None, + }, + None => None, + }; + let update_previous_value = initial_value_from_url.is_some(); + let (store, set_store) = get_store_signal( - initial_value, + initial_value_from_url.unwrap_or(initial_value), storage_signal, &storage_key, storage_enabled, storage, listen_to_storage_changes, + update_previous_value, ); let state = Signal::derive(move || { @@ -255,22 +270,34 @@ fn get_store_signal( storage_enabled: bool, storage: StorageType, listen_to_storage_changes: bool, + update_previous_value: bool, ) -> (Signal, WriteSignal) { - if let Some(storage_signal) = storage_signal { + let initial_value_copy = initial_value.clone(); + + let (store, set_store) = if let Some(storage_signal) = storage_signal { let (store, set_store) = storage_signal.split(); (store.into(), set_store) } else if storage_enabled { - let (store, set_store, _) = use_storage_with_options::( + let (store, set_store, remove) = use_storage_with_options::( storage, storage_key, UseStorageOptions::default() .listen_to_storage_changes(listen_to_storage_changes) .initial_value(initial_value), ); + if update_previous_value { + remove(); + } (store, set_store) } else { initial_value.into_signal() + }; + + if update_previous_value { + set_store.set(initial_value_copy.into_signal().0.get_untracked()); } + + (store, set_store) } impl Display for ColorMode { @@ -330,6 +357,10 @@ 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, + /// Custom modes that you plan to use as `ColorMode::Custom(x)`. Defaults to `vec![]`. custom_modes: Vec, @@ -386,6 +417,7 @@ 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, custom_modes: vec![], on_changed: Rc::new(move |mode, default_handler| (default_handler)(mode)), storage_signal: None,