ironhtml_bootstrap/
list_group.rs1use crate::Color;
7use ironhtml::typed::Element;
8use ironhtml_elements::{Button, Div, Li, Ul, A};
9
10extern crate alloc;
11use alloc::string::String;
12
13#[must_use]
25pub fn list_group(items: &[&str]) -> Element<Ul> {
26 items
27 .iter()
28 .fold(Element::<Ul>::new().class("list-group"), |ul, item| {
29 ul.child::<Li, _>(|li| li.class("list-group-item").text(*item))
30 })
31}
32
33#[must_use]
35pub fn list_group_flush(items: &[&str]) -> Element<Ul> {
36 items.iter().fold(
37 Element::<Ul>::new().class("list-group list-group-flush"),
38 |ul, item| ul.child::<Li, _>(|li| li.class("list-group-item").text(*item)),
39 )
40}
41
42pub struct ListGroupLink {
44 pub text: String,
45 pub href: String,
46 pub active: bool,
47 pub disabled: bool,
48 pub color: Option<Color>,
49}
50
51impl ListGroupLink {
52 #[must_use]
54 pub fn new(text: impl Into<String>, href: impl Into<String>) -> Self {
55 Self {
56 text: text.into(),
57 href: href.into(),
58 active: false,
59 disabled: false,
60 color: None,
61 }
62 }
63
64 #[must_use]
66 pub const fn active(mut self) -> Self {
67 self.active = true;
68 self
69 }
70
71 #[must_use]
73 pub const fn disabled(mut self) -> Self {
74 self.disabled = true;
75 self
76 }
77
78 #[must_use]
80 pub const fn color(mut self, color: Color) -> Self {
81 self.color = Some(color);
82 self
83 }
84}
85
86#[must_use]
104pub fn list_group_links(items: &[ListGroupLink]) -> Element<Div> {
105 items
106 .iter()
107 .fold(Element::<Div>::new().class("list-group"), |div, item| {
108 div.child::<A, _>(|_| list_group_link_item(item))
109 })
110}
111
112fn list_group_link_item(item: &ListGroupLink) -> Element<A> {
114 let mut class = String::from("list-group-item list-group-item-action");
115
116 if item.active {
117 class.push_str(" active");
118 }
119 if item.disabled {
120 class.push_str(" disabled");
121 }
122 if let Some(color) = item.color {
123 use core::fmt::Write;
124 let _ = write!(class, " list-group-item-{}", color.as_str());
125 }
126
127 let mut elem = Element::<A>::new()
128 .attr("href", &item.href)
129 .class(&class)
130 .text(&item.text);
131
132 if item.active {
133 elem = elem.attr("aria-current", "true");
134 }
135 if item.disabled {
136 elem = elem.attr("aria-disabled", "true");
137 }
138
139 elem
140}
141
142#[must_use]
144pub fn list_group_buttons(items: &[(String, bool, bool)]) -> Element<Div> {
145 items.iter().fold(
146 Element::<Div>::new().class("list-group"),
147 |div, (text, active, disabled)| {
148 div.child::<Button, _>(|btn| {
149 let mut class = String::from("list-group-item list-group-item-action");
150 if *active {
151 class.push_str(" active");
152 }
153
154 let mut btn = btn.attr("type", "button").class(&class).text(text);
155
156 if *active {
157 btn = btn.attr("aria-current", "true");
158 }
159 if *disabled {
160 btn = btn.bool_attr("disabled");
161 }
162 btn
163 })
164 },
165 )
166}
167
168#[must_use]
170pub fn list_group_numbered(items: &[&str]) -> Element<Ol> {
171 items.iter().fold(
172 Element::<Ol>::new().class("list-group list-group-numbered"),
173 |ol, item| ol.child::<Li, _>(|li| li.class("list-group-item").text(*item)),
174 )
175}
176
177#[must_use]
179pub fn list_group_horizontal(items: &[&str]) -> Element<Ul> {
180 items.iter().fold(
181 Element::<Ul>::new().class("list-group list-group-horizontal"),
182 |ul, item| ul.child::<Li, _>(|li| li.class("list-group-item").text(*item)),
183 )
184}
185
186use ironhtml_elements::Ol;
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use alloc::vec;
192
193 #[test]
194 fn test_list_group() {
195 let items = vec!["One", "Two", "Three"];
196 let list = list_group(&items);
197 let html = list.render();
198 assert!(html.contains("list-group"));
199 assert!(html.contains("list-group-item"));
200 }
201
202 #[test]
203 fn test_list_group_links() {
204 let items = vec![
205 ListGroupLink::new("Active", "#").active(),
206 ListGroupLink::new("Normal", "#"),
207 ListGroupLink::new("Disabled", "#").disabled(),
208 ];
209 let list = list_group_links(&items);
210 let html = list.render();
211 assert!(html.contains("list-group-item-action"));
212 assert!(html.contains("active"));
213 assert!(html.contains("disabled"));
214 }
215
216 #[test]
217 fn test_list_group_colored() {
218 let items = vec![ListGroupLink::new("Success", "#").color(Color::Success)];
219 let list = list_group_links(&items);
220 assert!(list.render().contains("list-group-item-success"));
221 }
222}