use crate::app::{App, Mode}; use crate::config::Config; use ratatui::{ layout::{Constraint, Direction, Layout}, style::{Modifier, Style}, text::{Line, Span}, widgets::{Block, BorderType, Borders, List, ListItem, ListState, Paragraph}, Frame, }; pub fn draw(f: &mut Frame, app: &mut App, config: &Config) { let theme = &config.theme; let size = f.area(); // Background if !theme.transparent { f.render_widget(Block::default().style(Style::default().bg(theme.crust())), size); } // Main layout with horizontal padding let outer_layout = Layout::default() .direction(Direction::Horizontal) .constraints([ Constraint::Length(1), // Left padding Constraint::Min(0), // Content Constraint::Length(1), // Right padding ]) .split(size); let chunks = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length(1), // Top padding Constraint::Min(3), // List Constraint::Length(3), // Input area Constraint::Length(1), // Bottom padding Constraint::Length(1), // Status bar ]) .split(outer_layout[1]); let max_key_len = app .vars .iter() .map(|v| v.key.len()) .max() .unwrap_or(20) .min(40); // List let items: Vec = app .vars .iter() .enumerate() .map(|(i, var)| { let is_selected = i == app.selected; let val = if is_selected && matches!(app.mode, Mode::Insert) { app.input.value() } else { &var.value }; let key_style = if is_selected { Style::default().fg(theme.crust()).add_modifier(Modifier::BOLD) } else { Style::default().fg(theme.lavender()) }; let value_style = if is_selected { Style::default().fg(theme.crust()) } else { Style::default().fg(theme.text()) }; let line = Line::from(vec![ Span::styled(format!(" {: theme.green(), Mode::Normal => theme.surface1(), }; let input_text = app.input.value(); let cursor_pos = app.input.visual_cursor(); let input = Paragraph::new(input_text) .style(Style::default().fg(theme.text())) .block( Block::default() .borders(Borders::ALL) .border_type(BorderType::Rounded) .title(input_title) .title_style(Style::default().fg(theme.peach()).add_modifier(Modifier::BOLD)) .border_style(Style::default().fg(input_border_color)), ); f.render_widget(input, chunks[2]); if let Mode::Insert = app.mode { f.set_cursor_position(ratatui::layout::Position::new( chunks[2].x + 1 + cursor_pos as u16, chunks[2].y + 1, )); } // Status bar let (mode_str, mode_style) = match app.mode { Mode::Normal => ( " NORMAL ", Style::default() .bg(theme.blue()) .fg(theme.crust()) .add_modifier(Modifier::BOLD), ), Mode::Insert => ( " INSERT ", Style::default() .bg(theme.green()) .fg(theme.crust()) .add_modifier(Modifier::BOLD), ), }; let status_msg = app.status_message.as_deref().unwrap_or_else(|| { match app.mode { Mode::Normal => " navigation | i: edit | :w: save | :q: quit ", Mode::Insert => " Esc: back to normal | Enter: commit ", } }); let status_line = Line::from(vec![ Span::styled(mode_str, mode_style), Span::styled(format!(" {} ", status_msg), Style::default().bg(theme.surface0()).fg(theme.text())), ]); let status = Paragraph::new(status_line).style(Style::default().bg(theme.surface0())); f.render_widget(status, chunks[4]); }