Skip to main content

dioxus_bootstrap/
theme.rs

1use dioxus::prelude::*;
2
3const AUTO: Asset = asset!("/assets/auto_mode.js");
4const DARK: Asset = asset!("/assets/dark_mode.js");
5const LIGHT: Asset = asset!("/assets/light_mode.js");
6
7#[derive(Clone, PartialEq, Debug)]
8pub enum ThemeMode {
9    Auto,
10    Dark,
11    Light,
12}
13
14impl From<&str> for ThemeMode {
15    fn from(value: &str) -> Self {
16        match value {
17            "dark" => Self::Dark,
18            "light" => Self::Light,
19            _ => Self::Auto,
20        }
21    }
22}
23impl Into<&str> for ThemeMode {
24    fn into(self: Self) -> &'static str {
25        match self {
26            Self::Dark => "dark",
27            Self::Light => "light",
28            _ => "auto",
29        }
30    }
31}
32
33#[derive(Clone, Props, PartialEq)]
34pub struct GlobalThemeProps {
35    #[props(optional, default = ThemeMode::Auto)]
36    pub mode: ThemeMode,
37    /// set to false if you don't want ot load the bootstrap assets from the CDN.
38    /// You will need to load them manually.
39    #[props(optional, default = true)]
40    pub cdn_load_assets: bool,
41}
42
43#[derive(Clone, Props, PartialEq)]
44pub struct LocalThemeProps {
45    #[props(optional, default = ThemeMode::Auto)]
46    pub mode: ThemeMode,
47    pub children: Element,
48}
49
50/// Sets dark/light mode based on system setting on the entire html tag.
51/// Also loads the required Bootstrap assets from the Bootstrap CDN. If
52/// you want to load those assets some other way, you can disable this
53/// with the cdn_load_assets prop.
54#[component]
55pub fn GlobalTheme(props: GlobalThemeProps) -> Element {
56    let mode = match props.mode {
57        ThemeMode::Light => LIGHT,
58        ThemeMode::Dark => DARK,
59        _ => AUTO,
60    };
61
62    rsx!{
63        if props.cdn_load_assets {
64            document::Link {
65                rel: "stylesheet",
66                href: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css",
67                integrity: "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH",
68                crossorigin: "anonymous"
69            }
70            document::Script {
71                src: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js",
72                integrity: "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
73                crossorigin: "anonymous"
74            }
75        }
76        document::Script {
77            src: mode
78        }
79    }
80}
81
82/// Overrides the larger mode for child nodes.
83#[component]
84pub fn LocalTheme(props: LocalThemeProps) -> Element {
85    let theme_requested: &str = props.mode.into();
86
87    rsx!{
88        div {
89            "data-bs-theme": theme_requested,
90            {props.children}
91        }
92    }
93}