use ratatui::{
Frame,
layout::Rect,
style::{Modifier, Style},
text::{Line, Span},
widgets::{Clear, Paragraph},
};
use crate::app::App;
use crate::ui::theme;
pub fn draw(frame: &mut Frame, app: &mut App) {
app.rects.workspace_picker_rows.clear();
app.rects.workspace_picker_filter_input = None;
if !app.workspace_picker_open {
return;
}
let Some(chev_rect) = app.rects.workspace_picker_chevron else {
return;
};
if app.config.workspaces.is_empty() {
return;
}
let t = theme::cur();
let filter_lc = app.workspace_picker_filter.to_ascii_lowercase();
let mut groups: Vec<(String, Vec<usize>)> = Vec::new();
for (i, w) in app.config.workspaces.iter().enumerate() {
let group = w.group.clone().unwrap_or_default();
let name_lc = w.name.to_ascii_lowercase();
let group_lc = group.to_ascii_lowercase();
if !filter_lc.is_empty() && !name_lc.contains(&filter_lc) && !group_lc.contains(&filter_lc)
{
continue;
}
if let Some(slot) = groups.iter_mut().find(|(g, _)| g == &group) {
slot.1.push(i);
} else {
groups.push((group, vec![i]));
}
}
if groups.is_empty() {
return;
}
let max_label = app
.config
.workspaces
.iter()
.map(|w| w.name.chars().count())
.max()
.unwrap_or(20);
let w = (max_label as u16 + 4).max(28);
let body_rows: u16 = groups
.iter()
.map(|(g, rows)| if g.is_empty() { rows.len() } else { 1 + rows.len() } as u16)
.sum::<u16>();
let h = body_rows + 4; let screen_w = frame.area().width;
let screen_h = frame.area().height;
let x = chev_rect.x.min(screen_w.saturating_sub(w));
let y = (chev_rect.y + 1).min(screen_h.saturating_sub(h));
let area = Rect {
x,
y,
width: w.min(screen_w),
height: h.min(screen_h),
};
frame.render_widget(Clear, area);
let block = crate::ui::design_tokens::modal_panel("Workspaces");
let inner = block.inner(area);
frame.render_widget(block, area);
let mut y = inner.y;
if y < inner.y + inner.height {
let display = if app.workspace_picker_filter.is_empty() {
"Filter workspaces…".to_string()
} else {
app.workspace_picker_filter.clone()
};
let fg = if app.workspace_picker_filter.is_empty() {
t.comment
} else {
t.fg
};
let cursor = "▏";
let pad = (inner.width as usize).saturating_sub(display.chars().count() + 1 + 1);
let line = Line::from(vec![
Span::styled("\u{F0349} ", Style::default().fg(t.comment).bg(t.bg2)),
Span::styled(display, Style::default().fg(fg).bg(t.bg2)),
Span::styled(cursor, Style::default().fg(t.cyan).bg(t.bg2)),
Span::styled(" ".repeat(pad), Style::default().bg(t.bg2)),
]);
let row = Rect {
x: inner.x,
y,
width: inner.width,
height: 1,
};
frame.render_widget(Paragraph::new(line), row);
app.rects.workspace_picker_filter_input = Some(row);
y += 1;
}
if y < inner.y + inner.height {
y += 1;
}
for (group, rows) in &groups {
if y >= inner.y + inner.height {
break;
}
if !group.is_empty() {
let header_line = Line::from(vec![Span::styled(
format!(" {group} "),
Style::default()
.fg(t.comment)
.bg(t.bg2)
.add_modifier(Modifier::BOLD),
)]);
frame.render_widget(
Paragraph::new(header_line),
Rect {
x: inner.x,
y,
width: inner.width,
height: 1,
},
);
y += 1;
}
for &i in rows {
if y >= inner.y + inner.height {
break;
}
let w_cfg = &app.config.workspaces[i];
let ws_idx = i + 1;
let line = Line::from(vec![
Span::styled(" ", Style::default().bg(t.bg2)),
Span::styled(w_cfg.name.clone(), Style::default().fg(t.fg).bg(t.bg2)),
]);
let row = Rect {
x: inner.x,
y,
width: inner.width,
height: 1,
};
frame.render_widget(Paragraph::new(line), row);
app.rects.workspace_picker_rows.push((row, ws_idx));
y += 1;
}
}
}