tui: Update navigation design

This commit is contained in:
Erik Kundt 2023-04-21 19:41:50 +02:00 committed by Alexis Sellier
parent 4a99e18562
commit 362f26a0c8
No known key found for this signature in database
7 changed files with 65 additions and 39 deletions

View File

@ -81,8 +81,7 @@ impl ViewPage for Home {
fn view(&mut self, app: &mut Application<Cid, Message, NoUserEvent>, frame: &mut Frame) {
let area = frame.size();
let navigation_h = 1u16;
let layout = layout::default_page(area, navigation_h);
let layout = layout::default_page(area);
app.view(&Cid::Home(HomeCid::Navigation), frame, layout[0]);
app.view(&self.active_component, frame, layout[1]);
@ -145,9 +144,7 @@ impl ViewPage for PatchView {
fn view(&mut self, app: &mut Application<Cid, Message, NoUserEvent>, frame: &mut Frame) {
let area = frame.size();
let navigation_h = 2u16;
let layout = layout::default_page(area, navigation_h);
let layout = layout::default_page(area);
app.view(&Cid::Patch(PatchCid::Navigation), frame, layout[0]);
app.view(&self.active_component, frame, layout[1]);

View File

@ -1,14 +1,15 @@
use tuirealm::command::{Cmd, CmdResult};
use tuirealm::props::{
AttrValue, Attribute, BorderSides, BorderType, Color, PropPayload, PropValue, Props, Style,
TextModifiers,
};
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
use tuirealm::tui::text::{Span, Spans};
use tuirealm::tui::widgets::{Block, Cell, Row};
use tuirealm::{Frame, MockComponent, State, StateValue};
use crate::ui::components::common::label::Label;
use crate::ui::ext::HeaderBlock;
use crate::ui::layout;
use crate::ui::state::TabState;
use crate::ui::widget::{Widget, WidgetComponent};
@ -35,16 +36,16 @@ impl WidgetComponent for GlobalListener {
#[derive(Clone)]
pub struct Tabs {
tabs: Vec<Widget<Label>>,
divider: Widget<Label>,
line: Widget<Label>,
state: TabState,
}
impl Tabs {
pub fn new(tabs: Vec<Widget<Label>>, divider: Widget<Label>) -> Self {
pub fn new(tabs: Vec<Widget<Label>>, line: Widget<Label>) -> Self {
let count = &tabs.len();
Self {
tabs,
divider,
line,
state: TabState {
selected: 0,
len: *count as u16,
@ -59,27 +60,46 @@ impl WidgetComponent for Tabs {
let display = properties
.get_or(Attribute::Display, AttrValue::Flag(true))
.unwrap_flag();
let foreground = properties
.get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
.unwrap_color();
let highlight = properties
.get_or(Attribute::HighlightedColor, AttrValue::Color(Color::Reset))
.unwrap_color();
if display {
let spans = self
.tabs
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
])
.split(area);
// Render tabs on first row, highlighting the selected tab.
let mut tabs = vec![];
for (index, tab) in self.tabs.iter().enumerate() {
let mut tab = tab.clone().to_boxed();
if index == selected as usize {
tab.attr(
Attribute::TextProps,
AttrValue::TextModifiers(TextModifiers::REVERSED),
);
}
tabs.push(tab.clone().to_boxed() as Box<dyn MockComponent>);
}
tabs.push(Widget::new(Label::default()).to_boxed());
let tab_layout = layout::h_stack(tabs, layout[1]);
for (mut tab, area) in tab_layout {
tab.view(frame, area);
}
// Repeat and render line on second row.
let overlines = vec![self.line.clone(); area.width as usize];
let overlines = overlines
.iter()
.map(|tab| Spans::from(vec![Span::from(tab)]))
.collect::<Vec<_>>();
let tabs = tuirealm::tui::widgets::Tabs::new(spans)
.style(Style::default().fg(foreground))
.highlight_style(Style::default().fg(highlight))
.divider(Span::from(&self.divider))
.select(selected as usize);
frame.render_widget(tabs, area);
.map(|l| l.clone().to_boxed() as Box<dyn MockComponent>)
.collect();
let line_layout = layout::h_stack(overlines, layout[2]);
for (mut line, area) in line_layout {
line.view(frame, area);
}
}
}

View File

@ -46,7 +46,8 @@ pub fn h_stack(
widgets.into_iter().zip(layout.into_iter()).collect()
}
pub fn default_page(area: Rect, nav_h: u16) -> Vec<Rect> {
pub fn default_page(area: Rect) -> Vec<Rect> {
let nav_h = 3u16;
let margin_h = 1u16;
let content_h = area.height.saturating_sub(nav_h.saturating_add(margin_h));

View File

@ -25,6 +25,7 @@ pub struct Icons {
pub property_divider: char,
pub shortcutbar_divider: char,
pub tab_divider: char,
pub tab_overline: char,
pub whitespace: char,
}
@ -55,7 +56,7 @@ pub fn default_dark() -> Theme {
colors: Colors {
default_fg: Color::Rgb(200, 200, 200),
tabs_fg: Color::Rgb(100, 100, 100),
tabs_highlighted_fg: Color::Rgb(38, 162, 105),
tabs_highlighted_fg: Color::Rgb(85, 85, 255),
workspaces_info_fg: Color::Rgb(220, 140, 40),
labeled_container_bg: Color::Rgb(20, 20, 20),
item_list_highlighted_bg: Color::Rgb(40, 40, 40),
@ -74,6 +75,7 @@ pub fn default_dark() -> Theme {
property_divider: '',
shortcutbar_divider: '',
tab_divider: '|',
tab_overline: '',
whitespace: ' ',
},
}

View File

@ -27,6 +27,11 @@ pub fn label(content: &str) -> Widget<Label> {
.width(width)
}
pub fn reversable_label(content: &str) -> Widget<Label> {
let content = &format!(" {content} ");
label(content)
}
pub fn container_header(theme: &Theme, label: &str) -> Widget<Header> {
let content = AttrValue::Payload(PropPayload::Vec(vec![PropValue::TextSpan(
TextSpan::from(&format!(" {label} ")).fg(theme.colors.default_fg),
@ -112,13 +117,11 @@ pub fn property_list(_theme: &Theme, properties: Vec<Widget<Property>>) -> Widge
}
pub fn tabs(theme: &Theme, tabs: Vec<Widget<Label>>) -> Widget<Tabs> {
let divider = label(&theme.icons.tab_divider.to_string());
let tabs = Tabs::new(tabs, divider);
let line =
label(&theme.icons.tab_overline.to_string()).foreground(theme.colors.tabs_highlighted_fg);
let tabs = Tabs::new(tabs, line);
Widget::new(tabs)
.height(1)
.foreground(theme.colors.tabs_fg)
.highlight(theme.colors.tabs_highlighted_fg)
Widget::new(tabs).height(2)
}
pub fn table(

View File

@ -13,9 +13,9 @@ pub fn navigation(theme: &Theme) -> Widget<Tabs> {
common::tabs(
theme,
vec![
common::label("dashboard"),
common::label("issues"),
common::label("patches"),
common::reversable_label("dashboard").foreground(theme.colors.tabs_highlighted_fg),
common::reversable_label("issues").foreground(theme.colors.tabs_highlighted_fg),
common::reversable_label("patches").foreground(theme.colors.tabs_highlighted_fg),
],
)
}

View File

@ -15,7 +15,10 @@ use crate::ui::theme::Theme;
pub fn navigation(theme: &Theme) -> Widget<Tabs> {
common::tabs(
theme,
vec![common::label("activity"), common::label("files")],
vec![
common::reversable_label("activity").foreground(theme.colors.tabs_highlighted_fg),
common::reversable_label("files").foreground(theme.colors.tabs_highlighted_fg),
],
)
}