diff --git a/radicle-tui/src/app/page.rs b/radicle-tui/src/app/page.rs index cd130ded..77f67141 100644 --- a/radicle-tui/src/app/page.rs +++ b/radicle-tui/src/app/page.rs @@ -81,7 +81,7 @@ impl ViewPage for Home { fn view(&mut self, app: &mut Application, frame: &mut Frame) { let area = frame.size(); - let navigation_h = 2u16; + let navigation_h = 1u16; let layout = layout::default_page(area, navigation_h); app.view(&Cid::Home(HomeCid::Navigation), frame, layout[0]); diff --git a/radicle-tui/src/ui/cob/patch.rs b/radicle-tui/src/ui/cob/patch.rs index c949c60b..6a174be7 100644 --- a/radicle-tui/src/ui/cob/patch.rs +++ b/radicle-tui/src/ui/cob/patch.rs @@ -69,15 +69,15 @@ impl List for (PatchId, Patch) { let author = format_author(patch, profile); let author = TextSpan::from(author).fg(theme.colors.browser_patch_list_author); - let tags = format_tags(patch); - let tags = TextSpan::from(tags).fg(theme.colors.browser_patch_list_tags); + let timestamp = format_timestamp(patch); + let timestamp = TextSpan::from(timestamp).fg(theme.colors.browser_patch_list_timestamp); let comments = format_comments(patch); let comments = TextSpan::from(comments).fg(theme.colors.browser_patch_list_comments); - let timestamp = format_timestamp(patch); - let timestamp = TextSpan::from(timestamp).fg(theme.colors.browser_patch_list_timestamp); + let tags = format_tags(patch); + let tags = TextSpan::from(tags).fg(theme.colors.browser_patch_list_tags); - vec![status, title, author, tags, comments, timestamp] + vec![status, title, author, timestamp, comments, tags] } } diff --git a/radicle-tui/src/ui/components/common/list.rs b/radicle-tui/src/ui/components/common/list.rs index 04064b7f..54ccc48a 100644 --- a/radicle-tui/src/ui/components/common/list.rs +++ b/radicle-tui/src/ui/components/common/list.rs @@ -1,10 +1,11 @@ use radicle::Profile; -use tuirealm::command::{Cmd, CmdResult, Direction}; +use tuirealm::command::{Cmd, CmdResult}; use tuirealm::props::{ - AttrValue, Attribute, Color, PropPayload, PropValue, Props, Style, TextModifiers, TextSpan, + AttrValue, Attribute, BorderSides, BorderType, Color, PropPayload, PropValue, Props, Style, + TextSpan, }; -use tuirealm::tui::layout::{Constraint, Rect}; -use tuirealm::tui::widgets::{Cell, Row, TableState}; +use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect}; +use tuirealm::tui::widgets::{Block, Cell, Row, TableState}; use tuirealm::{Frame, MockComponent, State, StateValue}; use crate::ui::components::common::label::Label; @@ -12,6 +13,8 @@ use crate::ui::layout; use crate::ui::theme::Theme; use crate::ui::widget::{Widget, WidgetComponent}; +use super::container::Header; + pub trait List { fn row(&self, theme: &Theme, profile: &Profile) -> Vec; } @@ -105,18 +108,17 @@ impl WidgetComponent for PropertyList { } pub struct Table { + header: Widget
, state: TableState, } -impl Default for Table { - fn default() -> Self { +impl Table { + pub fn new(header: Widget
) -> Self { let mut state = TableState::default(); state.select(Some(0)); - Self { state } + Self { header, state } } -} -impl Table { fn select_previous(&mut self) { let index = match self.state.selected() { Some(selected) if selected == 0 => 0, @@ -135,18 +137,6 @@ impl Table { self.state.select(Some(index)); } - fn header<'a>(spans: Vec) -> Row<'a> { - Row::new( - spans - .iter() - .map(|span| { - Cell::from(span.clone().unwrap_text_span().content) - .style(Style::default().add_modifier(TextModifiers::BOLD)) - }) - .collect::>(), - ) - } - fn rows<'a>(spans: Vec>) -> Vec> { spans .iter() @@ -173,19 +163,9 @@ impl WidgetComponent for Table { let content = properties .get_or(Attribute::Content, AttrValue::Table(vec![])) .unwrap_table(); - let background = properties - .get_or(Attribute::Background, AttrValue::Color(Color::Reset)) - .unwrap_color(); let highlight = properties .get_or(Attribute::HighlightedColor, AttrValue::Color(Color::Reset)) .unwrap_color(); - let header = properties - .get_or( - Attribute::Custom("header"), - AttrValue::Payload(PropPayload::Vec(vec![])), - ) - .unwrap_payload() - .unwrap_vec(); let widths = properties .get_or( Attribute::Custom("widths"), @@ -194,18 +174,27 @@ impl WidgetComponent for Table { .unwrap_payload() .unwrap_vec(); - let header = Self::header(header); + let layout = Layout::default() + .direction(Direction::Vertical) + .constraints(vec![Constraint::Length(3), Constraint::Min(1)]) + .split(area); + let rows = Self::rows(content); let widths = Self::widths(widths); - let table = tuirealm::tui::widgets::Table::new(rows) + let rows = tuirealm::tui::widgets::Table::new(rows) + .block( + Block::default() + .borders(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT) + .border_style(Style::default().fg(Color::Rgb(48, 48, 48))) + .border_type(BorderType::Rounded), + ) .highlight_style(Style::default().bg(highlight)) - .style(Style::default().bg(background)) .column_spacing(3u16) - .header(header) .widths(&widths); - frame.render_stateful_widget(table, area, &mut self.state); + self.header.view(frame, layout[0]); + frame.render_stateful_widget(rows, layout[1], &mut self.state); } fn state(&self) -> State { @@ -213,6 +202,8 @@ impl WidgetComponent for Table { } fn perform(&mut self, properties: &Props, cmd: Cmd) -> CmdResult { + use tuirealm::command::Direction; + let content = properties .get_or(Attribute::Content, AttrValue::Table(vec![])) .unwrap_table(); diff --git a/radicle-tui/src/ui/widget/common.rs b/radicle-tui/src/ui/widget/common.rs index 4ce6a1cf..ba68a98e 100644 --- a/radicle-tui/src/ui/widget/common.rs +++ b/radicle-tui/src/ui/widget/common.rs @@ -38,6 +38,22 @@ pub fn container_header(theme: &Theme, label: &str) -> Widget
{ .custom("widths", widths) } +pub fn table_header(theme: &Theme, labels: &[&str], widths: &[u16]) -> Widget
{ + let content = labels + .iter() + .map(|label| { + PropValue::TextSpan(TextSpan::from(label.to_string()).fg(theme.colors.default_fg)) + }) + .collect::>(); + let widths = AttrValue::Payload(PropPayload::Vec( + widths.iter().map(|w| PropValue::U16(*w)).collect(), + )); + + Widget::new(Header::default()) + .content(AttrValue::Payload(PropPayload::Vec(content))) + .custom("widths", widths) +} + pub fn labeled_container( theme: &Theme, title: &str, @@ -105,12 +121,25 @@ pub fn tabs(theme: &Theme, tabs: Vec>) -> Widget { .highlight(theme.colors.tabs_highlighted_fg) } -pub fn table(theme: &Theme, items: &[impl List], profile: &Profile) -> Widget { - let table = Table::default(); +pub fn table( + theme: &Theme, + labels: &[&str], + widths: &[u16], + items: &[impl List], + profile: &Profile, +) -> Widget
{ let items = items.iter().map(|item| item.row(theme, profile)).collect(); + let header = table_header(theme, labels, widths); + let table = Table::new(header); + + let widths = AttrValue::Payload(PropPayload::Vec( + widths.iter().map(|w| PropValue::U16(*w)).collect(), + )); + Widget::new(table) .content(AttrValue::Table(items)) + .custom("widths", widths) .background(theme.colors.labeled_container_bg) .highlight(theme.colors.item_list_highlighted_bg) } diff --git a/radicle-tui/src/ui/widget/home.rs b/radicle-tui/src/ui/widget/home.rs index 6c125369..f178745d 100644 --- a/radicle-tui/src/ui/widget/home.rs +++ b/radicle-tui/src/ui/widget/home.rs @@ -1,8 +1,6 @@ use radicle::cob::patch::{Patch, PatchId}; use radicle::identity::{Id, Project}; use radicle::Profile; -use tuirealm::props::{PropPayload, PropValue, TextSpan}; -use tuirealm::AttrValue; use crate::ui::components::common::container::Tabs; use crate::ui::components::common::Browser; @@ -63,26 +61,10 @@ pub fn patches( ], ); - let widths = AttrValue::Payload(PropPayload::Vec(vec![ - PropValue::U16(2), - PropValue::U16(43), - PropValue::U16(15), - PropValue::U16(15), - PropValue::U16(5), - PropValue::U16(20), - ])); - let header = AttrValue::Payload(PropPayload::Vec(vec![ - PropValue::TextSpan(TextSpan::from("")), - PropValue::TextSpan(TextSpan::from("title")), - PropValue::TextSpan(TextSpan::from("author")), - PropValue::TextSpan(TextSpan::from("tags")), - PropValue::TextSpan(TextSpan::from("comments")), - PropValue::TextSpan(TextSpan::from("date")), - ])); + let labels = vec!["", "title", "author", "time", "comments", "tags"]; + let widths = vec![3u16, 42, 15, 10, 5, 25]; - let table = common::table(theme, items, profile) - .custom("widths", widths) - .custom("header", header); + let table = common::table(theme, &labels, &widths, items, profile); let browser: Browser<(PatchId, Patch)> = Browser::new(table, shortcuts); Widget::new(browser)