Skip to main content

dioxus_element_plug/components/
badge.rs

1use dioxus::prelude::*;
2
3/// Badge type variants
4#[derive(Clone, PartialEq)]
5pub enum BadgeType {
6    Primary,
7    Success,
8    Warning,
9    Info,
10    Danger,
11}
12
13impl BadgeType {
14    pub fn as_class(&self) -> &'static str {
15        match self {
16            BadgeType::Primary => "el-badge__content--primary",
17            BadgeType::Success => "el-badge__content--success",
18            BadgeType::Warning => "el-badge__content--warning",
19            BadgeType::Info => "el-badge__content--info",
20            BadgeType::Danger => "el-badge__content--danger",
21        }
22    }
23}
24
25/// Badge props
26#[derive(Props, Clone, PartialEq)]
27pub struct BadgeProps {
28    /// Content to wrap with badge
29    #[props(default)]
30    pub children: Element,
31
32    /// Display value (string or number as string)
33    #[props(default)]
34    pub value: Option<String>,
35
36    /// Maximum value, shows `{max}+` when exceeded
37    #[props(default = 99)]
38    pub max: u32,
39
40    /// If a little dot is displayed
41    #[props(default = false)]
42    pub is_dot: bool,
43
44    /// Hidden badge
45    #[props(default = false)]
46    pub hidden: bool,
47
48    /// Badge type
49    #[props(default = BadgeType::Danger)]
50    pub badge_type: BadgeType,
51
52    /// Whether to show badge when value is zero
53    #[props(default = true)]
54    pub show_zero: bool,
55
56    /// Custom dot background color
57    #[props(default)]
58    pub color: Option<String>,
59
60    /// Additional CSS classes
61    #[props(default)]
62    pub class: Option<String>,
63
64    /// Inline styles
65    #[props(default)]
66    pub style: Option<String>,
67}
68
69/// Badge component for displaying notification counts or status indicators
70///
71/// ## Example
72///
73/// ```rust,ignore
74/// rsx! {
75///     Badge { value: Some("5".to_string()), badge_type: BadgeType::Danger,
76///         Button { "Messages" }
77///     }
78/// }
79/// ```
80#[component]
81pub fn Badge(props: BadgeProps) -> Element {
82    if props.hidden {
83        return rsx! { {props.children} };
84    }
85
86    let mut class_names = vec!["el-badge".to_string()];
87    if let Some(ref custom_class) = props.class {
88        class_names.push(custom_class.clone());
89    }
90    let class_string = class_names.join(" ");
91
92    let mut content_classes = vec!["el-badge__content".to_string()];
93    content_classes.push(props.badge_type.as_class().to_string());
94
95    if props.is_dot {
96        content_classes.push("is-dot".to_string());
97    }
98
99    let content_class_string = content_classes.join(" ");
100
101    // Compute display value
102    let display_value = if props.is_dot {
103        String::new()
104    } else {
105        match &props.value {
106            Some(val) => {
107                if let Ok(num) = val.parse::<u32>() {
108                    if num == 0 && !props.show_zero {
109                        String::new()
110                    } else if num > props.max {
111                        format!("{}+", props.max)
112                    } else {
113                        val.clone()
114                    }
115                } else {
116                    val.clone()
117                }
118            }
119            None => String::new(),
120        }
121    };
122
123    let show_content = !display_value.is_empty() || props.is_dot;
124
125    let mut content_style = props.style.clone().unwrap_or_default();
126    if let Some(ref color) = props.color {
127        content_style = format!("background-color: {}; {}", color, content_style);
128    }
129
130    rsx! {
131        div {
132            class: "{class_string}",
133            {props.children}
134            if show_content {
135                sup {
136                    class: "{content_class_string}",
137                    style: "{content_style}",
138                    "{display_value}"
139                }
140            }
141        }
142    }
143}