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