added cookie support to use_color_mode

This commit is contained in:
Maccesch 2024-04-10 22:51:01 +01:00
parent ce2799c57d
commit 98dbdf8f86
7 changed files with 112 additions and 17 deletions

View file

@ -3,12 +3,16 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] -
## [0.10.7] - 2024-04-10
### New Functions 🚀
### New Function 🚀
- `sync_signal`
### Change 🔥
- `use_color_mode` now supports cookies.
## [0.10.6] - 2024-04-02
### Fixes 🍕

View file

@ -1,6 +1,6 @@
[package]
name = "leptos-use"
version = "0.10.6"
version = "0.10.7"
edition = "2021"
authors = ["Marc-Stefan Cassola"]
categories = ["gui", "web-programming"]
@ -131,8 +131,9 @@ features = [
]
[dev-dependencies]
rand = "0.8"
getrandom = { version = "0.2", features = ["js"] }
leptos_meta = "0.6"
rand = "0.8"
[features]
actix = ["dep:actix-web", "dep:leptos_actix", "dep:http0_2"]

View file

@ -13,7 +13,7 @@
<a href="https://crates.io/crates/leptos-use"><img src="https://img.shields.io/crates/v/leptos-use.svg?label=&color=%232C1275" alt="Crates.io"/></a>
<a href="https://leptos-use.rs/server_side_rendering.html"><img src="https://img.shields.io/badge/-SSR-%236a214b" alt="SSR"></a>
<a href="https://leptos-use.rs"><img src="https://img.shields.io/badge/-docs%20%26%20demos-%239A233F" alt="Docs & Demos"></a>
<a href="https://leptos-use.rs"><img src="https://img.shields.io/badge/-76%20functions-%23EF3939" alt="76 Functions" /></a>
<a href="https://leptos-use.rs"><img src="https://img.shields.io/badge/-77%20functions-%23EF3939" alt="77 Functions" /></a>
</p>
<br/>

View file

@ -12,6 +12,6 @@
<a href="https://crates.io/crates/leptos-use"><img src="https://img.shields.io/crates/v/leptos-use.svg?label=&color=%232C1275" alt="Crates.io"/></a>
<a href="https://leptos-use.rs/server_side_rendering.html"><img src="https://img.shields.io/badge/-SSR-%236a214b" alt="SSR"></a>
<a href="./get_started.html"><img src="https://img.shields.io/badge/-docs%20%26%20demos-%239A233F" alt="Docs & Demos"></a>
<a href="./functions.html"><img src="https://img.shields.io/badge/-76%20functions-%23EF3939" alt="76 Functions" /></a>
<a href="./functions.html"><img src="https://img.shields.io/badge/-77%20functions-%23EF3939" alt="77 Functions" /></a>
</p>
</div>

View file

