use crate::git::load::{Commit, FileEntry};
use ratatui::Frame;
use ratatui::layout::{Margin, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, ListItem, Scrollbar, ScrollbarOrientation, ScrollbarState};
pub fn commit_item(c: &Commit, unpushed: bool) -> ListItem<'static> {
let mark = if unpushed {
Span::styled(
"↑ ",
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
)
} else {
Span::raw(" ")
};
ListItem::new(Line::from(vec![
mark,
Span::styled(
format!("{:<8}", c.short),
Style::default().fg(Color::Yellow),
),
Span::styled(format!("{} ", c.date), Style::default().fg(Color::Green)),
Span::styled(
format!("<{}> ", c.committer),
Style::default().fg(Color::Blue),
),
Span::raw(c.subject.clone()),
]))
}
pub fn file_item(f: &FileEntry) -> ListItem<'static> {
let (color, ch) = status_glyph(f.status);
ListItem::new(Line::from(vec![
Span::styled(format!("{ch} "), Style::default().fg(color)),
Span::raw(f.path.clone()),
]))
}
fn status_glyph(status: char) -> (Color, char) {
match status {
'A' => (Color::Green, 'A'),
'M' => (Color::Yellow, 'M'),
'D' => (Color::Red, 'D'),
'R' => (Color::Cyan, 'R'),
c => (Color::Gray, c),
}
}
pub fn pane_block(title: String, active: bool) -> Block<'static> {
let color = if active { Color::Cyan } else { Color::DarkGray };
Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(color))
.title(title)
}
fn render_vscrollbar(frame: &mut Frame, area: Rect, total: usize, top: usize) {
let viewport = area.height.saturating_sub(2) as usize;
if total <= viewport {
return; }
let mut state = ScrollbarState::new(total - viewport).position(top);
let bar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(None)
.end_symbol(None);
frame.render_stateful_widget(bar, area.inner(Margin::new(0, 1)), &mut state);
}
pub fn diff_scrollbar(frame: &mut Frame, area: Rect, total_lines: usize, scroll: u16) {
render_vscrollbar(frame, area, total_lines, scroll as usize);
}
pub fn list_scrollbar(frame: &mut Frame, area: Rect, total: usize, offset: usize) {
render_vscrollbar(frame, area, total, offset);
}
pub fn diff_hscrollbar(frame: &mut Frame, area: Rect, max_line: usize, cell_w: u16, hscroll: u16) {
let cell = cell_w as usize;
if max_line <= cell {
return;
}
let mut state = ScrollbarState::new(max_line - cell).position(hscroll as usize);
let bar = Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
.begin_symbol(None)
.end_symbol(None)
.thumb_symbol("■");
frame.render_stateful_widget(bar, area.inner(Margin::new(1, 0)), &mut state);
}