Skip to main content

dioxus_bootstrap_css/
progress.rs

1use dioxus::prelude::*;
2
3use crate::types::Color;
4
5/// Bootstrap Progress container.
6///
7/// # Bootstrap HTML → Dioxus
8///
9/// ```html
10/// <!-- Bootstrap HTML -->
11/// <div class="progress">
12///   <div class="progress-bar bg-success" style="width: 75%">75%</div>
13/// </div>
14/// <!-- Stacked bars -->
15/// <div class="progress">
16///   <div class="progress-bar" style="width: 30%"></div>
17///   <div class="progress-bar bg-warning" style="width: 20%"></div>
18/// </div>
19/// ```
20///
21/// ```rust,no_run
22/// rsx! {
23///     Progress {
24///         ProgressBar { value: 75.0, color: Color::Success, show_label: true }
25///     }
26///     // Stacked bars
27///     Progress {
28///         ProgressBar { value: 30.0, color: Color::Primary }
29///         ProgressBar { value: 20.0, color: Color::Warning }
30///     }
31///     // Striped animated
32///     Progress {
33///         ProgressBar { value: 50.0, striped: true, animated: true }
34///     }
35/// }
36/// ```
37#[derive(Clone, PartialEq, Props)]
38pub struct ProgressProps {
39    /// Additional CSS classes.
40    #[props(default)]
41    pub class: String,
42    /// Child elements (ProgressBar components).
43    pub children: Element,
44}
45
46#[component]
47pub fn Progress(props: ProgressProps) -> Element {
48    let full_class = if props.class.is_empty() {
49        "progress".to_string()
50    } else {
51        format!("progress {}", props.class)
52    };
53
54    rsx! {
55        div { class: "{full_class}", {props.children} }
56    }
57}
58
59/// Bootstrap ProgressBar component (goes inside Progress).
60#[derive(Clone, PartialEq, Props)]
61pub struct ProgressBarProps {
62    /// Progress value (0.0 to 100.0).
63    #[props(default)]
64    pub value: f64,
65    /// Bar color.
66    #[props(default)]
67    pub color: Option<Color>,
68    /// Show striped pattern.
69    #[props(default)]
70    pub striped: bool,
71    /// Animate the stripes.
72    #[props(default)]
73    pub animated: bool,
74    /// Show the value as text inside the bar.
75    #[props(default)]
76    pub show_label: bool,
77    /// Additional CSS classes.
78    #[props(default)]
79    pub class: String,
80}
81
82#[component]
83pub fn ProgressBar(props: ProgressBarProps) -> Element {
84    let color_class = match &props.color {
85        Some(c) => format!(" bg-{c}"),
86        None => String::new(),
87    };
88    let striped = if props.striped || props.animated {
89        " progress-bar-striped"
90    } else {
91        ""
92    };
93    let animated = if props.animated {
94        " progress-bar-animated"
95    } else {
96        ""
97    };
98
99    let full_class = if props.class.is_empty() {
100        format!("progress-bar{color_class}{striped}{animated}")
101    } else {
102        format!(
103            "progress-bar{color_class}{striped}{animated} {}",
104            props.class
105        )
106    };
107
108    let width = format!("width: {}%", props.value);
109    let label = if props.show_label {
110        format!("{}%", props.value as u32)
111    } else {
112        String::new()
113    };
114
115    rsx! {
116        div {
117            class: "{full_class}",
118            role: "progressbar",
119            style: "{width}",
120            "aria-valuenow": "{props.value}",
121            "aria-valuemin": "0",
122            "aria-valuemax": "100",
123            "{label}"
124        }
125    }
126}