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 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 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}