use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::Paragraph;
use crate::components::panel::{ModalBg, ModalSpec, modal_chrome};
use crate::keys::leader::{LeaderEngine, LeaderNode};
use crate::settings::themes::Theme;
const CELL_WIDTH: u16 = 24;
pub fn desired_height(engine: &LeaderEngine, width: u16) -> u16 {
let n = engine.current_node().children().len() as u16;
let cols = (width.saturating_sub(2) / CELL_WIDTH).max(1);
let grid_rows = n.div_ceil(cols);
grid_rows + 3 }
pub fn render(
f: &mut Frame,
rect: Rect,
theme: &Theme,
engine: &LeaderEngine,
gateway_label: &str,
) {
let inner = modal_chrome(
f,
rect,
theme,
ModalSpec {
border: Some(Style::default().fg(theme.focus_border.to_ratatui())),
bg: ModalBg::Hard,
..Default::default()
},
);
if inner.height == 0 {
return;
}
let node = engine.current_node();
let keycap = Style::default()
.fg(theme.yellow.to_ratatui())
.add_modifier(Modifier::BOLD);
let muted = Style::default().fg(theme.gray.to_ratatui());
let caption_style = Style::default().fg(theme.fg_secondary.to_ratatui());
let mut pressed = format!(" {gateway_label}");
for c in engine.path() {
pressed.push(' ');
pressed.push(*c);
}
let controls = "Esc cancel · BkSp up ";
let controls_w = controls.len() as u16;
let header_cols = ratatui::layout::Layout::default()
.direction(ratatui::layout::Direction::Horizontal)
.constraints([
ratatui::layout::Constraint::Min(0),
ratatui::layout::Constraint::Length(controls_w),
])
.split(Rect::new(inner.x, inner.y, inner.width, 1));
f.render_widget(
Paragraph::new(Line::from(vec![
Span::styled(pressed, keycap),
Span::styled(format!(" {}", node.label()), caption_style),
])),
header_cols[0],
);
f.render_widget(
Paragraph::new(Line::from(Span::styled(controls, muted)))
.alignment(ratatui::layout::Alignment::Right),
header_cols[1],
);
let children = node.children();
if children.is_empty() {
return;
}
let cols = (inner.width / CELL_WIDTH).max(1) as usize;
let rows = children.len().div_ceil(cols);
let arrow = Span::styled(" → ", muted);
for (i, (key, child)) in children.iter().enumerate() {
let col = i / rows;
let row = i % rows;
let y = inner.y + 1 + row as u16;
if y >= inner.bottom() {
continue;
}
let x = inner.x + (col as u16) * CELL_WIDTH;
if x >= inner.right() {
continue;
}
let target_style = match child {
LeaderNode::Group { .. } => Style::default().fg(theme.aqua.to_ratatui()),
LeaderNode::Leaf { .. } => Style::default().fg(theme.fg.to_ratatui()),
};
let cell = Rect::new(x, y, CELL_WIDTH.min(inner.right() - x), 1);
f.render_widget(
Paragraph::new(Line::from(vec![
Span::styled(format!(" {key}"), keycap),
arrow.clone(),
Span::styled(child.label().to_string(), target_style),
])),
cell,
);
}
}