1use ratatui::{
2 layout::{Alignment, Constraint, Direction, Layout, Rect},
3 text::{Line, Span},
4 widgets::Paragraph,
5 Frame,
6};
7
8use crate::{block::{focusable_block, render_scrollbar}, Theme};
9
10pub enum KvRow {
12 Header(String),
14 Field { key: String, value: String },
16 Separator,
18}
19
20pub fn render_kv_table(
29 f: &mut Frame,
30 area: Rect,
31 title: &str,
32 shortcut: Option<u8>,
33 rows: &[KvRow],
34 scroll: u16,
35 focused: bool,
36 theme: &Theme,
37) {
38 let block = focusable_block(title, shortcut, focused, theme);
39 let inner = block.inner(area);
40 f.render_widget(block, area);
41 render_scrollbar(f, area, rows.len(), scroll as usize);
42
43 if inner.height == 0 || rows.is_empty() {
44 return;
45 }
46
47 let max_key_len = rows
49 .iter()
50 .filter_map(|r| match r {
51 KvRow::Field { key, .. } => Some(key.chars().count()),
52 _ => None,
53 })
54 .max()
55 .unwrap_or(0);
56 let key_col_width = (max_key_len as u16).min((inner.width as f32 * 0.30) as u16).max(1);
57
58 let visible_height = inner.height as usize;
59 let skip = scroll as usize;
60
61 for (i, row) in rows.iter().skip(skip).take(visible_height).enumerate() {
62 let row_y = inner.y + i as u16;
63 let row_area = Rect { x: inner.x, y: row_y, width: inner.width, height: 1 };
64
65 match row {
66 KvRow::Header(text) => {
67 let para = Paragraph::new(Line::from(Span::styled(
68 text.clone(),
69 theme.section_header,
70 )));
71 f.render_widget(para, row_area);
72 }
73 KvRow::Separator => {
74 }
76 KvRow::Field { key, value } => {
77 let val_col_width = inner.width.saturating_sub(key_col_width + 1); let chunks = Layout::default()
80 .direction(Direction::Horizontal)
81 .constraints([
82 Constraint::Length(key_col_width),
83 Constraint::Length(1), Constraint::Length(val_col_width),
85 ])
86 .split(row_area);
87
88 let key_para = Paragraph::new(Line::from(Span::styled(
89 key.clone(),
90 theme.hint,
91 )))
92 .alignment(Alignment::Right);
93
94 let val_para = Paragraph::new(Line::from(Span::styled(
95 value.clone(),
96 theme.body,
97 )));
98
99 f.render_widget(key_para, chunks[0]);
100 f.render_widget(val_para, chunks[2]);
101 }
102 }
103 }
104}