use ratatui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, }; use crate::model::Model; use crate::ui::app::AppMode; use crate::ui::cat_tree::{CatTreeEntry, build_cat_tree}; use crate::ui::panel::PanelContent; use crate::view::Axis; fn axis_display(axis: Axis) -> (&'static str, Color) { match axis { Axis::Row => ("Row ↕", Color::Green), Axis::Column => ("Col ↔", Color::Blue), Axis::Page => ("Page ☰", Color::Magenta), Axis::None => ("None ∅", Color::DarkGray), } } pub struct CategoryContent<'a> { model: &'a Model, tree: Vec, } impl<'a> CategoryContent<'a> { pub fn new(model: &'a Model, expanded: &'a std::collections::HashSet) -> Self { let tree = build_cat_tree(model, expanded); Self { model, tree } } } impl PanelContent for CategoryContent<'_> { fn is_active(&self, mode: &AppMode) -> bool { matches!( mode, AppMode::CategoryPanel | AppMode::ItemAdd { .. } | AppMode::CategoryAdd { .. } ) } fn active_color(&self) -> Color { Color::Cyan } fn title(&self) -> &str { " Categories " } fn item_count(&self) -> usize { self.tree.len() } fn empty_message(&self) -> &str { "(no categories — use :add-cat )" } fn render_item(&self, index: usize, is_selected: bool, inner: Rect, buf: &mut Buffer) { let y = inner.y + index as u16; let view = self.model.active_view(); let base_style = if is_selected { Style::default() .fg(Color::Black) .bg(Color::Cyan) .add_modifier(Modifier::BOLD) } else { Style::default() }; if is_selected { let fill = " ".repeat(inner.width as usize); buf.set_string(inner.x, y, &fill, base_style); } match &self.tree[index] { CatTreeEntry::Category { name, item_count, expanded, } => { let indicator = if *expanded { "▼" } else { "▶" }; let (axis_str, axis_color) = axis_display(view.axis_of(name)); let name_part = format!("{indicator} {name} ({item_count})"); let axis_part = format!(" [{axis_str}]"); buf.set_string(inner.x, y, &name_part, base_style); if name_part.len() + axis_part.len() < inner.width as usize { buf.set_string( inner.x + name_part.len() as u16, y, &axis_part, if is_selected { base_style } else { Style::default().fg(axis_color) }, ); } } CatTreeEntry::Item { item_name, .. } => { let label = format!(" · {item_name}"); buf.set_string(inner.x, y, &label, base_style); } } } }