trackWork 0.13.0

A terminal-based time tracking application for managing work sessions
use ratatui::{
    layout::{Alignment, Constraint, Direction, Layout, Rect},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Paragraph, Wrap},
    Frame,
};

/// Get the changelog content by parsing APP_CHANGELOG.md
pub fn get_changelog() -> Vec<Line<'static>> {
    const CHANGELOG: &str = include_str!("../../APP_CHANGELOG.md");

    let mut lines = Vec::new();

    for line in CHANGELOG.lines() {
        let trimmed = line.trim();

        // Skip the title line
        if trimmed.starts_with("# ") {
            continue;
        }

        // Version header
        if trimmed.starts_with("## ") {
            let version = trimmed.trim_start_matches("## ");
            lines.push(Line::from(vec![
                Span::styled(
                    version.to_string(),
                    Style::default()
                        .fg(Color::Cyan)
                        .add_modifier(Modifier::BOLD),
                ),
            ]));
        }
        // Bullet point
        else if trimmed.starts_with("- ") {
            let text = trimmed.trim_start_matches("- ");
            lines.push(Line::from(vec![
                Span::styled("", Style::default().fg(Color::Green)),
                Span::raw(text.to_string()),
            ]));
        }
        // Empty line
        else if trimmed.is_empty() {
            lines.push(Line::from(""));
        }
    }

    lines
}

/// Draw the What's New modal
pub fn draw_whats_new(f: &mut Frame) {
    let area = centered_rect(80, 80, f.area());

    // Create the modal block
    let block = Block::default()
        .borders(Borders::ALL)
        .border_style(Style::default().fg(Color::Cyan))
        .title(vec![
            Span::raw(" "),
            Span::styled(
                format!("🎉 trackWork v{} - What's New", env!("CARGO_PKG_VERSION")),
                Style::default()
                    .fg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::raw(" "),
        ]);

    // Split the modal into title, content, and footer
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Min(3),    // Content area
            Constraint::Length(3), // Footer
        ])
        .split(area);

    // Render the main block
    f.render_widget(block, area);

    // Content area (changelog)
    let content_area = Rect {
        x: chunks[0].x + 2,
        y: chunks[0].y + 1,
        width: chunks[0].width.saturating_sub(4),
        height: chunks[0].height.saturating_sub(2),
    };

    let changelog = get_changelog();
    let content = Paragraph::new(changelog)
        .wrap(Wrap { trim: false })
        .alignment(Alignment::Left);

    f.render_widget(content, content_area);

    // Footer (help text)
    let footer_area = Rect {
        x: chunks[1].x + 2,
        y: chunks[1].y,
        width: chunks[1].width.saturating_sub(4),
        height: chunks[1].height,
    };

    let help_text = vec![Line::from(vec![
        Span::styled("Press ", Style::default().fg(Color::Gray)),
        Span::styled("Enter", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)),
        Span::styled(" or ", Style::default().fg(Color::Gray)),
        Span::styled("Esc", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)),
        Span::styled(" to close", Style::default().fg(Color::Gray)),
    ])];

    let footer = Paragraph::new(help_text).alignment(Alignment::Center);
    f.render_widget(footer, footer_area);
}

/// Helper function to create a centered rectangle
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
    let popup_layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Percentage((100 - percent_y) / 2),
            Constraint::Percentage(percent_y),
            Constraint::Percentage((100 - percent_y) / 2),
        ])
        .split(r);

    Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Percentage((100 - percent_x) / 2),
            Constraint::Percentage(percent_x),
            Constraint::Percentage((100 - percent_x) / 2),
        ])
        .split(popup_layout[1])[1]
}