From fe3b6d6ffdc2e6d899dcf64d1e97a6aa53fdef5f Mon Sep 17 00:00:00 2001 From: lancebord Date: Sat, 7 Mar 2026 20:05:24 -0500 Subject: chat name colors --- src/main.rs | 4 +-- src/tui/app.rs | 6 +--- src/tui/ui.rs | 100 +++++++++++++++++++++++++++++++-------------------------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/src/main.rs b/src/main.rs index 061dbc2..9c3d631 100644 --- a/src/main.rs +++ b/src/main.rs @@ -169,7 +169,7 @@ fn handle_input(text: &str, app: &mut AppState, client: &mut Client) -> bool { if app.connected && !app.channel.is_empty() { // Regular chat message to active channel client.privmsg(&app.channel, text); - app.push_message(&app.nick.clone(), text, true); + app.push_message(&app.nick.clone(), text); } } false @@ -206,7 +206,7 @@ fn handle_irc_event(event: IrcEvent, app: &mut AppState) { if !is_self { // Don't re-echo our own messages (we already pushed them in handle_input) if target == app.channel || target == app.nick { - app.push_message(&from, &text, false); + app.push_message(&from, &text); } } } diff --git a/src/tui/app.rs b/src/tui/app.rs index 0b5d77e..82342c0 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -7,8 +7,6 @@ pub struct ChatLine { pub is_system: bool, /// true = NOTICE pub is_notice: bool, - /// true = this is our own message - pub is_self: bool, } /// All mutable state the TUI needs to render and respond to input @@ -46,13 +44,12 @@ impl AppState { } /// Push a chat message - pub fn push_message(&mut self, nick: &str, text: &str, is_self: bool) { + pub fn push_message(&mut self, nick: &str, text: &str) { self.messages.push(ChatLine { nick: nick.to_string(), text: text.to_string(), is_system: false, is_notice: false, - is_self, }); } @@ -63,7 +60,6 @@ impl AppState { text: text.to_string(), is_system: true, is_notice: false, - is_self: false, }); } diff --git a/src/tui/ui.rs b/src/tui/ui.rs index f6c5369..4878848 100644 --- a/src/tui/ui.rs +++ b/src/tui/ui.rs @@ -12,17 +12,11 @@ use unicode_width::UnicodeWidthStr; // Dark terminal aesthetic: near-black background, cool grey chrome, // amber accent for our own nick, cyan for others, muted green for system. -const BG: Color = Color::Rgb(16, 16, 16); -const ORANGE: Color = Color::Rgb(251, 84, 43); // border / panel bg -const FG: Color = Color::Rgb(204, 204, 204); // main foreground -const GRAY: Color = Color::Rgb(74, 74, 74); // other nicks -const LIGHT_ORANGE: Color = Color::Rgb(255, 122, 89); // system messages - pub fn draw(f: &mut Frame, state: &AppState) { let area = f.area(); // Fill background - f.render_widget(Block::default().style(Style::default().bg(BG)), area); + f.render_widget(Block::default().style(Style::default()), area); // ── Outer layout: title bar + body + status bar ─────────────────────── let outer = Layout::default() @@ -43,19 +37,18 @@ fn draw_titlebar(f: &mut Frame, area: Rect, state: &AppState) { let title = Line::from(vec![ Span::styled( "  ", - Style::default().fg(ORANGE).add_modifier(Modifier::BOLD), - ), - Span::styled( - "speakez", - Style::default().fg(FG).add_modifier(Modifier::BOLD), + Style::default() + .fg(Color::Green) + .add_modifier(Modifier::BOLD), ), - Span::styled(" │ ", Style::default().fg(FG)), + Span::styled("speakez", Style::default().add_modifier(Modifier::BOLD)), + Span::styled(" │ ", Style::default()), Span::styled( &state.channel, - Style::default().fg(FG).add_modifier(Modifier::BOLD), + Style::default().add_modifier(Modifier::BOLD), ), - Span::styled(" │ ", Style::default().fg(FG)), - Span::styled(&state.nick, Style::default().fg(ORANGE)), + Span::styled(" │ ", Style::default()), + Span::styled(&state.nick, Style::default().fg(Color::Green)), ]); f.render_widget(Paragraph::new(title).style(Style::default()), area); @@ -99,8 +92,8 @@ fn draw_chat_log(f: &mut Frame, area: Rect, state: &AppState) { let block = Block::default() .borders(Borders::ALL) .border_type(BorderType::Plain) - .border_style(Style::default().fg(ORANGE)) - .style(Style::default().bg(BG)); + .border_style(Style::default().fg(Color::Green)) + .style(Style::default()); let inner_width = area.width.saturating_sub(2) as usize; let inner_height = area.height.saturating_sub(2) as usize; @@ -155,17 +148,17 @@ fn render_chat_line(msg: &super::app::ChatLine) -> Line<'static> { return Line::from(Span::styled( format!(" ∙ {}", msg.text), Style::default() - .fg(LIGHT_ORANGE) + .fg(Color::DarkGray) .add_modifier(Modifier::DIM), )); } - let nick_style = if msg.is_self { - Style::default().fg(ORANGE).add_modifier(Modifier::BOLD) - } else if msg.is_notice { - Style::default().fg(ORANGE) + let nick_style = if msg.is_notice { + Style::default().fg(Color::Green) } else { - Style::default().fg(GRAY) + Style::default() + .fg(color_from_str(&msg.nick)) + .add_modifier(Modifier::BOLD) }; let nick = format!("{}", msg.nick); @@ -173,10 +166,23 @@ fn render_chat_line(msg: &super::app::ChatLine) -> Line<'static> { Line::from(vec![ Span::styled(nick, nick_style), Span::styled(" ", Style::default()), - Span::styled(msg.text.clone(), Style::default().fg(FG)), + Span::styled(msg.text.clone(), Style::default()), ]) } +fn color_from_str(s: &str) -> Color { + let sum: u32 = s.chars().map(|c| c as u32).sum(); + match sum % 6 { + 0 => Color::Red, + 1 => Color::Green, + 2 => Color::Yellow, + 3 => Color::Blue, + 4 => Color::Magenta, + 5 => Color::Cyan, + _ => unreachable!(), + } +} + fn draw_input(f: &mut Frame, area: Rect, state: &AppState) { // Show a blinking cursor indicator at the cursor position let before = &state.input[..state.cursor]; @@ -194,19 +200,21 @@ fn draw_input(f: &mut Frame, area: Rect, state: &AppState) { }; let line = Line::from(vec![ - Span::styled(before.to_string(), Style::default().fg(FG)), + Span::styled(before.to_string(), Style::default()), Span::styled( cursor_char.to_string(), - Style::default().bg(FG).fg(BG).add_modifier(Modifier::BOLD), + Style::default() + .bg(Color::White) + .add_modifier(Modifier::BOLD), ), - Span::styled(after_cursor.to_string(), Style::default().fg(FG)), + Span::styled(after_cursor.to_string(), Style::default()), ]); let block = Block::default() .borders(Borders::ALL) .border_type(BorderType::Plain) - .border_style(Style::default().fg(ORANGE)) - .title(Span::styled(" send ", Style::default().fg(FG))); + .border_style(Style::default().fg(Color::Green)) + .title(Span::styled(" send ", Style::default())); f.render_widget(Paragraph::new(line).block(block), area); } @@ -226,14 +234,19 @@ fn draw_members_panel(f: &mut Frame, area: Rect, state: &AppState) { }; let sigil_style = if sigil == "@" { - Style::default().fg(ORANGE) + Style::default().fg(Color::Green) } else { - Style::default().fg(FG) + Style::default() }; ListItem::new(Line::from(vec![ Span::styled(sigil.to_string(), sigil_style), - Span::styled(rest.to_string(), Style::default().fg(FG)), + Span::styled( + rest.to_string(), + Style::default() + .fg(color_from_str(nick.as_str())) + .add_modifier(Modifier::BOLD), + ), ])) }) .collect(); @@ -246,18 +259,18 @@ fn draw_members_panel(f: &mut Frame, area: Rect, state: &AppState) { fn draw_statusbar(f: &mut Frame, area: Rect, state: &AppState) { let (status_text, status_style) = if state.connected { - ("● connected", Style::default().fg(LIGHT_ORANGE)) + ("● connected", Style::default().fg(Color::LightGreen)) } else { - ("○ connecting…", Style::default().fg(GRAY)) + ("○ connecting…", Style::default().fg(Color::Gray)) }; let line = Line::from(vec![ Span::styled(" ", Style::default()), Span::styled(status_text, status_style), - Span::styled(" │ ", Style::default().fg(FG)), - Span::styled(&state.status, Style::default().fg(FG)), - Span::styled(" │ ", Style::default().fg(FG)), - Span::styled("Ctrl-C quit", Style::default().fg(FG)), + Span::styled(" │ ", Style::default()), + Span::styled(&state.status, Style::default()), + Span::styled(" │ ", Style::default()), + Span::styled("Ctrl-C quit", Style::default()), ]); f.render_widget(Paragraph::new(line).style(Style::default()), area); @@ -268,10 +281,7 @@ fn panel_block(title: &str) -> Block<'static> { Block::default() .borders(Borders::ALL) .border_type(BorderType::Plain) - .border_style(Style::default().fg(ORANGE)) - .title(Span::styled( - format!(" {} ", title), - Style::default().fg(FG), - )) - .style(Style::default().bg(BG)) + .border_style(Style::default().fg(Color::Green)) + .title(Span::styled(format!(" {} ", title), Style::default())) + .style(Style::default()) } -- cgit v1.2.3-59-g8ed1b