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