usenet_reborn 0.2.2

Terminal-based Usenet NNTP client written in Rust with ratatui/crossterm.
use ratatui::{
    layout::{Constraint, Rect},
    style::{Color, Modifier, Style},
    widgets::{Block, Borders, Cell, Row, Table},
    Frame,
};

/// Static list of keybindings: (Pane, Key combo, Description)
const BINDINGS: &[(&str, &str, &str)] = &[
    (
        "Global",
        "Ctrl+h / Ctrl+l",
        "➤ Switch between Newsgroups ↔ Articles views",
    ),
    ("", "Ctrl+u", "➤ Update/Check for new articles on server"),
    ("Groups", "j / k", "➤ Move selection up/down in groups list"),
    ("", "Enter", "➤ Load unread articles for selected group"),
    ("", "q", "➤ Quit from the program"),
    (
        "Articles",
        "j / k",
        "➤ Move selection up/down in articles list",
    ),
    (
        "",
        "Ctrl+r",
        "➤ Mark all articles as read on selected newsgroup",
    ),
    (
        "",
        "Space",
        "➤ Toggle read/unread flag for selected article",
    ),
    ("", "Enter", "➤ Display article body"),
    (
        "",
        "n",
        "➤ Compose new post (popup for newsgroups & subject)",
    ),
    ("", "r", "➤ Reply to selected article"),
    ("", "Esc", "➤ Back to Groups view"),
    ("Article", "j / k", "➤ Scroll body up/down"),
    ("", "o", "➤ Open links in article with xdg-open"),
    ("", "r", "➤ Reply to this article"),
    ("", "q / Esc", "➤ Back to Articles view"),
];

/// Render the help table in the given `area`.
pub fn render_help(f: &mut Frame<'_>, area: Rect) {
    // Build table rows (excluding separator)
    let rows: Vec<Row> = BINDINGS
        .iter()
        .map(|(pane, key, desc)| {
            let pane_cell = Cell::from(*pane).style(
                Style::default()
                    .fg(Color::Yellow)
                    .add_modifier(Modifier::BOLD),
            );
            let key_cell = Cell::from(*key).style(
                Style::default()
                    .fg(Color::LightGreen)
                    .add_modifier(Modifier::BOLD),
            );
            let desc_cell = Cell::from(*desc).style(Style::default().fg(Color::Rgb(186, 85, 211)));
            Row::new(vec![pane_cell, key_cell, desc_cell])
        })
        .collect();

    // Separator line below the header
    let separator = Row::new(vec![
        Cell::from("".repeat(10)),
        Cell::from("".repeat(20)),
        Cell::from("".repeat(50)),
    ])
    .style(Style::default().fg(Color::White));

    // Combine separator + actual rows
    let mut table_rows = Vec::with_capacity(rows.len() + 1);
    table_rows.push(separator);
    table_rows.extend(rows);

    // Header row
    let header = Row::new(vec![
        Cell::from("Panel").style(
            Style::default()
                .fg(Color::Yellow)
                .add_modifier(Modifier::BOLD),
        ),
        Cell::from("Key").style(
            Style::default()
                .fg(Color::LightGreen)
                .add_modifier(Modifier::BOLD),
        ),
        Cell::from("Description").style(
            Style::default()
                .fg(Color::Rgb(186, 85, 211))
                .add_modifier(Modifier::BOLD),
        ),
    ]);

    // Build and render the table
    let table = Table::new(
        table_rows,
        &[
            Constraint::Length(10),
            Constraint::Length(20),
            Constraint::Min(10),
        ],
    )
    .header(header)
    .block(Block::default().borders(Borders::ALL).title("Keybindings"));

    f.render_widget(table, area);
}