Skip to main content

tui/components/
stepper.rs

1use crate::rendering::line::Line;
2use crate::rendering::render_context::ViewContext;
3use crate::rendering::span::Span;
4use crate::rendering::style::Style;
5
6pub enum StepVisualState {
7    Complete,
8    Current,
9    Upcoming,
10}
11
12pub struct StepperItem<'a> {
13    pub label: &'a str,
14    pub state: StepVisualState,
15}
16
17pub struct Stepper<'a> {
18    pub items: &'a [StepperItem<'a>],
19    pub separator: &'a str,
20    pub leading_padding: usize,
21}
22
23impl Stepper<'_> {
24    pub fn render(&self, ctx: &ViewContext) -> Line {
25        let padding = " ".repeat(self.leading_padding);
26        let mut line = Line::new(padding);
27        for (i, item) in self.items.iter().enumerate() {
28            let (glyph, style) = match item.state {
29                StepVisualState::Complete => ("\u{25cf} ", Style::fg(ctx.theme.text_secondary())),
30                StepVisualState::Current => ("\u{25c9} ", Style::fg(ctx.theme.primary())),
31                StepVisualState::Upcoming => ("\u{25cb} ", Style::fg(ctx.theme.muted())),
32            };
33            line.push_span(Span::with_style(glyph.to_string(), style));
34            line.push_span(Span::with_style(item.label.to_string(), style));
35            if i + 1 < self.items.len() {
36                line.push_span(Span::with_style(self.separator.to_string(), Style::fg(ctx.theme.muted())));
37            }
38        }
39        line
40    }
41}