Skip to main content

shadow_design/
alert.rs

1use crate::icon::{Icon, IconKind};
2use dioxus::prelude::*;
3
4#[derive(Clone, Copy, PartialEq, Debug, Default)]
5pub enum AlertVariant {
6    #[default]
7    Info,
8    Success,
9    Warning,
10    Danger,
11}
12
13impl AlertVariant {
14    pub fn scss_class(&self) -> &'static str {
15        match self {
16            AlertVariant::Info => "sd-alert--info",
17            AlertVariant::Success => "sd-alert--success",
18            AlertVariant::Warning => "sd-alert--warning",
19            AlertVariant::Danger => "sd-alert--danger",
20        }
21    }
22
23    pub fn name(&self) -> &'static str {
24        match self {
25            AlertVariant::Info => "info",
26            AlertVariant::Success => "success",
27            AlertVariant::Warning => "warning",
28            AlertVariant::Danger => "danger",
29        }
30    }
31
32    pub fn glow_class(&self) -> &'static str {
33        match self {
34            AlertVariant::Info => "sd-alert--glow-info",
35            AlertVariant::Success => "sd-alert--glow-success",
36            AlertVariant::Warning => "sd-alert--glow-warning",
37            AlertVariant::Danger => "sd-alert--glow-danger",
38        }
39    }
40
41    pub fn title_class(&self) -> &'static str {
42        match self {
43            AlertVariant::Info => "sd-alert__title--info",
44            AlertVariant::Success => "sd-alert__title--success",
45            AlertVariant::Warning => "sd-alert__title--warning",
46            AlertVariant::Danger => "sd-alert__title--danger",
47        }
48    }
49
50    pub fn icon_kind(&self) -> IconKind {
51        match self {
52            AlertVariant::Info => IconKind::Info,
53            AlertVariant::Success => IconKind::CheckCircle,
54            AlertVariant::Warning => IconKind::AlertTriangle,
55            AlertVariant::Danger => IconKind::XCircle,
56        }
57    }
58
59    pub fn icon_color_class(&self) -> &'static str {
60        match self {
61            AlertVariant::Info => "sd-alert__icon--info",
62            AlertVariant::Success => "sd-alert__icon--success",
63            AlertVariant::Warning => "sd-alert__icon--warning",
64            AlertVariant::Danger => "sd-alert__icon--danger",
65        }
66    }
67}
68
69#[component]
70pub fn Alert(
71    #[props(default)] title: Option<String>,
72    #[props(default)] variant: AlertVariant,
73    #[props(default)] class: String,
74    #[props(default)] glow: Option<bool>,
75    on_close: Option<EventHandler<MouseEvent>>,
76    children: Element,
77) -> Element {
78    let title_variant_class = variant.title_class();
79    let icon_color_class = variant.icon_color_class();
80
81    #[cfg(feature = "theme")]
82    let theme_val = crate::theme::use_theme()();
83    #[cfg(feature = "theme")]
84    let radius_class = theme_val.radius_scale.md();
85    #[cfg(feature = "theme")]
86    let base_override = theme_val.resolve_component_base("alert").unwrap_or("");
87    #[cfg(feature = "theme")]
88    let class_modifiers = theme_val.resolve_class_modifiers("alert", &class);
89    #[cfg(feature = "theme")]
90    let variant_class = theme_val.resolve_variant_class("alert", variant.name(), variant.scss_class());
91    #[cfg(feature = "theme")]
92    let glow_class = theme_val.resolve_elevation_class("alert", glow);
93
94    #[cfg(not(feature = "theme"))]
95    let base_override = "";
96    #[cfg(not(feature = "theme"))]
97    let class_modifiers = String::new();
98    #[cfg(not(feature = "theme"))]
99    let variant_class = variant.scss_class().to_string();
100    #[cfg(not(feature = "theme"))]
101    let radius_class = "";
102    #[cfg(not(feature = "theme"))]
103    let glow_class = if glow.unwrap_or(false) {
104        variant.glow_class().to_string()
105    } else {
106        String::new()
107    };
108
109    let icon_kind = variant.icon_kind();
110
111    rsx! {
112        div {
113            class: "sd-alert {base_override} {variant_class} {glow_class} {radius_class} {class_modifiers} {class}",
114            span { class: "sd-alert__icon {icon_color_class}",
115                Icon { kind: icon_kind, size: 18 }
116            }
117            div { class: "sd-alert__content",
118                if let Some(t) = title {
119                    h4 { class: "sd-alert__title {title_variant_class}", "{t}" }
120                }
121                div { class: "sd-alert__body", {children} }
122            }
123            if let Some(close_handler) = on_close {
124                button {
125                    r#type: "button",
126                    class: "sd-alert__close",
127                    onclick: move |e| close_handler.call(e),
128                    Icon { kind: IconKind::X, size: 14 }
129                }
130            }
131        }
132    }
133}