//! Centered modal frame with border and title. use crate::theme; use ratatui::layout::Rect; use ratatui::style::{Color, Style}; use ratatui::widgets::{Block, Borders, Clear, Paragraph}; use ratatui::Frame; /// Centered modal overlay with titled border. pub struct ModalFrame<'a> { title: &'a str, width: u16, height: u16, border_color: Option, } impl<'a> ModalFrame<'a> { pub fn new(title: &'a str) -> Self { Self { title, width: 40, height: 5, border_color: None, } } pub fn width(mut self, w: u16) -> Self { self.width = w; self } pub fn height(mut self, h: u16) -> Self { self.height = h; self } pub fn border_color(mut self, c: Color) -> Self { self.border_color = Some(c); self } pub fn render_centered(&self, frame: &mut Frame, term: Rect) -> Rect { let t = theme::get(); let width = self.width.min(term.width.saturating_sub(4)); let height = self.height.min(term.height.saturating_sub(4)); let x = term.x + (term.width.saturating_sub(width)) / 2; let y = term.y + (term.height.saturating_sub(height)) / 2; let area = Rect::new(x, y, width, height); frame.render_widget(Clear, area); // Fill background with theme color let bg_fill = " ".repeat(area.width as usize); for row in 0..area.height { let line_area = Rect::new(area.x, area.y + row, area.width, 1); frame.render_widget( Paragraph::new(bg_fill.clone()).style(Style::new().bg(t.ui.bg)), line_area, ); } let border_color = self.border_color.unwrap_or(t.ui.text_primary); let block = Block::default() .borders(Borders::ALL) .title(self.title) .border_style(Style::new().fg(border_color)); let inner = block.inner(area); frame.render_widget(block, area); inner } }