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("Ctrl+U / Ctrl+D", "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("Ctrl+U / Ctrl+D", "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}