pub mod command_completion;
pub mod command_menu;
pub mod dialogs;
pub mod help;
mod kanban;
pub mod layout;
pub mod preview;
mod sidebar;
mod statusbar;
pub mod welcome;
use crate::app::App;
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::Frame;
pub fn render(f: &mut Frame, app: &App) {
render_split_tree(f, f.area(), &app.split_tree, app);
if let Some(dialog) = &app.dialog {
dialogs::render_dialog(f, dialog);
}
if app.mode == crate::app::Mode::Help {
help::render(f, f.area());
}
if app.mode == crate::app::Mode::Preview {
preview::render(f, f.area(), app);
}
if app.mode == crate::app::Mode::SpaceMenu {
command_menu::render(f, f.area(), app);
}
if app.mode == crate::app::Mode::Command {
command_completion::render(f, f.area(), app);
}
if app.show_welcome_dialog {
welcome::render(f, f.area(), &app.config);
}
}
fn render_split_tree(f: &mut Frame, area: ratatui::layout::Rect, node: &layout::SplitNode, app: &App) {
use layout::SplitNode;
match node {
SplitNode::Leaf { project_id, id } => {
let is_focused = *id == app.focused_pane;
if let Some(pid) = project_id {
if let Some(project) = app.projects.iter().find(|p| &p.name == pid) {
kanban::render(f, area, project, is_focused, app);
} else {
render_empty_pane(f, area, "项目未找到", is_focused);
}
} else {
render_empty_pane(f, area, "无项目 - 按 Space p o 打开项目", is_focused);
}
}
SplitNode::Horizontal { left, right, ratio } => {
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage((ratio * 100.0) as u16),
Constraint::Percentage(((1.0 - ratio) * 100.0) as u16),
])
.split(area);
render_split_tree(f, chunks[0], left, app);
render_split_tree(f, chunks[1], right, app);
}
SplitNode::Vertical { top, bottom, ratio } => {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Percentage((ratio * 100.0) as u16),
Constraint::Percentage(((1.0 - ratio) * 100.0) as u16),
])
.split(area);
render_split_tree(f, chunks[0], top, app);
render_split_tree(f, chunks[1], bottom, app);
}
}
}
fn render_empty_pane(f: &mut Frame, area: ratatui::layout::Rect, message: &str, is_focused: bool) {
use ratatui::style::{Color, Style};
use ratatui::widgets::{Block, Borders, Paragraph};
let border_style = if is_focused {
Style::default().fg(Color::Cyan)
} else {
Style::default().fg(Color::DarkGray)
};
let block = Block::default()
.borders(Borders::ALL)
.border_style(border_style)
.border_type(ratatui::widgets::BorderType::Rounded);
let paragraph = Paragraph::new(message)
.block(block)
.style(Style::default().fg(Color::Gray));
f.render_widget(paragraph, area);
}