Skip to main content

yew_nav_link/components/
badge.rs

1//! # `NavBadge`
2//!
3//! Small colored label for showing counts, statuses, or labels inside
4//! navigation links. Renders a `<span>` you can place anywhere inside
5//! a `NavLink` or `NavItem`.
6//!
7//! # Quick Start
8//!
9//! ```rust
10//! use yew::prelude::*;
11//! use yew_nav_link::{NavBadge, NavItem, NavLink, NavList};
12//! use yew_router::prelude::*;
13//!
14//! # #[derive(Clone, PartialEq, Routable)]
15//! # enum Route {
16//! #     #[at("/")]
17//! #     Home,
18//! # }
19//! #[component]
20//! fn Nav() -> Html {
21//!     html! {
22//!         <NavList>
23//!             <NavItem>
24//!                 <NavLink<Route> to={Route::Home}>
25//!                     { "Messages " }
26//!                     <NavBadge variant="danger">{ "3" }</NavBadge>
27//!                 </NavLink<Route>>
28//!             </NavItem>
29//!         </NavList>
30//!     }
31//! }
32//! ```
33//!
34//! Available variants: `"primary"`, `"success"`, `"warning"`, `"danger"`.
35//! Set `pill=true` for fully rounded corners.
36//!
37//! # CSS Classes
38//!
39//! | Class | When Applied |
40//! |-------|--------------|
41//! | `nav-badge` | Always |
42//! | `nav-badge-pill` | When `pill` is `true` |
43//! | `nav-badge-{variant}` | Based on the `variant` prop |
44//!
45//! # Props
46//!
47//! | Prop | Type | Default | Description |
48//! |------|------|---------|-------------|
49//! | `variant` | `&'static str` | `"primary"` | Color variant |
50//! | `pill` | `bool` | `false` | Rounded pill shape |
51//! | `classes` | `Classes` | — | Additional CSS classes |
52//! | `children` | `Children` | — | Badge content |
53
54use yew::prelude::*;
55
56/// Properties for the [`NavBadge`] component.
57///
58/// | Prop | Type | Default | Description |
59/// |------|------|---------|-------------|
60/// | `variant` | `&'static str` | `"primary"` | Visual variant name |
61/// | `pill` | `bool` | `false` | Pill-shaped corners |
62/// | `classes` | `Classes` | — | Additional CSS classes |
63/// | `children` | `Children` | — | Badge content |
64#[derive(Properties, Clone, PartialEq, Debug)]
65pub struct NavBadgeProps {
66    /// Additional CSS classes applied to the badge.
67    #[prop_or_default]
68    pub classes: Classes,
69
70    /// Visual variant name, e.g. `"primary"`, `"success"`, `"danger"`.
71    #[prop_or("primary")]
72    pub variant: &'static str,
73
74    /// Render the badge with pill-shaped (fully rounded) corners.
75    #[prop_or_default]
76    pub pill: bool,
77
78    /// Content rendered inside the badge.
79    #[prop_or_default]
80    pub children: Children
81}
82
83/// Badge component for displaying status or count indicators on navigation
84/// items.
85///
86/// # CSS Classes
87///
88/// - `nav-badge` - Always applied
89/// - `nav-badge-pill` - Applied when `pill` is `true`
90/// - `nav-badge-{variant}` - Applied based on the `variant` prop
91#[function_component]
92pub fn NavBadge(props: &NavBadgeProps) -> Html {
93    let mut classes = props.classes.clone();
94    classes.push("nav-badge");
95
96    if props.pill {
97        classes.push("nav-badge-pill");
98    }
99
100    let variant_class = format!("nav-badge-{}", props.variant);
101    classes.push(variant_class);
102
103    html! {
104        <span {classes}>
105            { for props.children.iter() }
106        </span>
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn nav_badge_props_default() {
116        let props = NavBadgeProps {
117            classes:  Classes::default(),
118            variant:  "primary",
119            pill:     false,
120            children: Children::new(vec![])
121        };
122
123        assert!(!props.pill);
124        assert_eq!(props.variant, "primary");
125    }
126
127    #[test]
128    fn nav_badge_clone() {
129        let props1 = NavBadgeProps {
130            classes:  Classes::from("test"),
131            variant:  "success",
132            pill:     true,
133            children: Children::new(vec![])
134        };
135
136        let props2 = props1.clone();
137        assert_eq!(props1.variant, props2.variant);
138        assert_eq!(props1.pill, props2.pill);
139    }
140}