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
This commit is contained in:
2025-10-25 00:26:01 +02:00
parent 6e12bb3acb
commit 40e42c8918
6 changed files with 61 additions and 76 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,28 +5646,20 @@ 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(
[
let vertical = Layout::vertical([
Constraint::Percentage((100 - percent_y) / 2),
Constraint::Percentage(percent_y),
Constraint::Percentage((100 - percent_y) / 2),
]
.as_ref(),
)
])
.flex(Flex::Center)
.split(area);
Layout::default()
.direction(Direction::Horizontal)
.constraints(
[
Layout::horizontal([
Constraint::Percentage((100 - percent_x) / 2),
Constraint::Percentage(percent_x),
Constraint::Percentage((100 - percent_x) / 2),
]
.as_ref(),
)
])
.flex(Flex::Center)
.split(vertical[1])[1]
}