use crate::TcaTheme;
use ratatui::{
buffer::Buffer,
layout::{Constraint, Layout, Rect},
style::{Style, Stylize},
text::Line,
widgets::{Block, Borders, Paragraph, Widget, Wrap},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColorPicker<'a> {
theme: &'a TcaTheme,
title: Option<String>,
instructions: Option<String>,
}
impl<'a> ColorPicker<'a> {
pub const fn new(theme: &'a TcaTheme) -> Self {
Self {
theme,
title: None,
instructions: None,
}
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
self.instructions = Some(instructions.into());
self
}
}
impl Widget for ColorPicker<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
let theme = self.theme;
let border_color = theme.ui.border_primary;
let title_color = theme.ui.fg_primary;
let bg = theme.ui.bg_primary;
let fg = theme.ui.fg_primary;
let mut block = Block::bordered()
.bg(bg)
.fg(fg)
.borders(Borders::ALL)
.border_style(Style::default().fg(border_color))
.title_style(Style::default().fg(title_color));
if let Some(title) = self.title {
block = block.title(Line::from(title).centered());
}
if let Some(instructions) = self.instructions {
block = block.title_bottom(Line::from(instructions).centered());
}
let inner = block.inner(area);
block.render(area, buf);
let chunks = Layout::horizontal([
Constraint::Percentage(40),
Constraint::Percentage(30),
Constraint::Percentage(30),
])
.split(inner);
let mut left_lines = vec![Line::from(format!("Theme: {}", theme.meta.name))
.style(Style::default().fg(title_color))];
if !theme.meta.author.is_empty() {
left_lines.push(Line::from(format!("Author: {}", theme.meta.author)));
}
left_lines.push(Line::from(""));
left_lines.push(Line::from("ANSI Colors:"));
left_lines.extend([
Line::from(" black").style(Style::default().fg(theme.ansi.black)),
Line::from(" red").style(Style::default().fg(theme.ansi.red)),
Line::from(" green").style(Style::default().fg(theme.ansi.green)),
Line::from(" yellow").style(Style::default().fg(theme.ansi.yellow)),
Line::from(" blue").style(Style::default().fg(theme.ansi.blue)),
Line::from(" magenta").style(Style::default().fg(theme.ansi.magenta)),
Line::from(" cyan").style(Style::default().fg(theme.ansi.cyan)),
Line::from(" white").style(Style::default().fg(theme.ansi.white)),
Line::from(" bright_black").style(Style::default().fg(theme.ansi.bright_black)),
Line::from(" bright_red").style(Style::default().fg(theme.ansi.bright_red)),
Line::from(" bright_green").style(Style::default().fg(theme.ansi.bright_green)),
Line::from(" bright_yellow").style(Style::default().fg(theme.ansi.bright_yellow)),
Line::from(" bright_blue").style(Style::default().fg(theme.ansi.bright_blue)),
Line::from(" bright_magenta").style(Style::default().fg(theme.ansi.bright_magenta)),
Line::from(" bright_cyan").style(Style::default().fg(theme.ansi.bright_cyan)),
Line::from(" bright_white").style(Style::default().fg(theme.ansi.bright_white)),
]);
let mut center_lines = vec![Line::from("Semantic Colors:")];
center_lines.extend([
Line::from(" error").style(Style::default().fg(theme.semantic.error)),
Line::from(" warning").style(Style::default().fg(theme.semantic.warning)),
Line::from(" success").style(Style::default().fg(theme.semantic.success)),
Line::from(" info").style(Style::default().fg(theme.semantic.info)),
Line::from(" highlight").style(Style::default().fg(theme.semantic.highlight)),
Line::from(" link").style(Style::default().fg(theme.semantic.link)),
]);
center_lines.push(Line::from(""));
center_lines.push(Line::from("UI Colors:"));
center_lines.extend([
Line::from(" bg_primary").style(
Style::default()
.fg(theme.ui.bg_primary)
.bg(theme.ui.fg_primary),
),
Line::from(" bg_secondary").style(
Style::default()
.fg(theme.ui.bg_secondary)
.bg(theme.ui.fg_primary),
),
Line::from(" fg_primary").style(Style::default().fg(theme.ui.fg_primary)),
Line::from(" fg_secondary").style(Style::default().fg(theme.ui.fg_secondary)),
Line::from(" fg_muted").style(Style::default().fg(theme.ui.fg_muted)),
Line::from(" border_primary").style(Style::default().fg(theme.ui.border_primary)),
Line::from(" border_muted").style(Style::default().fg(theme.ui.border_muted)),
Line::from(" cursor_primary").style(Style::default().bg(theme.ui.cursor_primary)),
Line::from(" cursor_muted").style(Style::default().bg(theme.ui.cursor_muted)),
Line::from(" selection_bg").style(
Style::default()
.bg(theme.ui.selection_bg)
.fg(theme.ui.fg_primary),
),
Line::from(" selection_fg").style(Style::default().fg(theme.ui.selection_fg)),
]);
let mut right_lines = vec![Line::from("Base24 Slots:")];
let slot_names = [
"base00", "base01", "base02", "base03", "base04", "base05", "base06", "base07",
"base08", "base09", "base0a", "base0b", "base0c", "base0d", "base0e", "base0f",
"base10", "base11", "base12", "base13", "base14", "base15", "base16", "base17",
];
for (i, name) in slot_names.iter().enumerate() {
right_lines.push(
Line::from(format!(" {}", name)).style(Style::default().fg(theme.base24[i])),
);
}
Paragraph::new(left_lines)
.wrap(Wrap { trim: false })
.render(chunks[0], buf);
Paragraph::new(center_lines).render(chunks[1], buf);
Paragraph::new(right_lines).render(chunks[2], buf);
}
}