From 60c73fb573c99f7bec74b2f7600786da2478e035 Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 29 Nov 2024 15:17:14 -0700 Subject: [PATCH 01/11] feat(tui): popup to help list keybinds --- crates/turborepo-ui/src/tui/app.rs | 16 +++++++++- crates/turborepo-ui/src/tui/event.rs | 1 + crates/turborepo-ui/src/tui/input.rs | 8 ++++- crates/turborepo-ui/src/tui/mod.rs | 1 + crates/turborepo-ui/src/tui/popup.rs | 47 ++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 crates/turborepo-ui/src/tui/popup.rs diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index 4fe0faaf06cc8..ef48778964f98 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -8,7 +8,7 @@ use std::{ use ratatui::{ backend::{Backend, CrosstermBackend}, layout::{Constraint, Layout}, - widgets::TableState, + widgets::{Clear, TableState}, Frame, Terminal, }; use tokio::{ @@ -17,6 +17,8 @@ use tokio::{ }; use tracing::{debug, trace}; +use crate::tui::popup; + pub const FRAMERATE: Duration = Duration::from_millis(3); const RESIZE_DEBOUNCE_DELAY: Duration = Duration::from_millis(10); @@ -53,6 +55,7 @@ pub struct App { selected_task_index: usize, has_user_scrolled: bool, has_sidebar: bool, + showing_help_popup: bool, done: bool, } @@ -98,6 +101,7 @@ impl App { selected_task_index, has_sidebar: true, has_user_scrolled: has_user_interacted, + showing_help_popup: false, } } @@ -118,6 +122,7 @@ impl App { Ok(InputOptions { focus: &self.focus, has_selection, + is_help_popup_open: self.showing_help_popup, }) } @@ -790,6 +795,9 @@ fn update( Event::ToggleSidebar => { app.has_sidebar = !app.has_sidebar; } + Event::ToggleHelpPopup => { + app.showing_help_popup = !app.showing_help_popup; + } Event::Input { bytes } => { app.forward_input(&bytes)?; } @@ -858,6 +866,12 @@ fn view(app: &mut App, f: &mut Frame) { f.render_stateful_widget(&table_to_render, table, &mut app.scroll); f.render_widget(&pane_to_render, pane); + + if app.showing_help_popup { + let area = popup::popup_area(app.size, 80, 80); + f.render_widget(Clear, area); // Clears background underneath popup + f.render_widget(popup::block(), area); + } } #[cfg(test)] diff --git a/crates/turborepo-ui/src/tui/event.rs b/crates/turborepo-ui/src/tui/event.rs index 446f110d8f176..4259938c07c2e 100644 --- a/crates/turborepo-ui/src/tui/event.rs +++ b/crates/turborepo-ui/src/tui/event.rs @@ -51,6 +51,7 @@ pub enum Event { cols: u16, }, ToggleSidebar, + ToggleHelpPopup, SearchEnter, SearchExit { restore_scroll: bool, diff --git a/crates/turborepo-ui/src/tui/input.rs b/crates/turborepo-ui/src/tui/input.rs index 9e4b84bdab496..f34ee311f3d28 100644 --- a/crates/turborepo-ui/src/tui/input.rs +++ b/crates/turborepo-ui/src/tui/input.rs @@ -12,6 +12,7 @@ use super::{ pub struct InputOptions<'a> { pub focus: &'a LayoutSections, pub has_selection: bool, + pub is_help_popup_open: bool, } pub fn start_crossterm_stream(tx: mpsc::Sender) -> Option> { @@ -51,7 +52,7 @@ impl<'a> InputOptions<'a> { } /// Converts a crossterm key event into a TUI interaction event -fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option { +fn translate_key_event(mut options: InputOptions, key_event: KeyEvent) -> Option { // On Windows events for releasing a key are produced // We skip these to avoid emitting 2 events per key press. // There is still a `Repeat` event for when a key is held that will pass through @@ -80,6 +81,10 @@ fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option { Some(Event::SearchEnter) } + KeyCode::Esc if options.is_help_popup_open => { + options.is_help_popup_open = false; + Some(Event::ToggleHelpPopup) + } KeyCode::Esc if matches!(options.focus, LayoutSections::Search { .. }) => { Some(Event::SearchExit { restore_scroll: true, @@ -112,6 +117,7 @@ fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option { Some(Event::ScrollDown) } + KeyCode::Char('m') => Some(Event::ToggleHelpPopup), KeyCode::Up | KeyCode::Char('k') => Some(Event::Up), KeyCode::Down | KeyCode::Char('j') => Some(Event::Down), KeyCode::Enter | KeyCode::Char('i') => Some(Event::EnterInteractive), diff --git a/crates/turborepo-ui/src/tui/mod.rs b/crates/turborepo-ui/src/tui/mod.rs index 5e0995829d507..dc0b2a82091a3 100644 --- a/crates/turborepo-ui/src/tui/mod.rs +++ b/crates/turborepo-ui/src/tui/mod.rs @@ -5,6 +5,7 @@ pub mod event; mod handle; mod input; mod pane; +mod popup; mod search; mod size; mod spinner; diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs new file mode 100644 index 0000000000000..0cccbfc0bfc6c --- /dev/null +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -0,0 +1,47 @@ +use ratatui::{ + layout::{Constraint, Flex, Layout, Rect}, + style::{Modifier, Style, Stylize}, + text::{Line, Text}, + widgets::{Block, List, ListItem, Padding, Paragraph}, +}; + +use crate::tui::size::SizeInfo; + +pub fn popup_area(area: SizeInfo, percent_x: u16, percent_y: u16) -> Rect { + let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center); + let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center); + let [area] = vertical.areas(Rect { + x: 0, + y: 0, + width: area.task_list_width() + area.pane_cols(), + height: area.pane_rows(), + }); + let [area] = horizontal.areas(area); + area +} + +pub fn block() -> List<'static> { + let mer = Block::bordered() + .title(" Terminal UI keymaps ") + .padding(Padding::uniform(1)); + + let list_items = vec![ + "m - Toggle this help popup", + "↑ or j - Select previous task", + "↓ or k - Select next task", + "h - Toggle task list visibility", + "/ - Filter tasks to search term", + "i - Interact with task", + "CTRL+z - Stop interacting with task", + "c - Copy logs selection (Only when logs are selected)", + "CTRL+n - Scroll logs up", + "CTRL+p - Scroll logs down", + ]; + + List::new( + list_items + .into_iter() + .map(|item| ListItem::new(Line::from(item))), + ) + .block(mer) +} From ddb0055a712b20d8ac12d8d1ceacc7797382fe93 Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 29 Nov 2024 15:24:09 -0700 Subject: [PATCH 02/11] WIP --- crates/turborepo-ui/src/tui/popup.rs | 2 +- crates/turborepo-ui/src/tui/table.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index 0cccbfc0bfc6c..e3d7985352612 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -22,7 +22,7 @@ pub fn popup_area(area: SizeInfo, percent_x: u16, percent_y: u16) -> Rect { pub fn block() -> List<'static> { let mer = Block::bordered() - .title(" Terminal UI keymaps ") + .title(" Terminal UI keybinds ") .padding(Padding::uniform(1)); let list_items = vec![ diff --git a/crates/turborepo-ui/src/tui/table.rs b/crates/turborepo-ui/src/tui/table.rs index 1757d8657f9ae..3490b36ab6e54 100644 --- a/crates/turborepo-ui/src/tui/table.rs +++ b/crates/turborepo-ui/src/tui/table.rs @@ -21,8 +21,8 @@ pub struct TaskTable<'b> { spinner: SpinnerState, } -const TASK_NAVIGATE_INSTRUCTIONS: &str = "↑ ↓ to navigate"; -const HIDE_INSTRUCTIONS: &str = "h to hide"; +const TASK_NAVIGATE_INSTRUCTIONS: &str = "↑ ↓ - Select"; +const MORE_BINDS_INSTRUCTIONS: &str = "m - More binds"; impl<'b> TaskTable<'b> { /// Construct a new table with all of the planned tasks @@ -122,7 +122,7 @@ impl<'a> StatefulWidget for &'a TaskTable<'a> { ) .footer( vec![Text::styled( - format!("{TASK_NAVIGATE_INSTRUCTIONS}\n{HIDE_INSTRUCTIONS}"), + format!("{TASK_NAVIGATE_INSTRUCTIONS}\n{MORE_BINDS_INSTRUCTIONS}"), Style::default().add_modifier(Modifier::DIM), )] .into_iter() From 60c231885e70a751689cbfd80c1c4a0f7fa3fcce Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 29 Nov 2024 16:00:16 -0700 Subject: [PATCH 03/11] WIP --- crates/turborepo-ui/src/tui/app.rs | 2 +- crates/turborepo-ui/src/tui/input.rs | 2 +- crates/turborepo-ui/src/tui/popup.rs | 65 +++++++++++++++++----------- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index ef48778964f98..7f52cb74c9d9f 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -868,7 +868,7 @@ fn view(app: &mut App, f: &mut Frame) { f.render_widget(&pane_to_render, pane); if app.showing_help_popup { - let area = popup::popup_area(app.size, 80, 80); + let area = popup::popup_area(app.size); f.render_widget(Clear, area); // Clears background underneath popup f.render_widget(popup::block(), area); } diff --git a/crates/turborepo-ui/src/tui/input.rs b/crates/turborepo-ui/src/tui/input.rs index f34ee311f3d28..157d5b06423bd 100644 --- a/crates/turborepo-ui/src/tui/input.rs +++ b/crates/turborepo-ui/src/tui/input.rs @@ -90,7 +90,6 @@ fn translate_key_event(mut options: InputOptions, key_event: KeyEvent) -> Option restore_scroll: true, }) } - KeyCode::Char('h') => Some(Event::ToggleSidebar), KeyCode::Enter if matches!(options.focus, LayoutSections::Search { .. }) => { Some(Event::SearchExit { restore_scroll: false, @@ -117,6 +116,7 @@ fn translate_key_event(mut options: InputOptions, key_event: KeyEvent) -> Option KeyCode::Char('n') if key_event.modifiers == KeyModifiers::CONTROL => { Some(Event::ScrollDown) } + KeyCode::Char('h') => Some(Event::ToggleSidebar), KeyCode::Char('m') => Some(Event::ToggleHelpPopup), KeyCode::Up | KeyCode::Char('k') => Some(Event::Up), KeyCode::Down | KeyCode::Char('j') => Some(Event::Down), diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index e3d7985352612..876c934a5753d 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -1,20 +1,46 @@ use ratatui::{ layout::{Constraint, Flex, Layout, Rect}, - style::{Modifier, Style, Stylize}, - text::{Line, Text}, - widgets::{Block, List, ListItem, Padding, Paragraph}, + text::Line, + widgets::{Block, List, ListItem, Padding}, }; -use crate::tui::size::SizeInfo; +use super::size::SizeInfo; -pub fn popup_area(area: SizeInfo, percent_x: u16, percent_y: u16) -> Rect { - let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center); - let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center); +const BIND_LIST_ITEMS: [&str; 11] = [ + "m - Toggle this help popup", + "↑ or j - Select previous task", + "↓ or k - Select next task", + "h - Toggle task list visibility", + "/ - Filter tasks to search term", + "ESC - Clear filter", + "i - Interact with task", + "CTRL+z - Stop interacting with task", + "c - Copy logs selection (Only when logs are selected)", + "CTRL+n - Scroll logs up", + "CTRL+p - Scroll logs down", +]; + +pub fn popup_area(area: SizeInfo) -> Rect { + let popup_width = BIND_LIST_ITEMS + .iter() + .map(|s| s.len() + 4) + .max() + .unwrap_or(0) as u16; + let popup_height = (BIND_LIST_ITEMS.len() + 4) as u16; + + let screen_width = area.task_list_width() + area.pane_cols(); + let screen_height = area.pane_rows(); + + let x = (screen_width - popup_width) / 2; + let y = (screen_height - popup_height) / 2; + + let vertical = Layout::vertical([Constraint::Percentage(100)]).flex(Flex::Center); + let horizontal = Layout::horizontal([Constraint::Percentage(100)]).flex(Flex::Center); let [area] = vertical.areas(Rect { - x: 0, - y: 0, - width: area.task_list_width() + area.pane_cols(), - height: area.pane_rows(), + x, + y, + width: popup_width, + height: popup_height, }); let [area] = horizontal.areas(area); area @@ -22,24 +48,11 @@ pub fn popup_area(area: SizeInfo, percent_x: u16, percent_y: u16) -> Rect { pub fn block() -> List<'static> { let mer = Block::bordered() - .title(" Terminal UI keybinds ") + .title(" Keybinds ") .padding(Padding::uniform(1)); - let list_items = vec![ - "m - Toggle this help popup", - "↑ or j - Select previous task", - "↓ or k - Select next task", - "h - Toggle task list visibility", - "/ - Filter tasks to search term", - "i - Interact with task", - "CTRL+z - Stop interacting with task", - "c - Copy logs selection (Only when logs are selected)", - "CTRL+n - Scroll logs up", - "CTRL+p - Scroll logs down", - ]; - List::new( - list_items + BIND_LIST_ITEMS .into_iter() .map(|item| ListItem::new(Line::from(item))), ) From f4418703c27e243e86008b9a2f150f9cca3a8e92 Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 29 Nov 2024 16:01:52 -0700 Subject: [PATCH 04/11] WIP --- crates/turborepo-ui/src/tui/app.rs | 6 +++--- crates/turborepo-ui/src/tui/popup.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index 7f52cb74c9d9f..2d4fa868225ef 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -17,7 +17,7 @@ use tokio::{ }; use tracing::{debug, trace}; -use crate::tui::popup; +use crate::tui::popup::{popup, popup_area}; pub const FRAMERATE: Duration = Duration::from_millis(3); const RESIZE_DEBOUNCE_DELAY: Duration = Duration::from_millis(10); @@ -868,9 +868,9 @@ fn view(app: &mut App, f: &mut Frame) { f.render_widget(&pane_to_render, pane); if app.showing_help_popup { - let area = popup::popup_area(app.size); + let area = popup_area(app.size); f.render_widget(Clear, area); // Clears background underneath popup - f.render_widget(popup::block(), area); + f.render_widget(popup(), area); } } diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index 876c934a5753d..3bcb156b93c82 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -46,8 +46,8 @@ pub fn popup_area(area: SizeInfo) -> Rect { area } -pub fn block() -> List<'static> { - let mer = Block::bordered() +pub fn popup() -> List<'static> { + let outer = Block::bordered() .title(" Keybinds ") .padding(Padding::uniform(1)); @@ -56,5 +56,5 @@ pub fn block() -> List<'static> { .into_iter() .map(|item| ListItem::new(Line::from(item))), ) - .block(mer) + .block(outer) } From f23616dad3fa964184e6fccf39f7ba22db54ea5d Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 29 Nov 2024 16:04:23 -0700 Subject: [PATCH 05/11] WIP --- crates/turborepo-ui/src/tui/input.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/turborepo-ui/src/tui/input.rs b/crates/turborepo-ui/src/tui/input.rs index 157d5b06423bd..900cbe9ccfb7d 100644 --- a/crates/turborepo-ui/src/tui/input.rs +++ b/crates/turborepo-ui/src/tui/input.rs @@ -52,7 +52,7 @@ impl<'a> InputOptions<'a> { } /// Converts a crossterm key event into a TUI interaction event -fn translate_key_event(mut options: InputOptions, key_event: KeyEvent) -> Option { +fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option { // On Windows events for releasing a key are produced // We skip these to avoid emitting 2 events per key press. // There is still a `Repeat` event for when a key is held that will pass through @@ -81,10 +81,7 @@ fn translate_key_event(mut options: InputOptions, key_event: KeyEvent) -> Option KeyCode::Char('/') if matches!(options.focus, LayoutSections::TaskList) => { Some(Event::SearchEnter) } - KeyCode::Esc if options.is_help_popup_open => { - options.is_help_popup_open = false; - Some(Event::ToggleHelpPopup) - } + KeyCode::Esc if options.is_help_popup_open => Some(Event::ToggleHelpPopup), KeyCode::Esc if matches!(options.focus, LayoutSections::Search { .. }) => { Some(Event::SearchExit { restore_scroll: true, From 8a0798170535ae56238521c248e07713a079ff55 Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Sun, 1 Dec 2024 12:26:30 -0700 Subject: [PATCH 06/11] WIP --- crates/turborepo-ui/src/tui/popup.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index 3bcb156b93c82..9ea1feffa73ba 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -1,3 +1,5 @@ +use std::cmp::min; + use ratatui::{ layout::{Constraint, Flex, Layout, Rect}, text::Line, @@ -14,22 +16,22 @@ const BIND_LIST_ITEMS: [&str; 11] = [ "/ - Filter tasks to search term", "ESC - Clear filter", "i - Interact with task", - "CTRL+z - Stop interacting with task", + "Ctrl+z - Stop interacting with task", "c - Copy logs selection (Only when logs are selected)", - "CTRL+n - Scroll logs up", - "CTRL+p - Scroll logs down", + "Ctrl+n - Scroll logs up", + "Ctrl+p - Scroll logs down", ]; pub fn popup_area(area: SizeInfo) -> Rect { + let screen_width = area.task_list_width() + area.pane_cols(); + let screen_height = area.pane_rows(); + let popup_width = BIND_LIST_ITEMS .iter() .map(|s| s.len() + 4) .max() .unwrap_or(0) as u16; - let popup_height = (BIND_LIST_ITEMS.len() + 4) as u16; - - let screen_width = area.task_list_width() + area.pane_cols(); - let screen_height = area.pane_rows(); + let popup_height = min((BIND_LIST_ITEMS.len() + 4) as u16, screen_height); let x = (screen_width - popup_width) / 2; let y = (screen_height - popup_height) / 2; From 767303db1be1d50a3c1103dd196f9532b3db4077 Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Thu, 5 Dec 2024 05:27:58 -0700 Subject: [PATCH 07/11] Update crates/turborepo-ui/src/tui/app.rs Co-authored-by: Chris Olszewski --- crates/turborepo-ui/src/tui/app.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index 653ea57af49fe..1514008566e6f 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -100,7 +100,6 @@ impl App { task_list_scroll: TableState::default().with_selected(selected_task_index), selected_task_index, has_sidebar: true, - has_user_scrolled: has_user_interacted, showing_help_popup: false, is_task_selection_pinned: has_user_interacted, } From aa32a482f91f7178fae0b0f736a228e78d9872ed Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 6 Dec 2024 15:18:23 -0700 Subject: [PATCH 08/11] WIP --- crates/turborepo-ui/src/tui/app.rs | 3 +- crates/turborepo-ui/src/tui/popup.rs | 58 +++++++++++++++++++--------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index 1514008566e6f..030ebfd836473 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -873,8 +873,9 @@ fn view(app: &mut App, f: &mut Frame) { if app.showing_help_popup { let area = popup_area(app.size); + let area = area.intersection(*f.buffer_mut().area()); f.render_widget(Clear, area); // Clears background underneath popup - f.render_widget(popup(), area); + f.render_widget(popup(app.size), area); } } diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index 9ea1feffa73ba..0ac39c37c983a 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -3,21 +3,21 @@ use std::cmp::min; use ratatui::{ layout::{Constraint, Flex, Layout, Rect}, text::Line, - widgets::{Block, List, ListItem, Padding}, + widgets::{Block, List, ListItem, Padding, Paragraph}, }; use super::size::SizeInfo; const BIND_LIST_ITEMS: [&str; 11] = [ - "m - Toggle this help popup", + "m - Toggle this help popup", "↑ or j - Select previous task", "↓ or k - Select next task", - "h - Toggle task list visibility", - "/ - Filter tasks to search term", - "ESC - Clear filter", - "i - Interact with task", + "h - Toggle task list", + "/ - Filter tasks to search term", + "ESC - Clear filter", + "i - Interact with task", "Ctrl+z - Stop interacting with task", - "c - Copy logs selection (Only when logs are selected)", + "c - Copy logs selection (Only when logs are selected)", "Ctrl+n - Scroll logs up", "Ctrl+p - Scroll logs down", ]; @@ -28,13 +28,16 @@ pub fn popup_area(area: SizeInfo) -> Rect { let popup_width = BIND_LIST_ITEMS .iter() - .map(|s| s.len() + 4) + .map(|s| s.len().saturating_add(4)) .max() .unwrap_or(0) as u16; - let popup_height = min((BIND_LIST_ITEMS.len() + 4) as u16, screen_height); + let popup_height = min( + (BIND_LIST_ITEMS.len().saturating_add(4)) as u16, + screen_height, + ); - let x = (screen_width - popup_width) / 2; - let y = (screen_height - popup_height) / 2; + let x = screen_width.saturating_sub(popup_width) / 2; + let y = screen_height.saturating_sub(popup_height) / 2; let vertical = Layout::vertical([Constraint::Percentage(100)]).flex(Flex::Center); let horizontal = Layout::horizontal([Constraint::Percentage(100)]).flex(Flex::Center); @@ -48,15 +51,34 @@ pub fn popup_area(area: SizeInfo) -> Rect { area } -pub fn popup() -> List<'static> { +pub fn popup(area: SizeInfo) -> List<'static> { + let available_height = area.pane_rows().saturating_sub(4); + + let items: Vec = BIND_LIST_ITEMS + .iter() + .take(available_height as usize) + .map(|item| ListItem::new(Line::from(*item))) + .collect(); + + let title_bottom = if area.pane_rows().saturating_sub(4) < BIND_LIST_ITEMS.len() as u16 { + let binds_not_visible = BIND_LIST_ITEMS + .len() + .saturating_sub(area.pane_rows().saturating_sub(4) as usize); + + let pluralize = if binds_not_visible > 1 { "s" } else { "" }; + let message = format!( + "{} more bind{}. Make your terminal taller.", + binds_not_visible, pluralize + ); + Line::from(message) + } else { + Line::from("") + }; + let outer = Block::bordered() .title(" Keybinds ") + .title_bottom(format!("{title_bottom}").to_string()) .padding(Padding::uniform(1)); - List::new( - BIND_LIST_ITEMS - .into_iter() - .map(|item| ListItem::new(Line::from(item))), - ) - .block(outer) + List::new(items).block(outer) } From 4fe26b8c240ceed09c704bd28b564c35409bc6fe Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 6 Dec 2024 20:39:40 -0700 Subject: [PATCH 09/11] WIP --- crates/turborepo-ui/src/tui/app.rs | 4 ++-- crates/turborepo-ui/src/tui/input.rs | 1 - crates/turborepo-ui/src/tui/popup.rs | 27 ++++++++++++--------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index 030ebfd836473..7705e3bf010f5 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -872,10 +872,10 @@ fn view(app: &mut App, f: &mut Frame) { f.render_widget(&pane_to_render, pane); if app.showing_help_popup { - let area = popup_area(app.size); + let area = popup_area(*f.buffer_mut().area()); let area = area.intersection(*f.buffer_mut().area()); f.render_widget(Clear, area); // Clears background underneath popup - f.render_widget(popup(app.size), area); + f.render_widget(popup(area), area); } } diff --git a/crates/turborepo-ui/src/tui/input.rs b/crates/turborepo-ui/src/tui/input.rs index c3401aae6adf8..8e262878ff8de 100644 --- a/crates/turborepo-ui/src/tui/input.rs +++ b/crates/turborepo-ui/src/tui/input.rs @@ -114,7 +114,6 @@ fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option { Some(Event::ScrollDown) } - KeyCode::Char('h') => Some(Event::ToggleSidebar), KeyCode::Char('m') => Some(Event::ToggleHelpPopup), KeyCode::Up | KeyCode::Char('k') => Some(Event::Up), KeyCode::Down | KeyCode::Char('j') => Some(Event::Down), diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index 0ac39c37c983a..4ca2ebae9d2e0 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -3,11 +3,9 @@ use std::cmp::min; use ratatui::{ layout::{Constraint, Flex, Layout, Rect}, text::Line, - widgets::{Block, List, ListItem, Padding, Paragraph}, + widgets::{Block, List, ListItem, Padding}, }; -use super::size::SizeInfo; - const BIND_LIST_ITEMS: [&str; 11] = [ "m - Toggle this help popup", "↑ or j - Select previous task", @@ -22,9 +20,9 @@ const BIND_LIST_ITEMS: [&str; 11] = [ "Ctrl+p - Scroll logs down", ]; -pub fn popup_area(area: SizeInfo) -> Rect { - let screen_width = area.task_list_width() + area.pane_cols(); - let screen_height = area.pane_rows(); +pub fn popup_area(area: Rect) -> Rect { + let screen_width = area.width; + let screen_height = area.height; let popup_width = BIND_LIST_ITEMS .iter() @@ -41,6 +39,7 @@ pub fn popup_area(area: SizeInfo) -> Rect { let vertical = Layout::vertical([Constraint::Percentage(100)]).flex(Flex::Center); let horizontal = Layout::horizontal([Constraint::Percentage(100)]).flex(Flex::Center); + let [area] = vertical.areas(Rect { x, y, @@ -51,23 +50,21 @@ pub fn popup_area(area: SizeInfo) -> Rect { area } -pub fn popup(area: SizeInfo) -> List<'static> { - let available_height = area.pane_rows().saturating_sub(4); +pub fn popup(area: Rect) -> List<'static> { + let available_height = area.height.saturating_sub(4) as usize; let items: Vec = BIND_LIST_ITEMS .iter() - .take(available_height as usize) + .take(available_height) .map(|item| ListItem::new(Line::from(*item))) .collect(); - let title_bottom = if area.pane_rows().saturating_sub(4) < BIND_LIST_ITEMS.len() as u16 { - let binds_not_visible = BIND_LIST_ITEMS - .len() - .saturating_sub(area.pane_rows().saturating_sub(4) as usize); + let title_bottom = if available_height < BIND_LIST_ITEMS.len() { + let binds_not_visible = BIND_LIST_ITEMS.len().saturating_sub(available_height); let pluralize = if binds_not_visible > 1 { "s" } else { "" }; let message = format!( - "{} more bind{}. Make your terminal taller.", + " {} more bind{}. Make your terminal taller. ", binds_not_visible, pluralize ); Line::from(message) @@ -77,7 +74,7 @@ pub fn popup(area: SizeInfo) -> List<'static> { let outer = Block::bordered() .title(" Keybinds ") - .title_bottom(format!("{title_bottom}").to_string()) + .title_bottom(title_bottom.to_string()) .padding(Padding::uniform(1)); List::new(items).block(outer) From 9b991e753a23748d132218151ee8e34dcbc1b61e Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 6 Dec 2024 20:49:18 -0700 Subject: [PATCH 10/11] WIP --- crates/turborepo-ui/src/tui/popup.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/turborepo-ui/src/tui/popup.rs b/crates/turborepo-ui/src/tui/popup.rs index 4ca2ebae9d2e0..d8a0e49187101 100644 --- a/crates/turborepo-ui/src/tui/popup.rs +++ b/crates/turborepo-ui/src/tui/popup.rs @@ -6,7 +6,7 @@ use ratatui::{ widgets::{Block, List, ListItem, Padding}, }; -const BIND_LIST_ITEMS: [&str; 11] = [ +const BIND_LIST: [&str; 11] = [ "m - Toggle this help popup", "↑ or j - Select previous task", "↓ or k - Select next task", @@ -24,15 +24,12 @@ pub fn popup_area(area: Rect) -> Rect { let screen_width = area.width; let screen_height = area.height; - let popup_width = BIND_LIST_ITEMS + let popup_width = BIND_LIST .iter() .map(|s| s.len().saturating_add(4)) .max() .unwrap_or(0) as u16; - let popup_height = min( - (BIND_LIST_ITEMS.len().saturating_add(4)) as u16, - screen_height, - ); + let popup_height = min((BIND_LIST.len().saturating_add(4)) as u16, screen_height); let x = screen_width.saturating_sub(popup_width) / 2; let y = screen_height.saturating_sub(popup_height) / 2; @@ -40,27 +37,29 @@ pub fn popup_area(area: Rect) -> Rect { let vertical = Layout::vertical([Constraint::Percentage(100)]).flex(Flex::Center); let horizontal = Layout::horizontal([Constraint::Percentage(100)]).flex(Flex::Center); - let [area] = vertical.areas(Rect { + let [vertical_area] = vertical.areas(Rect { x, y, width: popup_width, height: popup_height, }); - let [area] = horizontal.areas(area); + + let [area] = horizontal.areas(vertical_area); + area } pub fn popup(area: Rect) -> List<'static> { let available_height = area.height.saturating_sub(4) as usize; - let items: Vec = BIND_LIST_ITEMS + let items: Vec = BIND_LIST .iter() .take(available_height) .map(|item| ListItem::new(Line::from(*item))) .collect(); - let title_bottom = if available_height < BIND_LIST_ITEMS.len() { - let binds_not_visible = BIND_LIST_ITEMS.len().saturating_sub(available_height); + let title_bottom = if available_height < BIND_LIST.len() { + let binds_not_visible = BIND_LIST.len().saturating_sub(available_height); let pluralize = if binds_not_visible > 1 { "s" } else { "" }; let message = format!( From f1828cf966c03aca0a58a369e4399b157128d0bb Mon Sep 17 00:00:00 2001 From: Anthony Shew Date: Fri, 6 Dec 2024 21:06:35 -0700 Subject: [PATCH 11/11] WIP --- crates/turborepo-ui/src/tui/input.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/turborepo-ui/src/tui/input.rs b/crates/turborepo-ui/src/tui/input.rs index 8e262878ff8de..2a0b16b425b83 100644 --- a/crates/turborepo-ui/src/tui/input.rs +++ b/crates/turborepo-ui/src/tui/input.rs @@ -446,6 +446,7 @@ mod test { InputOptions { focus: search(), has_selection: false, + is_help_popup_open: false, } }