diff --git a/rq-cli/src/app.rs b/rq-cli/src/app.rs index 664e960..c0afc7e 100644 --- a/rq-cli/src/app.rs +++ b/rq-cli/src/app.rs @@ -13,13 +13,16 @@ use tokio::sync::mpsc::{channel, Receiver, Sender}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use crate::components::{ - menu::{Menu, MenuItem}, + legend::Legend, + menu::{self, Menu, MenuItem}, message_dialog::{Message, MessageDialog}, popup::Popup, - response_panel::ResponsePanel, + response_panel::{self, ResponsePanel}, BlockComponent, HandleSuccess, }; +const KEYMAPS: &[(&str, &str); 1] = &[("Esc/q", "exit")]; + #[derive(Default)] enum FocusState { #[default] @@ -199,19 +202,36 @@ impl App { } pub fn draw(&self, f: &mut crate::terminal::Frame<'_>) { + let [main_chunk, legend_chunk] = { + let x = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Min(1), Constraint::Length(1)]) + .split(f.size()); + + [x[0], x[1]] + }; + // Create two chunks with equal screen space let [list_chunk, response_chunk] = { let x = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) - .split(f.size()); + .split(main_chunk); [x[0], x[1]] }; - let (list_border_style, response_border_style) = match self.focus { - FocusState::RequestsList => (Style::default().fg(Color::Blue), Style::default()), - FocusState::ResponseBuffer => (Style::default(), Style::default().fg(Color::Blue)), + let (list_border_style, response_border_style, focused_keymaps) = match self.focus { + FocusState::RequestsList => ( + Style::default().fg(Color::Blue), + Style::default(), + menu::KEYMAPS.iter(), + ), + FocusState::ResponseBuffer => ( + Style::default(), + Style::default().fg(Color::Blue), + response_panel::KEYMAPS.iter(), + ), }; let list_block = Block::default() @@ -226,6 +246,11 @@ impl App { self.request_menu.render(f, list_chunk, list_block); let response_panel = &self.responses[self.request_menu.idx()]; response_panel.render(f, response_chunk, response_block); + Legend::new(KEYMAPS.iter().chain(focused_keymaps)).render( + f, + legend_chunk, + Block::default(), + ); if let Some(popup) = self.message_popup.as_ref() { popup.render(f, f.size(), Block::default().borders(Borders::ALL)); diff --git a/rq-cli/src/components/legend.rs b/rq-cli/src/components/legend.rs new file mode 100644 index 0000000..7db5f23 --- /dev/null +++ b/rq-cli/src/components/legend.rs @@ -0,0 +1,46 @@ +use ratatui::{ + style::{Modifier, Style}, + text::{Line, Span}, + widgets::Paragraph, +}; + +use super::BlockComponent; + +pub struct Legend<'a> { + keymaps: Vec<&'a (&'a str, &'a str)>, +} + +impl<'a> Legend<'a> { + pub fn new>(keymaps: I) -> Self { + Self { + keymaps: keymaps.collect(), + } + } +} + +impl BlockComponent for Legend<'_> { + fn render( + &self, + frame: &mut crate::terminal::Frame, + area: ratatui::prelude::Rect, + block: ratatui::widgets::Block, + ) { + let spans = self + .keymaps + .iter() + .flat_map(|(k, v)| { + [ + Span::styled( + format!(" {k} "), + Style::default().add_modifier(Modifier::REVERSED), + ), + Span::from(format!(" {v} ")), + ] + }) + .collect::>(); + + let p = Paragraph::new(Line::from(spans)); + + frame.render_widget(p.block(block), area); + } +} diff --git a/rq-cli/src/components/menu.rs b/rq-cli/src/components/menu.rs index 4655923..b8f0a8f 100644 --- a/rq-cli/src/components/menu.rs +++ b/rq-cli/src/components/menu.rs @@ -6,6 +6,8 @@ use ratatui::{ use super::BlockComponent; +pub const KEYMAPS: &[(&str, &str); 2] = &[("↓/↑ j/k", "next/previous"), ("Enter", "select")]; + pub trait MenuItem { fn render(&self) -> Vec>; fn render_highlighted(&self) -> Vec> { diff --git a/rq-cli/src/components/mod.rs b/rq-cli/src/components/mod.rs index 1b0a43f..0e7ab1a 100644 --- a/rq-cli/src/components/mod.rs +++ b/rq-cli/src/components/mod.rs @@ -4,6 +4,7 @@ use ratatui::{prelude::Rect, widgets::Block}; use crate::terminal::Frame; pub mod input; +pub mod legend; pub mod menu; pub mod message_dialog; pub mod popup; diff --git a/rq-cli/src/components/response_panel.rs b/rq-cli/src/components/response_panel.rs index afcdee4..7c530ec 100644 --- a/rq-cli/src/components/response_panel.rs +++ b/rq-cli/src/components/response_panel.rs @@ -19,6 +19,12 @@ use super::{ BlockComponent, HandleResult, HandleSuccess, }; +pub const KEYMAPS: &[(&str, &str); 3] = &[ + ("↓/↑ j/k", "scroll down/up"), + ("Enter", "send request"), + ("s", "save"), +]; + #[derive(Copy, Clone, Default)] enum SaveOption { #[default]