shuire 0.1.1

Vim-like TUI git diff viewer
use ratatui::{
    Frame,
    layout::{Constraint, Direction, Layout},
    style::{Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Clear, List, ListItem, ListState, Paragraph},
};

use crate::{state::App, theme::Theme, ui::centered_rect};

pub fn render(f: &mut Frame, app: &App, theme: &Theme) {
    let area = centered_rect(70, 70, f.area());
    f.render_widget(Clear, area);

    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([Constraint::Length(3), Constraint::Min(1)])
        .split(area);

    let filter_block = Block::default()
        .borders(Borders::ALL)
        .title(Span::styled(
            " Revision selector (Enter=apply, Esc=cancel) ",
            Style::default()
                .fg(theme.bg)
                .bg(theme.shuire)
                .add_modifier(Modifier::BOLD),
        ))
        .border_style(Style::default().fg(theme.shuire).bg(theme.bg_alt))
        .style(Style::default().bg(theme.bg_alt));
    let filter_line = Line::from(vec![
        Span::styled(" /", Style::default().fg(theme.dialog_border)),
        Span::styled(app.input.clone(), Style::default().fg(theme.dialog_body_fg)),
        Span::styled("", Style::default().fg(theme.caret_bg)),
    ]);
    f.render_widget(Paragraph::new(filter_line).block(filter_block), chunks[0]);

    let filtered = app.filtered_revisions();
    let items: Vec<ListItem> = filtered
        .iter()
        .map(|&i| {
            let entry = &app.revisions[i];
            let (refname, summary) = match entry.split_once('\t') {
                Some((a, b)) => (a, b),
                None => (entry.as_str(), ""),
            };
            ListItem::new(Line::from(vec![
                Span::styled(
                    format!(" {:<24} ", refname),
                    Style::default()
                        .fg(theme.dialog_location_fg)
                        .add_modifier(Modifier::BOLD),
                ),
                Span::styled(
                    summary.to_string(),
                    Style::default().fg(theme.dialog_body_fg),
                ),
            ]))
        })
        .collect();

    let list_block = Block::default()
        .borders(Borders::ALL)
        .title(format!(" {} refs ", filtered.len()))
        .border_style(Style::default().fg(theme.shuire).bg(theme.bg_alt))
        .style(Style::default().bg(theme.bg_alt));
    let list = List::new(items).block(list_block).highlight_style(
        Style::default()
            .bg(theme.cursor_bg)
            .add_modifier(Modifier::BOLD),
    );

    let mut state = ListState::default();
    if !filtered.is_empty() {
        state.select(Some(app.revision_cursor.min(filtered.len() - 1)));
    }
    f.render_stateful_widget(list, chunks[1], &mut state);
}