use ratatui::Frame;
use ratatui::buffer::{Buffer, CellDiffOption};
use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Paragraph};
use crate::model::Issue;
use std::num::NonZeroU16;
mod render;
mod state;
pub use render::*;
pub use state::*;
pub(crate) fn dash_number<T: std::fmt::Display>(value: Option<T>) -> String {
value.map_or_else(|| "-".to_string(), |value| value.to_string())
}
pub(crate) fn dash_cell(value: Option<&str>) -> String {
let value = value.unwrap_or_default().trim();
if value.is_empty() {
return "-".to_string();
}
value
.chars()
.map(|ch| if ch == '\n' || ch == '\r' { ' ' } else { ch })
.collect()
}
pub(crate) fn time_entry_heading() -> String {
format!(
"{:<18} {:>7} {:<10} {:<14} {}",
TIME_COLUMNS[0], TIME_COLUMNS[1], TIME_COLUMNS[2], TIME_COLUMNS[3], TIME_COLUMNS[4]
)
}
pub(crate) fn time_entry_row(entry: &crate::time_tracking::TimeEntry) -> String {
let cells = [
dash_cell(Some(entry.id.as_str())),
dash_number(entry.minutes()),
dash_cell(entry.date.as_deref()),
dash_cell(Some(entry.author.as_str())),
dash_cell(entry.note.as_deref()),
];
let mut row = String::new();
for (index, cell) in cells.iter().enumerate() {
if index > 0 {
row.push_str(" ");
}
let width = TIME_WIDTHS[index];
if index == 1 {
row.push_str(&format!("{cell:>width$}"));
} else if width == 0 {
row.push_str(cell);
} else {
row.push_str(&format!("{cell:<width$}"));
}
}
row
}
#[cfg(test)]
mod tests;