Monster commit: native version
This commit is contained in:
@@ -5,6 +5,6 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8"
|
||||
ratatui = "0.29"
|
||||
ratatui = "0.30"
|
||||
regex = "1"
|
||||
tui-textarea = { version = "0.7", features = ["search"] }
|
||||
tui-textarea = { git = "https://github.com/phsym/tui-textarea", branch = "main", features = ["search"] }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::theme::confirm;
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::Frame;
|
||||
@@ -25,7 +26,7 @@ impl<'a> ConfirmModal<'a> {
|
||||
let inner = ModalFrame::new(self.title)
|
||||
.width(30)
|
||||
.height(5)
|
||||
.border_color(Color::Yellow)
|
||||
.border_color(confirm::BORDER)
|
||||
.render_centered(frame, term);
|
||||
|
||||
let rows = Layout::vertical([Constraint::Length(1), Constraint::Length(1)]).split(inner);
|
||||
@@ -36,12 +37,12 @@ impl<'a> ConfirmModal<'a> {
|
||||
);
|
||||
|
||||
let yes_style = if self.selected {
|
||||
Style::new().fg(Color::Black).bg(Color::Yellow)
|
||||
Style::new().fg(confirm::BUTTON_SELECTED_FG).bg(confirm::BUTTON_SELECTED_BG)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
let no_style = if !self.selected {
|
||||
Style::new().fg(Color::Black).bg(Color::Yellow)
|
||||
Style::new().fg(confirm::BUTTON_SELECTED_FG).bg(confirm::BUTTON_SELECTED_BG)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::theme::editor_widget;
|
||||
use ratatui::{
|
||||
layout::Rect,
|
||||
style::{Color, Modifier, Style},
|
||||
style::{Modifier, Style},
|
||||
text::{Line, Span},
|
||||
widgets::{Clear, Paragraph},
|
||||
Frame,
|
||||
@@ -333,8 +334,8 @@ impl Editor {
|
||||
|
||||
pub fn render(&self, frame: &mut Frame, area: Rect, highlighter: Highlighter) {
|
||||
let (cursor_row, cursor_col) = self.text.cursor();
|
||||
let cursor_style = Style::default().bg(Color::White).fg(Color::Black);
|
||||
let selection_style = Style::default().bg(Color::Rgb(60, 80, 120));
|
||||
let cursor_style = Style::default().bg(editor_widget::CURSOR_BG).fg(editor_widget::CURSOR_FG);
|
||||
let selection_style = Style::default().bg(editor_widget::SELECTION_BG);
|
||||
|
||||
let selection = self.text.selection_range();
|
||||
|
||||
@@ -412,9 +413,9 @@ impl Editor {
|
||||
let list_area = Rect::new(popup_x, popup_y, list_width, total_height);
|
||||
frame.render_widget(Clear, list_area);
|
||||
|
||||
let highlight_style = Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD);
|
||||
let normal_style = Style::default().fg(Color::White);
|
||||
let bg_style = Style::default().bg(Color::Rgb(30, 30, 40));
|
||||
let highlight_style = Style::default().fg(editor_widget::COMPLETION_SELECTED).add_modifier(Modifier::BOLD);
|
||||
let normal_style = Style::default().fg(editor_widget::COMPLETION_FG);
|
||||
let bg_style = Style::default().bg(editor_widget::COMPLETION_BG);
|
||||
|
||||
let list_lines: Vec<Line> = (scroll_offset..scroll_offset + visible_count)
|
||||
.map(|i| {
|
||||
@@ -427,7 +428,7 @@ impl Editor {
|
||||
};
|
||||
let prefix = if i == self.completion.cursor { "> " } else { " " };
|
||||
let display = format!("{prefix}{name:<width$}", width = list_width as usize - 2);
|
||||
Line::from(Span::styled(display, style.bg(Color::Rgb(30, 30, 40))))
|
||||
Line::from(Span::styled(display, style.bg(editor_widget::COMPLETION_BG)))
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -450,15 +451,15 @@ impl Editor {
|
||||
let candidate = &self.completion.candidates[selected_idx];
|
||||
|
||||
let name_style = Style::default()
|
||||
.fg(Color::Yellow)
|
||||
.fg(editor_widget::COMPLETION_SELECTED)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
.bg(Color::Rgb(30, 30, 40));
|
||||
.bg(editor_widget::COMPLETION_BG);
|
||||
let desc_style = Style::default()
|
||||
.fg(Color::White)
|
||||
.bg(Color::Rgb(30, 30, 40));
|
||||
.fg(editor_widget::COMPLETION_FG)
|
||||
.bg(editor_widget::COMPLETION_BG);
|
||||
let example_style = Style::default()
|
||||
.fg(Color::Rgb(120, 200, 160))
|
||||
.bg(Color::Rgb(30, 30, 40));
|
||||
.fg(editor_widget::COMPLETION_EXAMPLE)
|
||||
.bg(editor_widget::COMPLETION_BG);
|
||||
|
||||
let w = doc_width as usize;
|
||||
let mut doc_lines: Vec<Line> = Vec::new();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::theme::{browser, input, ui};
|
||||
use ratatui::style::Color;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::Frame;
|
||||
@@ -25,7 +27,7 @@ impl<'a> FileBrowserModal<'a> {
|
||||
entries,
|
||||
selected: 0,
|
||||
scroll_offset: 0,
|
||||
border_color: Color::White,
|
||||
border_color: ui::TEXT_PRIMARY,
|
||||
width: 60,
|
||||
height: 16,
|
||||
}
|
||||
@@ -69,8 +71,8 @@ impl<'a> FileBrowserModal<'a> {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
Span::raw("> "),
|
||||
Span::styled(self.input, Style::new().fg(Color::Cyan)),
|
||||
Span::styled("█", Style::new().fg(Color::White)),
|
||||
Span::styled(self.input, Style::new().fg(input::TEXT)),
|
||||
Span::styled("█", Style::new().fg(input::CURSOR)),
|
||||
])),
|
||||
rows[0],
|
||||
);
|
||||
@@ -95,13 +97,13 @@ impl<'a> FileBrowserModal<'a> {
|
||||
format!("{prefix}{name}")
|
||||
};
|
||||
let color = if is_selected {
|
||||
Color::Yellow
|
||||
browser::SELECTED
|
||||
} else if *is_dir {
|
||||
Color::Blue
|
||||
browser::DIRECTORY
|
||||
} else if *is_cagire {
|
||||
Color::Magenta
|
||||
browser::PROJECT_FILE
|
||||
} else {
|
||||
Color::White
|
||||
browser::FILE
|
||||
};
|
||||
Line::from(Span::styled(display, Style::new().fg(color)))
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ mod scope;
|
||||
mod sparkles;
|
||||
mod spectrum;
|
||||
mod text_input;
|
||||
pub mod theme;
|
||||
mod vu_meter;
|
||||
|
||||
pub use confirm::ConfirmModal;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::theme::{hint, ui};
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::style::{Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::Frame;
|
||||
@@ -50,10 +51,10 @@ impl<'a> ListSelect<'a> {
|
||||
}
|
||||
|
||||
pub fn render(self, frame: &mut Frame, area: Rect) {
|
||||
let cursor_style = Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD);
|
||||
let selected_style = Style::new().fg(Color::Cyan);
|
||||
let cursor_style = Style::new().fg(hint::KEY).add_modifier(Modifier::BOLD);
|
||||
let selected_style = Style::new().fg(ui::ACCENT);
|
||||
let normal_style = Style::default();
|
||||
let indicator_style = Style::new().fg(Color::DarkGray);
|
||||
let indicator_style = Style::new().fg(ui::TEXT_DIM);
|
||||
|
||||
let visible_end = (self.scroll_offset + self.visible_count).min(self.items.len());
|
||||
let has_above = self.scroll_offset > 0;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::theme::ui;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::widgets::{Block, Borders, Clear};
|
||||
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
|
||||
use ratatui::Frame;
|
||||
|
||||
pub struct ModalFrame<'a> {
|
||||
@@ -16,7 +17,7 @@ impl<'a> ModalFrame<'a> {
|
||||
title,
|
||||
width: 40,
|
||||
height: 5,
|
||||
border_color: Color::White,
|
||||
border_color: ui::TEXT_PRIMARY,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +46,16 @@ impl<'a> ModalFrame<'a> {
|
||||
|
||||
frame.render_widget(Clear, area);
|
||||
|
||||
// Fill background with theme color
|
||||
let bg_fill = " ".repeat(area.width as usize);
|
||||
for row in 0..area.height {
|
||||
let line_area = Rect::new(area.x, area.y + row, area.width, 1);
|
||||
frame.render_widget(
|
||||
Paragraph::new(bg_fill.clone()).style(Style::new().bg(ui::BG)),
|
||||
line_area,
|
||||
);
|
||||
}
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(self.title)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::theme::{nav, ui};
|
||||
use ratatui::layout::{Alignment, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::widgets::{Clear, Paragraph};
|
||||
use ratatui::Frame;
|
||||
|
||||
@@ -48,6 +49,16 @@ impl<'a> NavMinimap<'a> {
|
||||
|
||||
frame.render_widget(Clear, area);
|
||||
|
||||
// Fill background with theme color
|
||||
let bg_fill = " ".repeat(area.width as usize);
|
||||
for row in 0..area.height {
|
||||
let line_area = Rect::new(area.x, area.y + row, area.width, 1);
|
||||
frame.render_widget(
|
||||
Paragraph::new(bg_fill.clone()).style(Style::new().bg(ui::BG)),
|
||||
line_area,
|
||||
);
|
||||
}
|
||||
|
||||
let inner_x = area.x + pad;
|
||||
let inner_y = area.y + pad;
|
||||
|
||||
@@ -62,9 +73,9 @@ impl<'a> NavMinimap<'a> {
|
||||
|
||||
fn render_tile(&self, frame: &mut Frame, area: Rect, label: &str, is_selected: bool) {
|
||||
let (bg, fg) = if is_selected {
|
||||
(Color::Rgb(50, 90, 110), Color::White)
|
||||
(nav::SELECTED_BG, nav::SELECTED_FG)
|
||||
} else {
|
||||
(Color::Rgb(30, 35, 45), Color::Rgb(100, 105, 115))
|
||||
(nav::UNSELECTED_BG, nav::UNSELECTED_FG)
|
||||
};
|
||||
|
||||
// Fill background
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::theme::{browser, search};
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::style::{Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Paragraph};
|
||||
use ratatui::Frame;
|
||||
@@ -59,9 +60,9 @@ impl<'a> SampleBrowser<'a> {
|
||||
|
||||
pub fn render(self, frame: &mut Frame, area: Rect) {
|
||||
let border_style = if self.focused {
|
||||
Style::new().fg(Color::Yellow)
|
||||
Style::new().fg(browser::FOCUSED_BORDER)
|
||||
} else {
|
||||
Style::new().fg(Color::DarkGray)
|
||||
Style::new().fg(browser::UNFOCUSED_BORDER)
|
||||
};
|
||||
|
||||
let block = Block::default()
|
||||
@@ -96,9 +97,9 @@ impl<'a> SampleBrowser<'a> {
|
||||
|
||||
fn render_search(&self, frame: &mut Frame, area: Rect) {
|
||||
let style = if self.search_active {
|
||||
Style::new().fg(Color::Yellow)
|
||||
Style::new().fg(search::ACTIVE)
|
||||
} else {
|
||||
Style::new().fg(Color::DarkGray)
|
||||
Style::new().fg(search::INACTIVE)
|
||||
};
|
||||
let cursor = if self.search_active { "_" } else { "" };
|
||||
let text = format!("/{}{}", self.search_query, cursor);
|
||||
@@ -114,7 +115,7 @@ impl<'a> SampleBrowser<'a> {
|
||||
} else {
|
||||
"No matches"
|
||||
};
|
||||
let line = Line::from(Span::styled(msg, Style::new().fg(Color::DarkGray)));
|
||||
let line = Line::from(Span::styled(msg, Style::new().fg(browser::EMPTY_TEXT)));
|
||||
frame.render_widget(Paragraph::new(vec![line]), area);
|
||||
return;
|
||||
}
|
||||
@@ -129,23 +130,23 @@ impl<'a> SampleBrowser<'a> {
|
||||
|
||||
let (icon, icon_color) = match entry.kind {
|
||||
TreeLineKind::Root { expanded: true } | TreeLineKind::Folder { expanded: true } => {
|
||||
("\u{25BC} ", Color::Cyan)
|
||||
("\u{25BC} ", browser::FOLDER_ICON)
|
||||
}
|
||||
TreeLineKind::Root { expanded: false }
|
||||
| TreeLineKind::Folder { expanded: false } => ("\u{25B6} ", Color::Cyan),
|
||||
TreeLineKind::File => ("\u{266A} ", Color::DarkGray),
|
||||
| TreeLineKind::Folder { expanded: false } => ("\u{25B6} ", browser::FOLDER_ICON),
|
||||
TreeLineKind::File => ("\u{266A} ", browser::FILE_ICON),
|
||||
};
|
||||
|
||||
let label_style = if is_cursor && self.focused {
|
||||
Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD)
|
||||
Style::new().fg(browser::SELECTED).add_modifier(Modifier::BOLD)
|
||||
} else if is_cursor {
|
||||
Style::new().fg(Color::White)
|
||||
Style::new().fg(browser::FILE)
|
||||
} else {
|
||||
match entry.kind {
|
||||
TreeLineKind::Root { .. } => {
|
||||
Style::new().fg(Color::White).add_modifier(Modifier::BOLD)
|
||||
Style::new().fg(browser::ROOT).add_modifier(Modifier::BOLD)
|
||||
}
|
||||
TreeLineKind::Folder { .. } => Style::new().fg(Color::Cyan),
|
||||
TreeLineKind::Folder { .. } => Style::new().fg(browser::DIRECTORY),
|
||||
TreeLineKind::File => Style::default(),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::theme::meter;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::Color;
|
||||
@@ -26,7 +27,7 @@ impl<'a> Scope<'a> {
|
||||
Self {
|
||||
data,
|
||||
orientation: Orientation::Horizontal,
|
||||
color: Color::Green,
|
||||
color: meter::LOW,
|
||||
gain: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::theme::sparkle;
|
||||
use rand::Rng;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
@@ -5,13 +6,6 @@ use ratatui::style::{Color, Style};
|
||||
use ratatui::widgets::Widget;
|
||||
|
||||
const CHARS: &[char] = &['·', '✦', '✧', '°', '•', '+', '⋆', '*'];
|
||||
const COLORS: &[(u8, u8, u8)] = &[
|
||||
(200, 220, 255),
|
||||
(255, 200, 150),
|
||||
(150, 255, 200),
|
||||
(255, 150, 200),
|
||||
(200, 150, 255),
|
||||
];
|
||||
|
||||
struct Sparkle {
|
||||
x: u16,
|
||||
@@ -47,17 +41,17 @@ impl Sparkles {
|
||||
|
||||
impl Widget for &Sparkles {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
for sparkle in &self.sparkles {
|
||||
let color = COLORS[sparkle.char_idx % COLORS.len()];
|
||||
let intensity = (sparkle.life as f32 / 30.0).min(1.0);
|
||||
for sp in &self.sparkles {
|
||||
let color = sparkle::COLORS[sp.char_idx % sparkle::COLORS.len()];
|
||||
let intensity = (sp.life as f32 / 30.0).min(1.0);
|
||||
let r = (color.0 as f32 * intensity) as u8;
|
||||
let g = (color.1 as f32 * intensity) as u8;
|
||||
let b = (color.2 as f32 * intensity) as u8;
|
||||
|
||||
if sparkle.x < area.width && sparkle.y < area.height {
|
||||
let x = area.x + sparkle.x;
|
||||
let y = area.y + sparkle.y;
|
||||
let ch = CHARS[sparkle.char_idx];
|
||||
if sp.x < area.width && sp.y < area.height {
|
||||
let x = area.x + sp.x;
|
||||
let y = area.y + sp.y;
|
||||
let ch = CHARS[sp.char_idx];
|
||||
buf[(x, y)].set_char(ch).set_style(Style::new().fg(Color::Rgb(r, g, b)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::theme::meter;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::Color;
|
||||
@@ -39,11 +40,11 @@ impl Widget for Spectrum<'_> {
|
||||
let y = area.y + area.height - 1 - row as u16;
|
||||
let ratio = row as f32 / area.height as f32;
|
||||
let color = if ratio < 0.33 {
|
||||
Color::Rgb(40, 180, 80)
|
||||
Color::Rgb(meter::LOW_RGB.0, meter::LOW_RGB.1, meter::LOW_RGB.2)
|
||||
} else if ratio < 0.66 {
|
||||
Color::Rgb(220, 180, 40)
|
||||
Color::Rgb(meter::MID_RGB.0, meter::MID_RGB.1, meter::MID_RGB.2)
|
||||
} else {
|
||||
Color::Rgb(220, 60, 40)
|
||||
Color::Rgb(meter::HIGH_RGB.0, meter::HIGH_RGB.1, meter::HIGH_RGB.2)
|
||||
};
|
||||
for dx in 0..band_width as u16 {
|
||||
let x = x_start + dx;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::theme::{input, ui};
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
@@ -20,7 +21,7 @@ impl<'a> TextInputModal<'a> {
|
||||
title,
|
||||
input,
|
||||
hint: None,
|
||||
border_color: Color::White,
|
||||
border_color: ui::TEXT_PRIMARY,
|
||||
width: 50,
|
||||
}
|
||||
}
|
||||
@@ -56,15 +57,15 @@ impl<'a> TextInputModal<'a> {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
Span::raw("> "),
|
||||
Span::styled(self.input, Style::new().fg(Color::Cyan)),
|
||||
Span::styled("█", Style::new().fg(Color::White)),
|
||||
Span::styled(self.input, Style::new().fg(input::TEXT)),
|
||||
Span::styled("█", Style::new().fg(input::CURSOR)),
|
||||
])),
|
||||
rows[0],
|
||||
);
|
||||
|
||||
if let Some(hint) = self.hint {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Span::styled(hint, Style::new().fg(Color::DarkGray))),
|
||||
Paragraph::new(Span::styled(hint, Style::new().fg(input::HINT))),
|
||||
rows[1],
|
||||
);
|
||||
}
|
||||
@@ -72,8 +73,8 @@ impl<'a> TextInputModal<'a> {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
Span::raw("> "),
|
||||
Span::styled(self.input, Style::new().fg(Color::Cyan)),
|
||||
Span::styled("█", Style::new().fg(Color::White)),
|
||||
Span::styled(self.input, Style::new().fg(input::TEXT)),
|
||||
Span::styled("█", Style::new().fg(input::CURSOR)),
|
||||
])),
|
||||
inner,
|
||||
);
|
||||
|
||||
377
crates/ratatui/src/theme.rs
Normal file
377
crates/ratatui/src/theme.rs
Normal file
@@ -0,0 +1,377 @@
|
||||
//! Centralized color definitions for Cagire TUI.
|
||||
//! Based on Catppuccin Mocha palette.
|
||||
|
||||
use ratatui::style::Color;
|
||||
|
||||
// Catppuccin Mocha base palette
|
||||
mod palette {
|
||||
use super::*;
|
||||
|
||||
// Backgrounds (dark to light)
|
||||
pub const CRUST: Color = Color::Rgb(17, 17, 27);
|
||||
pub const MANTLE: Color = Color::Rgb(24, 24, 37);
|
||||
pub const BASE: Color = Color::Rgb(30, 30, 46);
|
||||
pub const SURFACE0: Color = Color::Rgb(49, 50, 68);
|
||||
pub const SURFACE1: Color = Color::Rgb(69, 71, 90);
|
||||
pub const SURFACE2: Color = Color::Rgb(88, 91, 112);
|
||||
|
||||
// Overlays
|
||||
pub const OVERLAY0: Color = Color::Rgb(108, 112, 134);
|
||||
pub const OVERLAY1: Color = Color::Rgb(127, 132, 156);
|
||||
pub const OVERLAY2: Color = Color::Rgb(147, 153, 178);
|
||||
|
||||
// Text (dim to bright)
|
||||
pub const SUBTEXT0: Color = Color::Rgb(166, 173, 200);
|
||||
pub const SUBTEXT1: Color = Color::Rgb(186, 194, 222);
|
||||
pub const TEXT: Color = Color::Rgb(205, 214, 244);
|
||||
|
||||
// Accent colors
|
||||
pub const ROSEWATER: Color = Color::Rgb(245, 224, 220);
|
||||
pub const FLAMINGO: Color = Color::Rgb(242, 205, 205);
|
||||
pub const PINK: Color = Color::Rgb(245, 194, 231);
|
||||
pub const MAUVE: Color = Color::Rgb(203, 166, 247);
|
||||
pub const RED: Color = Color::Rgb(243, 139, 168);
|
||||
pub const MAROON: Color = Color::Rgb(235, 160, 172);
|
||||
pub const PEACH: Color = Color::Rgb(250, 179, 135);
|
||||
pub const YELLOW: Color = Color::Rgb(249, 226, 175);
|
||||
pub const GREEN: Color = Color::Rgb(166, 227, 161);
|
||||
pub const TEAL: Color = Color::Rgb(148, 226, 213);
|
||||
pub const SKY: Color = Color::Rgb(137, 220, 235);
|
||||
pub const SAPPHIRE: Color = Color::Rgb(116, 199, 236);
|
||||
pub const BLUE: Color = Color::Rgb(137, 180, 250);
|
||||
pub const LAVENDER: Color = Color::Rgb(180, 190, 254);
|
||||
}
|
||||
|
||||
pub mod ui {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const BG: Color = BASE;
|
||||
pub const BG_RGB: (u8, u8, u8) = (30, 30, 46);
|
||||
pub const TEXT_PRIMARY: Color = TEXT;
|
||||
pub const TEXT_MUTED: Color = SUBTEXT0;
|
||||
pub const TEXT_DIM: Color = OVERLAY1;
|
||||
pub const BORDER: Color = SURFACE1;
|
||||
pub const HEADER: Color = LAVENDER;
|
||||
pub const UNFOCUSED: Color = OVERLAY0;
|
||||
pub const ACCENT: Color = MAUVE;
|
||||
pub const SURFACE: Color = SURFACE0;
|
||||
}
|
||||
|
||||
pub mod status {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const PLAYING_BG: Color = Color::Rgb(30, 50, 40);
|
||||
pub const PLAYING_FG: Color = GREEN;
|
||||
pub const STOPPED_BG: Color = Color::Rgb(50, 30, 40);
|
||||
pub const STOPPED_FG: Color = RED;
|
||||
pub const FILL_ON: Color = GREEN;
|
||||
pub const FILL_OFF: Color = OVERLAY0;
|
||||
pub const FILL_BG: Color = SURFACE0;
|
||||
}
|
||||
|
||||
pub mod selection {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const CURSOR_BG: Color = MAUVE;
|
||||
pub const CURSOR_FG: Color = CRUST;
|
||||
pub const SELECTED_BG: Color = Color::Rgb(60, 60, 90);
|
||||
pub const SELECTED_FG: Color = LAVENDER;
|
||||
pub const IN_RANGE_BG: Color = Color::Rgb(50, 50, 75);
|
||||
pub const IN_RANGE_FG: Color = SUBTEXT1;
|
||||
// Aliases for simpler API
|
||||
pub const CURSOR: Color = CURSOR_BG;
|
||||
pub const SELECTED: Color = SELECTED_BG;
|
||||
pub const IN_RANGE: Color = IN_RANGE_BG;
|
||||
}
|
||||
|
||||
pub mod tile {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const PLAYING_ACTIVE_BG: Color = Color::Rgb(80, 50, 60);
|
||||
pub const PLAYING_ACTIVE_FG: Color = PEACH;
|
||||
pub const PLAYING_INACTIVE_BG: Color = Color::Rgb(70, 55, 45);
|
||||
pub const PLAYING_INACTIVE_FG: Color = YELLOW;
|
||||
pub const ACTIVE_BG: Color = Color::Rgb(40, 55, 55);
|
||||
pub const ACTIVE_FG: Color = TEAL;
|
||||
pub const INACTIVE_BG: Color = SURFACE0;
|
||||
pub const INACTIVE_FG: Color = SUBTEXT0;
|
||||
// Combined states for selected/in-range + active
|
||||
pub const ACTIVE_SELECTED_BG: Color = Color::Rgb(70, 60, 80);
|
||||
pub const ACTIVE_IN_RANGE_BG: Color = Color::Rgb(55, 55, 70);
|
||||
|
||||
// Link colors (derived from palette accents, dimmed for backgrounds)
|
||||
pub const LINK_BRIGHT: [(u8, u8, u8); 5] = [
|
||||
(203, 166, 247), // Mauve
|
||||
(245, 194, 231), // Pink
|
||||
(250, 179, 135), // Peach
|
||||
(137, 220, 235), // Sky
|
||||
(166, 227, 161), // Green
|
||||
];
|
||||
pub const LINK_DIM: [(u8, u8, u8); 5] = [
|
||||
(70, 55, 85), // Mauve dimmed
|
||||
(85, 65, 80), // Pink dimmed
|
||||
(85, 60, 45), // Peach dimmed
|
||||
(45, 75, 80), // Sky dimmed
|
||||
(55, 80, 55), // Green dimmed
|
||||
];
|
||||
}
|
||||
|
||||
pub mod header {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const TEMPO_BG: Color = Color::Rgb(50, 40, 60);
|
||||
pub const TEMPO_FG: Color = MAUVE;
|
||||
pub const BANK_BG: Color = Color::Rgb(35, 50, 55);
|
||||
pub const BANK_FG: Color = SAPPHIRE;
|
||||
pub const PATTERN_BG: Color = Color::Rgb(40, 50, 50);
|
||||
pub const PATTERN_FG: Color = TEAL;
|
||||
pub const STATS_BG: Color = SURFACE0;
|
||||
pub const STATS_FG: Color = SUBTEXT0;
|
||||
}
|
||||
|
||||
pub mod modal {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const BORDER: Color = LAVENDER;
|
||||
pub const BORDER_ACCENT: Color = MAUVE;
|
||||
pub const BORDER_WARN: Color = PEACH;
|
||||
pub const BORDER_DIM: Color = OVERLAY1;
|
||||
// Semantic modal colors
|
||||
pub const CONFIRM: Color = PEACH;
|
||||
pub const RENAME: Color = MAUVE;
|
||||
pub const INPUT: Color = SAPPHIRE;
|
||||
pub const EDITOR: Color = LAVENDER;
|
||||
pub const PREVIEW: Color = OVERLAY1;
|
||||
}
|
||||
|
||||
pub mod flash {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const ERROR_BG: Color = Color::Rgb(50, 30, 40);
|
||||
pub const ERROR_FG: Color = RED;
|
||||
pub const SUCCESS_BG: Color = Color::Rgb(30, 50, 40);
|
||||
pub const SUCCESS_FG: Color = GREEN;
|
||||
pub const INFO_BG: Color = SURFACE0;
|
||||
pub const INFO_FG: Color = TEXT;
|
||||
// Event flash tint (dimmed mauve)
|
||||
pub const EVENT_RGB: (u8, u8, u8) = (55, 45, 70);
|
||||
}
|
||||
|
||||
pub mod list {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const PLAYING_BG: Color = Color::Rgb(35, 55, 45);
|
||||
pub const PLAYING_FG: Color = GREEN;
|
||||
pub const STAGED_PLAY_BG: Color = Color::Rgb(55, 45, 65);
|
||||
pub const STAGED_PLAY_FG: Color = MAUVE;
|
||||
pub const STAGED_STOP_BG: Color = Color::Rgb(60, 40, 50);
|
||||
pub const STAGED_STOP_FG: Color = MAROON;
|
||||
pub const EDIT_BG: Color = Color::Rgb(40, 55, 55);
|
||||
pub const EDIT_FG: Color = TEAL;
|
||||
pub const HOVER_BG: Color = SURFACE1;
|
||||
pub const HOVER_FG: Color = TEXT;
|
||||
}
|
||||
|
||||
pub mod link_status {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const DISABLED: Color = RED;
|
||||
pub const CONNECTED: Color = GREEN;
|
||||
pub const LISTENING: Color = YELLOW;
|
||||
}
|
||||
|
||||
pub mod syntax {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const GAP_BG: Color = MANTLE;
|
||||
pub const EXECUTED_BG: Color = Color::Rgb(45, 40, 55);
|
||||
pub const SELECTED_BG: Color = Color::Rgb(70, 55, 40);
|
||||
|
||||
// (fg, bg) tuples - fg is bright accent, bg is subtle tint
|
||||
pub const EMIT: (Color, Color) = (TEXT, Color::Rgb(80, 50, 60));
|
||||
pub const NUMBER: (Color, Color) = (PEACH, Color::Rgb(55, 45, 35));
|
||||
pub const STRING: (Color, Color) = (GREEN, Color::Rgb(35, 50, 40));
|
||||
pub const COMMENT: (Color, Color) = (OVERLAY1, CRUST);
|
||||
pub const KEYWORD: (Color, Color) = (MAUVE, Color::Rgb(50, 40, 60));
|
||||
pub const STACK_OP: (Color, Color) = (SAPPHIRE, Color::Rgb(35, 45, 55));
|
||||
pub const OPERATOR: (Color, Color) = (YELLOW, Color::Rgb(55, 50, 35));
|
||||
pub const SOUND: (Color, Color) = (TEAL, Color::Rgb(35, 55, 55));
|
||||
pub const PARAM: (Color, Color) = (LAVENDER, Color::Rgb(45, 45, 60));
|
||||
pub const CONTEXT: (Color, Color) = (PEACH, Color::Rgb(55, 45, 35));
|
||||
pub const NOTE: (Color, Color) = (GREEN, Color::Rgb(35, 50, 40));
|
||||
pub const INTERVAL: (Color, Color) = (Color::Rgb(180, 230, 150), Color::Rgb(40, 55, 35));
|
||||
pub const VARIABLE: (Color, Color) = (PINK, Color::Rgb(55, 40, 55));
|
||||
pub const VARY: (Color, Color) = (YELLOW, Color::Rgb(55, 50, 35));
|
||||
pub const GENERATOR: (Color, Color) = (TEAL, Color::Rgb(35, 55, 50));
|
||||
pub const DEFAULT: (Color, Color) = (SUBTEXT0, MANTLE);
|
||||
}
|
||||
|
||||
pub mod table {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const ROW_EVEN: Color = MANTLE;
|
||||
pub const ROW_ODD: Color = BASE;
|
||||
}
|
||||
|
||||
pub mod values {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const TEMPO: Color = PEACH;
|
||||
pub const VALUE: Color = SUBTEXT0;
|
||||
}
|
||||
|
||||
pub mod hint {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const KEY: Color = PEACH;
|
||||
pub const TEXT: Color = OVERLAY1;
|
||||
}
|
||||
|
||||
pub mod nav {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const SELECTED_BG: Color = Color::Rgb(60, 50, 75);
|
||||
pub const SELECTED_FG: Color = TEXT;
|
||||
pub const UNSELECTED_BG: Color = SURFACE0;
|
||||
pub const UNSELECTED_FG: Color = OVERLAY1;
|
||||
}
|
||||
|
||||
pub mod editor_widget {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const CURSOR_BG: Color = TEXT;
|
||||
pub const CURSOR_FG: Color = CRUST;
|
||||
pub const SELECTION_BG: Color = Color::Rgb(50, 60, 90);
|
||||
pub const COMPLETION_BG: Color = SURFACE0;
|
||||
pub const COMPLETION_FG: Color = TEXT;
|
||||
pub const COMPLETION_SELECTED: Color = PEACH;
|
||||
pub const COMPLETION_EXAMPLE: Color = TEAL;
|
||||
}
|
||||
|
||||
pub mod browser {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const DIRECTORY: Color = SAPPHIRE;
|
||||
pub const PROJECT_FILE: Color = MAUVE;
|
||||
pub const SELECTED: Color = PEACH;
|
||||
pub const FILE: Color = TEXT;
|
||||
pub const FOCUSED_BORDER: Color = PEACH;
|
||||
pub const UNFOCUSED_BORDER: Color = OVERLAY0;
|
||||
pub const ROOT: Color = TEXT;
|
||||
pub const FILE_ICON: Color = OVERLAY1;
|
||||
pub const FOLDER_ICON: Color = SAPPHIRE;
|
||||
pub const EMPTY_TEXT: Color = OVERLAY1;
|
||||
}
|
||||
|
||||
pub mod input {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const TEXT: Color = SAPPHIRE;
|
||||
pub const CURSOR: Color = super::palette::TEXT;
|
||||
pub const HINT: Color = OVERLAY1;
|
||||
}
|
||||
|
||||
pub mod search {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const ACTIVE: Color = PEACH;
|
||||
pub const INACTIVE: Color = OVERLAY0;
|
||||
pub const MATCH_BG: Color = YELLOW;
|
||||
pub const MATCH_FG: Color = CRUST;
|
||||
}
|
||||
|
||||
pub mod markdown {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const H1: Color = SAPPHIRE;
|
||||
pub const H2: Color = PEACH;
|
||||
pub const H3: Color = MAUVE;
|
||||
pub const CODE: Color = GREEN;
|
||||
pub const CODE_BORDER: Color = Color::Rgb(60, 60, 70);
|
||||
pub const LINK: Color = TEAL;
|
||||
pub const LINK_URL: Color = Color::Rgb(100, 100, 100);
|
||||
pub const QUOTE: Color = OVERLAY1;
|
||||
pub const TEXT: Color = super::palette::TEXT;
|
||||
pub const LIST: Color = super::palette::TEXT;
|
||||
}
|
||||
|
||||
pub mod engine {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const HEADER: Color = Color::Rgb(100, 160, 180);
|
||||
pub const HEADER_FOCUSED: Color = YELLOW;
|
||||
pub const DIVIDER: Color = Color::Rgb(60, 65, 70);
|
||||
pub const SCROLL_INDICATOR: Color = Color::Rgb(80, 85, 95);
|
||||
pub const LABEL: Color = Color::Rgb(120, 125, 135);
|
||||
pub const LABEL_FOCUSED: Color = Color::Rgb(150, 155, 165);
|
||||
pub const LABEL_DIM: Color = Color::Rgb(100, 105, 115);
|
||||
pub const VALUE: Color = Color::Rgb(180, 180, 190);
|
||||
pub const FOCUSED: Color = YELLOW;
|
||||
pub const NORMAL: Color = TEXT;
|
||||
pub const DIM: Color = Color::Rgb(80, 85, 95);
|
||||
pub const PATH: Color = Color::Rgb(120, 125, 135);
|
||||
pub const BORDER_MAGENTA: Color = MAUVE;
|
||||
pub const BORDER_GREEN: Color = GREEN;
|
||||
pub const BORDER_CYAN: Color = SAPPHIRE;
|
||||
pub const SEPARATOR: Color = Color::Rgb(60, 65, 75);
|
||||
pub const HINT_ACTIVE: Color = Color::Rgb(180, 180, 100);
|
||||
pub const HINT_INACTIVE: Color = Color::Rgb(60, 60, 70);
|
||||
}
|
||||
|
||||
pub mod dict {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const WORD_NAME: Color = GREEN;
|
||||
pub const WORD_BG: Color = Color::Rgb(40, 50, 60);
|
||||
pub const ALIAS: Color = OVERLAY1;
|
||||
pub const STACK_SIG: Color = MAUVE;
|
||||
pub const DESCRIPTION: Color = TEXT;
|
||||
pub const EXAMPLE: Color = Color::Rgb(120, 130, 140);
|
||||
pub const CATEGORY_FOCUSED: Color = YELLOW;
|
||||
pub const CATEGORY_SELECTED: Color = SAPPHIRE;
|
||||
pub const CATEGORY_NORMAL: Color = TEXT;
|
||||
pub const CATEGORY_DIMMED: Color = Color::Rgb(80, 80, 90);
|
||||
pub const BORDER_FOCUSED: Color = YELLOW;
|
||||
pub const BORDER_NORMAL: Color = Color::Rgb(60, 60, 70);
|
||||
pub const HEADER_DESC: Color = Color::Rgb(140, 145, 155);
|
||||
}
|
||||
|
||||
pub mod title {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const BIG_TITLE: Color = MAUVE;
|
||||
pub const AUTHOR: Color = LAVENDER;
|
||||
pub const LINK: Color = TEAL;
|
||||
pub const LICENSE: Color = PEACH;
|
||||
pub const PROMPT: Color = Color::Rgb(140, 160, 170);
|
||||
pub const SUBTITLE: Color = TEXT;
|
||||
}
|
||||
|
||||
pub mod meter {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const LOW: Color = GREEN;
|
||||
pub const MID: Color = YELLOW;
|
||||
pub const HIGH: Color = RED;
|
||||
pub const LOW_RGB: (u8, u8, u8) = (40, 180, 80);
|
||||
pub const MID_RGB: (u8, u8, u8) = (220, 180, 40);
|
||||
pub const HIGH_RGB: (u8, u8, u8) = (220, 60, 40);
|
||||
}
|
||||
|
||||
pub mod sparkle {
|
||||
pub const COLORS: &[(u8, u8, u8)] = &[
|
||||
(200, 220, 255), // Lavender-ish
|
||||
(250, 179, 135), // Peach
|
||||
(166, 227, 161), // Green
|
||||
(245, 194, 231), // Pink
|
||||
(203, 166, 247), // Mauve
|
||||
];
|
||||
}
|
||||
|
||||
pub mod confirm {
|
||||
use super::*;
|
||||
use palette::*;
|
||||
pub const BORDER: Color = PEACH;
|
||||
pub const BUTTON_SELECTED_BG: Color = PEACH;
|
||||
pub const BUTTON_SELECTED_FG: Color = CRUST;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::theme::meter;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::Color;
|
||||
@@ -31,11 +32,11 @@ impl VuMeter {
|
||||
|
||||
fn row_to_color(row_position: f32) -> Color {
|
||||
if row_position > 0.9 {
|
||||
Color::Red
|
||||
meter::HIGH
|
||||
} else if row_position > 0.75 {
|
||||
Color::Yellow
|
||||
meter::MID
|
||||
} else {
|
||||
Color::Green
|
||||
meter::LOW
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user