// Stepper Component - Multi-step progress indicator
use super::traits::Renderable
pub struct StepperStep {
label: string,
description: string,
completed: bool,
}
impl StepperStep {
pub fn new(label: string) -> StepperStep {
StepperStep {
label: label,
description: String::new(),
completed: false,
}
}
pub fn description(self, desc: string) -> StepperStep {
self.description = desc;
self
}
pub fn completed(self, completed: bool) -> StepperStep {
self.completed = completed;
self
}
}
pub struct Stepper {
steps: Vec<StepperStep>,
current_step: i32,
}
impl Stepper {
pub fn new() -> Stepper {
Stepper {
steps: Vec::new(),
current_step: 0,
}
}
pub fn step(self, step: StepperStep) -> Stepper {
self.steps.push(step);
self
}
pub fn current_step(self, index: i32) -> Stepper {
self.current_step = index;
self
}
}
impl Renderable for Stepper {
fn render(self) -> string {
let mut html = String::new();
html.push_str("<div style='display: flex; align-items: center; justify-content: space-between; padding: 24px 0;'>");
let total_steps = self.steps.len() as i32;
for (step_index, step) in self.steps.iter().enumerate() {
let step_index = step_index as i32;
let is_current = step_index == self.current_step;
let is_completed = step.completed || step_index < self.current_step;
// Step circle
html.push_str("<div style='display: flex; flex-direction: column; align-items: center; flex: 1;'>");
// Circle
let bg_color = if is_completed {
"#10b981"
} else if is_current {
"#3b82f6"
} else {
"#e2e8f0"
};
let text_color = if is_completed || is_current {
"white"
} else {
"#718096"
};
html.push_str("<div style='width: 40px; height: 40px; border-radius: 50%; background: ");
html.push_str(bg_color);
html.push_str("; color: ");
html.push_str(text_color);
html.push_str("; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 16px; margin-bottom: 8px;'>");
if is_completed {
html.push('✓');
} else {
html.push_str(&format!("{}", step_index + 1));
}
html.push_str("</div>");
// Label
html.push_str("<div style='text-align: center;'>");
html.push_str("<div style='font-weight: 600; font-size: 14px; color: ");
if is_current {
html.push_str("#1a202c");
} else {
html.push_str("#718096");
}
html.push_str("; margin-bottom: 4px;'>");
html.push_str(&step.label);
html.push_str("</div>");
if step.description.len() > 0 {
html.push_str("<div style='font-size: 12px; color: #a0aec0;'>");
html.push_str(&step.description);
html.push_str("</div>");
}
html.push_str("</div>");
html.push_str("</div>");
// Connector line (except for last step)
if step_index < total_steps - 1 {
let line_color = if is_completed {
"#10b981"
} else {
"#e2e8f0"
};
html.push_str("<div style='flex: 1; height: 2px; background: ");
html.push_str(line_color);
html.push_str("; margin: 0 8px; margin-bottom: 48px;'></div>");
}
}
html.push_str("</div>");
html
}
}