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:
@@ -34,9 +34,9 @@ futures = "0.3"
|
|||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
|
|
||||||
# TUI framework
|
# TUI framework
|
||||||
ratatui = "0.28"
|
ratatui = { version = "0.29", features = ["palette"] }
|
||||||
crossterm = "0.28"
|
crossterm = "0.28.1"
|
||||||
tui-textarea = "0.6"
|
tui-textarea = "0.7"
|
||||||
|
|
||||||
# HTTP client and JSON handling
|
# HTTP client and JSON handling
|
||||||
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] }
|
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ serde_json = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
unicode-segmentation = "1.11"
|
unicode-segmentation = "1.11"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.2"
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
textwrap = { workspace = true }
|
textwrap = { workspace = true }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ description = "Lightweight markdown to ratatui::Text renderer for OWLEN"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ratatui = { workspace = true }
|
ratatui = { workspace = true }
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.2"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ ratatui = { workspace = true }
|
|||||||
crossterm = { workspace = true }
|
crossterm = { workspace = true }
|
||||||
tui-textarea = { workspace = true }
|
tui-textarea = { workspace = true }
|
||||||
textwrap = { workspace = true }
|
textwrap = { workspace = true }
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.2"
|
||||||
unicode-segmentation = "1.11"
|
unicode-segmentation = "1.11"
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
globset = "0.4"
|
globset = "0.4"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use owlen_core::theme::Theme;
|
use owlen_core::theme::Theme;
|
||||||
use ratatui::style::Color;
|
use ratatui::style::{Color, palette::tailwind};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct GlassPalette {
|
pub struct GlassPalette {
|
||||||
@@ -18,40 +18,40 @@ impl GlassPalette {
|
|||||||
let luminance = color_luminance(theme.background);
|
let luminance = color_luminance(theme.background);
|
||||||
if luminance < 0.5 {
|
if luminance < 0.5 {
|
||||||
Self {
|
Self {
|
||||||
active: Color::Rgb(26, 28, 40),
|
active: tailwind::SLATE.c900,
|
||||||
inactive: Color::Rgb(18, 20, 30),
|
inactive: tailwind::SLATE.c800,
|
||||||
highlight: Color::Rgb(32, 35, 48),
|
highlight: tailwind::SLATE.c800,
|
||||||
track: Color::Rgb(35, 38, 50),
|
track: tailwind::SLATE.c700,
|
||||||
label: Color::Rgb(241, 245, 249),
|
label: tailwind::SLATE.c100,
|
||||||
shadow: Color::Rgb(8, 9, 16),
|
shadow: tailwind::SLATE.c950,
|
||||||
context_stops: [
|
context_stops: [
|
||||||
Color::Rgb(56, 189, 248),
|
tailwind::SKY.c400,
|
||||||
Color::Rgb(250, 204, 21),
|
tailwind::AMBER.c300,
|
||||||
Color::Rgb(248, 113, 113),
|
tailwind::ROSE.c400,
|
||||||
],
|
],
|
||||||
usage_stops: [
|
usage_stops: [
|
||||||
Color::Rgb(34, 211, 238),
|
tailwind::CYAN.c400,
|
||||||
Color::Rgb(250, 204, 21),
|
tailwind::AMBER.c300,
|
||||||
Color::Rgb(248, 113, 113),
|
tailwind::ROSE.c400,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
active: Color::Rgb(242, 247, 255),
|
active: tailwind::ZINC.c100,
|
||||||
inactive: Color::Rgb(229, 235, 250),
|
inactive: tailwind::ZINC.c200,
|
||||||
highlight: Color::Rgb(224, 230, 248),
|
highlight: tailwind::ZINC.c200,
|
||||||
track: Color::Rgb(203, 210, 230),
|
track: tailwind::ZINC.c300,
|
||||||
label: Color::Rgb(31, 41, 55),
|
label: tailwind::SLATE.c700,
|
||||||
shadow: Color::Rgb(200, 205, 220),
|
shadow: tailwind::ZINC.c300,
|
||||||
context_stops: [
|
context_stops: [
|
||||||
Color::Rgb(59, 130, 246),
|
tailwind::BLUE.c500,
|
||||||
Color::Rgb(234, 179, 8),
|
tailwind::AMBER.c400,
|
||||||
Color::Rgb(239, 68, 68),
|
tailwind::ROSE.c500,
|
||||||
],
|
],
|
||||||
usage_stops: [
|
usage_stops: [
|
||||||
Color::Rgb(20, 184, 166),
|
tailwind::TEAL.c400,
|
||||||
Color::Rgb(245, 158, 11),
|
tailwind::AMBER.c400,
|
||||||
Color::Rgb(239, 68, 68),
|
tailwind::ROSE.c500,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ impl GlassPalette {
|
|||||||
|
|
||||||
pub fn gradient_color(stops: &[Color; 3], t: f64) -> Color {
|
pub fn gradient_color(stops: &[Color; 3], t: f64) -> Color {
|
||||||
let clamped = t.clamp(0.0, 1.0);
|
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 scaled = clamped * segments as f64;
|
||||||
let index = scaled.floor() as usize;
|
let index = scaled.floor() as usize;
|
||||||
let frac = scaled - index as f64;
|
let frac = scaled - index as f64;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use log::Level;
|
use log::Level;
|
||||||
use pathdiff::diff_paths;
|
use pathdiff::diff_paths;
|
||||||
use ratatui::Frame;
|
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::style::{Color, Modifier, Style};
|
||||||
use ratatui::text::{Line, Span};
|
use ratatui::text::{Line, Span};
|
||||||
use ratatui::widgets::block::Padding;
|
use ratatui::widgets::block::Padding;
|
||||||
@@ -421,9 +421,8 @@ fn render_chat_header(
|
|||||||
constraints.push(Constraint::Min(2));
|
constraints.push(Constraint::Min(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
let rows = Layout::default()
|
let rows = Layout::vertical(constraints)
|
||||||
.direction(Direction::Vertical)
|
.flex(Flex::Start)
|
||||||
.constraints(constraints)
|
|
||||||
.split(highlight_area);
|
.split(highlight_area);
|
||||||
|
|
||||||
render_header_top(frame, rows[0], app, palette, theme);
|
render_header_top(frame, rows[0], app, palette, theme);
|
||||||
@@ -444,9 +443,8 @@ fn render_header_top(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let columns = Layout::default()
|
let columns = Layout::horizontal([Constraint::Percentage(60), Constraint::Percentage(40)])
|
||||||
.direction(Direction::Horizontal)
|
.flex(Flex::SpaceBetween)
|
||||||
.constraints([Constraint::Percentage(60), Constraint::Percentage(40)])
|
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
let mut left_spans = Vec::new();
|
let mut left_spans = Vec::new();
|
||||||
@@ -558,9 +556,8 @@ fn render_header_bars(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let columns = Layout::default()
|
let columns = Layout::horizontal([Constraint::Percentage(45), Constraint::Percentage(55)])
|
||||||
.direction(Direction::Horizontal)
|
.flex(Flex::SpaceBetween)
|
||||||
.constraints([Constraint::Percentage(45), Constraint::Percentage(55)])
|
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
render_context_column(frame, columns[0], app, palette, theme);
|
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 header_height = header_height.max(3).min(frame_area.height);
|
||||||
|
|
||||||
let segments = if frame_area.height <= header_height {
|
let segments = if frame_area.height <= header_height {
|
||||||
Layout::default()
|
Layout::vertical([Constraint::Length(frame_area.height)])
|
||||||
.direction(Direction::Vertical)
|
.flex(Flex::Start)
|
||||||
.constraints([Constraint::Length(frame_area.height)])
|
|
||||||
.split(frame_area)
|
.split(frame_area)
|
||||||
} else {
|
} else {
|
||||||
Layout::default()
|
Layout::vertical([Constraint::Length(header_height), Constraint::Min(1)])
|
||||||
.direction(Direction::Vertical)
|
.flex(Flex::Start)
|
||||||
.constraints([Constraint::Length(header_height), Constraint::Min(1)])
|
|
||||||
.split(frame_area)
|
.split(frame_area)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -874,17 +869,15 @@ pub fn render_chat(frame: &mut Frame<'_>, app: &mut ChatApp) {
|
|||||||
} else {
|
} else {
|
||||||
let max_sidebar = content_area.width.saturating_sub(30).max(10);
|
let max_sidebar = content_area.width.saturating_sub(30).max(10);
|
||||||
let sidebar_width = app.file_panel_width().min(max_sidebar).max(10);
|
let sidebar_width = app.file_panel_width().min(max_sidebar).max(10);
|
||||||
let segments = Layout::default()
|
let segments = Layout::horizontal([Constraint::Length(sidebar_width), Constraint::Min(30)])
|
||||||
.direction(Direction::Horizontal)
|
.flex(Flex::Start)
|
||||||
.constraints([Constraint::Length(sidebar_width), Constraint::Min(30)])
|
|
||||||
.split(content_area);
|
.split(content_area);
|
||||||
(Some(segments[0]), segments[1])
|
(Some(segments[0]), segments[1])
|
||||||
};
|
};
|
||||||
|
|
||||||
let (chat_area, code_area) = if app.should_show_code_view() {
|
let (chat_area, code_area) = if app.should_show_code_view() {
|
||||||
let segments = Layout::default()
|
let segments = Layout::horizontal([Constraint::Percentage(65), Constraint::Percentage(35)])
|
||||||
.direction(Direction::Horizontal)
|
.flex(Flex::Start)
|
||||||
.constraints([Constraint::Percentage(65), Constraint::Percentage(35)])
|
|
||||||
.split(main_area);
|
.split(main_area);
|
||||||
(segments[0], Some(segments[1]))
|
(segments[0], Some(segments[1]))
|
||||||
} else {
|
} 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 {
|
fn centered_rect(percent_x: u16, percent_y: u16, area: Rect) -> Rect {
|
||||||
let vertical = Layout::default()
|
let vertical = Layout::vertical([
|
||||||
.direction(Direction::Vertical)
|
Constraint::Percentage((100 - percent_y) / 2),
|
||||||
.constraints(
|
Constraint::Percentage(percent_y),
|
||||||
[
|
Constraint::Percentage((100 - percent_y) / 2),
|
||||||
Constraint::Percentage((100 - percent_y) / 2),
|
])
|
||||||
Constraint::Percentage(percent_y),
|
.flex(Flex::Center)
|
||||||
Constraint::Percentage((100 - percent_y) / 2),
|
.split(area);
|
||||||
]
|
|
||||||
.as_ref(),
|
|
||||||
)
|
|
||||||
.split(area);
|
|
||||||
|
|
||||||
Layout::default()
|
Layout::horizontal([
|
||||||
.direction(Direction::Horizontal)
|
Constraint::Percentage((100 - percent_x) / 2),
|
||||||
.constraints(
|
Constraint::Percentage(percent_x),
|
||||||
[
|
Constraint::Percentage((100 - percent_x) / 2),
|
||||||
Constraint::Percentage((100 - percent_x) / 2),
|
])
|
||||||
Constraint::Percentage(percent_x),
|
.flex(Flex::Center)
|
||||||
Constraint::Percentage((100 - percent_x) / 2),
|
.split(vertical[1])[1]
|
||||||
]
|
|
||||||
.as_ref(),
|
|
||||||
)
|
|
||||||
.split(vertical[1])[1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format tool output JSON into a nice human-readable format
|
/// Format tool output JSON into a nice human-readable format
|
||||||
|
|||||||
Reference in New Issue
Block a user