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)]
68pub struct ThemeProviderProps {
69 pub theme: Signal<Theme>,
71}
72
73#[component]
74pub fn ThemeProvider(props: ThemeProviderProps) -> Element {
75 let theme_signal = props.theme;
76
77 use_effect(move || {
79 let theme = *theme_signal.read();
80 let theme_str = theme.as_str();
81 document::eval(&format!(
82 "document.documentElement.setAttribute('data-bs-theme', '{theme_str}');"
83 ));
84 });
85
86 rsx! {}
87}
88
89#[derive(Clone, PartialEq, Props)]
103pub struct ThemeToggleProps {
104 pub theme: Signal<Theme>,
106 #[props(default)]
108 pub color: Option<Color>,
109 #[props(default)]
111 pub class: String,
112}
113
114#[component]
115pub fn ThemeToggle(props: ThemeToggleProps) -> Element {
116 let theme = *props.theme.read();
117 let mut theme_signal = props.theme;
118
119 let icon = match theme {
120 Theme::Light => "moon-stars",
121 Theme::Dark => "sun",
122 };
123
124 let label = match theme {
125 Theme::Light => "Switch to dark mode",
126 Theme::Dark => "Switch to light mode",
127 };
128
129 let btn_class = match &props.color {
130 Some(c) => format!("btn btn-outline-{c}"),
131 None => "btn btn-outline-secondary".to_string(),
132 };
133
134 let full_class = if props.class.is_empty() {
135 btn_class
136 } else {
137 format!("{btn_class} {}", props.class)
138 };
139
140 rsx! {
141 button {
142 class: "{full_class}",
143 r#type: "button",
144 title: "{label}",
145 "aria-label": "{label}",
146 onclick: move |_| {
147 let new_theme = theme.toggle();
148 theme_signal.set(new_theme);
149 },
150 i { class: "bi bi-{icon}" }
151 }
152 }
153}