Merge pull request #168 from SoapyDev/theme_revised

Refactoring : Easily add theme and cycle through
This commit is contained in:
Chris Titus 2024-08-16 11:11:56 -05:00 committed by GitHub
commit e4f2911cdf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 119 additions and 57 deletions

View File

@ -10,6 +10,7 @@ use std::{
time::Duration,
};
use crate::theme::Theme;
use clap::Parser;
use crossterm::{
cursor::RestorePosition,
@ -25,24 +26,21 @@ use ratatui::{
};
use state::AppState;
use tempdir::TempDir;
use theme::THEMES;
/// This is a binary :), Chris, change this to update the documentation on -h
// Linux utility toolbox
#[derive(Debug, Parser)]
struct Args {
/// Enable compatibility mode (disable icons and RGB colors)
#[arg(short, long, default_value_t = false)]
compat: bool,
#[arg(short, long, value_enum)]
#[arg(default_value_t = Theme::Default)]
#[arg(help = "Set the theme to use in the application")]
theme: Theme,
}
fn main() -> std::io::Result<()> {
let args = Args::parse();
let theme = if args.compat {
THEMES[0].clone()
} else {
THEMES[1].clone()
};
let theme = args.theme;
let commands_dir = include_dir!("src/commands");
let temp_dir: TempDir = TempDir::new("linutil_scripts").unwrap();
commands_dir

View File

@ -69,7 +69,7 @@ impl AppState {
pub fn draw(&mut self, frame: &mut Frame) {
let longest_tab_display_len = TABS
.iter()
.map(|tab| tab.name.len() + self.theme.tab_icon.len())
.map(|tab| tab.name.len() + self.theme.tab_icon().len())
.max()
.unwrap_or(0);
@ -88,15 +88,15 @@ impl AppState {
let tabs = TABS.iter().map(|tab| tab.name).collect::<Vec<_>>();
let tab_hl_style = if let Focus::TabList = self.focus {
Style::default().reversed().fg(self.theme.tab_color)
Style::default().reversed().fg(self.theme.tab_color())
} else {
Style::new().fg(self.theme.tab_color)
Style::new().fg(self.theme.tab_color())
};
let list = List::new(tabs)
.block(Block::default().borders(Borders::ALL))
.highlight_style(tab_hl_style)
.highlight_symbol(self.theme.tab_icon);
.highlight_symbol(self.theme.tab_icon());
frame.render_stateful_widget(list, left_chunks[1], &mut self.current_tab);
let chunks = Layout::default()
@ -122,7 +122,7 @@ impl AppState {
let mut items: Vec<Line> = Vec::new();
if !self.at_root() {
items.push(
Line::from(format!("{} ..", self.theme.dir_icon)).style(self.theme.dir_color),
Line::from(format!("{} ..", self.theme.dir_icon())).style(self.theme.dir_color()),
);
}
@ -131,11 +131,11 @@ impl AppState {
node, has_children, ..
}| {
if *has_children {
Line::from(format!("{} {}", self.theme.dir_icon, node.name))
.style(self.theme.dir_color)
Line::from(format!("{} {}", self.theme.dir_icon(), node.name))
.style(self.theme.dir_color())
} else {
Line::from(format!("{} {}", self.theme.cmd_icon, node.name))
.style(self.theme.cmd_color)
Line::from(format!("{} {}", self.theme.cmd_icon(), node.name))
.style(self.theme.cmd_color())
}
},
));
@ -196,6 +196,8 @@ impl AppState {
self.refresh_tab();
}
KeyCode::Char('/') => self.enter_search(),
KeyCode::Char('t') => self.theme = self.theme.next(),
KeyCode::Char('T') => self.theme = self.theme.prev(),
_ => {}
},
Focus::List if key.kind != KeyEventKind::Release => match key.code {
@ -212,6 +214,8 @@ impl AppState {
}
KeyCode::Char('/') => self.enter_search(),
KeyCode::Tab => self.focus = Focus::TabList,
KeyCode::Char('t') => self.theme = self.theme.next(),
KeyCode::Char('T') => self.theme = self.theme.prev(),
_ => {}
},
_ => {}

View File

@ -1,42 +1,102 @@
use clap::ValueEnum;
use ratatui::style::Color;
#[derive(Clone)]
pub struct Theme {
pub dir_color: Color,
pub cmd_color: Color,
pub tab_color: Color,
pub dir_icon: &'static str,
pub cmd_icon: &'static str,
pub tab_icon: &'static str,
pub success_color: Color,
pub fail_color: Color,
pub focused_color: Color,
pub unfocused_color: Color,
// Add the Theme name here for a new theme
// This is more secure than the previous list
// We cannot index out of bounds, and we are giving
// names to our various themes, making it very clear
// This will make it easy to add new themes
#[derive(Clone, Debug, PartialEq, Default, ValueEnum, Copy)]
pub enum Theme {
#[default]
Default,
Compatible,
}
pub const THEMES: [Theme; 2] = [
Theme {
dir_color: Color::Blue,
cmd_color: Color::LightGreen,
tab_color: Color::Yellow,
dir_icon: "[DIR]",
cmd_icon: "[CMD]",
tab_icon: ">> ",
success_color: Color::Green,
fail_color: Color::Red,
focused_color: Color::LightBlue,
unfocused_color: Color::Gray,
},
Theme {
dir_color: Color::Blue,
cmd_color: Color::Rgb(204, 224, 208),
tab_color: Color::Rgb(255, 255, 85),
dir_icon: "",
cmd_icon: "",
tab_icon: "",
fail_color: Color::Rgb(199, 55, 44),
success_color: Color::Rgb(5, 255, 55),
focused_color: Color::LightBlue,
unfocused_color: Color::Gray,
},
];
impl Theme {
pub fn dir_color(&self) -> Color {
match self {
Theme::Default => Color::Blue,
Theme::Compatible => Color::Blue,
}
}
pub fn cmd_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(204, 224, 208),
Theme::Compatible => Color::LightGreen,
}
}
pub fn tab_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(255, 255, 85),
Theme::Compatible => Color::Yellow,
}
}
pub fn dir_icon(&self) -> &'static str {
match self {
Theme::Default => "",
Theme::Compatible => "[DIR]",
}
}
pub fn cmd_icon(&self) -> &'static str {
match self {
Theme::Default => "",
Theme::Compatible => "[CMD]",
}
}
pub fn tab_icon(&self) -> &'static str {
match self {
Theme::Default => "",
Theme::Compatible => ">> ",
}
}
pub fn success_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(199, 55, 44),
Theme::Compatible => Color::Green,
}
}
pub fn fail_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(5, 255, 55),
Theme::Compatible => Color::Red,
}
}
pub fn focused_color(&self) -> Color {
match self {
Theme::Default => Color::LightBlue,
Theme::Compatible => Color::LightBlue,
}
}
pub fn unfocused_color(&self) -> Color {
match self {
Theme::Default => Color::Gray,
Theme::Compatible => Color::Gray,
}
}
}
impl Theme {
#[allow(unused)]
pub fn next(self) -> Self {
let position = self as usize;
let types = Theme::value_variants();
types[(position + 1) % types.len()].into()
}
#[allow(unused)]
pub fn prev(self) -> Self {
let position = self as usize;
let types = Theme::value_variants();
types[(position + types.len() - 1) % types.len()].into()
}
}