mod add_task;
mod confirm;
mod delete_project;
mod filter_sort;
mod move_to_project;
mod project;
mod quick_capture;
mod settings;
pub use add_task::AddTaskDialog;
pub use confirm::ConfirmDialog;
pub use delete_project::{DeleteProjectChoice, DeleteProjectDialog};
pub use filter_sort::FilterSortDialog;
pub use move_to_project::MoveToProjectDialog;
pub use project::ProjectDialog;
pub use quick_capture::{QuickCaptureAction, QuickCaptureDialog};
pub use settings::{SettingsDialog, SettingsOption};
use ratatui::{
buffer::Buffer,
layout::{Constraint, Flex, Layout, Rect},
style::{Modifier, Style},
symbols::border,
text::Span,
widgets::{Block, Borders, Clear, Widget},
Frame,
};
use super::theme;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DialogAction {
None,
Submit,
Cancel,
}
#[derive(Debug)]
pub enum Dialog {
AddTask(Box<AddTaskDialog>),
Confirm(ConfirmDialog),
DeleteProject(DeleteProjectDialog),
FilterSort(FilterSortDialog),
MoveToProject(MoveToProjectDialog),
Project(ProjectDialog),
Settings(SettingsDialog),
QuickCapture(Box<QuickCaptureDialog>),
}
impl Dialog {
pub fn render(&self, frame: &mut Frame) {
match self {
Dialog::AddTask(dialog) => dialog.render(frame),
Dialog::Confirm(dialog) => dialog.render(frame),
Dialog::DeleteProject(dialog) => dialog.render(frame),
Dialog::FilterSort(dialog) => dialog.render(frame),
Dialog::MoveToProject(dialog) => dialog.render(frame),
Dialog::Project(dialog) => dialog.render(frame),
Dialog::Settings(dialog) => dialog.render(frame),
Dialog::QuickCapture(dialog) => dialog.render(frame),
}
}
}
pub fn centered_rect(width: u16, height: u16, area: Rect) -> Rect {
let [area] = Layout::horizontal([Constraint::Length(width)])
.flex(Flex::Center)
.areas(area);
let [area] = Layout::vertical([Constraint::Length(height)])
.flex(Flex::Center)
.areas(area);
area
}
pub fn render_dialog_background(area: Rect, buf: &mut Buffer) {
Clear.render(area, buf);
for y in area.y..area.y + area.height {
for x in area.x..area.x + area.width {
buf[(x, y)].set_style(Style::default().bg(theme::BG_DARK));
}
}
}
pub fn render_dialog_box(area: Rect, buf: &mut Buffer, title: &str) {
let block = dialog_block(title, false);
block.render(area, buf);
}
pub fn dialog_block(title: &str, destructive: bool) -> Block<'static> {
let border_color = if destructive {
theme::ERROR
} else {
theme::PRIMARY_LIGHT
};
let title_style = Style::default()
.fg(border_color)
.add_modifier(Modifier::BOLD);
Block::default()
.title(Span::styled(format!(" {} ", title), title_style))
.borders(Borders::ALL)
.border_set(border::ROUNDED)
.border_style(Style::default().fg(border_color))
.style(Style::default().bg(theme::BG_ELEVATED))
}
pub fn field_block(label: &str, focused: bool) -> Block<'static> {
let border_color = if focused {
theme::PRIMARY_LIGHT
} else {
theme::BORDER
};
let label_style = if focused {
Style::default()
.fg(theme::PRIMARY_LIGHT)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(theme::TEXT_MUTED)
};
Block::default()
.title(Span::styled(format!(" {} ", label), label_style))
.borders(Borders::ALL)
.border_set(border::ROUNDED)
.border_style(Style::default().fg(border_color))
}
pub fn selected_style() -> Style {
Style::default()
.bg(theme::BG_SELECTION)
.fg(theme::TEXT_PRIMARY)
.add_modifier(Modifier::BOLD)
}
pub fn unselected_style() -> Style {
Style::default().fg(theme::TEXT_SECONDARY)
}
pub fn hint_style() -> Style {
Style::default().fg(theme::TEXT_MUTED)
}
pub fn button_focused_style() -> Style {
Style::default()
.bg(theme::PRIMARY)
.fg(theme::TEXT_PRIMARY)
.add_modifier(Modifier::BOLD)
}
pub fn button_style() -> Style {
Style::default()
.fg(theme::TEXT_SECONDARY)
}
pub fn button_danger_style() -> Style {
Style::default()
.bg(theme::ERROR)
.fg(theme::TEXT_PRIMARY)
.add_modifier(Modifier::BOLD)
}