use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
text::{Line, Span},
widgets::Paragraph,
Frame,
};
use crate::{block::{focusable_block, render_scrollbar}, Theme};
pub enum KvRow {
Header(String),
Field { key: String, value: String },
Separator,
}
pub fn render_kv_table(
f: &mut Frame,
area: Rect,
title: &str,
shortcut: Option<u8>,
rows: &[KvRow],
scroll: u16,
focused: bool,
theme: &Theme,
) {
let block = focusable_block(title, shortcut, focused, theme);
let inner = block.inner(area);
f.render_widget(block, area);
render_scrollbar(f, area, rows.len(), scroll as usize);
if inner.height == 0 || rows.is_empty() {
return;
}
let max_key_len = rows
.iter()
.filter_map(|r| match r {
KvRow::Field { key, .. } => Some(key.chars().count()),
_ => None,
})
.max()
.unwrap_or(0);
let key_col_width = (max_key_len as u16).min((inner.width as f32 * 0.30) as u16).max(1);
let visible_height = inner.height as usize;
let skip = scroll as usize;
for (i, row) in rows.iter().skip(skip).take(visible_height).enumerate() {
let row_y = inner.y + i as u16;
let row_area = Rect { x: inner.x, y: row_y, width: inner.width, height: 1 };
match row {
KvRow::Header(text) => {
let para = Paragraph::new(Line::from(Span::styled(
text.clone(),
theme.section_header,
)));
f.render_widget(para, row_area);
}
KvRow::Separator => {
}
KvRow::Field { key, value } => {
let val_col_width = inner.width.saturating_sub(key_col_width + 1);
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Length(key_col_width),
Constraint::Length(1), Constraint::Length(val_col_width),
])
.split(row_area);
let key_para = Paragraph::new(Line::from(Span::styled(
key.clone(),
theme.hint,
)))
.alignment(Alignment::Right);
let val_para = Paragraph::new(Line::from(Span::styled(
value.clone(),
theme.body,
)));
f.render_widget(key_para, chunks[0]);
f.render_widget(val_para, chunks[2]);
}
}
}
}