tui: Show project payload
Signed-off-by: Erik Kundt <erik@zirkular.io>
This commit is contained in:
parent
897f4c5250
commit
791c378d4e
|
|
@ -9,7 +9,7 @@ use tuirealm::tui::layout::{Constraint, Direction, Layout};
|
|||
use tuirealm::{Application, Component, Frame, NoUserEvent, Sub, SubClause, SubEventClause};
|
||||
|
||||
use radicle_tui::ui;
|
||||
use radicle_tui::ui::components::{GlobalListener, ShortcutBar};
|
||||
use radicle_tui::ui::components::{GlobalListener, LabeledContainer, PropertyList, ShortcutBar};
|
||||
use radicle_tui::ui::theme;
|
||||
use radicle_tui::ui::widget::Widget;
|
||||
|
||||
|
|
@ -33,6 +33,7 @@ pub enum Message {
|
|||
/// All components known to this application.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
pub enum ComponentId {
|
||||
Workspaces,
|
||||
ShortcutBar,
|
||||
GlobalListener,
|
||||
}
|
||||
|
|
@ -53,6 +54,25 @@ impl Tui<ComponentId, Message> for App {
|
|||
fn init(&mut self, app: &mut Application<ComponentId, Message, NoUserEvent>) -> Result<()> {
|
||||
let theme = theme::default_dark();
|
||||
|
||||
app.mount(
|
||||
ComponentId::Workspaces,
|
||||
ui::labeled_container(
|
||||
&theme,
|
||||
"about",
|
||||
ui::property_list(
|
||||
&theme,
|
||||
vec![
|
||||
ui::property(&theme, "id", &self.id.to_string()),
|
||||
ui::property(&theme, "name", self.project.name()),
|
||||
ui::property(&theme, "description", self.project.description()),
|
||||
],
|
||||
)
|
||||
.to_boxed(),
|
||||
)
|
||||
.to_boxed(),
|
||||
vec![],
|
||||
)?;
|
||||
|
||||
app.mount(
|
||||
ComponentId::ShortcutBar,
|
||||
ui::shortcut_bar(
|
||||
|
|
@ -114,6 +134,7 @@ impl Tui<ComponentId, Message> for App {
|
|||
)
|
||||
.split(area);
|
||||
|
||||
app.view(&ComponentId::Workspaces, frame, layout[0]);
|
||||
app.view(&ComponentId::ShortcutBar, frame, layout[1]);
|
||||
}
|
||||
|
||||
|
|
@ -147,6 +168,18 @@ impl Component<Message, NoUserEvent> for Widget<GlobalListener> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Component<Message, NoUserEvent> for Widget<LabeledContainer> {
|
||||
fn on(&mut self, _event: Event<NoUserEvent>) -> Option<Message> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Message, NoUserEvent> for Widget<PropertyList> {
|
||||
fn on(&mut self, _event: Event<NoUserEvent>) -> Option<Message> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Message, NoUserEvent> for Widget<ShortcutBar> {
|
||||
fn on(&mut self, _event: Event<NoUserEvent>) -> Option<Message> {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ pub mod widget;
|
|||
use tuirealm::props::Attribute;
|
||||
use tuirealm::{MockComponent, StateValue};
|
||||
|
||||
use components::{GlobalListener, Label, Property, PropertyList, Shortcut, ShortcutBar};
|
||||
use components::{
|
||||
ContainerHeader, GlobalListener, Label, LabeledContainer, Property, PropertyList, Shortcut,
|
||||
ShortcutBar,
|
||||
};
|
||||
use widget::Widget;
|
||||
|
||||
pub fn global_listener() -> Widget<GlobalListener> {
|
||||
|
|
@ -21,6 +24,21 @@ pub fn label(content: &str) -> Widget<Label> {
|
|||
Widget::new(label).height(1).width(width)
|
||||
}
|
||||
|
||||
pub fn labeled_container(
|
||||
theme: &theme::Theme,
|
||||
title: &str,
|
||||
component: Box<dyn MockComponent>,
|
||||
) -> Widget<LabeledContainer> {
|
||||
let title = label(&format!(" {} ", title))
|
||||
.foreground(theme.colors.default_fg)
|
||||
.background(theme.colors.labeled_container_bg);
|
||||
let spacer = label("");
|
||||
let header = Widget::new(ContainerHeader::new(title, spacer));
|
||||
let container = LabeledContainer::new(header, component);
|
||||
|
||||
Widget::new(container).background(theme.colors.labeled_container_bg)
|
||||
}
|
||||
|
||||
pub fn shortcut(theme: &theme::Theme, short: &str, long: &str) -> Widget<Shortcut> {
|
||||
let short = label(short).foreground(theme.colors.shortcut_short_fg);
|
||||
let divider = label(&theme.icons.whitespace.to_string());
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use tui_realm_stdlib::Phantom;
|
||||
|
||||
use tuirealm::command::{Cmd, CmdResult};
|
||||
use tuirealm::props::{AttrValue, Attribute, Color, Props};
|
||||
use tuirealm::tui::layout::Rect;
|
||||
use tuirealm::props::{AttrValue, Attribute, Color, Props, Style};
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use tuirealm::tui::widgets::Block;
|
||||
use tuirealm::{Frame, MockComponent, State, StateValue};
|
||||
|
||||
use super::layout;
|
||||
|
|
@ -57,15 +58,20 @@ impl WidgetComponent for Label {
|
|||
let foreground = properties
|
||||
.get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
|
||||
.unwrap_color();
|
||||
let background = properties
|
||||
.get_or(Attribute::Background, AttrValue::Color(Color::Reset))
|
||||
.unwrap_color();
|
||||
|
||||
if display {
|
||||
let mut label = match properties.get(Attribute::TextProps) {
|
||||
Some(modifiers) => Label::default()
|
||||
.foreground(foreground)
|
||||
.background(background)
|
||||
.modifiers(modifiers.unwrap_text_modifiers())
|
||||
.text(self.content.clone().unwrap_string()),
|
||||
None => Label::default()
|
||||
.foreground(foreground)
|
||||
.background(background)
|
||||
.text(self.content.clone().unwrap_string()),
|
||||
};
|
||||
|
||||
|
|
@ -82,6 +88,102 @@ impl WidgetComponent for Label {
|
|||
}
|
||||
}
|
||||
|
||||
/// A labeled container header.
|
||||
#[derive(Clone)]
|
||||
pub struct ContainerHeader {
|
||||
content: Widget<Label>,
|
||||
spacer: Widget<Label>,
|
||||
}
|
||||
|
||||
impl ContainerHeader {
|
||||
pub fn new(content: Widget<Label>, spacer: Widget<Label>) -> Self {
|
||||
Self { content, spacer }
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetComponent for ContainerHeader {
|
||||
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
|
||||
let display = properties
|
||||
.get_or(Attribute::Display, AttrValue::Flag(true))
|
||||
.unwrap_flag();
|
||||
|
||||
if display {
|
||||
let labels: Vec<Box<dyn MockComponent>> = vec![
|
||||
self.content.clone().to_boxed(),
|
||||
self.spacer.clone().to_boxed(),
|
||||
];
|
||||
|
||||
let layout = layout::h_stack(labels, area);
|
||||
for (mut shortcut, area) in layout {
|
||||
shortcut.view(frame, area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn state(&self) -> State {
|
||||
State::None
|
||||
}
|
||||
|
||||
fn perform(&mut self, _cmd: Cmd) -> CmdResult {
|
||||
CmdResult::None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LabeledContainer {
|
||||
header: Widget<ContainerHeader>,
|
||||
component: Box<dyn MockComponent>,
|
||||
}
|
||||
|
||||
impl LabeledContainer {
|
||||
pub fn new(header: Widget<ContainerHeader>, component: Box<dyn MockComponent>) -> Self {
|
||||
Self { header, component }
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetComponent for LabeledContainer {
|
||||
fn view(&mut self, properties: &Props, frame: &mut Frame, area: Rect) {
|
||||
let display = properties
|
||||
.get_or(Attribute::Display, AttrValue::Flag(true))
|
||||
.unwrap_flag();
|
||||
let background = properties
|
||||
.get_or(Attribute::Background, AttrValue::Color(Color::Reset))
|
||||
.unwrap_color();
|
||||
let header_height = self
|
||||
.header
|
||||
.query(Attribute::Height)
|
||||
.unwrap_or(AttrValue::Size(1))
|
||||
.unwrap_size();
|
||||
|
||||
if display {
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Length(header_height), Constraint::Length(0)].as_ref())
|
||||
.split(area);
|
||||
|
||||
self.header.view(frame, layout[0]);
|
||||
|
||||
// Make some space on the left
|
||||
let inner_layout = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(vec![Constraint::Length(1), Constraint::Min(0)].as_ref())
|
||||
.split(layout[1]);
|
||||
// reverse draw order: child needs to be drawn first?
|
||||
self.component.view(frame, inner_layout[1]);
|
||||
|
||||
let block = Block::default().style(Style::default().bg(background));
|
||||
frame.render_widget(block, layout[1]);
|
||||
}
|
||||
}
|
||||
|
||||
fn state(&self) -> State {
|
||||
State::None
|
||||
}
|
||||
|
||||
fn perform(&mut self, cmd: Cmd) -> CmdResult {
|
||||
self.component.perform(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
/// A shortcut that consists of a label displaying the "hotkey", a label that displays
|
||||
/// the action and a spacer between them.
|
||||
#[derive(Clone)]
|
||||
|
|
@ -226,6 +328,8 @@ impl WidgetComponent for Property {
|
|||
}
|
||||
|
||||
/// A component that can display lists of labeled properties
|
||||
#[derive(Default)]
|
||||
#[allow(clippy::vec_box)]
|
||||
pub struct PropertyList {
|
||||
properties: Vec<Widget<Property>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use tuirealm::props::Color;
|
|||
#[derive(Debug)]
|
||||
pub struct Colors {
|
||||
pub default_fg: Color,
|
||||
pub labeled_container_bg: Color,
|
||||
pub property_name_fg: Color,
|
||||
pub property_divider_fg: Color,
|
||||
pub shortcut_short_fg: Color,
|
||||
|
|
@ -43,6 +44,7 @@ pub fn default_dark() -> Theme {
|
|||
name: String::from("Radicle Dark"),
|
||||
colors: Colors {
|
||||
default_fg: Color::Rgb(200, 200, 200),
|
||||
labeled_container_bg: Color::Rgb(20, 20, 20),
|
||||
property_name_fg: Color::Rgb(85, 85, 255),
|
||||
property_divider_fg: Color::Rgb(10, 206, 209),
|
||||
shortcut_short_fg: Color::Rgb(100, 100, 100),
|
||||
|
|
|
|||
Loading…
Reference in New Issue