Skip to main content

prompt_readme/
prompt-readme.rs

1//! The input hero collage for the README, mirroring the C sparcli demo in a
2//! slim form: a titled hero panel and a balanced multi-column dashboard of
3//! statically rendered prompt frames (no boxes/hints, default theme).
4//!
5//! `cargo run --example prompt-readme`
6//!
7//! Each prompt's frame is produced by its `frame()` method (no TTY, no
8//! interaction); columns are stacked with `vstack` and joined with `Columns`.
9//! The fuzzy column is composed directly so the example needs no extra
10//! features.
11
12use sparcli::prelude::*;
13use sparcli::{
14    Columns, Confirm, Date, DatePicker, NumberInput, Panel, PasswordInput,
15    Select, TextInput, Textarea,
16};
17
18fn main() -> Result<()> {
19    println!();
20    let board = dashboard();
21    hero(board.width() as u16)?;
22    println!();
23    board.print()?;
24    Ok(())
25}
26
27/// A blank one-line spacer for `vstack`.
28fn blank() -> Rendered {
29    Rendered::new(vec![Line::default()])
30}
31
32/// The top hero panel, sized to match the dashboard width.
33fn hero(width: u16) -> Result<()> {
34    let theme = theme();
35    let body = Text::new(vec![
36        Line::raw("Interactive prompts - confirm · select · text · password ·"),
37        Line::raw("number · textarea · fuzzy · date."),
38    ]);
39    Panel::new(body)
40        .border(BorderType::Rounded)
41        .border_style(Style::new().fg(theme.accent))
42        .title(
43            Title::new(" sparcli · input widgets ")
44                .align(Align::Center)
45                .style(theme.title),
46        )
47        .content_align(Align::Center)
48        .width(width)
49        .print()
50}
51
52/// The balanced three-column dashboard of prompt frames.
53fn dashboard() -> Rendered {
54    Columns::new()
55        .add_rendered(left_column())
56        .add_rendered(middle_column())
57        .add_rendered(calendar_column())
58        .gap(3)
59        .separator(BorderType::Single)
60        .render(0)
61}
62
63/// Left column: the confirm prompt with the input fields stacked beneath it,
64/// then the notes textarea.
65fn left_column() -> Rendered {
66    vstack(
67        &[
68            Confirm::new("Deploy to production?").default_yes().frame(),
69            blank(),
70            TextInput::new("Service").initial("api-gateway").frame(),
71            PasswordInput::new("Password").initial("hunter2").frame(),
72            NumberInput::new("Replicas")
73                .initial(3.0)
74                .range(1.0, 10.0)
75                .frame(),
76            TextInput::new("Email")
77                .placeholder("you@example.com")
78                .frame(),
79            TextInput::new("Region")
80                .initial("eu-")
81                .suggestions(["eu-central-1"])
82                .frame(),
83            blank(),
84            Textarea::new("Notes")
85                .initial("first line\nsecond line\nthird line")
86                .frame(),
87        ],
88        0,
89    )
90}
91
92/// Middle column: the single- and multi-select prompts.
93fn middle_column() -> Rendered {
94    vstack(
95        &[
96            Select::new("Environment")
97                .options(["staging", "production", "local"])
98                .cursor(1)
99                .frame(),
100            blank(),
101            Select::new("Targets")
102                .multi()
103                .options(["web", "api", "worker", "db"])
104                .checked([0, 2])
105                .frame(),
106        ],
107        0,
108    )
109}
110
111/// Right column: the date picker with the fuzzy finder beneath it.
112fn calendar_column() -> Rendered {
113    let date = DatePicker::new("Release date")
114        .initial(Date::new(2026, 5, 15))
115        .frame();
116    vstack(&[date, blank(), fuzzy_block()], 0)
117}
118
119/// A composed snapshot of an inline fuzzy finder (no `fuzzy` feature needed
120/// for this static screenshot).
121fn fuzzy_block() -> Rendered {
122    let theme = theme();
123    Rendered::new(vec![
124        Line::new(vec![
125            Span::styled("Language ".to_string(), theme.title),
126            Span::raw("ru"),
127            Span::styled(" ".to_string(), theme.cursor),
128        ]),
129        Line::new(vec![
130            Span::styled("‣ ".to_string(), theme.selection),
131            Span::styled("Rust".to_string(), theme.selection),
132        ]),
133    ])
134}