mermaid_cli/render/widgets/
attachment.rs1use ratatui::{
7 buffer::Buffer,
8 layout::Rect,
9 style::{Modifier, Style},
10 text::{Line, Span},
11 widgets::Widget,
12};
13
14use crate::domain::Attachment;
15use crate::render::theme::Theme;
16
17pub struct AttachmentWidget<'a> {
19 pub attachments: &'a [Attachment],
20 pub theme: &'a Theme,
21 pub focused: bool,
23 pub selected: usize,
25}
26
27impl<'a> Widget for AttachmentWidget<'a> {
28 fn render(self, area: Rect, buf: &mut Buffer) {
29 if self.attachments.is_empty() || area.height == 0 {
30 return;
31 }
32
33 let hint_style = Style::new().fg(self.theme.colors.text_secondary.to_color());
34
35 let mut spans = vec![Span::raw(" ")];
37
38 for (i, attachment) in self.attachments.iter().enumerate() {
39 let is_selected = self.focused && i == self.selected;
40 let size_display = format_size(attachment.size_bytes);
41
42 let label_style = if is_selected {
43 Style::new()
44 .fg(self.theme.colors.background.to_color())
45 .bg(self.theme.colors.info.to_color())
46 .add_modifier(Modifier::BOLD)
47 } else {
48 Style::new()
49 .fg(self.theme.colors.info.to_color())
50 .add_modifier(Modifier::BOLD)
51 };
52
53 spans.push(Span::styled(format!("[Image #{}]", i + 1), label_style));
54 spans.push(Span::styled(
55 format!(
56 " ({}, {}) ",
57 attachment.format.to_uppercase(),
58 size_display
59 ),
60 hint_style,
61 ));
62 }
63
64 if self.focused {
66 spans.push(Span::styled(
67 "→ to next · ← to prev · Delete to remove · Esc to cancel",
68 hint_style,
69 ));
70 } else {
71 spans.push(Span::styled("(↑ to select)", hint_style));
72 }
73
74 let line = Line::from(spans);
75 buf.set_line(area.x, area.y, &line, area.width);
76 }
77}
78
79fn format_size(bytes: usize) -> String {
80 if bytes < 1024 {
81 format!("{}B", bytes)
82 } else if bytes < 1024 * 1024 {
83 format!("{:.0}KB", bytes as f64 / 1024.0)
84 } else {
85 format!("{:.1}MB", bytes as f64 / (1024.0 * 1024.0))
86 }
87}