dioxus_bootstrap_css/
theme.rs1use dioxus::prelude::*;
2
3use crate::types::Color;
4
5#[derive(Clone, Copy, Debug, Default, PartialEq)]
7pub enum Theme {
8 #[default]
9 Light,
10 Dark,
11}
12
13impl Theme {
14 pub fn toggle(self) -> Self {
16 match self {
17 Theme::Light => Theme::Dark,
18 Theme::Dark => Theme::Light,
19 }
20 }
21
22 pub fn as_str(&self) -> &'static str {
24 match self {
25 Theme::Light => "light",
26 Theme::Dark => "dark",
27 }
28 }
29}
30
31impl std::fmt::Display for Theme {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(f, "{}", self.as_str())
34 }
35}
36
37#[derive(Clone, PartialEq, Props)]
59pub struct ThemeProviderProps {
60 pub theme: Signal<Theme>,
62}
63
64#[component]
65pub fn ThemeProvider(props: ThemeProviderProps) -> Element {
66 let theme_signal = props.theme;
67
68 use_effect(move || {
70 let theme = *theme_signal.read();
71 let theme_str = theme.as_str();
72 document::eval(&format!(
73 "document.documentElement.setAttribute('data-bs-theme', '{theme_str}');"
74 ));
75 });
76
77 rsx! {}
78}
79
80#[derive(Clone, PartialEq, Props)]
90pub struct ThemeToggleProps {
91 pub theme: Signal<Theme>,
93 #[props(default)]
95 pub color: Option<Color>,
96 #[props(default)]
98 pub class: String,
99}
100
101#[component]
102pub fn ThemeToggle(props: ThemeToggleProps) -> Element {
103 let theme = *props.theme.read();
104 let mut theme_signal = props.theme;
105
106 let icon = match theme {
107 Theme::Light => "moon-stars",
108 Theme::Dark => "sun",
109 };
110
111 let label = match theme {
112 Theme::Light => "Switch to dark mode",
113 Theme::Dark => "Switch to light mode",
114 };
115
116 let btn_class = match &props.color {
117 Some(c) => format!("btn btn-outline-{c}"),
118 None => "btn btn-outline-secondary".to_string(),
119 };
120
121 let full_class = if props.class.is_empty() {
122 btn_class
123 } else {
124 format!("{btn_class} {}", props.class)
125 };
126
127 rsx! {
128 button {
129 class: "{full_class}",
130 r#type: "button",
131 title: "{label}",
132 "aria-label": "{label}",
133 onclick: move |_| {
134 let new_theme = theme.toggle();
135 theme_signal.set(new_theme);
136 },
137 i { class: "bi bi-{icon}" }
138 }
139 }
140}