From 40e42c8918518bbef08355c3b057e06ec7ba5a03 Mon Sep 17 00:00:00 2001 From: vikingowl Date: Sat, 25 Oct 2025 00:26:01 +0200 Subject: [PATCH] chore(deps/ui): upgrade ratatui 0.29 and refresh gradients Acceptance Criteria: - Workspace builds against ratatui 0.29, crossterm 0.28.1, and tui-textarea 0.7 with palette support enabled - Chat header context and usage gauges render with refreshed tailwind gradients - Header layout uses the Flex API to balance top-row metadata across window widths Test Notes: - cargo test -p owlen-tui --- Cargo.toml | 6 +-- crates/owlen-core/Cargo.toml | 2 +- crates/owlen-markdown/Cargo.toml | 2 +- crates/owlen-tui/Cargo.toml | 2 +- crates/owlen-tui/src/glass.rs | 52 +++++++++++------------ crates/owlen-tui/src/ui.rs | 73 +++++++++++++------------------- 6 files changed, 61 insertions(+), 76 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 39ceb91..222c488 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,9 +34,9 @@ futures = "0.3" futures-util = "0.3" # TUI framework -ratatui = "0.28" -crossterm = "0.28" -tui-textarea = "0.6" +ratatui = { version = "0.29", features = ["palette"] } +crossterm = "0.28.1" +tui-textarea = "0.7" # HTTP client and JSON handling reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] } diff --git a/crates/owlen-core/Cargo.toml b/crates/owlen-core/Cargo.toml index 2f728bc..8acb01d 100644 --- a/crates/owlen-core/Cargo.toml +++ b/crates/owlen-core/Cargo.toml @@ -17,7 +17,7 @@ serde_json = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } unicode-segmentation = "1.11" -unicode-width = "0.1" +unicode-width = "0.2" uuid = { workspace = true } textwrap = { workspace = true } futures = { workspace = true } diff --git a/crates/owlen-markdown/Cargo.toml b/crates/owlen-markdown/Cargo.toml index b117a32..f3519f6 100644 --- a/crates/owlen-markdown/Cargo.toml +++ b/crates/owlen-markdown/Cargo.toml @@ -7,4 +7,4 @@ description = "Lightweight markdown to ratatui::Text renderer for OWLEN" [dependencies] ratatui = { workspace = true } -unicode-width = "0.1" +unicode-width = "0.2" diff --git a/crates/owlen-tui/Cargo.toml b/crates/owlen-tui/Cargo.toml index de83d9a..326f6fd 100644 --- a/crates/owlen-tui/Cargo.toml +++ b/crates/owlen-tui/Cargo.toml @@ -17,7 +17,7 @@ ratatui = { workspace = true } crossterm = { workspace = true } tui-textarea = { workspace = true } textwrap = { workspace = true } -unicode-width = "0.1" +unicode-width = "0.2" unicode-segmentation = "1.11" async-trait = "0.1" globset = "0.4" diff --git a/crates/owlen-tui/src/glass.rs b/crates/owlen-tui/src/glass.rs index 9f23b5c..dd9ed9e 100644 --- a/crates/owlen-tui/src/glass.rs +++ b/crates/owlen-tui/src/glass.rs @@ -1,5 +1,5 @@ use owlen_core::theme::Theme; -use ratatui::style::Color; +use ratatui::style::{Color, palette::tailwind}; #[derive(Clone, Copy)] pub struct GlassPalette { @@ -18,40 +18,40 @@ impl GlassPalette { let luminance = color_luminance(theme.background); if luminance < 0.5 { Self { - active: Color::Rgb(26, 28, 40), - inactive: Color::Rgb(18, 20, 30), - highlight: Color::Rgb(32, 35, 48), - track: Color::Rgb(35, 38, 50), - label: Color::Rgb(241, 245, 249), - shadow: Color::Rgb(8, 9, 16), + active: tailwind::SLATE.c900, + inactive: tailwind::SLATE.c800, + highlight: tailwind::SLATE.c800, + track: tailwind::SLATE.c700, + label: tailwind::SLATE.c100, + shadow: tailwind::SLATE.c950, context_stops: [ - Color::Rgb(56, 189, 248), - Color::Rgb(250, 204, 21), - Color::Rgb(248, 113, 113), + tailwind::SKY.c400, + tailwind::AMBER.c300, + tailwind::ROSE.c400, ], usage_stops: [ - Color::Rgb(34, 211, 238), - Color::Rgb(250, 204, 21), - Color::Rgb(248, 113, 113), + tailwind::CYAN.c400, + tailwind::AMBER.c300, + tailwind::ROSE.c400, ], } } else { Self { - active: Color::Rgb(242, 247, 255), - inactive: Color::Rgb(229, 235, 250), - highlight: Color::Rgb(224, 230, 248), - track: Color::Rgb(203, 210, 230), - label: Color::Rgb(31, 41, 55), - shadow: Color::Rgb(200, 205, 220), + active: tailwind::ZINC.c100, + inactive: tailwind::ZINC.c200, + highlight: tailwind::ZINC.c200, + track: tailwind::ZINC.c300, + label: tailwind::SLATE.c700, + shadow: tailwind::ZINC.c300, context_stops: [ - Color::Rgb(59, 130, 246), - Color::Rgb(234, 179, 8), - Color::Rgb(239, 68, 68), + tailwind::BLUE.c500, + tailwind::AMBER.c400, + tailwind::ROSE.c500, ], usage_stops: [ - Color::Rgb(20, 184, 166), - Color::Rgb(245, 158, 11), - Color::Rgb(239, 68, 68), + tailwind::TEAL.c400, + tailwind::AMBER.c400, + tailwind::ROSE.c500, ], } } @@ -60,7 +60,7 @@ impl GlassPalette { pub fn gradient_color(stops: &[Color; 3], t: f64) -> Color { let clamped = t.clamp(0.0, 1.0); - let segments = stops.len() - 1; + let segments = stops.len().saturating_sub(1).max(1); let scaled = clamped * segments as f64; let index = scaled.floor() as usize; let frac = scaled - index as f64; diff --git a/crates/owlen-tui/src/ui.rs b/crates/owlen-tui/src/ui.rs index 841fed3..c273bc9 100644 --- a/crates/owlen-tui/src/ui.rs +++ b/crates/owlen-tui/src/ui.rs @@ -1,7 +1,7 @@ use log::Level; use pathdiff::diff_paths; use ratatui::Frame; -use ratatui::layout::{Alignment, Constraint, Direction, Layout, Rect}; +use ratatui::layout::{Alignment, Constraint, Direction, Flex, Layout, Rect}; use ratatui::style::{Color, Modifier, Style}; use ratatui::text::{Line, Span}; use ratatui::widgets::block::Padding; @@ -421,9 +421,8 @@ fn render_chat_header( constraints.push(Constraint::Min(2)); } - let rows = Layout::default() - .direction(Direction::Vertical) - .constraints(constraints) + let rows = Layout::vertical(constraints) + .flex(Flex::Start) .split(highlight_area); render_header_top(frame, rows[0], app, palette, theme); @@ -444,9 +443,8 @@ fn render_header_top( return; } - let columns = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(60), Constraint::Percentage(40)]) + let columns = Layout::horizontal([Constraint::Percentage(60), Constraint::Percentage(40)]) + .flex(Flex::SpaceBetween) .split(area); let mut left_spans = Vec::new(); @@ -558,9 +556,8 @@ fn render_header_bars( return; } - let columns = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(45), Constraint::Percentage(55)]) + let columns = Layout::horizontal([Constraint::Percentage(45), Constraint::Percentage(55)]) + .flex(Flex::SpaceBetween) .split(area); render_context_column(frame, columns[0], app, palette, theme); @@ -823,14 +820,12 @@ pub fn render_chat(frame: &mut Frame<'_>, app: &mut ChatApp) { let header_height = header_height.max(3).min(frame_area.height); let segments = if frame_area.height <= header_height { - Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Length(frame_area.height)]) + Layout::vertical([Constraint::Length(frame_area.height)]) + .flex(Flex::Start) .split(frame_area) } else { - Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Length(header_height), Constraint::Min(1)]) + Layout::vertical([Constraint::Length(header_height), Constraint::Min(1)]) + .flex(Flex::Start) .split(frame_area) }; @@ -874,17 +869,15 @@ pub fn render_chat(frame: &mut Frame<'_>, app: &mut ChatApp) { } else { let max_sidebar = content_area.width.saturating_sub(30).max(10); let sidebar_width = app.file_panel_width().min(max_sidebar).max(10); - let segments = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Length(sidebar_width), Constraint::Min(30)]) + let segments = Layout::horizontal([Constraint::Length(sidebar_width), Constraint::Min(30)]) + .flex(Flex::Start) .split(content_area); (Some(segments[0]), segments[1]) }; let (chat_area, code_area) = if app.should_show_code_view() { - let segments = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(65), Constraint::Percentage(35)]) + let segments = Layout::horizontal([Constraint::Percentage(65), Constraint::Percentage(35)]) + .flex(Flex::Start) .split(main_area); (segments[0], Some(segments[1])) } else { @@ -5653,29 +5646,21 @@ fn render_symbol_search(frame: &mut Frame<'_>, app: &mut ChatApp) { } fn centered_rect(percent_x: u16, percent_y: u16, area: Rect) -> Rect { - let vertical = Layout::default() - .direction(Direction::Vertical) - .constraints( - [ - Constraint::Percentage((100 - percent_y) / 2), - Constraint::Percentage(percent_y), - Constraint::Percentage((100 - percent_y) / 2), - ] - .as_ref(), - ) - .split(area); + let vertical = Layout::vertical([ + Constraint::Percentage((100 - percent_y) / 2), + Constraint::Percentage(percent_y), + Constraint::Percentage((100 - percent_y) / 2), + ]) + .flex(Flex::Center) + .split(area); - Layout::default() - .direction(Direction::Horizontal) - .constraints( - [ - Constraint::Percentage((100 - percent_x) / 2), - Constraint::Percentage(percent_x), - Constraint::Percentage((100 - percent_x) / 2), - ] - .as_ref(), - ) - .split(vertical[1])[1] + Layout::horizontal([ + Constraint::Percentage((100 - percent_x) / 2), + Constraint::Percentage(percent_x), + Constraint::Percentage((100 - percent_x) / 2), + ]) + .flex(Flex::Center) + .split(vertical[1])[1] } /// Format tool output JSON into a nice human-readable format