use ratatui::{
Frame,
prelude::Rect,
style::{Modifier, Style},
text::{Line, Span},
widgets::{Block, BorderType, Borders, Clear, Paragraph, Wrap},
};
use crate::i18n;
use crate::state::types::{AppMode, NewsSortMode};
use crate::state::{AppState, SortMode};
use crate::theme::theme;
pub fn render_sort_menu(f: &mut Frame, app: &mut AppState, area: Rect, btn_x: u16) {
let th = theme();
app.sort_menu_rect = None;
if app.sort_menu_open {
let opts: Vec<(String, bool)> = if matches!(app.app_mode, AppMode::News) {
vec![
(
"Date (newest)".to_string(),
app.news_sort_mode == NewsSortMode::DateDesc,
),
(
"Date (oldest)".to_string(),
app.news_sort_mode == NewsSortMode::DateAsc,
),
(
"Title".to_string(),
app.news_sort_mode == NewsSortMode::Title,
),
(
"Source".to_string(),
app.news_sort_mode == NewsSortMode::SourceThenTitle,
),
(
"Severity (critical first)".to_string(),
app.news_sort_mode == NewsSortMode::SeverityThenDate,
),
(
"Unread first".to_string(),
app.news_sort_mode == NewsSortMode::UnreadThenDate,
),
]
} else {
vec![
(
i18n::t(app, "app.results.sort_menu.options.alphabetical"),
matches!(app.sort_mode, SortMode::RepoThenName),
),
(
i18n::t(app, "app.results.sort_menu.options.aur_popularity"),
matches!(app.sort_mode, SortMode::AurPopularityThenOfficial),
),
(
i18n::t(app, "app.results.sort_menu.options.best_matches"),
matches!(app.sort_mode, SortMode::BestMatches),
),
]
};
let widest = opts
.iter()
.map(|(s, _)| u16::try_from(s.len()).map_or(u16::MAX, |x| x))
.max()
.unwrap_or(0);
let w = widest.saturating_add(2).min(area.width.saturating_sub(2));
let rect_w = w.saturating_add(2);
let max_x = area.x + area.width.saturating_sub(rect_w);
let menu_x = btn_x.min(max_x);
let menu_y = area.y.saturating_add(1); let h = u16::try_from(opts.len())
.unwrap_or(u16::MAX)
.saturating_add(2); let rect = ratatui::prelude::Rect {
x: menu_x,
y: menu_y,
width: rect_w,
height: h,
};
app.sort_menu_rect = Some((rect.x + 1, rect.y + 1, w, h.saturating_sub(2)));
let mut lines: Vec<Line> = Vec::new();
for (text, selected) in &opts {
let is_selected = *selected;
let mark = if is_selected { "✔ " } else { " " };
let style = if is_selected {
Style::default()
.fg(th.crust)
.bg(th.lavender)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(th.text)
};
lines.push(Line::from(vec![
Span::styled(mark.to_string(), Style::default().fg(th.overlay1)),
Span::styled(text.clone(), style),
]));
}
let menu = Paragraph::new(lines)
.style(Style::default().fg(th.text).bg(th.base))
.wrap(Wrap { trim: true })
.block(
Block::default()
.title(Span::styled(
format!(" {} ", i18n::t(app, "app.results.sort_menu.title")),
Style::default().fg(th.overlay1),
))
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(th.surface2)),
);
f.render_widget(Clear, rect);
f.render_widget(menu, rect);
}
}