@ -21,7 +21,7 @@ simple_logger = "4"
tokio = { version = "1", features = ["full"], optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
wasm-bindgen = "0.2.88"
wasm-bindgen = "0.2.92"
thiserror = "1.0.38"
tracing = { version = "0.1.37", optional = true }
http = "1"

View file

@ -6,9 +6,10 @@ use leptos_router::*;
use leptos_use::storage::use_local_storage;
use leptos_use::utils::FromToStringCodec;
use leptos_use::{
use_color_mode, use_cookie_with_options, use_debounce_fn, use_event_listener, use_interval,
use_intl_number_format, use_preferred_dark, use_timestamp, use_window, ColorMode,
UseColorModeReturn, UseCookieOptions, UseIntervalReturn, UseIntlNumberFormatOptions,
use_color_mode_with_options, use_cookie_with_options, use_debounce_fn, use_event_listener,
use_interval, use_intl_number_format, use_preferred_dark, use_timestamp, use_window, ColorMode,
UseColorModeOptions, UseColorModeReturn, UseCookieOptions, UseIntervalReturn,
UseIntlNumberFormatOptions,
};
#[component]
@ -65,7 +66,8 @@ fn HomePage() -> impl IntoView {
);
debounced_fn();
let UseColorModeReturn { mode, set_mode, .. } = use_color_mode();
let UseColorModeReturn { mode, set_mode, .. } =
use_color_mode_with_options(UseColorModeOptions::default().cookie_enabled(true));
let timestamp = use_timestamp();
@ -79,6 +81,8 @@ fn HomePage() -> impl IntoView {
);
view! {
<Html class=move || mode.get().to_string()/>
<h1>Leptos-Use SSR Example</h1>
<button on:click=on_click>Click Me: {count}</button>
<p>Locale zh-Hans-CN-u-nu-hanidec: {zh_count}</p>
@ -98,12 +102,11 @@ fn HomePage() -> impl IntoView {
#[component]
pub fn LocalStorageTest() -> impl IntoView {
let UseIntervalReturn { counter, .. } = use_interval(1000);
logging::log!("test log");
let (state, set_state, ..) = use_local_storage::<String, FromToStringCodec>("test-state");
view! {
<p>{counter}</p>
<input
<input
class="block"
prop:value=move || state.get()
on:input=move |e| set_state.update(|s| *s = event_target_value(&e))

View file

@ -2,8 +2,11 @@ use crate::core::url;
use crate::core::StorageType;
use crate::core::{ElementMaybeSignal, MaybeRwSignal};
use crate::storage::{use_storage_with_options, UseStorageOptions};
use crate::use_preferred_dark;
use crate::utils::FromToStringCodec;
use crate::{
sync_signal_with_options, use_cookie_with_options, use_preferred_dark, SyncSignalOptions,
UseCookieOptions,
};
use default_struct_builder::DefaultBuilder;
use leptos::*;
use std::fmt::{Display, Formatter};
@ -83,15 +86,47 @@ use wasm_bindgen::JsCast;
/// # }
/// ```
///
/// ### Cookies
///
/// To persist color mode in a cookie, use `use_cookie_with_options` and specify `.cookie_enabled(true)`.
///
/// > Note: To work with SSR you have to add the `axum` or `actix` feature as described in [`use_cookie`].
///
/// ```rust
/// # use leptos::*;
/// # use leptos_meta::*;
/// # use leptos_use::{use_color_mode_with_options, UseColorModeOptions, UseColorModeReturn};
/// #
/// # #[component]
/// # fn Demo() -> impl IntoView {
/// let UseColorModeReturn { mode, set_mode, .. } = use_color_mode_with_options(
/// UseColorModeOptions::default()
/// .cookie_enabled(true),
/// );
///
/// // This adds the color mode class to the `<html>` element even with SSR
/// view! {
/// <Html class=move || mode.get().to_string()/>
/// }
/// # }
/// ```
///
/// For a working example please check out the [ssr example](https://github.com/Synphonyte/leptos-use/blob/main/examples/ssr/src/app.rs).
///
/// ## Server-Side Rendering
///
/// On the server this will by default return `ColorMode::Light`. Persistence is disabled, of course.
/// On the server this will by default return `ColorMode::Light`. Persistence with storage is disabled.
///
/// If `cookie_enabled` is set to `true`, cookies will be used and if present this value will be used
/// on the server as well as on the client. Please note that you have to add the `axum` or `actix`
/// feature as described in [`use_cookie`].
///
/// ## See also
///
/// * [`use_dark`]
/// * [`use_preferred_dark`]
/// * [`use_storage`]
/// * [`use_cookie`]
pub fn use_color_mode() -> UseColorModeReturn {
use_color_mode_with_options(UseColorModeOptions::default())
}
@ -115,6 +150,8 @@ where
storage_key,
storage,
storage_enabled,
cookie_name,
cookie_enabled,
emit_auto,
transition_enabled,
listen_to_storage_changes,
@ -146,8 +183,9 @@ where
}
}
let initial_stored_value = initial_value_from_url.clone().unwrap_or(initial_value);
let (store, set_store) = get_store_signal(
initial_value_from_url.clone().unwrap_or(initial_value),
initial_stored_value.clone(),
storage_signal,
&storage_key,
storage_enabled,
@ -155,6 +193,28 @@ where
listen_to_storage_changes,
);
let (initial_stored_value, _) = initial_stored_value.into_signal();
let initial_stored_value = initial_stored_value.get_untracked();
let (cookie, set_cookie) =
get_cookie_signal(initial_stored_value.clone(), &cookie_name, cookie_enabled);
let _ = sync_signal_with_options(
(cookie, set_cookie),
(store, set_store),
SyncSignalOptions::with_transforms(
{
let initial_stored_value = initial_stored_value.clone();
move |cookie: &Option<ColorMode>| {
cookie
.clone()
.unwrap_or_else(|| initial_stored_value.clone())
}
},
move |store: &ColorMode| Some(store.clone()),
),
);
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 {
@ -267,6 +327,22 @@ pub enum ColorMode {
Custom(String),
}
fn get_cookie_signal(
initial_value: ColorMode,
cookie_name: &str,
cookie_enabled: bool,
) -> (Signal<Option<ColorMode>>, WriteSignal<Option<ColorMode>>) {
if cookie_enabled {
use_cookie_with_options::<ColorMode, FromToStringCodec>(
cookie_name,
UseCookieOptions::<ColorMode, _>::default().default_value(Some(initial_value)),
)
} else {
let (value, set_value) = create_signal(Some(initial_value));
(value.into(), set_value)
}
}
fn get_store_signal(
initial_value: MaybeRwSignal<ColorMode>,
storage_signal: Option<RwSignal<ColorMode>>,
@ -383,10 +459,19 @@ where
/// Defaults to `Local`.
storage: StorageType,
/// If the color mode should be persisted. If `true` this required the
/// If the color mode should be persisted.
/// Defaults to `true`.
storage_enabled: bool,
/// Name of the cookie that should be used to persist the color mode.
/// Defaults to `"leptos-use-color-scheme"`.
#[builder(into)]
cookie_name: String,
/// If the color mode should be persisted through a cookie.
/// Defaults to `false`.
cookie_enabled: bool,
/// Emit `auto` mode from state
///
/// When set to `true`, preferred mode won't be translated into `light` or `dark`.
@ -422,6 +507,8 @@ impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
storage_key: "leptos-use-color-scheme".into(),
storage: StorageType::default(),
storage_enabled: true,
cookie_name: "leptos-use-color-scheme".into(),
cookie_enabled: false,
emit_auto: false,
transition_enabled: false,
listen_to_storage_changes: true,