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