use crate::{action::Action, theme::Theme};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use ratatui::{
layout::Rect,
style::{Modifier, Style},
widgets::{Block, Borders},
Frame,
};
use tui_textarea::TextArea;
pub struct QueryInput {
textarea: TextArea<'static>,
focused: bool,
theme: Theme,
}
impl QueryInput {
pub fn new() -> Self {
let mut textarea = TextArea::default();
textarea.set_cursor_line_style(Style::default());
textarea.set_placeholder_text("Enter query or /command... (e.g., \"What are the main entities?\" or \"/config file.json5\")");
Self {
textarea,
focused: true,
theme: Theme::default(),
}
}
pub fn handle_key(&mut self, key: KeyEvent) -> Option<Action> {
if !self.focused {
return None;
}
match (key.code, key.modifiers) {
(KeyCode::Enter, KeyModifiers::NONE) => {
let content = self.textarea.lines().join("\n");
if content.trim().is_empty() {
return Some(Action::SetStatus(
crate::action::StatusType::Warning,
"Cannot submit empty input".to_string(),
));
}
self.textarea = TextArea::default();
self.textarea.set_cursor_line_style(Style::default());
self.textarea.set_placeholder_text("Enter query or /command... (e.g., \"What are the main entities?\" or \"/config file.json5\")");
if crate::mode::is_slash_command(&content) {
Some(Action::ExecuteSlashCommand(content))
} else {
Some(Action::ExecuteQuery(content))
}
},
(KeyCode::Char('d'), KeyModifiers::CONTROL) => {
self.textarea = TextArea::default();
self.textarea.set_cursor_line_style(Style::default());
self.textarea.set_placeholder_text("Enter query or /command... (e.g., \"What are the main entities?\" or \"/config file.json5\")");
Some(Action::Noop) },
_ => {
self.textarea.input(key);
Some(Action::Noop) },
}
}
pub fn set_focused(&mut self, focused: bool) {
self.focused = focused;
}
}
impl super::Component for QueryInput {
fn handle_action(&mut self, action: &Action) -> Option<Action> {
match action {
Action::FocusQueryInput => {
self.set_focused(true);
None
},
_ => None,
}
}
fn render(&mut self, f: &mut Frame, area: Rect) {
let border_color = if self.focused {
ratatui::style::Color::Green
} else {
self.theme.border
};
let title = if self.focused {
"💬 Input (Enter to submit | Ctrl+D to clear | Ctrl+N to focus panels)"
} else {
"💬 Input (Ctrl+N/Ctrl+P to cycle panels | Esc to return here)"
};
let block = Block::default()
.title(title)
.borders(Borders::ALL)
.border_style(
Style::default()
.fg(border_color)
.add_modifier(if self.focused {
Modifier::BOLD
} else {
Modifier::empty()
}),
);
self.textarea.set_block(block);
self.textarea.set_cursor_style(if self.focused {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default()
});
f.render_widget(&self.textarea, area);
}
}
impl Default for QueryInput {
fn default() -> Self {
Self::new()
}
}