use ratatui::{
Frame,
layout::{Constraint, Flex, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Clear, Paragraph},
};
use crate::app::ConfigPopupState;
use crate::theme::{Palette, Theme};
const ACTIVE_BULLET: &str = "●";
const INACTIVE_BULLET: &str = "○";
pub fn render_config_popup(
f: &mut Frame,
state: &ConfigPopupState,
theme: Theme,
show_line_numbers: bool,
palette: &Palette,
) {
let area = centered_rect(46, 15, f.area());
f.render_widget(Clear, area);
let lines = build_lines(state, theme, show_line_numbers, palette);
let block = Block::default()
.title(" Settings ")
.title_style(palette.title_style())
.borders(Borders::ALL)
.border_style(Style::new().fg(palette.border_focused));
f.render_widget(Paragraph::new(lines).block(block), area);
}
fn build_lines<'a>(
state: &ConfigPopupState,
theme: Theme,
show_line_numbers: bool,
palette: &Palette,
) -> Vec<Line<'a>> {
let section_style = Style::new()
.fg(palette.accent_alt)
.add_modifier(Modifier::BOLD);
let text_style = Style::new().fg(palette.foreground);
let cursor_style = Style::new().fg(palette.accent).add_modifier(Modifier::BOLD);
let dim_style = palette.dim_style();
let active_style = Style::new()
.fg(palette.accent_alt)
.add_modifier(Modifier::BOLD);
let mut lines: Vec<Line> = Vec::new();
lines.push(Line::from(""));
let mut row = 0usize;
lines.push(Line::from(vec![
Span::styled(" ", text_style),
Span::styled(ConfigPopupState::SECTIONS[0].0, section_style),
]));
for &t in Theme::ALL {
lines.push(option_line(
row == state.cursor,
t == theme,
t.label(),
cursor_style,
active_style,
text_style,
dim_style,
));
row += 1;
}
lines.push(Line::from(""));
lines.push(Line::from(vec![
Span::styled(" ", text_style),
Span::styled(ConfigPopupState::SECTIONS[1].0, section_style),
]));
lines.push(option_line(
row == state.cursor,
show_line_numbers,
"Show line numbers",
cursor_style,
active_style,
text_style,
dim_style,
));
row += 1;
let _ = row;
lines.push(Line::from(""));
lines.push(Line::from(vec![
Span::styled(" ", text_style),
Span::styled("↑↓ / j k", cursor_style),
Span::styled(" Navigate ", dim_style),
Span::styled("Enter", cursor_style),
Span::styled(" Apply ", dim_style),
Span::styled("Esc/c", cursor_style),
Span::styled(" Close", dim_style),
]));
lines
}
fn option_line<'a>(
is_cursor: bool,
is_active: bool,
label: &'a str,
cursor_style: Style,
active_style: Style,
text_style: Style,
dim_style: Style,
) -> Line<'a> {
let arrow = if is_cursor { "> " } else { " " };
let bullet = if is_active {
ACTIVE_BULLET
} else {
INACTIVE_BULLET
};
let bullet_style = if is_active { active_style } else { dim_style };
let label_style = if is_cursor {
cursor_style
} else {
Style::new().fg(Color::White)
};
Line::from(vec![
Span::styled(" ", text_style),
Span::styled(arrow, cursor_style),
Span::styled(bullet, bullet_style),
Span::styled(" ", text_style),
Span::styled(label, label_style),
])
}
fn centered_rect(width: u16, height: u16, area: Rect) -> Rect {
let vertical = Layout::vertical([Constraint::Length(height)])
.flex(Flex::Center)
.split(area);
Layout::horizontal([Constraint::Length(width)])
.flex(Flex::Center)
.split(vertical[0])[0]
}