diff --git a/crates/owlen-tui/src/chat_app.rs b/crates/owlen-tui/src/chat_app.rs index 69b9f06..832dc47 100644 --- a/crates/owlen-tui/src/chat_app.rs +++ b/crates/owlen-tui/src/chat_app.rs @@ -15,7 +15,7 @@ use owlen_core::{ ui::{AppState, AutoScroll, FocusedPanel, InputMode, RoleLabelDisplay}, }; use pathdiff::diff_paths; -use ratatui::style::{Modifier, Style}; +use ratatui::style::{Color, Modifier, Style}; use ratatui::text::{Line, Span}; use textwrap::{Options, WordSeparator, wrap}; use tokio::{ @@ -1806,11 +1806,24 @@ impl ChatApp { match role { Role::User => Style::default().fg(theme.user_message_role), Role::Assistant => Style::default().fg(theme.assistant_message_role), - Role::System => Style::default().fg(theme.unfocused_panel_border), + Role::System => Style::default().fg(theme.mode_command), Role::Tool => Style::default().fg(theme.info), } } + fn message_border_style(theme: &Theme, role: &Role) -> Style { + let base_color = match role { + Role::User => theme.user_message_role, + Role::Assistant => theme.assistant_message_role, + Role::System => theme.mode_command, + Role::Tool => theme.info, + }; + + let dimmed = Self::dim_color(base_color); + + Style::default().fg(dimmed).add_modifier(Modifier::DIM) + } + fn content_style(theme: &Theme, role: &Role) -> Style { if matches!(role, Role::Tool) { Style::default().fg(theme.tool_output) @@ -1819,6 +1832,46 @@ impl ChatApp { } } + fn dim_color(color: Color) -> Color { + match color { + Color::Reset | Color::Indexed(_) => color, + _ => { + if let Some((r, g, b)) = Self::color_to_rgb(color) { + let dim_component = |component: u8| -> u8 { + let value = ((component as u16) * 2) / 5; + value as u8 + }; + Color::Rgb(dim_component(r), dim_component(g), dim_component(b)) + } else { + color + } + } + } + } + + fn color_to_rgb(color: Color) -> Option<(u8, u8, u8)> { + match color { + Color::Black => Some((0, 0, 0)), + Color::Red => Some((205, 0, 0)), + Color::Green => Some((0, 205, 0)), + Color::Yellow => Some((205, 205, 0)), + Color::Blue => Some((0, 0, 205)), + Color::Magenta => Some((205, 0, 205)), + Color::Cyan => Some((0, 205, 205)), + Color::Gray => Some((170, 170, 170)), + Color::DarkGray => Some((85, 85, 85)), + Color::LightRed => Some((255, 85, 85)), + Color::LightGreen => Some((85, 255, 85)), + Color::LightYellow => Some((255, 255, 85)), + Color::LightBlue => Some((85, 85, 255)), + Color::LightMagenta => Some((255, 85, 255)), + Color::LightCyan => Some((85, 255, 255)), + Color::White => Some((255, 255, 255)), + Color::Rgb(r, g, b) => Some((r, g, b)), + Color::Reset | Color::Indexed(_) => None, + } + } + fn message_content_hash(role: &Role, content: &str, tool_signature: &str) -> u64 { let mut hasher = DefaultHasher::new(); role.to_string().hash(&mut hasher); @@ -2128,10 +2181,10 @@ impl ChatApp { } for line in lines { - card_lines.push(Self::wrap_card_body_line(line, inner_width, theme)); + card_lines.push(Self::wrap_card_body_line(line, inner_width, theme, role)); } - card_lines.push(Self::build_card_footer(card_width, theme)); + card_lines.push(Self::build_card_footer(card_width, theme, role)); card_lines } @@ -2142,7 +2195,7 @@ impl ChatApp { card_width: usize, theme: &Theme, ) -> Line<'static> { - let border_style = Style::default().fg(theme.unfocused_panel_border); + let border_style = Self::message_border_style(theme, role); let role_style = Self::role_style(theme, role).add_modifier(Modifier::BOLD); let meta_style = Style::default().fg(theme.placeholder); let tool_style = Style::default() @@ -2199,8 +2252,8 @@ impl ChatApp { Line::from(spans) } - fn build_card_footer(card_width: usize, theme: &Theme) -> Line<'static> { - let border_style = Style::default().fg(theme.unfocused_panel_border); + fn build_card_footer(card_width: usize, theme: &Theme, role: &Role) -> Line<'static> { + let border_style = Self::message_border_style(theme, role); let mut spans = Vec::new(); spans.push(Span::styled("└", border_style)); let horizontal = card_width.saturating_sub(2); @@ -2215,8 +2268,9 @@ impl ChatApp { line: Line<'static>, inner_width: usize, theme: &Theme, + role: &Role, ) -> Line<'static> { - let border_style = Style::default().fg(theme.unfocused_panel_border); + let border_style = Self::message_border_style(theme, role); let mut spans = Vec::new(); spans.push(Span::styled("│ ", border_style));