Feature 3: relative due dates right-aligned in task list

- Replace absolute date with relative string (Overdue, Xh left, X days left)
- Overdue in Red, <24h in Yellow, >=24h in DarkGray
- Due string right-aligned via padding calculation
This commit is contained in:
Ruben Rosario
2026-06-21 16:24:54 +01:00
parent 5cb8d0cd4e
commit aa91fb7a9d
+34 -10
View File
@@ -49,6 +49,24 @@ pub fn render_tabs_bar(
frame.render_widget(tabs, area); frame.render_widget(tabs, area);
} }
fn relative_due_str(due: chrono::NaiveDateTime) -> (String, Color) {
let now = chrono::Local::now().naive_local();
let diff = due - now;
if diff < chrono::Duration::zero() {
(" Overdue ".to_string(), Color::Red)
} else if diff < chrono::Duration::hours(24) {
let hours = diff.num_hours();
(format!(" {}h left ", hours), Color::Yellow)
} else {
let days = diff.num_days();
(
format!(" {} day{} left ", days, if days == 1 { "" } else { "s" }),
Color::DarkGray,
)
}
}
pub fn render_task_list( pub fn render_task_list(
frame: &mut Frame, frame: &mut Frame,
area: Rect, area: Rect,
@@ -61,6 +79,8 @@ pub fn render_task_list(
let done = tasks.iter().filter(|t| t.status == TaskStatus::Completed).count(); let done = tasks.iter().filter(|t| t.status == TaskStatus::Completed).count();
let todo = total - done; let todo = total - done;
let content_width = (area.width as usize).saturating_sub(5);
let items: Vec<ListItem> = tasks let items: Vec<ListItem> = tasks
.iter() .iter()
.map(|task| { .map(|task| {
@@ -69,12 +89,12 @@ pub fn render_task_list(
TaskStatus::NeedsAction => "[ ]", TaskStatus::NeedsAction => "[ ]",
}; };
let due_str = task let (due_text, due_color) = task
.due .due
.map(|d| d.format(" %d/%m/%Y %H:%M").to_string()) .map(relative_due_str)
.unwrap_or_default(); .unwrap_or((String::new(), Color::DarkGray));
let content = Line::from(vec![ let mut spans = vec![
Span::styled( Span::styled(
format!("{} ", checkbox), format!("{} ", checkbox),
Style::default().fg(if task.status == TaskStatus::Completed { Style::default().fg(if task.status == TaskStatus::Completed {
@@ -93,12 +113,16 @@ pub fn render_task_list(
}, },
), ),
), ),
Span::styled( ];
due_str,
Style::default().fg(Color::DarkGray), if !due_text.is_empty() {
), let left_len: usize = spans.iter().map(|s| s.content.len()).sum();
]); let pad = content_width.saturating_sub(left_len + due_text.len());
ListItem::new(content) spans.push(Span::raw(" ".repeat(pad)));
spans.push(Span::styled(due_text, Style::default().fg(due_color)));
}
ListItem::new(Line::from(spans))
}) })
.collect(); .collect();