use ratatui::style::Color;
static COLOR_RX: Color = Color::Rgb(255, 233, 193);
static COLOR_TX: Color = Color::Rgb(205, 140, 140);
macro_rules! optional_config_struct {
($($struct_name:ident, $($key_name:ident),*);*) => {
$(
#[derive(Debug, serde::Deserialize, Clone, PartialEq, Eq)]
struct $struct_name {
$(
$key_name: Option<String>,
)*
}
)*
};
}
macro_rules! config_struct {
($($struct_name:ident, $($key_name:ident),*);*) => {
$(
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub struct $struct_name {
$(
pub $key_name: Color,
)*
}
)*
};
}
impl AppColors {
fn map_color(color_str: Option<&str>, setter: &mut Color) {
color_str.map(|i| i.parse::<Color>().map(|i| *setter = i));
}
}
impl From<Option<ConfigColors>> for AppColors {
#[allow(clippy::too_many_lines)]
fn from(value: Option<ConfigColors>) -> Self {
let mut app_colors = Self::new();
if let Some(config_colors) = value {
if let Some(hb) = config_colors.headers_bar {
Self::map_color(
hb.background.as_deref(),
&mut app_colors.headers_bar.background,
);
Self::map_color(
hb.loading_spinner.as_deref(),
&mut app_colors.headers_bar.loading_spinner,
);
Self::map_color(hb.text.as_deref(), &mut app_colors.headers_bar.text);
Self::map_color(
hb.text_selected.as_deref(),
&mut app_colors.headers_bar.text_selected,
);
}
if let Some(b) = config_colors.borders {
Self::map_color(b.selected.as_deref(), &mut app_colors.borders.selected);
Self::map_color(b.unselected.as_deref(), &mut app_colors.borders.unselected);
}
if let Some(ep) = config_colors.popup_error {
Self::map_color(
ep.background.as_deref(),
&mut app_colors.popup_error.background,
);
Self::map_color(ep.text.as_deref(), &mut app_colors.popup_error.text);
}
if let Some(fc) = config_colors.filter {
Self::map_color(fc.background.as_deref(), &mut app_colors.filter.background);
Self::map_color(fc.highlight.as_deref(), &mut app_colors.filter.highlight);
Self::map_color(
fc.selected_filter_background.as_deref(),
&mut app_colors.filter.selected_filter_background,
);
Self::map_color(
fc.selected_filter_text.as_deref(),
&mut app_colors.filter.selected_filter_text,
);
Self::map_color(fc.text.as_deref(), &mut app_colors.filter.text);
}
if let Some(ls) = config_colors.log_search {
Self::map_color(
ls.background.as_deref(),
&mut app_colors.log_search.background,
);
Self::map_color(
ls.highlight.as_deref(),
&mut app_colors.log_search.highlight,
);
Self::map_color(
ls.button_text.as_deref(),
&mut app_colors.log_search.button_text,
);
Self::map_color(ls.text.as_deref(), &mut app_colors.log_search.text);
}
if let Some(hp) = config_colors.popup_help {
Self::map_color(
hp.background.as_deref(),
&mut app_colors.popup_help.background,
);
Self::map_color(hp.text.as_deref(), &mut app_colors.popup_help.text);
Self::map_color(
hp.text_highlight.as_deref(),
&mut app_colors.popup_help.text_highlight,
);
}
if let Some(ip) = config_colors.popup_info {
Self::map_color(
ip.background.as_deref(),
&mut app_colors.popup_info.background,
);
Self::map_color(ip.text.as_deref(), &mut app_colors.popup_info.text);
}
if let Some(dp) = config_colors.popup_delete {
Self::map_color(
dp.background.as_deref(),
&mut app_colors.popup_delete.background,
);
Self::map_color(dp.text.as_deref(), &mut app_colors.popup_delete.text);
Self::map_color(
dp.text_highlight.as_deref(),
&mut app_colors.popup_delete.text_highlight,
);
}
if let Some(cc) = config_colors.chart_cpu {
Self::map_color(
cc.background.as_deref(),
&mut app_colors.chart_cpu.background,
);
Self::map_color(cc.border.as_deref(), &mut app_colors.chart_cpu.border);
Self::map_color(cc.max.as_deref(), &mut app_colors.chart_cpu.max);
Self::map_color(cc.points.as_deref(), &mut app_colors.chart_cpu.points);
Self::map_color(cc.title.as_deref(), &mut app_colors.chart_cpu.title);
Self::map_color(cc.y_axis.as_deref(), &mut app_colors.chart_cpu.y_axis);
}
if let Some(cm) = config_colors.chart_memory {
Self::map_color(
cm.background.as_deref(),
&mut app_colors.chart_memory.background,
);
Self::map_color(cm.border.as_deref(), &mut app_colors.chart_memory.border);
Self::map_color(cm.max.as_deref(), &mut app_colors.chart_memory.max);
Self::map_color(cm.points.as_deref(), &mut app_colors.chart_memory.points);
Self::map_color(cm.title.as_deref(), &mut app_colors.chart_memory.title);
Self::map_color(cm.y_axis.as_deref(), &mut app_colors.chart_memory.y_axis);
}
if let Some(cp) = config_colors.chart_ports {
Self::map_color(
cp.background.as_deref(),
&mut app_colors.chart_ports.background,
);
Self::map_color(cp.border.as_deref(), &mut app_colors.chart_ports.border);
Self::map_color(cp.headings.as_deref(), &mut app_colors.chart_ports.headings);
Self::map_color(cp.text.as_deref(), &mut app_colors.chart_ports.text);
Self::map_color(cp.title.as_deref(), &mut app_colors.chart_ports.title);
}
if let Some(c) = config_colors.containers {
Self::map_color(
c.background.as_deref(),
&mut app_colors.containers.background,
);
Self::map_color(c.icon.as_deref(), &mut app_colors.containers.icon);
Self::map_color(c.text.as_deref(), &mut app_colors.containers.text);
Self::map_color(c.text_rx.as_deref(), &mut app_colors.containers.text_rx);
Self::map_color(c.text_tx.as_deref(), &mut app_colors.containers.text_tx);
}
if let Some(cc) = config_colors.commands {
Self::map_color(
cc.background.as_deref(),
&mut app_colors.commands.background,
);
Self::map_color(cc.pause.as_deref(), &mut app_colors.commands.pause);
Self::map_color(cc.restart.as_deref(), &mut app_colors.commands.restart);
Self::map_color(cc.stop.as_deref(), &mut app_colors.commands.stop);
Self::map_color(cc.delete.as_deref(), &mut app_colors.commands.start);
Self::map_color(cc.resume.as_deref(), &mut app_colors.commands.resume);
Self::map_color(cc.start.as_deref(), &mut app_colors.commands.start);
}
if let Some(cl) = config_colors.logs {
Self::map_color(cl.background.as_deref(), &mut app_colors.logs.background);
Self::map_color(cl.text.as_deref(), &mut app_colors.logs.text);
}
if let Some(cs) = config_colors.container_state {
Self::map_color(cs.dead.as_deref(), &mut app_colors.container_state.dead);
Self::map_color(cs.exited.as_deref(), &mut app_colors.container_state.exited);
Self::map_color(cs.paused.as_deref(), &mut app_colors.container_state.paused);
Self::map_color(
cs.removing.as_deref(),
&mut app_colors.container_state.removing,
);
Self::map_color(
cs.restarting.as_deref(),
&mut app_colors.container_state.restarting,
);
Self::map_color(
cs.running_healthy.as_deref(),
&mut app_colors.container_state.running_healthy,
);
Self::map_color(
cs.running_unhealthy.as_deref(),
&mut app_colors.container_state.running_unhealthy,
);
Self::map_color(
cs.unknown.as_deref(),
&mut app_colors.container_state.unknown,
);
}
}
app_colors
}
}
const ORANGE: Color = Color::Rgb(255, 178, 36);
optional_config_struct!(
ConfigBackgroundText, background, text;
ConfigBackgroundTextHighlight, background, text, text_highlight;
ConfigBorders, selected, unselected;
ConfigChartBandwidth, background, border, max_rx, max_tx, title_tx, title_rx, points_rx, points_tx, y_axis;
ConfigChartCpu, background, border, order, title, max, points,y_axis;
ConfigChartMemory, background, border, title, max, points, y_axis;
ConfigChartPorts, background, border, title, headings, text;
ConfigCommands, background, pause, restart, stop, delete, resume, start;
ConfigContainers, background, icon, text, text_rx, text_tx;
ConfigContainerState, background, dead, exited, paused, removing, restarting, running_healthy, running_unhealthy, unknown;
ConfigFilter, background, text, selected_filter_background, selected_filter_text, highlight;
ConfigLogSearch, background, text, button_text, highlight;
ConfigHeadersBar, background, loading_spinner, text, text_selected;
ConfigLogs, background, text
);
config_struct!(
Borders, selected, unselected;
ChartCpu, background, border, title, max, points, y_axis;
ChartMemory, background, border, title, max, points, y_axis;
ChartBandwidth, background, border, max_rx, max_tx, title_rx, title_tx, points_rx, points_tx, y_axis;
ChartPorts, background, border, title, headings, text;
Commands, background, pause, restart, stop, delete, resume, start;
Containers, background, icon, text, text_rx, text_tx;
ContainerState, dead, exited, paused, removing, restarting, running_healthy, running_unhealthy, unknown;
Filter, background, text, selected_filter_background, selected_filter_text, highlight;
LogSearch, background, text, button_text, highlight;
HeadersBar, background, text_selected, loading_spinner, text;
Logs, background, text;
PopupDelete, background, text, text_highlight;
PopupError, background, text;
PopupHelp, background, text, text_highlight;
PopupInfo, background, text
);
#[derive(Debug, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct ConfigColors {
borders: Option<ConfigBorders>,
chart_cpu: Option<ConfigChartCpu>,
chart_memory: Option<ConfigChartMemory>,
chart_bandwidth: Option<ConfigChartBandwidth>,
chart_ports: Option<ConfigChartPorts>,
commands: Option<ConfigCommands>,
container_state: Option<ConfigContainerState>,
containers: Option<ConfigContainers>,
filter: Option<ConfigFilter>,
log_search: Option<ConfigLogSearch>,
headers_bar: Option<ConfigHeadersBar>,
logs: Option<ConfigLogs>,
popup_delete: Option<ConfigBackgroundTextHighlight>,
popup_error: Option<ConfigBackgroundText>,
popup_help: Option<ConfigBackgroundTextHighlight>,
popup_info: Option<ConfigBackgroundText>,
}
impl HeadersBar {
const fn new() -> Self {
Self {
background: Color::Magenta,
loading_spinner: Color::White,
text: Color::Black,
text_selected: Color::Gray,
}
}
}
impl Borders {
const fn new() -> Self {
Self {
selected: Color::LightCyan,
unselected: Color::Gray,
}
}
}
impl Commands {
const fn new() -> Self {
Self {
background: Color::Reset,
pause: Color::Yellow,
restart: Color::Magenta,
stop: Color::Red,
delete: Color::Gray,
resume: Color::Blue,
start: Color::Green,
}
}
}
impl ChartBandwidth {
const fn new() -> Self {
Self {
background: Color::Reset,
border: Color::White,
max_rx: COLOR_RX,
title_rx: COLOR_RX,
title_tx: COLOR_TX,
max_tx: COLOR_TX,
points_rx: COLOR_RX,
points_tx: COLOR_TX,
y_axis: Color::White,
}
}
}
impl ChartCpu {
const fn new() -> Self {
Self {
background: Color::Reset,
border: Color::White,
title: Color::Green,
max: ORANGE,
points: Color::Magenta,
y_axis: Color::White,
}
}
}
impl ChartMemory {
const fn new() -> Self {
Self {
background: Color::Reset,
border: Color::White,
title: Color::Green,
max: ORANGE,
points: Color::Cyan,
y_axis: Color::White,
}
}
}
impl ChartPorts {
const fn new() -> Self {
Self {
background: Color::Reset,
border: Color::White,
title: Color::Green,
headings: Color::Yellow,
text: Color::White,
}
}
}
impl Containers {
const fn new() -> Self {
Self {
background: Color::Reset,
icon: Color::White,
text: Color::Blue,
text_rx: COLOR_RX,
text_tx: COLOR_TX,
}
}
}
impl ContainerState {
const fn new() -> Self {
Self {
paused: Color::Yellow,
removing: Color::LightRed,
restarting: Color::LightGreen,
running_healthy: Color::Green,
running_unhealthy: ORANGE,
dead: Color::Red,
exited: Color::Red,
unknown: Color::Red,
}
}
}
impl Filter {
const fn new() -> Self {
Self {
background: Color::Reset,
highlight: Color::Magenta,
selected_filter_background: Color::Gray,
selected_filter_text: Color::Black,
text: Color::Gray,
}
}
}
impl LogSearch {
const fn new() -> Self {
Self {
background: Color::Reset,
highlight: Color::Magenta,
button_text: Color::Black,
text: Color::Gray,
}
}
}
impl Logs {
const fn new() -> Self {
Self {
background: Color::Reset,
text: Color::Reset,
}
}
}
impl PopupError {
const fn new() -> Self {
Self {
background: Color::Red,
text: Color::White,
}
}
}
impl PopupInfo {
const fn new() -> Self {
Self {
background: Color::Blue,
text: Color::White,
}
}
}
impl PopupHelp {
const fn new() -> Self {
Self {
background: Color::Magenta,
text: Color::Black,
text_highlight: Color::White,
}
}
}
impl PopupDelete {
const fn new() -> Self {
Self {
background: Color::White,
text: Color::Black,
text_highlight: Color::Red,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub struct AppColors {
pub borders: Borders,
pub chart_cpu: ChartCpu,
pub chart_memory: ChartMemory,
pub chart_bandwidth: ChartBandwidth,
pub chart_ports: ChartPorts,
pub commands: Commands,
pub container_state: ContainerState,
pub containers: Containers,
pub log_search: LogSearch,
pub filter: Filter,
pub headers_bar: HeadersBar,
pub logs: Logs,
pub popup_delete: PopupDelete,
pub popup_error: PopupError,
pub popup_help: PopupHelp,
pub popup_info: PopupInfo,
}
impl AppColors {
pub const fn new() -> Self {
Self {
borders: Borders::new(),
chart_cpu: ChartCpu::new(),
chart_memory: ChartMemory::new(),
chart_bandwidth: ChartBandwidth::new(),
chart_ports: ChartPorts::new(),
commands: Commands::new(),
container_state: ContainerState::new(),
containers: Containers::new(),
log_search: LogSearch::new(),
filter: Filter::new(),
headers_bar: HeadersBar::new(),
logs: Logs::new(),
popup_delete: PopupDelete::new(),
popup_error: PopupError::new(),
popup_help: PopupHelp::new(),
popup_info: PopupInfo::new(),
}
}
}