use crate::theme::{input, ui}; use ratatui::layout::{Constraint, Layout, Rect}; use ratatui::style::{Color, Style}; use ratatui::text::{Line, Span}; use ratatui::widgets::Paragraph; use ratatui::Frame; use super::ModalFrame; pub struct TextInputModal<'a> { title: &'a str, input: &'a str, hint: Option<&'a str>, border_color: Color, width: u16, } impl<'a> TextInputModal<'a> { pub fn new(title: &'a str, input: &'a str) -> Self { Self { title, input, hint: None, border_color: ui::TEXT_PRIMARY, width: 50, } } pub fn hint(mut self, h: &'a str) -> Self { self.hint = Some(h); self } pub fn border_color(mut self, c: Color) -> Self { self.border_color = c; self } pub fn width(mut self, w: u16) -> Self { self.width = w; self } pub fn render_centered(self, frame: &mut Frame, term: Rect) { let height = if self.hint.is_some() { 6 } else { 5 }; let inner = ModalFrame::new(self.title) .width(self.width) .height(height) .border_color(self.border_color) .render_centered(frame, term); if self.hint.is_some() { let rows = Layout::vertical([Constraint::Length(1), Constraint::Length(1)]).split(inner); frame.render_widget( Paragraph::new(Line::from(vec![ Span::raw("> "), Span::styled(self.input, Style::new().fg(input::TEXT)), Span::styled("█", Style::new().fg(input::CURSOR)), ])), rows[0], ); if let Some(hint) = self.hint { frame.render_widget( Paragraph::new(Span::styled(hint, Style::new().fg(input::HINT))), rows[1], ); } } else { frame.render_widget( Paragraph::new(Line::from(vec![ Span::raw("> "), Span::styled(self.input, Style::new().fg(input::TEXT)), Span::styled("█", Style::new().fg(input::CURSOR)), ])), inner, ); } } }