102 lines
2.6 KiB
Rust
102 lines
2.6 KiB
Rust
|
|
use ratatui::{
|
||
|
|
layout::{Constraint, Direction, Layout, Rect},
|
||
|
|
style::{Color, Modifier, Style},
|
||
|
|
text::{Line, Span},
|
||
|
|
widgets::{Block, Borders, List, ListItem, Paragraph},
|
||
|
|
Frame,
|
||
|
|
};
|
||
|
|
|
||
|
|
use crate::state::{AppState, TimeItem};
|
||
|
|
|
||
|
|
const ACTIVE_COLOR: Color = Color::Green;
|
||
|
|
const INACTIVE_COLOR: Color = Color::Yellow;
|
||
|
|
|
||
|
|
pub fn render(frame: &mut Frame, state: &AppState) {
|
||
|
|
let chunks = Layout::default()
|
||
|
|
.direction(Direction::Vertical)
|
||
|
|
.constraints([
|
||
|
|
Constraint::Ratio(1, 3),
|
||
|
|
Constraint::Ratio(1, 3),
|
||
|
|
Constraint::Ratio(1, 3),
|
||
|
|
])
|
||
|
|
.split(frame.size());
|
||
|
|
|
||
|
|
render_section(
|
||
|
|
frame,
|
||
|
|
chunks[0],
|
||
|
|
"Permanent Items",
|
||
|
|
&state.permanent_items,
|
||
|
|
state.current_pane == 0,
|
||
|
|
state.selected_indices[0],
|
||
|
|
state,
|
||
|
|
);
|
||
|
|
|
||
|
|
render_section(
|
||
|
|
frame,
|
||
|
|
chunks[1],
|
||
|
|
"Recurring Items",
|
||
|
|
&state.recurring_items,
|
||
|
|
state.current_pane == 1,
|
||
|
|
state.selected_indices[1],
|
||
|
|
state,
|
||
|
|
);
|
||
|
|
|
||
|
|
render_section(
|
||
|
|
frame,
|
||
|
|
chunks[2],
|
||
|
|
"Recent Items",
|
||
|
|
&state.recent_items,
|
||
|
|
state.current_pane == 2,
|
||
|
|
state.selected_indices[2],
|
||
|
|
state,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn render_section(
|
||
|
|
frame: &mut Frame,
|
||
|
|
area: Rect,
|
||
|
|
title: &str,
|
||
|
|
items: &[TimeItem],
|
||
|
|
is_active: bool,
|
||
|
|
selected: usize,
|
||
|
|
state: &AppState,
|
||
|
|
) {
|
||
|
|
let border_color = if is_active { ACTIVE_COLOR } else { INACTIVE_COLOR };
|
||
|
|
|
||
|
|
let block = Block::default()
|
||
|
|
.borders(Borders::ALL)
|
||
|
|
.title(title)
|
||
|
|
.style(Style::default().fg(border_color));
|
||
|
|
|
||
|
|
let items: Vec<ListItem> = items
|
||
|
|
.iter()
|
||
|
|
.enumerate()
|
||
|
|
.map(|(i, item)| {
|
||
|
|
let is_running = state
|
||
|
|
.active_timer
|
||
|
|
.as_ref()
|
||
|
|
.map(|(active, _)| active.name == item.name)
|
||
|
|
.unwrap_or(false);
|
||
|
|
|
||
|
|
let style = if is_running {
|
||
|
|
Style::default().fg(ACTIVE_COLOR).add_modifier(Modifier::BOLD)
|
||
|
|
} else if i == selected && is_active {
|
||
|
|
Style::default().fg(border_color).add_modifier(Modifier::REVERSED)
|
||
|
|
} else {
|
||
|
|
Style::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
let mut line = item.name.clone();
|
||
|
|
if !item.tags.is_empty() {
|
||
|
|
line.push_str(" [");
|
||
|
|
line.push_str(&item.tags.join(", "));
|
||
|
|
line.push(']');
|
||
|
|
}
|
||
|
|
|
||
|
|
ListItem::new(Line::from(vec![Span::styled(line, style)]))
|
||
|
|
})
|
||
|
|
.collect();
|
||
|
|
|
||
|
|
let list = List::new(items).block(block);
|
||
|
|
frame.render_widget(list, area);
|
||
|
|
}
|