Monster commit: native version

This commit is contained in:
2026-01-30 15:03:49 +01:00
parent c2e6dfe88b
commit 44d1e9af24
35 changed files with 1491 additions and 366 deletions

View File

@@ -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"] }

View File

@@ -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()
};

View File

@@ -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();

View File

@@ -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)))
})

View File

@@ -9,6 +9,7 @@ mod scope;
mod sparkles;
mod spectrum;
mod text_input;
pub mod theme;
mod vu_meter;
pub use confirm::ConfirmModal;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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(),
}
};

View File

@@ -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,
}
}

View File

@@ -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)));
}
}

View File

@@ -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;

View File

@@ -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
View 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;
}

View File

@@ -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
}
}
}