diff options
Diffstat (limited to 'src/ui/dialogs.rs')
| -rw-r--r-- | src/ui/dialogs.rs | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/ui/dialogs.rs b/src/ui/dialogs.rs new file mode 100644 index 00000000..78f1d1cb --- /dev/null +++ b/src/ui/dialogs.rs @@ -0,0 +1,213 @@ +use ratatui::{ + layout::{Constraint, Layout, Rect}, + style::{Modifier, Style}, + text::{Line, Span}, + widgets::{Clear, Paragraph}, + Frame, +}; + +use super::widgets::{ + action_button_row_rects, centered_popup_rect, panel_contrast_fg, render_action_button, + render_modal_header, render_modal_shell, render_panel_shell, ActionButtonSpec, +}; +use crate::app::{AppState, Mode}; + +pub(crate) fn rename_button_rects(inner: Rect) -> (Rect, Rect, Rect) { + let rects = action_button_row_rects( + inner, + &[ + ActionButtonSpec { + hint: Some("↵"), + label: "save", + }, + ActionButtonSpec { + hint: Some("^c"), + label: "clear", + }, + ActionButtonSpec { + hint: Some("esc"), + label: "cancel", + }, + ], + 2, + 3, + ); + (rects[0], rects[1], rects[2]) +} + +pub(super) fn render_rename_overlay(app: &AppState, frame: &mut Frame, area: Rect) { + super::dim_background(frame, area); + + let title = match app.mode { + Mode::RenameWorkspace => "rename workspace", + Mode::RenameTab if app.creating_new_tab => "new tab", + Mode::RenameTab => "rename tab", + _ => return, + }; + + let Some(inner) = render_modal_shell(frame, area, 56, 7, &app.palette) else { + return; + }; + if inner.height < 4 { + return; + } + + let rows = Layout::vertical([ + Constraint::Length(1), + Constraint::Length(1), + Constraint::Length(1), + Constraint::Length(1), + Constraint::Min(0), + ]) + .areas::<5>(inner); + + render_modal_header(frame, rows[0], title, &app.palette); + + let input_rect = Rect::new(rows[2].x, rows[2].y, rows[2].width, 1); + frame.render_widget(Clear, input_rect); + frame.render_widget( + Paragraph::new(format!(" {}█", app.name_input)).style( + Style::default() + .fg(app.palette.text) + .bg(app.palette.surface0), + ), + input_rect, + ); + + let (save_rect, clear_rect, cancel_rect) = rename_button_rects(inner); + + render_action_button( + frame, + save_rect, + Some("↵"), + "save", + Style::default() + .fg(panel_contrast_fg(&app.palette)) + .bg(app.palette.accent) + .add_modifier(Modifier::BOLD), + ); + render_action_button( + frame, + clear_rect, + Some("^c"), + "clear", + Style::default() + .fg(app.palette.text) + .bg(app.palette.surface0) + .add_modifier(Modifier::BOLD), + ); + render_action_button( + frame, + cancel_rect, + Some("esc"), + "cancel", + Style::default() + .fg(app.palette.text) + .bg(app.palette.surface0) + .add_modifier(Modifier::BOLD), + ); +} + +pub(super) fn render_confirm_close_overlay(app: &AppState, frame: &mut Frame, area: Rect) { + let ws_name = app + .workspaces + .get(app.selected) + .map(|ws| ws.display_name()) + .unwrap_or_else(|| "?".to_string()); + let pane_count = app + .workspaces + .get(app.selected) + .map(|ws| ws.layout.pane_count()) + .unwrap_or(0); + + let pane_text = if pane_count == 1 { + "1 pane".to_string() + } else { + format!("{pane_count} panes") + }; + + super::dim_background(frame, area); + + let Some(popup) = confirm_close_popup_rect(area) else { + return; + }; + + let warn = Style::default() + .fg(app.palette.red) + .add_modifier(Modifier::BOLD); + let dim = Style::default().fg(app.palette.overlay0); + + let title_line = Line::from(vec![Span::styled(" Close workspace?", warn)]); + + let detail_line = Line::from(vec![ + Span::styled( + format!(" {ws_name}"), + Style::default() + .fg(app.palette.text) + .add_modifier(Modifier::BOLD), + ), + Span::styled(format!(" — {pane_text}"), dim), + ]); + + let Some(inner) = render_panel_shell(frame, popup, app.palette.red, app.palette.panel_bg) + else { + return; + }; + + if inner.height >= 3 { + let rows = Layout::vertical([ + Constraint::Length(1), + Constraint::Length(1), + Constraint::Length(1), + ]) + .areas::<3>(inner); + + frame.render_widget(Paragraph::new(title_line), rows[0]); + frame.render_widget(Paragraph::new(detail_line), rows[1]); + + let (confirm_rect, cancel_rect) = confirm_close_button_rects(inner); + render_action_button( + frame, + confirm_rect, + Some("↵"), + "confirm", + Style::default() + .fg(panel_contrast_fg(&app.palette)) + .bg(app.palette.red) + .add_modifier(Modifier::BOLD), + ); + render_action_button( + frame, + cancel_rect, + Some("esc"), + "cancel", + Style::default() + .fg(app.palette.text) + .bg(app.palette.surface0) + .add_modifier(Modifier::BOLD), + ); + } +} + +pub(crate) fn confirm_close_popup_rect(area: Rect) -> Option<Rect> { + centered_popup_rect(area, 44, 5) +} + +pub(crate) fn confirm_close_button_rects(inner: Rect) -> (Rect, Rect) { + let rects = action_button_row_rects( + inner, + &[ + ActionButtonSpec { + hint: Some("↵"), + label: "confirm", + }, + ActionButtonSpec { + hint: Some("esc"), + label: "cancel", + }, + ], + 2, + 2, + ); + (rects[0], rects[1]) +} |
