mermaid_cli/render/widgets/
approval.rs1use ratatui::buffer::Buffer;
6use ratatui::layout::Rect;
7use ratatui::style::{Color, Modifier, Style};
8use ratatui::text::{Line, Span};
9use ratatui::widgets::{Block, Borders, Paragraph, Widget};
10
11use crate::render::theme::Theme;
12
13pub struct ApprovalModalWidget<'a> {
14 pub theme: &'a Theme,
15 pub title: String,
16 pub body: &'a str,
18 pub options: Vec<String>,
20 pub selected_index: Option<usize>,
23 pub accent: Color,
25}
26
27impl<'a> Widget for ApprovalModalWidget<'a> {
28 fn render(self, area: Rect, buf: &mut Buffer) {
29 let block = Block::default()
30 .borders(Borders::ALL)
31 .title(self.title)
32 .border_style(Style::default().fg(self.accent));
33
34 let inner_width = area.width.saturating_sub(4).max(8) as usize;
35 let mut lines: Vec<Line<'_>> = Vec::new();
36 for raw in self.body.lines() {
37 lines.push(Line::from(Span::styled(
38 truncate(raw, inner_width),
39 Style::default().fg(Color::White),
40 )));
41 }
42 lines.push(Line::from(""));
43 for (idx, opt) in self.options.iter().enumerate() {
44 let style = if self.selected_index == Some(idx) {
45 Style::default()
47 .fg(self.theme.colors.text_highlight.to_color())
48 .add_modifier(Modifier::BOLD | Modifier::REVERSED)
49 } else {
50 Style::default()
51 .fg(Color::White)
52 .add_modifier(Modifier::BOLD)
53 };
54 lines.push(Line::from(Span::styled(format!(" {}", opt), style)));
55 }
56 Paragraph::new(lines).block(block).render(area, buf);
57 }
58}
59
60fn truncate(s: &str, max: usize) -> String {
61 if s.chars().count() <= max {
62 s.to_string()
63 } else {
64 let cut = s.floor_char_boundary(max);
65 format!("{}…", &s[..cut])
66 }
67}