ironhtml_bootstrap/
progress.rs

1//! Bootstrap progress bar components.
2//!
3//! Provides type-safe Bootstrap progress bars matching the
4//! [Bootstrap progress documentation](https://getbootstrap.com/docs/5.3/components/progress/).
5
6use crate::Color;
7use ironhtml::typed::Element;
8use ironhtml_elements::Div;
9
10extern crate alloc;
11use alloc::format;
12use alloc::string::ToString;
13
14/// Create a Bootstrap progress bar.
15///
16/// ## Example
17///
18/// ```rust
19/// use ironhtml_bootstrap::progress::progress;
20///
21/// let bar = progress(75);
22/// assert!(bar.render().contains("progress"));
23/// assert!(bar.render().contains("75%"));
24/// ```
25#[must_use]
26pub fn progress(percent: u8) -> Element<Div> {
27    let percent = percent.min(100);
28    let width = format!("width: {percent}%");
29    let label = format!("{percent}%");
30
31    Element::<Div>::new()
32        .class("progress")
33        .attr("role", "progressbar")
34        .attr("aria-valuenow", percent.to_string())
35        .attr("aria-valuemin", "0")
36        .attr("aria-valuemax", "100")
37        .child::<Div, _>(|bar| bar.class("progress-bar").attr("style", &width).text(&label))
38}
39
40/// Create a progress bar without label.
41#[must_use]
42pub fn progress_silent(percent: u8) -> Element<Div> {
43    let percent = percent.min(100);
44    let width = format!("width: {percent}%");
45
46    Element::<Div>::new()
47        .class("progress")
48        .attr("role", "progressbar")
49        .attr("aria-valuenow", percent.to_string())
50        .attr("aria-valuemin", "0")
51        .attr("aria-valuemax", "100")
52        .child::<Div, _>(|bar| bar.class("progress-bar").attr("style", &width))
53}
54
55/// Create a colored progress bar.
56#[must_use]
57pub fn progress_colored(percent: u8, color: Color) -> Element<Div> {
58    let percent = percent.min(100);
59    let width = format!("width: {percent}%");
60    let bar_class = format!("progress-bar bg-{}", color.as_str());
61
62    Element::<Div>::new()
63        .class("progress")
64        .attr("role", "progressbar")
65        .attr("aria-valuenow", percent.to_string())
66        .attr("aria-valuemin", "0")
67        .attr("aria-valuemax", "100")
68        .child::<Div, _>(|bar| bar.class(&bar_class).attr("style", &width))
69}
70
71/// Create a striped progress bar.
72#[must_use]
73pub fn progress_striped(percent: u8, color: Color) -> Element<Div> {
74    let percent = percent.min(100);
75    let width = format!("width: {percent}%");
76    let bar_class = format!("progress-bar progress-bar-striped bg-{}", color.as_str());
77
78    Element::<Div>::new()
79        .class("progress")
80        .attr("role", "progressbar")
81        .attr("aria-valuenow", percent.to_string())
82        .attr("aria-valuemin", "0")
83        .attr("aria-valuemax", "100")
84        .child::<Div, _>(|bar| bar.class(&bar_class).attr("style", &width))
85}
86
87/// Create an animated striped progress bar.
88#[must_use]
89pub fn progress_animated(percent: u8, color: Color) -> Element<Div> {
90    let percent = percent.min(100);
91    let width = format!("width: {percent}%");
92    let bar_class = format!(
93        "progress-bar progress-bar-striped progress-bar-animated bg-{}",
94        color.as_str()
95    );
96
97    Element::<Div>::new()
98        .class("progress")
99        .attr("role", "progressbar")
100        .attr("aria-valuenow", percent.to_string())
101        .attr("aria-valuemin", "0")
102        .attr("aria-valuemax", "100")
103        .child::<Div, _>(|bar| bar.class(&bar_class).attr("style", &width))
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn test_progress() {
112        let bar = progress(50);
113        let html = bar.render();
114        assert!(html.contains("progress"));
115        assert!(html.contains("progress-bar"));
116        assert!(html.contains("50%"));
117    }
118
119    #[test]
120    fn test_progress_colored() {
121        let bar = progress_colored(75, Color::Success);
122        assert!(bar.render().contains("bg-success"));
123    }
124
125    #[test]
126    fn test_progress_striped() {
127        let bar = progress_striped(60, Color::Info);
128        assert!(bar.render().contains("progress-bar-striped"));
129    }
130}