1use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Action {
8 Continue,
9 Quit,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Pane {
14 Ready,
15 List,
16 Claims,
17 Agenda,
18 Search,
19}
20
21impl Pane {
22 pub const ALL: [Pane; 5] = [
23 Pane::Ready,
24 Pane::List,
25 Pane::Claims,
26 Pane::Agenda,
27 Pane::Search,
28 ];
29
30 pub fn title(self) -> &'static str {
31 match self {
32 Self::Ready => "Ready",
33 Self::List => "List",
34 Self::Claims => "Claims",
35 Self::Agenda => "Agenda",
36 Self::Search => "Search",
37 }
38 }
39
40 pub fn index(self) -> usize {
41 Self::ALL.iter().position(|p| *p == self).unwrap_or(0)
42 }
43
44 pub fn from_index(i: usize) -> Self {
45 Self::ALL[i % Self::ALL.len()]
46 }
47
48 pub fn next(self) -> Self {
49 Self::from_index(self.index() + 1)
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum DetailTab {
55 Show,
56 Excerpt,
57 Tree,
58 Related,
59}
60
61impl DetailTab {
62 pub const ALL: [DetailTab; 4] = [
63 DetailTab::Show,
64 DetailTab::Excerpt,
65 DetailTab::Tree,
66 DetailTab::Related,
67 ];
68
69 pub fn title(self) -> &'static str {
70 match self {
71 Self::Show => "show",
72 Self::Excerpt => "excerpt",
73 Self::Tree => "tree",
74 Self::Related => "related",
75 }
76 }
77
78 pub fn next(self) -> Self {
79 let i = Self::ALL.iter().position(|t| *t == self).unwrap_or(0);
80 Self::ALL[(i + 1) % Self::ALL.len()]
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum Focus {
86 Rows,
87 Detail,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum PromptKind {
92 Search,
93 Note,
94 Project,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum ConfirmKind {
99 Done,
100 Cancelled,
101}
102
103impl ConfirmKind {
104 pub fn state(self) -> &'static str {
105 match self {
106 Self::Done => "DONE",
107 Self::Cancelled => "CANCELLED",
108 }
109 }
110}
111
112pub fn is_press(key: KeyEvent) -> bool {
113 key.kind == KeyEventKind::Press || key.kind == KeyEventKind::Repeat
114}
115
116pub fn char_of(key: KeyEvent) -> Option<char> {
117 match key.code {
118 KeyCode::Char(c) if key.modifiers.is_empty() || key.modifiers == KeyModifiers::SHIFT => {
119 Some(c)
120 }
121 _ => None,
122 }
123}
124
125pub const HELP: &str = "\
126vissue tui
127
128j/k, arrows move
129Tab, 1-5 pane (Ready List Claims Agenda Search)
130Enter focus detail / cycle detail tab
131p project filter
132/ search
133c claim
134n note
135s cycle TODO / STARTED / BLOCKED
136D DONE (confirm)
137X CANCELLED (confirm)
138o open (shared selection)
139y copy id
140R reload
141? this help
142q / Esc quit / back
143
144Body edits stay in the file.
145body lives in file; open the range above
146";