mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-11-15 16:00:38 +08:00
lib: Use themed style builders
This commit is contained in:
@@ -18,7 +18,7 @@ use radicle_tui as tui;
|
||||
use tui::cob;
|
||||
use tui::context::Context;
|
||||
use tui::ui::subscription;
|
||||
use tui::ui::theme::{self, Theme};
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::{Exit, PageStack, Tui};
|
||||
|
||||
use page::{IssuePage, ListPage};
|
||||
@@ -110,7 +110,7 @@ impl App {
|
||||
Self {
|
||||
context,
|
||||
pages: PageStack::default(),
|
||||
theme: theme::default_dark(),
|
||||
theme: Theme::default(),
|
||||
quit: false,
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ impl App {
|
||||
app: &mut Application<Cid, Message, NoUserEvent>,
|
||||
message: Message,
|
||||
) -> Result<Option<Message>> {
|
||||
let theme = theme::default_dark();
|
||||
let theme = Theme::default();
|
||||
match message {
|
||||
Message::Batch(messages) => {
|
||||
let mut results = vec![];
|
||||
|
||||
@@ -6,6 +6,7 @@ use radicle::cob::thread::CommentId;
|
||||
use radicle::cob::issue::Issue;
|
||||
use radicle::cob::issue::IssueId;
|
||||
|
||||
use tui::ui::theme::style;
|
||||
use tuirealm::command::{Cmd, CmdResult};
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use tuirealm::{AttrValue, Attribute, Frame, MockComponent, Props, State};
|
||||
@@ -72,7 +73,7 @@ impl IssueBrowser {
|
||||
};
|
||||
|
||||
let table = Widget::new(Table::new(&items, selected, header, widths, theme.clone()))
|
||||
.highlight(theme.colors.item_list_highlighted_bg);
|
||||
.highlight(style::highlight().fg.unwrap());
|
||||
|
||||
Self { items, table }
|
||||
}
|
||||
@@ -123,7 +124,7 @@ impl LargeList {
|
||||
selected.map(|(id, issue)| IssueItem::from((context.profile(), repo, id, issue)));
|
||||
|
||||
let list = Widget::new(List::new(&items, selected, theme.clone()))
|
||||
.highlight(theme.colors.item_list_highlighted_bg);
|
||||
.highlight(style::highlight().fg.unwrap());
|
||||
|
||||
let container = tui::ui::container(theme, list.to_boxed());
|
||||
|
||||
@@ -173,35 +174,35 @@ impl IssueHeader {
|
||||
let item = IssueItem::from((context.profile(), repo, id, issue.clone()));
|
||||
|
||||
let title = Property::new(
|
||||
tui::ui::label("Title").foreground(theme.colors.property_name_fg),
|
||||
tui::ui::label(item.title()).foreground(theme.colors.browser_list_title),
|
||||
tui::ui::label("Title").foreground(style::cyan().fg.unwrap()),
|
||||
tui::ui::label(item.title()).foreground(style::reset().fg.unwrap()),
|
||||
);
|
||||
|
||||
let author = match alias {
|
||||
Some(_) => tui::ui::label(&cob::format_author(issue.author().id(), &alias, by_you))
|
||||
.foreground(theme.colors.browser_list_author),
|
||||
None => tui::ui::label(&cob::format_author(issue.author().id(), &alias, by_you))
|
||||
.foreground(theme.colors.browser_list_author)
|
||||
.dim(),
|
||||
let author_style = match alias {
|
||||
Some(_) => style::magenta(),
|
||||
None => style::magenta_dim(),
|
||||
};
|
||||
|
||||
let author = tui::ui::label(&cob::format_author(issue.author().id(), &alias, by_you))
|
||||
.foreground(author_style.fg.unwrap());
|
||||
let author = Property::new(
|
||||
tui::ui::label("Author").foreground(theme.colors.property_name_fg),
|
||||
tui::ui::label("Author").foreground(style::cyan().fg.unwrap()),
|
||||
author,
|
||||
);
|
||||
|
||||
let issue_id = Property::new(
|
||||
tui::ui::label("Issue").foreground(theme.colors.property_name_fg),
|
||||
tui::ui::label(&id.to_string()).foreground(theme.colors.browser_list_description),
|
||||
tui::ui::label("Issue").foreground(style::cyan().fg.unwrap()),
|
||||
tui::ui::label(&id.to_string()).foreground(style::gray().fg.unwrap()),
|
||||
);
|
||||
|
||||
let labels = Property::new(
|
||||
tui::ui::label("Labels").foreground(theme.colors.property_name_fg),
|
||||
tui::ui::label("Labels").foreground(style::cyan().fg.unwrap()),
|
||||
tui::ui::label(&cob::format_labels(item.labels()))
|
||||
.foreground(theme.colors.browser_list_labels),
|
||||
.foreground(style::lightblue().fg.unwrap()),
|
||||
);
|
||||
|
||||
let assignees = Property::new(
|
||||
tui::ui::label("Assignees").foreground(theme.colors.property_name_fg),
|
||||
tui::ui::label("Assignees").foreground(style::cyan().fg.unwrap()),
|
||||
tui::ui::label(&cob::format_assignees(
|
||||
&item
|
||||
.assignees()
|
||||
@@ -209,12 +210,12 @@ impl IssueHeader {
|
||||
.map(|item| (item.did(), item.alias(), item.is_you()))
|
||||
.collect::<Vec<_>>(),
|
||||
))
|
||||
.foreground(theme.colors.browser_list_author),
|
||||
.foreground(author_style.fg.unwrap()),
|
||||
);
|
||||
|
||||
let state = Property::new(
|
||||
tui::ui::label("Status").foreground(theme.colors.property_name_fg),
|
||||
tui::ui::label(&item.state().to_string()).foreground(theme.colors.browser_list_title),
|
||||
tui::ui::label("Status").foreground(style::cyan().fg.unwrap()),
|
||||
tui::ui::label(&item.state().to_string()).foreground(style::reset().fg.unwrap()),
|
||||
);
|
||||
|
||||
let table = tui::ui::property_table(
|
||||
@@ -303,9 +304,9 @@ impl CommentBody {
|
||||
Some((_, comment)) => comment.body().to_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
let textarea = Widget::new(Textarea::new(theme.clone()))
|
||||
let textarea = Widget::new(Textarea::default())
|
||||
.content(AttrValue::String(content))
|
||||
.foreground(theme.colors.default_fg);
|
||||
.foreground(style::reset().fg.unwrap());
|
||||
|
||||
let textarea = tui::ui::container(theme, textarea.to_boxed());
|
||||
|
||||
@@ -335,7 +336,7 @@ impl WidgetComponent for CommentBody {
|
||||
pub fn list_navigation(theme: &Theme) -> Widget<Tabs> {
|
||||
tui::ui::tabs(
|
||||
theme,
|
||||
vec![tui::ui::reversable_label("Issues").foreground(theme.colors.tabs_highlighted_fg)],
|
||||
vec![tui::ui::reversable_label("Issues").foreground(style::magenta().fg.unwrap())],
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use radicle_tui as tui;
|
||||
|
||||
use tui::context::Context;
|
||||
use tui::ui::cob::PatchItem;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::theme::{style, Theme};
|
||||
use tui::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
use tui::ui::widget::container::Tabs;
|
||||
@@ -23,14 +23,14 @@ pub struct PatchBrowser {
|
||||
impl PatchBrowser {
|
||||
pub fn new(context: &Context, theme: &Theme, selected: Option<(PatchId, Patch)>) -> Self {
|
||||
let header = [
|
||||
tui::ui::label(" ● "),
|
||||
tui::ui::label("ID"),
|
||||
tui::ui::label("Title"),
|
||||
tui::ui::label("Author"),
|
||||
tui::ui::label("Head"),
|
||||
tui::ui::label("+"),
|
||||
tui::ui::label("-"),
|
||||
tui::ui::label("Updated"),
|
||||
tui::ui::label(" ● ").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("ID").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("Title").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("Author").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("Head").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("+").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("-").foreground(style::reset_dim().fg.unwrap()),
|
||||
tui::ui::label("Updated").foreground(style::reset_dim().fg.unwrap()),
|
||||
];
|
||||
|
||||
let widths = [
|
||||
@@ -65,7 +65,7 @@ impl PatchBrowser {
|
||||
};
|
||||
|
||||
let table = Widget::new(Table::new(&items, selected, header, widths, theme.clone()))
|
||||
.highlight(theme.colors.item_list_highlighted_bg);
|
||||
.highlight(style::highlight().fg.unwrap());
|
||||
|
||||
Self { items, table }
|
||||
}
|
||||
@@ -97,7 +97,7 @@ impl WidgetComponent for PatchBrowser {
|
||||
pub fn list_navigation(theme: &Theme) -> Widget<Tabs> {
|
||||
tui::ui::tabs(
|
||||
theme,
|
||||
vec![tui::ui::reversable_label("Patches").foreground(theme.colors.tabs_highlighted_fg)],
|
||||
vec![tui::ui::reversable_label("Patches").foreground(style::cyan().fg.unwrap())],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ pub fn patches(
|
||||
Widget::new(PatchBrowser::new(context, theme, selected))
|
||||
}
|
||||
|
||||
pub fn browse_context(context: &Context, theme: &Theme, progress: Progress) -> Widget<ContextBar> {
|
||||
pub fn browse_context(context: &Context, _theme: &Theme, progress: Progress) -> Widget<ContextBar> {
|
||||
use radicle::cob::patch::State;
|
||||
use tui::ui::{label, label_group};
|
||||
|
||||
@@ -132,49 +132,48 @@ pub fn browse_context(context: &Context, theme: &Theme, progress: Progress) -> W
|
||||
}
|
||||
|
||||
let context = label(" Patches ")
|
||||
.foreground(theme.colors.context_bg)
|
||||
.background(theme.colors.context_badge_bg);
|
||||
.foreground(style::magenta_reversed().fg.unwrap())
|
||||
.background(style::magenta_reversed().bg.unwrap());
|
||||
|
||||
let divider = label(" | ")
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let draft_n = label(&format!("{draft}"))
|
||||
.foreground(tuirealm::props::Color::Gray)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let draft = label(" Draft")
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let open_n = label(&format!("{open}"))
|
||||
.foreground(tuirealm::props::Color::Green)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::green().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let open = label(" Open")
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let archived_n = label(&format!("{archived}"))
|
||||
.foreground(tuirealm::props::Color::Yellow)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::yellow().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let archived = label(" Archived")
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let merged_n = label(&format!("{merged}"))
|
||||
.foreground(tuirealm::props::Color::Cyan)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::cyan().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let merged = label(" Merged ")
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let progress = label(&format!(" {} ", progress.to_string()))
|
||||
.foreground(theme.colors.context_bg)
|
||||
.background(theme.colors.context_badge_bg);
|
||||
.foreground(style::magenta_reversed().fg.unwrap())
|
||||
.background(style::magenta_reversed().bg.unwrap());
|
||||
|
||||
let spacer = label("").background(theme.colors.context_bg);
|
||||
let spacer = label("").background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let context_bar = ContextBar::new(
|
||||
theme.clone(),
|
||||
label_group(&[context]),
|
||||
label_group(&[spacer.clone()]),
|
||||
label_group(&[spacer]),
|
||||
|
||||
@@ -19,7 +19,7 @@ use radicle_tui as tui;
|
||||
|
||||
use tui::context::Context;
|
||||
use tui::ui::subscription;
|
||||
use tui::ui::theme::{self, Theme};
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::{Exit, PageStack, Tui};
|
||||
|
||||
use page::ListView;
|
||||
@@ -74,7 +74,7 @@ impl App {
|
||||
Self {
|
||||
context,
|
||||
pages: PageStack::default(),
|
||||
theme: theme::default_dark(),
|
||||
theme: Theme::default(),
|
||||
quit: false,
|
||||
patch_id: None,
|
||||
}
|
||||
@@ -96,7 +96,7 @@ impl App {
|
||||
app: &mut Application<Cid, Message, NoUserEvent>,
|
||||
message: Message,
|
||||
) -> Result<Option<Message>> {
|
||||
let theme = theme::default_dark();
|
||||
let theme = Theme::default();
|
||||
match message {
|
||||
Message::Batch(messages) => {
|
||||
let mut results = vec![];
|
||||
|
||||
@@ -20,7 +20,7 @@ use radicle_tui as tui;
|
||||
use tui::cob;
|
||||
use tui::context::Context;
|
||||
use tui::ui::subscription;
|
||||
use tui::ui::theme::{self, Theme};
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::{Exit, PageStack, Tui};
|
||||
|
||||
use page::{ListView, PatchView};
|
||||
@@ -94,7 +94,7 @@ impl App {
|
||||
Self {
|
||||
context,
|
||||
pages: PageStack::default(),
|
||||
theme: theme::default_dark(),
|
||||
theme: Theme::default(),
|
||||
quit: false,
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ impl App {
|
||||
app: &mut Application<Cid, Message, NoUserEvent>,
|
||||
message: Message,
|
||||
) -> Result<Option<Message>> {
|
||||
let theme = theme::default_dark();
|
||||
let theme = Theme::default();
|
||||
match message {
|
||||
Message::Batch(messages) => {
|
||||
let mut results = vec![];
|
||||
|
||||
@@ -11,7 +11,7 @@ use tui::context::Context;
|
||||
use tui::ui::cob;
|
||||
use tui::ui::cob::PatchItem;
|
||||
use tui::ui::layout;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::theme::{style, Theme};
|
||||
use tui::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
use tui::ui::widget::container::Tabs;
|
||||
@@ -69,7 +69,7 @@ impl PatchBrowser {
|
||||
};
|
||||
|
||||
let table = Widget::new(Table::new(&items, selected, header, widths, theme.clone()))
|
||||
.highlight(theme.colors.item_list_highlighted_bg);
|
||||
.highlight(style::highlight().fg.unwrap());
|
||||
|
||||
Self { items, table }
|
||||
}
|
||||
@@ -163,7 +163,7 @@ impl WidgetComponent for Files {
|
||||
pub fn list_navigation(theme: &Theme) -> Widget<Tabs> {
|
||||
tui::ui::tabs(
|
||||
theme,
|
||||
vec![tui::ui::reversable_label("Patches").foreground(theme.colors.tabs_highlighted_fg)],
|
||||
vec![tui::ui::reversable_label("Patches").foreground(style::magenta().fg.unwrap())],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -171,8 +171,8 @@ pub fn navigation(theme: &Theme) -> Widget<Tabs> {
|
||||
tui::ui::tabs(
|
||||
theme,
|
||||
vec![
|
||||
tui::ui::reversable_label("Activity").foreground(theme.colors.tabs_highlighted_fg),
|
||||
tui::ui::reversable_label("Files").foreground(theme.colors.tabs_highlighted_fg),
|
||||
tui::ui::reversable_label("Activity").foreground(style::magenta().fg.unwrap()),
|
||||
tui::ui::reversable_label("Files").foreground(style::magenta().fg.unwrap()),
|
||||
],
|
||||
)
|
||||
}
|
||||
@@ -185,15 +185,15 @@ pub fn patches(
|
||||
Widget::new(PatchBrowser::new(context, theme, selected))
|
||||
}
|
||||
|
||||
pub fn activity(theme: &Theme) -> Widget<Activity> {
|
||||
let not_implemented = tui::ui::label("not implemented").foreground(theme.colors.default_fg);
|
||||
pub fn activity(_theme: &Theme) -> Widget<Activity> {
|
||||
let not_implemented = tui::ui::label("not implemented").foreground(style::reset().fg.unwrap());
|
||||
let activity = Activity::new(not_implemented);
|
||||
|
||||
Widget::new(activity)
|
||||
}
|
||||
|
||||
pub fn files(theme: &Theme) -> Widget<Files> {
|
||||
let not_implemented = tui::ui::label("not implemented").foreground(theme.colors.default_fg);
|
||||
pub fn files(_theme: &Theme) -> Widget<Files> {
|
||||
let not_implemented = tui::ui::label("not implemented").foreground(style::reset().fg.unwrap());
|
||||
let files = Files::new(not_implemented);
|
||||
|
||||
Widget::new(files)
|
||||
|
||||
@@ -19,10 +19,10 @@ use widget::list::{ColumnWidth, Property, PropertyList, PropertyTable};
|
||||
|
||||
use widget::Widget;
|
||||
|
||||
use self::theme::{style, Theme};
|
||||
use self::widget::label::LabelGroup;
|
||||
|
||||
use super::context::Context;
|
||||
use crate::ui::theme::Theme;
|
||||
|
||||
pub fn global_listener() -> Widget<GlobalListener> {
|
||||
Widget::new(GlobalListener::default())
|
||||
@@ -75,7 +75,7 @@ pub fn labeled_container(
|
||||
) -> Widget<LabeledContainer> {
|
||||
let header = container_header(
|
||||
theme,
|
||||
label(&format!(" {title} ")).foreground(theme.colors.default_fg),
|
||||
label(&format!(" {title} ")).foreground(style::reset().fg.unwrap()),
|
||||
);
|
||||
let container = LabeledContainer::new(header, component, theme.clone());
|
||||
|
||||
@@ -83,9 +83,9 @@ pub fn labeled_container(
|
||||
}
|
||||
|
||||
pub fn shortcut(theme: &Theme, short: &str, long: &str) -> Widget<Shortcut> {
|
||||
let short = label(short).foreground(theme.colors.shortcut_short_fg);
|
||||
let short = label(short).foreground(style::gray().fg.unwrap());
|
||||
let long = label(long).foreground(style::gray_dim().fg.unwrap());
|
||||
let divider = label(&theme.icons.whitespace.to_string());
|
||||
let long = label(long).foreground(theme.colors.shortcut_long_fg);
|
||||
|
||||
// TODO: Remove when size constraints are implemented
|
||||
let short_w = short.query(Attribute::Width).unwrap().unwrap_size();
|
||||
@@ -100,16 +100,16 @@ pub fn shortcut(theme: &Theme, short: &str, long: &str) -> Widget<Shortcut> {
|
||||
|
||||
pub fn shortcuts(theme: &Theme, shortcuts: Vec<Widget<Shortcut>>) -> Widget<Shortcuts> {
|
||||
let divider = label(&format!(" {} ", theme.icons.shortcutbar_divider))
|
||||
.foreground(theme.colors.shortcutbar_divider_fg);
|
||||
.foreground(style::gray_dim().fg.unwrap());
|
||||
let shortcut_bar = Shortcuts::new(shortcuts, divider);
|
||||
|
||||
Widget::new(shortcut_bar).height(1)
|
||||
}
|
||||
|
||||
pub fn property(theme: &Theme, name: &str, value: &str) -> Widget<Property> {
|
||||
let name = label(name).foreground(theme.colors.property_name_fg);
|
||||
let name = label(name).foreground(style::cyan().fg.unwrap());
|
||||
let divider = label(&format!(" {} ", theme.icons.property_divider));
|
||||
let value = label(value).foreground(theme.colors.default_fg);
|
||||
let value = label(value).foreground(style::reset().fg.unwrap());
|
||||
|
||||
// TODO: Remove when size constraints are implemented
|
||||
let name_w = name.query(Attribute::Width).unwrap().unwrap_size();
|
||||
@@ -140,9 +140,9 @@ pub fn tabs(_theme: &Theme, tabs: Vec<Widget<Label>>) -> Widget<Tabs> {
|
||||
Widget::new(tabs).height(2)
|
||||
}
|
||||
|
||||
pub fn app_info(context: &Context, theme: &Theme) -> Widget<AppInfo> {
|
||||
let project = label(context.project().name()).foreground(theme.colors.app_header_project_fg);
|
||||
let rid = label(&format!(" ({})", context.id())).foreground(theme.colors.app_header_rid_fg);
|
||||
pub fn app_info(context: &Context) -> Widget<AppInfo> {
|
||||
let project = label(context.project().name()).foreground(style::cyan().fg.unwrap());
|
||||
let rid = label(&format!(" ({})", context.id())).foreground(style::yellow().fg.unwrap());
|
||||
|
||||
let project_w = project
|
||||
.query(Attribute::Width)
|
||||
@@ -163,17 +163,16 @@ pub fn app_header(
|
||||
nav: Option<Widget<Tabs>>,
|
||||
) -> Widget<AppHeader> {
|
||||
let line =
|
||||
label(&theme.icons.tab_overline.to_string()).foreground(theme.colors.tabs_highlighted_fg);
|
||||
label(&theme.icons.tab_overline.to_string()).foreground(style::magenta().fg.unwrap());
|
||||
let line = Widget::new(VerticalLine::new(line));
|
||||
let info = app_info(context, theme);
|
||||
let info = app_info(context);
|
||||
let header = AppHeader::new(nav, info, line);
|
||||
|
||||
Widget::new(header)
|
||||
}
|
||||
|
||||
pub fn info(theme: &Theme, message: &str) -> Widget<Popup> {
|
||||
let textarea =
|
||||
Widget::new(Textarea::new(theme.clone())).content(AttrValue::String(message.to_owned()));
|
||||
let textarea = Widget::new(Textarea::default()).content(AttrValue::String(message.to_owned()));
|
||||
let container = labeled_container(theme, "Info", textarea.to_boxed());
|
||||
|
||||
Widget::new(Popup::new(theme.clone(), container))
|
||||
@@ -182,8 +181,7 @@ pub fn info(theme: &Theme, message: &str) -> Widget<Popup> {
|
||||
}
|
||||
|
||||
pub fn warning(theme: &Theme, message: &str) -> Widget<Popup> {
|
||||
let textarea =
|
||||
Widget::new(Textarea::new(theme.clone())).content(AttrValue::String(message.to_owned()));
|
||||
let textarea = Widget::new(Textarea::default()).content(AttrValue::String(message.to_owned()));
|
||||
let container = labeled_container(theme, "Warning", textarea.to_boxed());
|
||||
|
||||
Widget::new(Popup::new(theme.clone(), container))
|
||||
@@ -192,8 +190,7 @@ pub fn warning(theme: &Theme, message: &str) -> Widget<Popup> {
|
||||
}
|
||||
|
||||
pub fn error(theme: &Theme, message: &str) -> Widget<Popup> {
|
||||
let textarea =
|
||||
Widget::new(Textarea::new(theme.clone())).content(AttrValue::String(message.to_owned()));
|
||||
let textarea = Widget::new(Textarea::default()).content(AttrValue::String(message.to_owned()));
|
||||
let container = labeled_container(theme, "Error", textarea.to_boxed());
|
||||
|
||||
Widget::new(Popup::new(theme.clone(), container))
|
||||
|
||||
+28
-57
@@ -2,7 +2,7 @@ pub mod format;
|
||||
|
||||
use radicle_surf;
|
||||
|
||||
use tuirealm::props::{Color, Style, TextModifiers};
|
||||
use tuirealm::props::{Color, Style};
|
||||
use tuirealm::tui::text::{Span, Spans};
|
||||
use tuirealm::tui::widgets::Cell;
|
||||
|
||||
@@ -20,6 +20,8 @@ use radicle::cob::{Label, Timestamp};
|
||||
use crate::ui::theme::Theme;
|
||||
use crate::ui::widget::list::{ListItem, TableItem};
|
||||
|
||||
use super::theme::style;
|
||||
|
||||
/// An author item that can be used in tables, list or trees.
|
||||
///
|
||||
/// Breaks up dependencies to [`Profile`] and [`Repository`] that
|
||||
@@ -142,21 +144,16 @@ impl TryFrom<(&Profile, &Repository, PatchId, Patch)> for PatchItem {
|
||||
}
|
||||
|
||||
impl TableItem<8> for PatchItem {
|
||||
fn row(&self, theme: &Theme) -> [Cell; 8] {
|
||||
fn row(&self, _theme: &Theme) -> [Cell; 8] {
|
||||
let (icon, color) = format_patch_state(&self.state);
|
||||
|
||||
let state = Cell::from(icon).style(Style::default().fg(color));
|
||||
|
||||
let id = Cell::from(format::cob(&self.id))
|
||||
.style(Style::default().fg(theme.colors.browser_list_id));
|
||||
|
||||
let title = Cell::from(self.title.clone())
|
||||
.style(Style::default().fg(theme.colors.browser_list_title));
|
||||
let id = Cell::from(format::cob(&self.id)).style(style::cyan());
|
||||
let title = Cell::from(self.title.clone()).style(style::reset());
|
||||
|
||||
let author_style = match &self.author.alias {
|
||||
Some(_) => Style::default().fg(theme.colors.browser_list_author),
|
||||
None => Style::default()
|
||||
.fg(theme.colors.browser_list_author)
|
||||
.add_modifier(TextModifiers::DIM),
|
||||
Some(_) => style::magenta(),
|
||||
None => style::magenta_dim(),
|
||||
};
|
||||
let author = Cell::from(format_author(
|
||||
&self.author.did,
|
||||
@@ -165,17 +162,10 @@ impl TableItem<8> for PatchItem {
|
||||
))
|
||||
.style(author_style);
|
||||
|
||||
let head = Cell::from(format::oid(self.head))
|
||||
.style(Style::default().fg(theme.colors.browser_patch_list_head));
|
||||
|
||||
let added = Cell::from(format!("+{}", self.added))
|
||||
.style(Style::default().fg(theme.colors.browser_patch_list_added));
|
||||
|
||||
let removed = Cell::from(format!("-{}", self.removed))
|
||||
.style(Style::default().fg(theme.colors.browser_patch_list_removed));
|
||||
|
||||
let updated = Cell::from(format::timestamp(&self.timestamp))
|
||||
.style(Style::default().fg(theme.colors.browser_list_timestamp));
|
||||
let head = Cell::from(format::oid(self.head)).style(style::lightblue());
|
||||
let added = Cell::from(format!("+{}", self.added)).style(style::green());
|
||||
let removed = Cell::from(format!("-{}", self.removed)).style(style::red());
|
||||
let updated = Cell::from(format::timestamp(&self.timestamp)).style(style::gray());
|
||||
|
||||
[state, id, title, author, head, added, removed, updated]
|
||||
}
|
||||
@@ -262,21 +252,16 @@ impl From<(&Profile, &Repository, IssueId, Issue)> for IssueItem {
|
||||
}
|
||||
|
||||
impl TableItem<7> for IssueItem {
|
||||
fn row(&self, theme: &Theme) -> [Cell; 7] {
|
||||
fn row(&self, _theme: &Theme) -> [Cell; 7] {
|
||||
let (icon, color) = format_issue_state(&self.state);
|
||||
|
||||
let state = Cell::from(icon).style(Style::default().fg(color));
|
||||
|
||||
let id = Cell::from(format::cob(&self.id))
|
||||
.style(Style::default().fg(theme.colors.browser_list_id));
|
||||
|
||||
let title = Cell::from(self.title.clone())
|
||||
.style(Style::default().fg(theme.colors.browser_list_title));
|
||||
let id = Cell::from(format::cob(&self.id)).style(style::cyan());
|
||||
let title = Cell::from(self.title.clone()).style(style::reset());
|
||||
|
||||
let author_style = match &self.author.alias {
|
||||
Some(_) => Style::default().fg(theme.colors.browser_list_author),
|
||||
None => Style::default()
|
||||
.fg(theme.colors.browser_list_author)
|
||||
.add_modifier(TextModifiers::DIM),
|
||||
Some(_) => style::magenta(),
|
||||
None => style::magenta_dim(),
|
||||
};
|
||||
let author = Cell::from(format_author(
|
||||
&self.author.did,
|
||||
@@ -285,19 +270,15 @@ impl TableItem<7> for IssueItem {
|
||||
))
|
||||
.style(author_style);
|
||||
|
||||
let labels = Cell::from(format_labels(&self.labels))
|
||||
.style(Style::default().fg(theme.colors.browser_list_labels));
|
||||
|
||||
let labels = Cell::from(format_labels(&self.labels)).style(style::lightblue());
|
||||
let assignees = self
|
||||
.assignees
|
||||
.iter()
|
||||
.map(|author| (author.did, author.alias.clone(), author.is_you))
|
||||
.collect::<Vec<_>>();
|
||||
let assignees = Cell::from(format_assignees(&assignees))
|
||||
.style(Style::default().fg(theme.colors.browser_list_author));
|
||||
|
||||
let opened = Cell::from(format::timestamp(&self.timestamp))
|
||||
.style(Style::default().fg(theme.colors.browser_list_timestamp));
|
||||
let assignees = Cell::from(format_assignees(&assignees)).style(author_style);
|
||||
let opened = Cell::from(format::timestamp(&self.timestamp)).style(style::gray());
|
||||
|
||||
[state, id, title, author, labels, assignees, opened]
|
||||
}
|
||||
@@ -307,18 +288,14 @@ impl ListItem for IssueItem {
|
||||
fn row(&self, theme: &Theme) -> tuirealm::tui::widgets::ListItem {
|
||||
let (state, state_color) = format_issue_state(&self.state);
|
||||
let author_style = match &self.author.alias {
|
||||
Some(_) => Style::default().fg(theme.colors.browser_list_author),
|
||||
None => Style::default()
|
||||
.fg(theme.colors.browser_list_author)
|
||||
.add_modifier(TextModifiers::DIM),
|
||||
Some(_) => style::magenta(),
|
||||
None => style::magenta_dim(),
|
||||
};
|
||||
|
||||
let lines = vec![
|
||||
Spans::from(vec![
|
||||
Span::styled(state, Style::default().fg(state_color)),
|
||||
Span::styled(
|
||||
self.title.clone(),
|
||||
Style::default().fg(theme.colors.browser_list_title),
|
||||
),
|
||||
Span::styled(self.title.clone(), style::reset()),
|
||||
]),
|
||||
Spans::from(vec![
|
||||
Span::raw(String::from(" ")),
|
||||
@@ -326,14 +303,8 @@ impl ListItem for IssueItem {
|
||||
format_author(&self.author.did, &self.author.alias, self.author.is_you),
|
||||
author_style,
|
||||
),
|
||||
Span::styled(
|
||||
format!(" {} ", theme.icons.property_divider),
|
||||
Style::default().fg(theme.colors.property_divider_fg),
|
||||
),
|
||||
Span::styled(
|
||||
format::timestamp(&self.timestamp),
|
||||
Style::default().fg(theme.colors.browser_list_timestamp),
|
||||
),
|
||||
Span::styled(format!(" {} ", theme.icons.property_divider), style::gray()),
|
||||
Span::styled(format::timestamp(&self.timestamp), style::gray()),
|
||||
]),
|
||||
];
|
||||
tuirealm::tui::widgets::ListItem::new(lines)
|
||||
|
||||
+107
-100
@@ -1,45 +1,4 @@
|
||||
use tuirealm::props::Color;
|
||||
|
||||
const COLOR_DEFAULT_FG: Color = Color::Rgb(200, 200, 200);
|
||||
const COLOR_DEFAULT_DARK_FG: Color = Color::Rgb(150, 150, 150);
|
||||
const COLOR_DEFAULT_DARK: Color = Color::Rgb(100, 100, 100);
|
||||
const COLOR_DEFAULT_DARKER: Color = Color::Rgb(70, 70, 70);
|
||||
const COLOR_DEFAULT_DARKEST: Color = Color::Rgb(40, 40, 40);
|
||||
const COLOR_DEFAULT_FAINT: Color = Color::Rgb(20, 20, 20);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Colors {
|
||||
pub default_fg: Color,
|
||||
pub tabs_highlighted_fg: Color,
|
||||
pub app_header_project_fg: Color,
|
||||
pub app_header_rid_fg: Color,
|
||||
pub labeled_container_bg: Color,
|
||||
pub item_list_highlighted_bg: Color,
|
||||
pub property_name_fg: Color,
|
||||
pub property_divider_fg: Color,
|
||||
pub shortcut_short_fg: Color,
|
||||
pub shortcut_long_fg: Color,
|
||||
pub shortcutbar_divider_fg: Color,
|
||||
pub browser_list_id: Color,
|
||||
pub browser_list_title: Color,
|
||||
pub browser_list_description: Color,
|
||||
pub browser_list_author: Color,
|
||||
pub browser_list_labels: Color,
|
||||
pub browser_list_comments: Color,
|
||||
pub browser_list_timestamp: Color,
|
||||
pub browser_patch_list_head: Color,
|
||||
pub browser_patch_list_added: Color,
|
||||
pub browser_patch_list_removed: Color,
|
||||
pub context_bg: Color,
|
||||
pub context_light: Color,
|
||||
pub context_dark: Color,
|
||||
pub context_badge_bg: Color,
|
||||
pub context_badge_edit_bg: Color,
|
||||
pub context_color_fg: Color,
|
||||
pub container_border_fg: Color,
|
||||
pub container_border_focus_fg: Color,
|
||||
pub input_placeholder_fg: Color,
|
||||
}
|
||||
use tuirealm::props::BorderType;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Icons {
|
||||
@@ -55,70 +14,118 @@ pub struct Tables {
|
||||
pub spacing: u16,
|
||||
}
|
||||
|
||||
/// The Radicle TUI theme. Will be defined in a JSON config file in the
|
||||
/// future. e.g.:
|
||||
/// {
|
||||
/// "name": "Default",
|
||||
/// "colors": {
|
||||
/// "foreground": "#ffffff",
|
||||
/// "propertyForeground": "#ffffff",
|
||||
/// "highlightedBackground": "#000000",
|
||||
/// },
|
||||
/// "icons": {
|
||||
/// "workspaces.divider": "|",
|
||||
/// "shortcuts.divider: "∙",
|
||||
/// }
|
||||
/// }
|
||||
/// The Radicle TUI theme. In the future, it might be defined in a JSON
|
||||
/// config file.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Theme {
|
||||
pub name: String,
|
||||
pub colors: Colors,
|
||||
pub icons: Icons,
|
||||
pub tables: Tables,
|
||||
pub border_type: BorderType,
|
||||
}
|
||||
|
||||
pub fn default_dark() -> Theme {
|
||||
Theme {
|
||||
name: String::from("Default"),
|
||||
colors: Colors {
|
||||
default_fg: COLOR_DEFAULT_FG,
|
||||
tabs_highlighted_fg: Color::Magenta,
|
||||
app_header_project_fg: Color::Cyan,
|
||||
app_header_rid_fg: Color::Yellow,
|
||||
labeled_container_bg: COLOR_DEFAULT_FAINT,
|
||||
item_list_highlighted_bg: COLOR_DEFAULT_DARKER,
|
||||
property_name_fg: Color::Cyan,
|
||||
property_divider_fg: COLOR_DEFAULT_DARK,
|
||||
shortcut_short_fg: COLOR_DEFAULT_DARK,
|
||||
shortcut_long_fg: COLOR_DEFAULT_DARKER,
|
||||
shortcutbar_divider_fg: COLOR_DEFAULT_DARKER,
|
||||
browser_list_id: Color::Cyan,
|
||||
browser_list_title: COLOR_DEFAULT_FG,
|
||||
browser_list_description: COLOR_DEFAULT_DARK,
|
||||
browser_list_author: Color::Magenta,
|
||||
browser_list_labels: Color::LightBlue,
|
||||
browser_list_comments: COLOR_DEFAULT_DARK_FG,
|
||||
browser_list_timestamp: COLOR_DEFAULT_DARK,
|
||||
browser_patch_list_head: Color::LightBlue,
|
||||
browser_patch_list_added: Color::Green,
|
||||
browser_patch_list_removed: Color::Red,
|
||||
context_bg: COLOR_DEFAULT_DARKEST,
|
||||
context_light: Color::Gray,
|
||||
context_dark: COLOR_DEFAULT_DARK,
|
||||
context_badge_bg: Color::Magenta,
|
||||
context_badge_edit_bg: Color::Red,
|
||||
context_color_fg: Color::Cyan,
|
||||
container_border_fg: COLOR_DEFAULT_DARKEST,
|
||||
container_border_focus_fg: COLOR_DEFAULT_DARK,
|
||||
input_placeholder_fg: COLOR_DEFAULT_DARK,
|
||||
},
|
||||
icons: Icons {
|
||||
property_divider: '∙',
|
||||
shortcutbar_divider: '∙',
|
||||
tab_divider: '|',
|
||||
tab_overline: '▔',
|
||||
whitespace: ' ',
|
||||
},
|
||||
tables: Tables { spacing: 2 },
|
||||
impl Default for Theme {
|
||||
fn default() -> Theme {
|
||||
Theme {
|
||||
name: String::from("Default"),
|
||||
icons: Icons {
|
||||
property_divider: '∙',
|
||||
shortcutbar_divider: '∙',
|
||||
tab_divider: '|',
|
||||
tab_overline: '▔',
|
||||
whitespace: ' ',
|
||||
},
|
||||
tables: Tables { spacing: 2 },
|
||||
border_type: BorderType::Rounded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod style {
|
||||
use tuirealm::props::{Color, Style, TextModifiers};
|
||||
|
||||
pub fn reset() -> Style {
|
||||
Style::default().fg(Color::Reset)
|
||||
}
|
||||
|
||||
pub fn reset_dim() -> Style {
|
||||
Style::default()
|
||||
.fg(Color::Reset)
|
||||
.add_modifier(TextModifiers::DIM)
|
||||
}
|
||||
|
||||
pub fn red() -> Style {
|
||||
Style::default().fg(Color::Red)
|
||||
}
|
||||
|
||||
pub fn green() -> Style {
|
||||
Style::default().fg(Color::Green)
|
||||
}
|
||||
|
||||
pub fn yellow() -> Style {
|
||||
Style::default().fg(Color::Yellow)
|
||||
}
|
||||
|
||||
pub fn blue() -> Style {
|
||||
Style::default().fg(Color::Blue)
|
||||
}
|
||||
|
||||
pub fn magenta() -> Style {
|
||||
Style::default().fg(Color::Magenta)
|
||||
}
|
||||
|
||||
pub fn magenta_dim() -> Style {
|
||||
Style::default()
|
||||
.fg(Color::Magenta)
|
||||
.add_modifier(TextModifiers::DIM)
|
||||
}
|
||||
|
||||
pub fn cyan() -> Style {
|
||||
Style::default().fg(Color::Cyan)
|
||||
}
|
||||
|
||||
pub fn lightblue() -> Style {
|
||||
Style::default().fg(Color::LightBlue)
|
||||
}
|
||||
|
||||
pub fn gray() -> Style {
|
||||
Style::default().fg(Color::Gray)
|
||||
}
|
||||
|
||||
pub fn gray_dim() -> Style {
|
||||
Style::default()
|
||||
.fg(Color::Gray)
|
||||
.add_modifier(TextModifiers::DIM)
|
||||
}
|
||||
|
||||
pub fn darkgray() -> Style {
|
||||
Style::default().fg(Color::DarkGray)
|
||||
}
|
||||
|
||||
pub fn default_reversed() -> Style {
|
||||
Style::default()
|
||||
.fg(Color::Reset)
|
||||
.bg(Color::DarkGray)
|
||||
.add_modifier(TextModifiers::DIM)
|
||||
}
|
||||
|
||||
pub fn magenta_reversed() -> Style {
|
||||
Style::default().fg(Color::DarkGray).bg(Color::Magenta)
|
||||
}
|
||||
|
||||
pub fn yellow_reversed() -> Style {
|
||||
Style::default().fg(Color::DarkGray).bg(Color::Yellow)
|
||||
}
|
||||
|
||||
pub fn border(focus: bool) -> Style {
|
||||
if focus {
|
||||
gray_dim()
|
||||
} else {
|
||||
darkgray()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn highlight() -> Style {
|
||||
darkgray()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use tuirealm::command::{Cmd, CmdResult};
|
||||
use tuirealm::props::{AttrValue, Attribute, BorderSides, BorderType, Props, Style, TextModifiers};
|
||||
use tuirealm::props::{AttrValue, Attribute, BorderSides, Props, TextModifiers};
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout, Margin, Rect};
|
||||
use tuirealm::tui::widgets::{Block, Cell, Clear, Row};
|
||||
use tuirealm::{Frame, MockComponent, State, StateValue};
|
||||
@@ -7,7 +7,7 @@ use tuirealm::{Frame, MockComponent, State, StateValue};
|
||||
use crate::ui::ext::HeaderBlock;
|
||||
use crate::ui::layout;
|
||||
use crate::ui::state::TabState;
|
||||
use crate::ui::theme::Theme;
|
||||
use crate::ui::theme::{style, Theme};
|
||||
use crate::ui::widget::{utils, Widget, WidgetComponent};
|
||||
|
||||
use super::label::Label;
|
||||
@@ -72,8 +72,6 @@ impl WidgetComponent for VerticalLine {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
/// A tab header that displays all labels horizontally aligned and separated
|
||||
/// by a divider. Highlights the label defined by the current tab index.
|
||||
#[derive(Clone)]
|
||||
@@ -278,17 +276,11 @@ impl<const W: usize> WidgetComponent for Header<W> {
|
||||
.get_or(Attribute::Focus, AttrValue::Flag(false))
|
||||
.unwrap_flag();
|
||||
|
||||
let color = if focus {
|
||||
self.theme.colors.container_border_focus_fg
|
||||
} else {
|
||||
self.theme.colors.container_border_fg
|
||||
};
|
||||
|
||||
if display {
|
||||
let block = HeaderBlock::default()
|
||||
.borders(BorderSides::all())
|
||||
.border_style(Style::default().fg(color))
|
||||
.border_type(BorderType::Rounded);
|
||||
.border_style(style::border(focus))
|
||||
.border_type(self.theme.border_type);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let layout = Layout::default()
|
||||
@@ -304,7 +296,7 @@ impl<const W: usize> WidgetComponent for Header<W> {
|
||||
.iter()
|
||||
.map(|label| {
|
||||
let cell: Cell = label.into();
|
||||
cell.style(Style::default().fg(self.theme.colors.default_fg))
|
||||
cell.style(style::reset())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
@@ -348,12 +340,6 @@ impl WidgetComponent for Container {
|
||||
.get_or(Attribute::Focus, AttrValue::Flag(false))
|
||||
.unwrap_flag();
|
||||
|
||||
let color = if focus {
|
||||
self.theme.colors.container_border_focus_fg
|
||||
} else {
|
||||
self.theme.colors.container_border_fg
|
||||
};
|
||||
|
||||
if display {
|
||||
// Make some space on the left
|
||||
let layout = Layout::default()
|
||||
@@ -369,8 +355,8 @@ impl WidgetComponent for Container {
|
||||
|
||||
let block = Block::default()
|
||||
.borders(BorderSides::ALL)
|
||||
.border_style(Style::default().fg(color))
|
||||
.border_type(BorderType::Rounded);
|
||||
.border_style(style::border(focus))
|
||||
.border_type(self.theme.border_type);
|
||||
frame.render_widget(block, area);
|
||||
}
|
||||
}
|
||||
@@ -409,12 +395,6 @@ impl WidgetComponent for LabeledContainer {
|
||||
.get_or(Attribute::Focus, AttrValue::Flag(false))
|
||||
.unwrap_flag();
|
||||
|
||||
let color = if focus {
|
||||
self.theme.colors.container_border_focus_fg
|
||||
} else {
|
||||
self.theme.colors.container_border_fg
|
||||
};
|
||||
|
||||
let header_height = self
|
||||
.header
|
||||
.query(Attribute::Height)
|
||||
@@ -432,8 +412,8 @@ impl WidgetComponent for LabeledContainer {
|
||||
|
||||
let block = Block::default()
|
||||
.borders(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT)
|
||||
.border_style(Style::default().fg(color))
|
||||
.border_type(BorderType::Rounded);
|
||||
.border_style(style::border(focus))
|
||||
.border_type(self.theme.border_type);
|
||||
frame.render_widget(block.clone(), layout[1]);
|
||||
|
||||
self.component
|
||||
|
||||
+14
-17
@@ -6,7 +6,7 @@ use tuirealm::{Frame, MockComponent, State};
|
||||
use super::label::{Label, LabelGroup};
|
||||
|
||||
use crate::ui::layout;
|
||||
use crate::ui::theme::Theme;
|
||||
use crate::ui::theme::{style, Theme};
|
||||
use crate::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
pub enum Progress {
|
||||
@@ -128,14 +128,12 @@ pub struct ContextBar {
|
||||
col_2: Widget<LabelGroup>,
|
||||
col_3: Widget<LabelGroup>,
|
||||
col_4: Widget<LabelGroup>,
|
||||
theme: Theme,
|
||||
}
|
||||
|
||||
impl ContextBar {
|
||||
pub const PROP_EDIT_MODE: &'static str = "edit-mode";
|
||||
|
||||
pub fn new(
|
||||
theme: Theme,
|
||||
col_0: Widget<LabelGroup>,
|
||||
col_1: Widget<LabelGroup>,
|
||||
col_2: Widget<LabelGroup>,
|
||||
@@ -143,7 +141,6 @@ impl ContextBar {
|
||||
col_4: Widget<LabelGroup>,
|
||||
) -> Self {
|
||||
Self {
|
||||
theme,
|
||||
col_0,
|
||||
col_1,
|
||||
col_2,
|
||||
@@ -173,7 +170,7 @@ impl WidgetComponent for ContextBar {
|
||||
if edit_mode {
|
||||
self.col_0.attr(
|
||||
Attribute::Background,
|
||||
AttrValue::Color(self.theme.colors.context_badge_edit_bg),
|
||||
AttrValue::Color(style::yellow_reversed().bg.unwrap()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -211,7 +208,7 @@ impl WidgetComponent for ContextBar {
|
||||
}
|
||||
|
||||
pub fn bar(
|
||||
theme: &Theme,
|
||||
_theme: &Theme,
|
||||
label_0: &str,
|
||||
label_1: &str,
|
||||
label_2: &str,
|
||||
@@ -221,20 +218,20 @@ pub fn bar(
|
||||
use crate::ui::{label, label_group};
|
||||
|
||||
let label_0 = label(&format!(" {label_0} "))
|
||||
.foreground(theme.colors.context_bg)
|
||||
.background(theme.colors.context_badge_bg);
|
||||
.foreground(style::magenta_reversed().fg.unwrap())
|
||||
.background(style::magenta_reversed().bg.unwrap());
|
||||
let label_1 = label(&format!(" {label_1} "))
|
||||
.foreground(theme.colors.context_color_fg)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let label_2 = label(&format!(" {label_2} "))
|
||||
.foreground(theme.colors.default_fg)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let label_3 = label(&format!(" {label_3} "))
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
let label_4 = label(&format!(" {label_4} "))
|
||||
.foreground(theme.colors.context_light)
|
||||
.background(theme.colors.context_bg);
|
||||
.foreground(style::default_reversed().fg.unwrap())
|
||||
.background(style::default_reversed().bg.unwrap());
|
||||
|
||||
let label_0 = label_group(&[label_0]);
|
||||
let label_1 = label_group(&[label_1]);
|
||||
@@ -242,7 +239,7 @@ pub fn bar(
|
||||
let label_3 = label_group(&[label_3]);
|
||||
let label_4 = label_group(&[label_4]);
|
||||
|
||||
let context_bar = ContextBar::new(theme.clone(), label_0, label_1, label_2, label_3, label_4);
|
||||
let context_bar = ContextBar::new(label_0, label_1, label_2, label_3, label_4);
|
||||
|
||||
Widget::new(context_bar).height(1)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use tuirealm::tui::layout::{Constraint, Direction, Margin, Rect};
|
||||
use tuirealm::{AttrValue, Attribute, Frame, MockComponent, Props, State, StateValue};
|
||||
|
||||
use crate::ui::state::FormState;
|
||||
use crate::ui::theme::Theme;
|
||||
use crate::ui::theme::{style, Theme};
|
||||
use crate::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
use super::container::Container;
|
||||
@@ -24,12 +24,12 @@ impl TextField {
|
||||
.wrap(false)
|
||||
.single_line(true)
|
||||
.cursor_line_style(Style::reset())
|
||||
.style(Style::default().fg(theme.colors.default_fg));
|
||||
.style(style::reset());
|
||||
let container = crate::ui::container(&theme, Box::new(input));
|
||||
|
||||
Self {
|
||||
input: container,
|
||||
placeholder: crate::ui::label(title).foreground(theme.colors.input_placeholder_fg),
|
||||
placeholder: crate::ui::label(title).foreground(style::gray_dim().fg.unwrap()),
|
||||
show_placeholder: true,
|
||||
}
|
||||
}
|
||||
@@ -98,12 +98,12 @@ impl TextArea {
|
||||
.wrap(true)
|
||||
.single_line(false)
|
||||
.cursor_line_style(Style::reset())
|
||||
.style(Style::default().fg(theme.colors.default_fg));
|
||||
.style(style::reset());
|
||||
let container = crate::ui::container(&theme, Box::new(input));
|
||||
|
||||
Self {
|
||||
input: container,
|
||||
placeholder: crate::ui::label(title).foreground(theme.colors.input_placeholder_fg),
|
||||
placeholder: crate::ui::label(title).foreground(style::gray_dim().fg.unwrap()),
|
||||
show_placeholder: true,
|
||||
}
|
||||
}
|
||||
|
||||
+4
-24
@@ -5,7 +5,7 @@ use tuirealm::tui::text::{Span, Spans, Text};
|
||||
use tuirealm::{Frame, MockComponent, State, StateValue};
|
||||
|
||||
use crate::ui::layout;
|
||||
use crate::ui::theme::Theme;
|
||||
use crate::ui::theme::style;
|
||||
use crate::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
/// A label that can be styled using a foreground color and text modifiers.
|
||||
@@ -123,9 +123,8 @@ impl WidgetComponent for LabelGroup {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Textarea {
|
||||
/// The current theme.
|
||||
theme: Theme,
|
||||
/// The scroll offset.
|
||||
offset: usize,
|
||||
/// The current line count.
|
||||
@@ -139,16 +138,6 @@ pub struct Textarea {
|
||||
impl Textarea {
|
||||
pub const PROP_DISPLAY_PROGRESS: &'static str = "display-progress";
|
||||
|
||||
pub fn new(theme: Theme) -> Self {
|
||||
Self {
|
||||
theme,
|
||||
offset: 0,
|
||||
len: 0,
|
||||
height: 0,
|
||||
scroll_percent: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_percent(offset: usize, len: usize, height: usize) -> usize {
|
||||
if height >= len {
|
||||
100
|
||||
@@ -170,9 +159,6 @@ impl WidgetComponent for Textarea {
|
||||
let focus = properties
|
||||
.get_or(Attribute::Focus, AttrValue::Flag(false))
|
||||
.unwrap_flag();
|
||||
let fg = properties
|
||||
.get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
|
||||
.unwrap_color();
|
||||
let display_progress = properties
|
||||
.get_or(
|
||||
Attribute::Custom(Self::PROP_DISPLAY_PROGRESS),
|
||||
@@ -189,12 +175,6 @@ impl WidgetComponent for Textarea {
|
||||
.constraints([Constraint::Min(1), Constraint::Length(1)])
|
||||
.split(area);
|
||||
|
||||
let highlight_color = if focus {
|
||||
self.theme.colors.container_border_focus_fg
|
||||
} else {
|
||||
self.theme.colors.container_border_fg
|
||||
};
|
||||
|
||||
// TODO: replace with `ratatui`'s reflow module when that becomes
|
||||
// public: https://github.com/tui-rs-revival/ratatui/pull/9.
|
||||
//
|
||||
@@ -212,7 +192,7 @@ impl WidgetComponent for Textarea {
|
||||
|
||||
let paragraph = Paragraph::new(body)
|
||||
.scroll((self.offset as u16, 0))
|
||||
.style(Style::default().fg(fg));
|
||||
.style(style::reset());
|
||||
frame.render_widget(paragraph, layout[0]);
|
||||
|
||||
self.scroll_percent = Self::scroll_percent(self.offset, self.len, self.height);
|
||||
@@ -220,7 +200,7 @@ impl WidgetComponent for Textarea {
|
||||
if display_progress {
|
||||
let progress = Spans::from(vec![Span::styled(
|
||||
format!("{} %", self.scroll_percent),
|
||||
Style::default().fg(highlight_color),
|
||||
style::border(focus),
|
||||
)]);
|
||||
|
||||
let progress = Paragraph::new(progress).alignment(Alignment::Right);
|
||||
|
||||
+4
-10
@@ -1,12 +1,12 @@
|
||||
use tuirealm::command::{Cmd, CmdResult};
|
||||
use tuirealm::props::{AttrValue, Attribute, BorderSides, BorderType, Color, Props, Style};
|
||||
use tuirealm::props::{AttrValue, Attribute, BorderSides, Color, Props, Style};
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use tuirealm::tui::widgets::{Block, Cell, ListState, Row, TableState};
|
||||
use tuirealm::{Frame, MockComponent, State, StateValue};
|
||||
|
||||
use crate::ui::layout;
|
||||
use crate::ui::state::ItemState;
|
||||
use crate::ui::theme::Theme;
|
||||
use crate::ui::theme::{style, Theme};
|
||||
use crate::ui::widget::{utils, Widget, WidgetComponent};
|
||||
|
||||
use super::container::Header;
|
||||
@@ -234,12 +234,6 @@ where
|
||||
.get_or(Attribute::Focus, AttrValue::Flag(false))
|
||||
.unwrap_flag();
|
||||
|
||||
let color = if focus {
|
||||
self.theme.colors.container_border_focus_fg
|
||||
} else {
|
||||
self.theme.colors.container_border_fg
|
||||
};
|
||||
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![Constraint::Length(3), Constraint::Min(1)])
|
||||
@@ -256,8 +250,8 @@ where
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT)
|
||||
.border_style(Style::default().fg(color))
|
||||
.border_type(BorderType::Rounded),
|
||||
.border_style(style::border(focus))
|
||||
.border_type(self.theme.border_type),
|
||||
)
|
||||
.highlight_style(Style::default().bg(highlight))
|
||||
.column_spacing(self.theme.tables.spacing)
|
||||
|
||||
Reference in New Issue
Block a user