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)]
51pub struct ThemeProviderProps {
52 pub theme: Signal<Theme>,
54}
55
56#[component]
57pub fn ThemeProvider(props: ThemeProviderProps) -> Element {
58 let theme_signal = props.theme;
59
60 use_effect(move || {
62 let theme = *theme_signal.read();
63 let theme_str = theme.as_str();
64 document::eval(&format!(
65 "document.documentElement.setAttribute('data-bs-theme', '{theme_str}');"
66 ));
67 });
68
69 rsx! {}
70}
71
72#[derive(Clone, PartialEq, Props)]
82pub struct ThemeToggleProps {
83 pub theme: Signal<Theme>,
85 #[props(default)]
87 pub color: Option<Color>,
88 #[props(default)]
90 pub class: String,
91}
92
93#[component]
94pub fn ThemeToggle(props: ThemeToggleProps) -> Element {
95 let theme = *props.theme.read();
96 let mut theme_signal = props.theme;
97
98 let icon = match theme {
99 Theme::Light => "moon-stars",
100 Theme::Dark => "sun",
101 };
102
103 let label = match theme {
104 Theme::Light => "Switch to dark mode",
105 Theme::Dark => "Switch to light mode",
106 };
107
108 let btn_class = match &props.color {
109 Some(c) => format!("btn btn-outline-{c}"),
110 None => "btn btn-outline-secondary".to_string(),
111 };
112
113 let full_class = if props.class.is_empty() {
114 btn_class
115 } else {
116 format!("{btn_class} {}", props.class)
117 };
118
119 rsx! {
120 button {
121 class: "{full_class}",
122 r#type: "button",
123 title: "{label}",
124 "aria-label": "{label}",
125 onclick: move |_| {
126 let new_theme = theme.toggle();
127 theme_signal.set(new_theme);
128 },
129 i { class: "bi bi-{icon}" }
130 }
131 }
132}