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(60, 70, 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        key_line("↑ / ↓", "Navigate module list (Intro/Examples views)"),
23        key_line("Tab / Esc", "Cycle views: Intro → Examples → Exercise"),
24        key_line("Enter", "Submit command"),
25        key_line("↑ / ↓", "Scroll output (Exercise view)"),
26        key_line("← / →", "Move cursor in input"),
27        Line::from(""),
28        Line::from(Span::styled(
29            "  Exercise shortcuts (Ctrl+key)",
30            Style::default()
31                .fg(Color::Cyan)
32                .add_modifier(Modifier::BOLD),
33        )),
34        Line::from(""),
35        key_line("Ctrl+N / Ctrl+P", "Next / previous exercise"),
36        key_line("Ctrl+T", "Reveal next hint"),
37        key_line("Ctrl+S", "Show/hide solution"),
38        key_line("Ctrl+F", "Toggle file viewer"),
39        key_line("Ctrl+R", "Reset exercise"),
40        key_line("Ctrl+L", "Clear output panel"),
41        Line::from(""),
42        key_line("q", "Quit (Intro/Examples)"),
43        key_line("Ctrl+C", "Quit (anywhere)"),
44        Line::from(""),
45        Line::from(Span::styled(
46            "Press Esc to close",
47            Style::default().fg(Color::DarkGray),
48        )),
49    ];
50
51    let para = Paragraph::new(lines).block(
52        Block::default()
53            .borders(Borders::ALL)
54            .title(" Help ")
55            .style(Style::default().bg(Color::Black)),
56    );
57
58    frame.render_widget(para, overlay);
59}
60
61fn key_line(key: &str, desc: &str) -> Line<'static> {
62    Line::from(vec![
63        Span::styled(
64            format!("  {:<15}", key),
65            Style::default()
66                .fg(Color::Yellow)
67                .add_modifier(Modifier::BOLD),
68        ),
69        Span::raw(desc.to_string()),
70    ])
71}
72
73fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
74    let vert = Layout::default()
75        .direction(Direction::Vertical)
76        .constraints([
77            Constraint::Percentage((100 - percent_y) / 2),
78            Constraint::Percentage(percent_y),
79            Constraint::Percentage((100 - percent_y) / 2),
80        ])
81        .split(r);
82    Layout::default()
83        .direction(Direction::Horizontal)
84        .constraints([
85            Constraint::Percentage((100 - percent_x) / 2),
86            Constraint::Percentage(percent_x),
87            Constraint::Percentage((100 - percent_x) / 2),
88        ])
89        .split(vert[1])[1]
90}