use crate::theme::Theme;
use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
text::{Line, Span},
widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
Frame,
};
pub struct HelpPanel;
impl HelpPanel {
pub fn new() -> Self {
Self
}
pub fn render(&self, frame: &mut Frame, theme: &Theme) {
let area = Self::centered_rect(60, 80, frame.size());
frame.render_widget(Clear, area);
let block = Block::default()
.title(" Arc Academy Terminal - Help ")
.title_alignment(Alignment::Center)
.borders(Borders::ALL)
.border_style(theme.style_border_focused())
.style(theme.style_block());
let inner = block.inner(area);
frame.render_widget(block, area);
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(7), Constraint::Length(6), Constraint::Length(5), Constraint::Min(1), ])
.split(inner);
let nav_items = vec![
ListItem::new(Line::from(vec![
Span::styled("Navigation", theme.style_header()),
])),
ListItem::new(Line::from(vec![
Span::styled(" Tab", theme.style_accent()),
Span::raw(" / "),
Span::styled("Shift+Tab", theme.style_accent()),
Span::raw(" → Switch panels"),
])),
ListItem::new(Line::from(vec![
Span::styled(" Ctrl+↑/↓", theme.style_accent()),
Span::raw(" → Scroll output (any panel)"),
])),
ListItem::new(Line::from(vec![
Span::styled(" ↑/↓", theme.style_accent()),
Span::raw(" or "),
Span::styled("j/k", theme.style_accent()),
Span::raw(" → Scroll (when Output focused)"),
])),
ListItem::new(Line::from(vec![
Span::styled(" PgUp/PgDn", theme.style_accent()),
Span::raw(" → Page scroll output"),
])),
];
frame.render_widget(List::new(nav_items), chunks[0]);
let edit_items = vec![
ListItem::new(Line::from(vec![
Span::styled("Command Editing", theme.style_header()),
])),
ListItem::new(Line::from(vec![
Span::styled(" Type", theme.style_accent()),
Span::raw(" → Enter command"),
])),
ListItem::new(Line::from(vec![
Span::styled(" Enter", theme.style_accent()),
Span::raw(" → Explain command"),
])),
ListItem::new(Line::from(vec![
Span::styled(" Backspace", theme.style_accent()),
Span::raw(" → Delete character"),
])),
];
frame.render_widget(List::new(edit_items), chunks[1]);
let action_items = vec![
ListItem::new(Line::from(vec![
Span::styled("Actions", theme.style_header()),
])),
ListItem::new(Line::from(vec![
Span::styled(" Ctrl+t", theme.style_accent()),
Span::raw(" → Toggle theme"),
])),
ListItem::new(Line::from(vec![
Span::styled(" q", theme.style_accent()),
Span::raw(" or "),
Span::styled("Ctrl+c", theme.style_accent()),
Span::raw(" → Quit"),
])),
];
frame.render_widget(List::new(action_items), chunks[2]);
let info = Paragraph::new(vec![
Line::from(""),
Line::from(vec![
Span::styled("Press ", theme.style_dim()),
Span::styled("?", theme.style_accent()),
Span::styled(" or ", theme.style_dim()),
Span::styled("Esc", theme.style_accent()),
Span::styled(" to close this help", theme.style_dim()),
]),
])
.alignment(Alignment::Center);
frame.render_widget(info, chunks[3]);
}
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
let popup_layout = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Percentage((100 - percent_y) / 2),
Constraint::Percentage(percent_y),
Constraint::Percentage((100 - percent_y) / 2),
])
.split(r);
Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage((100 - percent_x) / 2),
Constraint::Percentage(percent_x),
Constraint::Percentage((100 - percent_x) / 2),
])
.split(popup_layout[1])[1]
}
}
impl Default for HelpPanel {
fn default() -> Self {
Self::new()
}
}