tongo/components/
list.rs

1use crate::{
2    components::ComponentCommand,
3    system::{
4        command::{Command, CommandGroup},
5        event::Event,
6    },
7};
8use ratatui::{
9    prelude::*,
10    style::{Color, Style},
11    widgets::{Block, List, ListItem, ListState, StatefulWidget},
12};
13
14pub mod collections;
15pub mod connections;
16pub mod databases;
17
18#[derive(Debug, Default, Clone)]
19pub struct InnerList {
20    title: &'static str,
21    pub state: ListState,
22}
23
24impl InnerList {
25    fn new(title: &'static str) -> Self {
26        Self {
27            title,
28            ..Default::default()
29        }
30    }
31
32    fn base_commands() -> Vec<CommandGroup> {
33        vec![CommandGroup::new(
34            vec![Command::NavUp, Command::NavDown],
35            "navigate",
36        )]
37    }
38
39    fn handle_base_command(&mut self, command: &ComponentCommand, num_items: usize) -> Vec<Event> {
40        let mut out = vec![];
41        if let ComponentCommand::Command(command) = command {
42            match command {
43                Command::NavUp => {
44                    // jump to the bottom if we're at the top
45                    if self.state.selected() == Some(0) {
46                        self.state.select(Some(num_items.saturating_sub(1)));
47                    } else {
48                        self.state.select_previous();
49                    }
50                    out.push(Event::ListSelectionChanged);
51                }
52                Command::NavDown => {
53                    // jump to the top if we're at the bottom
54                    if self.state.selected() == Some(num_items.saturating_sub(1)) {
55                        self.state.select_first();
56                    } else {
57                        self.state.select_next();
58                    }
59                    out.push(Event::ListSelectionChanged);
60                }
61                _ => {}
62            }
63        }
64        out
65    }
66
67    fn render(&mut self, frame: &mut Frame, area: Rect, items: Vec<ListItem>, focused: bool) {
68        let (border_color, highlight_color) = if focused {
69            (Color::Green, Color::White)
70        } else {
71            (Color::White, Color::Gray)
72        };
73
74        let list = List::new(items)
75            .block(
76                Block::bordered()
77                    .title(self.title)
78                    .border_style(Style::default().fg(border_color)),
79            )
80            .highlight_style(Style::default().bold().black().bg(highlight_color));
81
82        StatefulWidget::render(list, area, frame.buffer_mut(), &mut self.state);
83    }
84}