tallyweb_frontend/
preferences.rs1use leptos::*;
2use serde::{Deserialize, Serialize};
3
4use super::*;
5
6pub type PrefResource = Resource<UserSession, Result<Preferences, ServerFnError>>;
7
8#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
9pub struct AccountAccentColor(pub String);
10
11impl AccountAccentColor {
12 fn new(user: &UserSession) -> Self {
13 let mut this = Self(String::new());
14 this.set_user(user);
15 this
16 }
17
18 pub fn set_user(&mut self, user: &UserSession) {
19 let letter = user
20 .username
21 .to_uppercase()
22 .chars()
23 .next()
24 .unwrap_or_default();
25 let color_hex = elements::letter_to_three_digit_hash(letter);
26 self.0 = format!("#{color_hex}")
27 }
28}
29
30impl std::fmt::Display for AccountAccentColor {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(f, "{}", self.0)
33 }
34}
35
36#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
37pub struct Preferences {
38 pub use_default_accent_color: bool,
39 pub accent_color: AccountAccentColor,
40 pub show_separator: bool,
41 pub multi_select: bool,
42 pub save_on_pause: bool,
43}
44
45impl Preferences {
46 pub fn new(user: &UserSession) -> Self {
47 let accent_color = AccountAccentColor::new(user);
48 Self {
49 use_default_accent_color: true,
50 accent_color,
51 show_separator: false,
52 multi_select: false,
53 save_on_pause: true,
54 }
55 }
56}
57
58#[cfg(feature = "ssr")]
59impl Preferences {
60 pub fn from_db(user: &UserSession, value: backend::DbPreferences) -> Self {
61 Self {
62 use_default_accent_color: value.use_default_accent_color,
63 accent_color: value
64 .accent_color
65 .map(|c| AccountAccentColor(c))
66 .unwrap_or(AccountAccentColor::new(user)),
67 show_separator: value.show_separator,
68 multi_select: value.multi_select,
69 save_on_pause: value.save_on_pause,
70 }
71 }
72}
73
74#[component(transparent)]
75pub fn ProvidePreferences(children: ChildrenFn) -> impl IntoView {
76 let user = expect_context::<RwSignal<UserSession>>();
77
78 let data = create_blocking_resource(user, api::get_user_preferences);
79 provide_context(data);
80
81 let pref_signal = create_rw_signal(Preferences::new(&user.get_untracked()));
82 provide_context(pref_signal);
83
84 let accent_color = create_read_slice(pref_signal, |p| p.accent_color.clone().0);
85
86 view! {
87 <Transition>
88
89 {if let Some(Ok(p)) = data.get() {
90 pref_signal.set(p.clone())
91 }} <div style=move || { format!("--accent: {}", accent_color()) }>{children()}</div>
92 </Transition>
93 }
94}