1use crate::app::App;
2use ratatui::{
3 layout::{Constraint, Direction, Layout},
4 style::{Modifier, Style},
5 text::{Line, Span},
6 widgets::{Block, Borders, List, ListItem, Paragraph},
7 Frame,
8};
9
10pub fn render(frame: &mut Frame, app: &App) {
11 let area = frame.area();
12 let theme = &app.tui_theme;
13
14 let chunks = Layout::default()
16 .direction(Direction::Vertical)
17 .constraints([
18 Constraint::Min(0), Constraint::Length(1), ])
21 .split(area);
22
23 let logs_area = chunks[0];
24 let footer_area = chunks[1];
25
26 let block = Block::default()
27 .title(format!("Logs ({} messages)", app.log_messages.len()))
28 .borders(Borders::ALL)
29 .border_style(Style::default().fg(theme.border))
30 .title_style(
31 Style::default()
32 .fg(theme.primary)
33 .add_modifier(Modifier::BOLD),
34 );
35
36 let inner = block.inner(logs_area);
37 frame.render_widget(block, logs_area);
38
39 if app.log_messages.is_empty() {
40 return;
41 }
42
43 let items: Vec<ListItem> = app
45 .log_messages
46 .iter()
47 .enumerate()
48 .map(|(idx, msg)| {
49 let color = if msg.to_lowercase().contains("error") {
51 theme.error
52 } else if msg.to_lowercase().contains("warn") {
53 theme.warning
54 } else if msg.to_lowercase().contains("debug") {
55 theme.muted
56 } else {
57 theme.foreground
58 };
59
60 ListItem::new(Line::from(vec![
61 Span::styled(format!("[{}] ", idx + 1), Style::default().fg(theme.muted)),
62 Span::styled(msg, Style::default().fg(color)),
63 ]))
64 })
65 .collect();
66
67 let list = List::new(items);
68 frame.render_widget(list, inner);
69
70 let footer_text = if let Some(status) = app.get_status_message() {
72 status.to_string()
73 } else {
74 " 1-4:views r:refresh t:theme ?:help q:quit".to_string()
75 };
76
77 let footer = Paragraph::new(footer_text).style(Style::default().fg(theme.muted));
78 frame.render_widget(footer, footer_area);
79}