dioxus_tw_components/components/molecules/lightswitch/
props.rs

1use crate::{atoms::icon::*, attributes::*};
2use dioxus::prelude::*;
3use dioxus_tw_components_macro::UiComp;
4use serde_json::Value;
5
6pub struct LightSwitchState {
7    active: bool,
8}
9
10impl LightSwitchState {
11    pub fn new(active: bool) -> Self {
12        Self { active }
13    }
14
15    fn toggle(&mut self) -> bool {
16        self.active = !self.active;
17        self.active
18    }
19
20    fn get_active(&self) -> bool {
21        self.active
22    }
23
24    fn set_active(&mut self, active: bool) {
25        self.active = active;
26    }
27}
28
29#[derive(Clone, PartialEq, Props, UiComp)]
30pub struct LightSwitchProps {
31    #[props(extends = GlobalAttributes)]
32    attributes: Vec<Attribute>,
33
34    #[props(optional)]
35    pub onclick: Option<EventHandler<MouseEvent>>,
36
37    children: Element,
38}
39
40impl std::default::Default for LightSwitchProps {
41    fn default() -> Self {
42        Self {
43            attributes: Vec::<Attribute>::default(),
44            onclick: None,
45            children: rsx! {},
46        }
47    }
48}
49
50/// This component inserts/remove "dark" in the DOM on the div with id of main
51#[component]
52pub fn LightSwitch(mut props: LightSwitchProps) -> Element {
53    props.update_class_attribute();
54
55    let storage_dark_theme = use_resource(move || async move {
56        // Get dark_theme from localStorage, if not found add it to false
57        let mut eval = document::eval(
58            r#"
59            var dark_theme = localStorage.getItem("dark_theme");
60            if (dark_theme == null) {
61                var dark_theme = false;
62                localStorage.setItem("dark_theme", dark_theme);
63            } else {
64                let main_div = document.getElementById("main");
65                if (main_div != null && dark_theme == "true") {
66                    main_div.classList.add("dark");
67                }
68            }
69            dioxus.send(dark_theme);
70            "#,
71        );
72
73        eval.recv().await
74    });
75
76    let mut state = use_signal(|| LightSwitchState::new(false));
77
78    use_effect(move || {
79        if let Some(Ok(Value::String(str))) = &*storage_dark_theme.read_unchecked() {
80            let parsed_str = str.parse::<bool>();
81            if let Ok(bool_value) = parsed_str {
82                state.write().set_active(bool_value);
83            }
84        };
85    });
86
87    let mut onclick = move |_| {
88        let dark_theme = state.write().toggle();
89        spawn(async move {
90            // Change value of dark_theme in localStorage
91            let eval = document::eval(
92                r#"
93                const dark_theme = await dioxus.recv();
94                localStorage.setItem("dark_theme", dark_theme);
95                let main_div = document.getElementById("main");
96                if (main != null) {
97                    if (dark_theme) {
98                        main_div.classList.add("dark");
99                    } else {
100                        main_div.classList.remove("dark");
101                    }
102                }
103                "#,
104            );
105            let _ = eval.send(dark_theme);
106        });
107    };
108
109    let icon = if state.read().get_active() {
110        rsx! {
111            Icon { icon: Icons::DarkMode }
112        }
113    } else {
114        rsx! {
115            Icon { icon: Icons::LightMode }
116        }
117    };
118
119    rsx! {
120        button {
121            r#type: "button",
122            onclick: move |e| {
123                match props.onclick {
124                    Some(p) => {
125                        state.write().toggle();
126                        p.call(e);
127                    }
128                    None => onclick(e),
129                }
130            },
131            ..props.attributes,
132            {icon}
133        }
134    }
135}