use ratatui::{
buffer::Buffer,
layout::{Constraint, Direction, Layout, Margin, Rect},
prelude::StatefulWidget,
text::{Line, Span},
widgets::{Block, BorderType, Borders, Clear, Paragraph, Row, Table, TableState, Widget},
};
use crate::{
domain::{parse_row, Project},
theme::theme,
ui::widget::Shortcuts,
};
pub struct ProjectsTable<'a> {
rows: Vec<Row<'a>>,
filter_active: bool,
filter_text: &'a str,
}
impl<'a> ProjectsTable<'a> {
pub fn new(projects: &'a [Project], filter_active: bool, filter_text: &'a str) -> Self {
Self {
rows: projects
.iter()
.map(|proj| parse_row(proj))
.enumerate()
.map(|(idx, r)| r.style(theme().table_row(idx)))
.collect(),
filter_active,
filter_text,
}
}
}
impl StatefulWidget for ProjectsTable<'_> {
type State = TableState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
Clear.render(area, buf);
let shortcuts = if self.filter_active {
Shortcuts::from(vec![("↵", "finish filter"), ("esc", "cancel")])
} else {
Shortcuts::from(vec![
("q", "quit"),
("w", "open web"),
("c", "config"),
("a", "last notification"),
("f/", "filter"),
("r", "refresh"),
("p", "pipeline refresh"),
("↑↓", "selection"),
("↵", "details"),
])
};
let (table_area, filter_area) = if self.filter_active {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Min(3), Constraint::Length(3), ])
.split(area);
(chunks[0], Some(chunks[1]))
} else {
(area, None)
};
Block::new()
.title(" gitlab pipelines ")
.title_style(theme().border_title)
.title_bottom(shortcuts.as_line())
.borders(if self.filter_active {
Borders::TOP | Borders::LEFT | Borders::RIGHT
} else {
Borders::ALL
})
.border_style(theme().table_border)
.style(theme().background)
.border_type(BorderType::Plain)
.render(table_area, buf);
let content_area = table_area.inner(Margin::new(2, 1));
let table = Table::new(self.rows, PROJECT_COLUMN_CONSTRAINTS)
.row_highlight_style(theme().highlight_symbol)
.column_spacing(1);
StatefulWidget::render(table, content_area, buf, state);
if let Some(filter_area) = filter_area {
let filter_content = Line::from(vec![
Span::from("Filter: "),
Span::from(self.filter_text).style(theme().highlight_symbol),
Span::from("█"), ]);
let filter_block = Block::new()
.borders(Borders::ALL)
.border_style(theme().table_border)
.style(theme().background);
Paragraph::new(filter_content)
.block(filter_block)
.render(filter_area, buf);
}
}
}
const PROJECT_COLUMN_CONSTRAINTS: [Constraint; 3] = [
Constraint::Length(16), Constraint::Min(40), Constraint::Percentage(100), ];