Skip to main content

cli_tutor/ui/
help_overlay.rs

1use crate::app::App;
2use ratatui::{
3    layout::{Constraint, Direction, Layout, Rect},
4    style::{Color, Modifier, Style},
5    text::{Line, Span},
6    widgets::{Block, Borders, Clear, Paragraph},
7    Frame,
8};
9
10pub fn render(_app: &App, frame: &mut Frame, area: Rect) {
11    let overlay = centered_rect(62, 85, area);
12    frame.render_widget(Clear, overlay);
13
14    let lines = vec![
15        Line::from(Span::styled(
16            "Keyboard Reference",
17            Style::default()
18                .add_modifier(Modifier::BOLD)
19                .fg(Color::Cyan),
20        )),
21        Line::from(""),
22        Line::from(Span::styled(
23            "  Browsing (Intro / Examples)",
24            Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD),
25        )),
26        Line::from(""),
27        key_line("↑ / ↓", "Navigate module list"),
28        key_line("Tab", "Cycle views: Intro → Examples → Exercise → Free"),
29        key_line("PgUp / PgDn", "Scroll content"),
30        key_line("/", "Fuzzy search modules"),
31        key_line("d", "Cycle difficulty filter"),
32        key_line("P", "Progress summary"),
33        key_line("q", "Quit"),
34        Line::from(""),
35        Line::from(Span::styled(
36            "  Exercise view",
37            Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD),
38        )),
39        Line::from(""),
40        key_line("Enter", "Submit command"),
41        key_line("↑ / ↓", "Browse command history"),
42        key_line("PgUp / PgDn", "Scroll output"),
43        key_line("← / →", "Move cursor"),
44        key_line("Ctrl+← / →", "Jump by word"),
45        key_line("Ctrl+N / Ctrl+P", "Next / previous exercise"),
46        key_line("Ctrl+T", "Reveal next hint"),
47        key_line("Ctrl+S", "Show/hide solution"),
48        key_line("Ctrl+F", "Toggle file viewer"),
49        key_line("Ctrl+R", "Reset exercise"),
50        key_line("Ctrl+L", "Clear output"),
51        key_line("Esc", "Back to browse"),
52        Line::from(""),
53        key_line("Ctrl+C", "Quit (anywhere)"),
54        key_line("P", "Progress summary (anywhere)"),
55        Line::from(""),
56        Line::from(Span::styled(
57            "Press Esc or ? to close",
58            Style::default().fg(Color::DarkGray),
59        )),
60    ];
61
62    let para = Paragraph::new(lines).block(
63        Block::default()
64            .borders(Borders::ALL)
65            .title(" Help ")
66            .style(Style::default().bg(Color::Black)),
67    );
68
69    frame.render_widget(para, overlay);
70}
71
72fn key_line(key: &str, desc: &str) -> Line<'static> {
73    Line::from(vec![
74        Span::styled(
75            format!("  {:<16}", key),
76            Style::default()
77                .fg(Color::Yellow)
78                .add_modifier(Modifier::BOLD),
79        ),
80        Span::raw(desc.to_string()),
81    ])
82}
83
84fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
85    let vert = Layout::default()
86        .direction(Direction::Vertical)
87        .constraints([
88            Constraint::Percentage((100 - percent_y) / 2),
89            Constraint::Percentage(percent_y),
90            Constraint::Percentage((100 - percent_y) / 2),
91        ])
92        .split(r);
93    Layout::default()
94        .direction(Direction::Horizontal)
95        .constraints([
96            Constraint::Percentage((100 - percent_x) / 2),
97            Constraint::Percentage(percent_x),
98            Constraint::Percentage((100 - percent_x) / 2),
99        ])
100        .split(vert[1])[1]
101}