ironhtml_bootstrap/
breadcrumb.rs1use ironhtml::typed::Element;
7use ironhtml_elements::{Li, Nav, Ol, A};
8
9extern crate alloc;
10use alloc::string::String;
11
12pub struct BreadcrumbItem {
14 pub label: String,
15 pub href: Option<String>,
16 pub active: bool,
17}
18
19impl BreadcrumbItem {
20 #[must_use]
22 pub fn link(label: impl Into<String>, href: impl Into<String>) -> Self {
23 Self {
24 label: label.into(),
25 href: Some(href.into()),
26 active: false,
27 }
28 }
29
30 #[must_use]
32 pub fn active(label: impl Into<String>) -> Self {
33 Self {
34 label: label.into(),
35 href: None,
36 active: true,
37 }
38 }
39}
40
41#[must_use]
59pub fn breadcrumb(items: &[BreadcrumbItem]) -> Element<Nav> {
60 Element::<Nav>::new()
61 .attr("aria-label", "breadcrumb")
62 .child::<Ol, _>(|ol| {
63 items.iter().fold(ol.class("breadcrumb"), |ol, item| {
64 ol.child::<Li, _>(|_| breadcrumb_item(item))
65 })
66 })
67}
68
69fn breadcrumb_item(item: &BreadcrumbItem) -> Element<Li> {
71 if item.active {
72 Element::<Li>::new()
73 .class("breadcrumb-item active")
74 .attr("aria-current", "page")
75 .text(&item.label)
76 } else if let Some(ref href) = item.href {
77 Element::<Li>::new()
78 .class("breadcrumb-item")
79 .child::<A, _>(|a| a.attr("href", href).text(&item.label))
80 } else {
81 Element::<Li>::new()
82 .class("breadcrumb-item")
83 .text(&item.label)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use alloc::vec;
91
92 #[test]
93 fn test_breadcrumb() {
94 let items = vec![
95 BreadcrumbItem::link("Home", "/"),
96 BreadcrumbItem::link("Products", "/products"),
97 BreadcrumbItem::active("Widget"),
98 ];
99
100 let nav = breadcrumb(&items);
101 let html = nav.render();
102 assert!(html.contains("breadcrumb"));
103 assert!(html.contains(r#"aria-label="breadcrumb"#));
104 assert!(html.contains(r#"href="/"#));
105 assert!(html.contains(r#"aria-current="page"#));
106 assert!(html.contains("active"));
107 }
108}