use crate::theme::Theme;
use arct_core::Explanation;
use ratatui::{
layout::Rect,
text::{Line, Span},
widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
Frame,
};
pub struct ExplanationPanel;
impl ExplanationPanel {
pub fn new() -> Self {
Self
}
pub fn render(
&self,
frame: &mut Frame,
area: Rect,
focused: bool,
explanation: Option<&Explanation>,
theme: &Theme,
ai_mode: bool,
ai_response: Option<&str>,
) {
let border_style = if focused {
theme.style_border_focused()
} else {
theme.style_border()
};
let title = if ai_mode {
" 🤖 AI Assistant "
} else {
" 📚 Learning "
};
let block = Block::default()
.title(title)
.borders(Borders::ALL)
.border_style(border_style);
if ai_mode {
if let Some(response) = ai_response {
let mut items = Vec::new();
items.push(ListItem::new(Line::from(vec![
Span::styled("🤖 ", theme.style_info()),
Span::styled("AI Response:", theme.style_header()),
])));
items.push(ListItem::new(Line::from("")));
for line in response.lines() {
items.push(ListItem::new(Line::from(vec![
Span::styled(line, theme.style_normal()),
])));
}
let list = List::new(items).block(block);
frame.render_widget(list, area);
} else {
let paragraph = Paragraph::new(vec![
Line::from(""),
Line::from(vec![
Span::styled("🤖 ", theme.style_info()),
Span::styled("AI Assistant Active", theme.style_accent()),
]),
Line::from(""),
Line::from(vec![
Span::styled("Ask me anything about shell commands!", theme.style_normal()),
]),
Line::from(""),
Line::from(vec![
Span::styled("Press ", theme.style_dim()),
Span::styled("Ctrl+A", theme.style_accent()),
Span::styled(" to return to shell mode", theme.style_dim()),
]),
])
.block(block)
.wrap(Wrap { trim: false });
frame.render_widget(paragraph, area);
}
} else if let Some(exp) = explanation {
let mut items = Vec::new();
items.push(ListItem::new(Line::from(vec![
Span::styled("📚 ", theme.style_info()),
Span::styled(&exp.summary, theme.style_accent()),
])));
items.push(ListItem::new(Line::from("")));
if !exp.flag_explanations.is_empty() {
items.push(ListItem::new(Line::from(vec![
Span::styled("🔍 ", theme.style_warning()),
Span::styled("Flag Explanations:", theme.style_header()),
])));
for flag_exp in &exp.flag_explanations {
items.push(ListItem::new(Line::from(vec![
Span::raw(" "),
Span::styled(&flag_exp.flag, theme.style_accent()),
Span::raw(" → "),
Span::styled(&flag_exp.description, theme.style_normal()),
])));
}
items.push(ListItem::new(Line::from("")));
}
if !exp.warnings.is_empty() {
items.push(ListItem::new(Line::from(vec![
Span::styled("⚠️ ", theme.style_warning()),
Span::styled("Warnings:", theme.style_warning()),
])));
for warning in &exp.warnings {
items.push(ListItem::new(Line::from(vec![
Span::raw(" • "),
Span::styled(&warning.message, theme.style_error()),
])));
}
items.push(ListItem::new(Line::from("")));
}
if !exp.tips.is_empty() {
items.push(ListItem::new(Line::from(vec![
Span::styled("💡 ", theme.style_info()),
Span::styled("Tips:", theme.style_header()),
])));
for tip in &exp.tips {
items.push(ListItem::new(Line::from(vec![
Span::raw(" "),
Span::styled(&tip.title, theme.style_accent()),
])));
items.push(ListItem::new(Line::from(vec![
Span::raw(" "),
Span::styled(&tip.content, theme.style_dim()),
])));
}
items.push(ListItem::new(Line::from("")));
}
if !exp.related_commands.is_empty() {
items.push(ListItem::new(Line::from(vec![
Span::styled("🔗 ", theme.style_success()),
Span::styled("Related: ", theme.style_secondary()),
Span::styled(exp.related_commands.join(", "), theme.style_dim()),
])));
}
let list = List::new(items).block(block);
frame.render_widget(list, area);
} else {
let paragraph = Paragraph::new(vec![
Line::from(""),
Line::from(vec![
Span::styled("👋 ", theme.style_info()),
Span::styled("Welcome to Arc Academy Terminal!", theme.style_accent()),
]),
Line::from(""),
Line::from(vec![
Span::styled("Type a command below and press ", theme.style_normal()),
Span::styled("Enter", theme.style_accent()),
Span::styled(" to see it explained.", theme.style_normal()),
]),
Line::from(""),
Line::from(vec![
Span::styled("Try: ", theme.style_dim()),
Span::styled("ls -lah", theme.style_accent()),
]),
Line::from(""),
Line::from(vec![
Span::styled("Press ", theme.style_dim()),
Span::styled("?", theme.style_accent()),
Span::styled(" for help", theme.style_dim()),
]),
])
.block(block)
.wrap(Wrap { trim: false });
frame.render_widget(paragraph, area);
}
}
}
impl Default for ExplanationPanel {
fn default() -> Self {
Self::new()
}
}