use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, List, ListItem};
use ratatui::Frame;
use gitkraft_core::Rgb;
use super::palette::{picker_name, PICKER_LEN};
use crate::app::App;
fn rgb_to_color(rgb: Rgb) -> Color {
Color::Rgb(rgb.r, rgb.g, rgb.b)
}
fn accent_color_for_row(row: usize) -> Color {
let index = if row == 0 {
gitkraft_core::current_system_theme_index()
} else {
row - 1
};
rgb_to_color(gitkraft_core::theme_by_index(index).accent)
}
pub fn render(app: &mut App, frame: &mut Frame, area: Rect) {
let theme = app.theme();
let current = app.picker_index();
let items: Vec<ListItem> = (0..PICKER_LEN)
.map(|i| {
let name = picker_name(i);
let number = format!("{:>2}. ", i);
let color = accent_color_for_row(i);
if i == current {
let line = Line::from(vec![
Span::styled(
"← ",
Style::default()
.fg(theme.warning)
.bg(theme.sel_bg)
.add_modifier(Modifier::BOLD),
),
Span::styled(
number,
Style::default()
.fg(theme.text_primary)
.bg(theme.sel_bg)
.add_modifier(Modifier::BOLD),
),
Span::styled(
name.to_string(),
Style::default()
.fg(color)
.bg(theme.sel_bg)
.add_modifier(Modifier::BOLD),
),
]);
ListItem::new(line)
} else {
let line = Line::from(vec![
Span::styled(" ", Style::default().fg(theme.text_muted)),
Span::styled(number, Style::default().fg(theme.text_muted)),
Span::styled(name.to_string(), Style::default().fg(color)),
]);
ListItem::new(line)
}
})
.collect();
let block = Block::default()
.title(" Themes ↑/k prev ↓/j/t next Enter/Esc close ")
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.border_active))
.style(Style::default().bg(theme.bg));
let highlight_style = Style::default()
.bg(theme.sel_bg)
.add_modifier(Modifier::BOLD);
let list = List::new(items)
.block(block)
.highlight_style(highlight_style);
let mut state = app.theme_list_state;
frame.render_stateful_widget(list, area, &mut state);
app.theme_list_state = state;
}
#[cfg(test)]
mod tests {
use super::*;
use ratatui::backend::TestBackend;
use ratatui::Terminal;
fn draw(app: &mut App) -> String {
let mut term = Terminal::new(TestBackend::new(60, 52)).unwrap();
term.draw(|f| render(app, f, f.area())).unwrap();
let buf = term.backend().buffer().clone();
buf.content().iter().map(|c| c.symbol()).collect::<String>()
}
#[test]
fn picker_renders_system_and_presets() {
let mut app = App::new();
app.set_follow_system();
let out = draw(&mut app);
assert!(out.contains("System"));
assert!(out.contains("Default"));
assert!(out.contains("←"));
}
#[test]
fn picker_marks_selected_preset() {
let mut app = App::new();
app.set_theme(9);
let out = draw(&mut app);
assert!(out.contains("Dracula"));
assert_eq!(app.theme_list_state.selected(), Some(10));
}
}