Scrolling help
This commit is contained in:
parent
eb7790ff8f
commit
857362b558
2 changed files with 118 additions and 34 deletions
60
src/app.rs
60
src/app.rs
|
|
@ -60,6 +60,7 @@ pub struct App {
|
||||||
pub log_view_content: Vec<String>,
|
pub log_view_content: Vec<String>,
|
||||||
pub log_view_scroll: usize,
|
pub log_view_scroll: usize,
|
||||||
pub log_view_selected: usize,
|
pub log_view_selected: usize,
|
||||||
|
pub help_scroll: usize,
|
||||||
pub clipboard: Option<arboard::Clipboard>,
|
pub clipboard: Option<arboard::Clipboard>,
|
||||||
pub status_message: Option<(String, std::time::Instant)>,
|
pub status_message: Option<(String, std::time::Instant)>,
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +98,7 @@ impl App {
|
||||||
log_view_content: Vec::new(),
|
log_view_content: Vec::new(),
|
||||||
log_view_scroll: 0,
|
log_view_scroll: 0,
|
||||||
log_view_selected: 0,
|
log_view_selected: 0,
|
||||||
|
help_scroll: 0,
|
||||||
clipboard: arboard::Clipboard::new().ok(),
|
clipboard: arboard::Clipboard::new().ok(),
|
||||||
status_message: None,
|
status_message: None,
|
||||||
})
|
})
|
||||||
|
|
@ -141,7 +143,10 @@ impl App {
|
||||||
(KeyCode::Char('p'), KeyModifiers::CONTROL) => self.change_pane(-1),
|
(KeyCode::Char('p'), KeyModifiers::CONTROL) => self.change_pane(-1),
|
||||||
(KeyCode::Enter, _) => self.toggle_current_item()?,
|
(KeyCode::Enter, _) => self.toggle_current_item()?,
|
||||||
(KeyCode::Char('e'), KeyModifiers::CONTROL) => self.edit_config()?,
|
(KeyCode::Char('e'), KeyModifiers::CONTROL) => self.edit_config()?,
|
||||||
(KeyCode::Char('?'), _) => self.current_screen = Screen::Help,
|
(KeyCode::Char('?'), _) => {
|
||||||
|
self.help_scroll = 0;
|
||||||
|
self.current_screen = Screen::Help;
|
||||||
|
}
|
||||||
(KeyCode::Char('c'), _) => self.edit_app_config()?,
|
(KeyCode::Char('c'), _) => self.edit_app_config()?,
|
||||||
(KeyCode::Char('n'), _) => self.start_new_entry(),
|
(KeyCode::Char('n'), _) => self.start_new_entry(),
|
||||||
(KeyCode::Char('p'), _) => self.start_reassign_project(),
|
(KeyCode::Char('p'), _) => self.start_reassign_project(),
|
||||||
|
|
@ -245,8 +250,26 @@ impl App {
|
||||||
fn handle_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
fn handle_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(KeyEvent { code, .. }) => match code {
|
Event::Key(KeyEvent { code, .. }) => match code {
|
||||||
KeyCode::Char('c') => self.current_screen = Screen::ConfigHelp,
|
KeyCode::Char('c') => {
|
||||||
KeyCode::Esc | KeyCode::Char('q') => self.current_screen = Screen::Main,
|
self.help_scroll = 0;
|
||||||
|
self.current_screen = Screen::ConfigHelp;
|
||||||
|
}
|
||||||
|
KeyCode::Char('j') | KeyCode::Down => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_add(1);
|
||||||
|
}
|
||||||
|
KeyCode::Char('k') | KeyCode::Up => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_sub(1);
|
||||||
|
}
|
||||||
|
KeyCode::PageDown => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_add(10);
|
||||||
|
}
|
||||||
|
KeyCode::PageUp => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_sub(10);
|
||||||
|
}
|
||||||
|
KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('?') => {
|
||||||
|
self.help_scroll = 0;
|
||||||
|
self.current_screen = Screen::Main;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -257,7 +280,22 @@ impl App {
|
||||||
fn handle_config_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
fn handle_config_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(KeyEvent { code, .. }) => match code {
|
Event::Key(KeyEvent { code, .. }) => match code {
|
||||||
KeyCode::Esc | KeyCode::Char('q') => self.current_screen = Screen::Help,
|
KeyCode::Char('j') | KeyCode::Down => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_add(1);
|
||||||
|
}
|
||||||
|
KeyCode::Char('k') | KeyCode::Up => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_sub(1);
|
||||||
|
}
|
||||||
|
KeyCode::PageDown => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_add(10);
|
||||||
|
}
|
||||||
|
KeyCode::PageUp => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_sub(10);
|
||||||
|
}
|
||||||
|
KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('?') => {
|
||||||
|
self.help_scroll = 0;
|
||||||
|
self.current_screen = Screen::Help;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -268,7 +306,20 @@ impl App {
|
||||||
fn handle_log_view_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
fn handle_log_view_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(KeyEvent { code, .. }) => match code {
|
Event::Key(KeyEvent { code, .. }) => match code {
|
||||||
|
KeyCode::Char('j') | KeyCode::Down => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_add(1);
|
||||||
|
}
|
||||||
|
KeyCode::Char('k') | KeyCode::Up => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_sub(1);
|
||||||
|
}
|
||||||
|
KeyCode::PageDown => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_add(10);
|
||||||
|
}
|
||||||
|
KeyCode::PageUp => {
|
||||||
|
self.help_scroll = self.help_scroll.saturating_sub(10);
|
||||||
|
}
|
||||||
KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('?') => {
|
KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('?') => {
|
||||||
|
self.help_scroll = 0;
|
||||||
self.current_screen = Screen::LogView;
|
self.current_screen = Screen::LogView;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -332,6 +383,7 @@ impl App {
|
||||||
self.needs_clear = true;
|
self.needs_clear = true;
|
||||||
}
|
}
|
||||||
KeyCode::Char('?') => {
|
KeyCode::Char('?') => {
|
||||||
|
self.help_scroll = 0;
|
||||||
self.current_screen = Screen::LogViewHelp;
|
self.current_screen = Screen::LogViewHelp;
|
||||||
}
|
}
|
||||||
KeyCode::Char('d') => {
|
KeyCode::Char('d') => {
|
||||||
|
|
|
||||||
92
src/ui.rs
92
src/ui.rs
|
|
@ -214,7 +214,7 @@ fn render_help_command_bar(frame: &mut Frame) {
|
||||||
frame.render_widget(command_bar, bar_area);
|
frame.render_widget(command_bar, bar_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_help(frame: &mut Frame, _app: &App) {
|
fn render_help(frame: &mut Frame, app: &App) {
|
||||||
let width = frame.size().width.saturating_sub(4).min(60);
|
let width = frame.size().width.saturating_sub(4).min(60);
|
||||||
let area = centered_rect(width, frame.size().height.saturating_sub(2), frame.size());
|
let area = centered_rect(width, frame.size().height.saturating_sub(2), frame.size());
|
||||||
|
|
||||||
|
|
@ -231,43 +231,53 @@ fn render_help(frame: &mut Frame, _app: &App) {
|
||||||
"3. Ad-Hoc Items: One-off tasks and quick entries",
|
"3. Ad-Hoc Items: One-off tasks and quick entries",
|
||||||
"",
|
"",
|
||||||
"Navigation:",
|
"Navigation:",
|
||||||
"- Use j/k or ↑/↓ to move selection up/down",
|
"- j/k or ↑/↓: Move selection up/down",
|
||||||
"- Use h/l or ←/→ to switch between panes",
|
"- h/l or ←/→: Switch between panes",
|
||||||
"- Use Ctrl+n/Ctrl+p to switch between panes",
|
"- Ctrl+n/Ctrl+p: Switch between panes",
|
||||||
"- Press Enter to start/stop time tracking",
|
"- Enter: Start/stop time tracking for selected item",
|
||||||
"- Press n to create a new task in the current section",
|
"- n: Create a new task in the current section",
|
||||||
"",
|
"",
|
||||||
"Main Commands:",
|
"Main Commands:",
|
||||||
"j/k, arrows - Navigate",
|
|
||||||
"h/l, arrows - Switch panes",
|
|
||||||
"Enter - Start/stop timer",
|
"Enter - Start/stop timer",
|
||||||
"d - Delete task",
|
"d - Delete task from list",
|
||||||
"p - Reassign project",
|
"p - Reassign project/tag",
|
||||||
"v - View Watson log (g to group, e to edit, x to delete, c to copy)",
|
"v - View Watson log",
|
||||||
"Ctrl+e - Edit tasks config",
|
"Ctrl+e - Edit tasks config file",
|
||||||
"c - Edit app config",
|
"c - Edit app config file",
|
||||||
"n - New task",
|
"n - New task",
|
||||||
"q - Quit",
|
"q - Quit",
|
||||||
"? (or ESC) - Exit help",
|
"? - Show/hide this help (ESC also works)",
|
||||||
|
"",
|
||||||
|
"Log View (press 'v'):",
|
||||||
|
"Once in log view, you can:",
|
||||||
|
"- Switch time periods: d (day), w (week), m (month)",
|
||||||
|
"- Toggle grouping: g (by date or by project)",
|
||||||
|
"- Change selection: h/l (entry → project → day → all)",
|
||||||
|
"- Navigate: j/k to move through selections",
|
||||||
|
"- Edit entry: e (entry level only)",
|
||||||
|
"- Delete entry: x (entry level only)",
|
||||||
|
"- Copy to clipboard: c (works at all levels)",
|
||||||
|
"- Press ? for detailed log view help",
|
||||||
];
|
];
|
||||||
|
|
||||||
let text = help_text.join("\n");
|
let text = help_text.join("\n");
|
||||||
|
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title("Help")
|
.title("Help (j/k to scroll)")
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.style(Style::default().fg(Color::White));
|
.style(Style::default().fg(Color::White));
|
||||||
|
|
||||||
let paragraph = Paragraph::new(text)
|
let paragraph = Paragraph::new(text)
|
||||||
.block(block)
|
.block(block)
|
||||||
.style(Style::default().fg(Color::White))
|
.style(Style::default().fg(Color::White))
|
||||||
|
.scroll((app.help_scroll as u16, 0))
|
||||||
.wrap(ratatui::widgets::Wrap { trim: true });
|
.wrap(ratatui::widgets::Wrap { trim: true });
|
||||||
|
|
||||||
frame.render_widget(paragraph, area);
|
frame.render_widget(paragraph, area);
|
||||||
render_help_command_bar(frame);
|
render_help_command_bar(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_config_help(frame: &mut Frame, _app: &App) {
|
fn render_config_help(frame: &mut Frame, app: &App) {
|
||||||
let width = frame.size().width.saturating_sub(4).min(60);
|
let width = frame.size().width.saturating_sub(4).min(60);
|
||||||
let area = centered_rect(width, frame.size().height.saturating_sub(2), frame.size());
|
let area = centered_rect(width, frame.size().height.saturating_sub(2), frame.size());
|
||||||
|
|
||||||
|
|
@ -276,35 +286,49 @@ fn render_config_help(frame: &mut Frame, _app: &App) {
|
||||||
let help_text = vec![
|
let help_text = vec![
|
||||||
"WAT Configuration",
|
"WAT Configuration",
|
||||||
"",
|
"",
|
||||||
"The configuration file is in YAML format and supports these options:",
|
"Configuration file location:",
|
||||||
|
" ~/.config/wat/config.yaml",
|
||||||
|
"",
|
||||||
|
"Available options:",
|
||||||
"",
|
"",
|
||||||
"show_help_hint: true/false",
|
"show_help_hint: true/false",
|
||||||
" Controls visibility of the help hint in the bottom bar",
|
" Default: true",
|
||||||
|
" Shows '(?) for help' hint in the bottom-right corner",
|
||||||
"",
|
"",
|
||||||
"projects: [list of strings]",
|
"projects: [list of project names]",
|
||||||
" List of available project names",
|
" Default: [] (empty)",
|
||||||
|
" List of available project names shown when reassigning",
|
||||||
|
" Example: [\"work\", \"personal\", \"client-a\"]",
|
||||||
"",
|
"",
|
||||||
"strict_projects: true/false",
|
"strict_projects: true/false",
|
||||||
" If true, only projects from the projects list are allowed",
|
" Default: false",
|
||||||
|
" When true, only allows projects from the 'projects' list",
|
||||||
|
" When false, any project name can be used",
|
||||||
"",
|
"",
|
||||||
"Example configuration:",
|
"Example configuration:",
|
||||||
|
"---",
|
||||||
"show_help_hint: true",
|
"show_help_hint: true",
|
||||||
"projects:",
|
|
||||||
" - project1",
|
|
||||||
" - project2",
|
|
||||||
"strict_projects: false",
|
"strict_projects: false",
|
||||||
|
"projects:",
|
||||||
|
" - work",
|
||||||
|
" - personal",
|
||||||
|
" - open-source",
|
||||||
|
"",
|
||||||
|
"Note: The config file is created automatically on first run.",
|
||||||
|
"Edit it with 'c' from the main screen or manually with your editor.",
|
||||||
];
|
];
|
||||||
|
|
||||||
let text = help_text.join("\n");
|
let text = help_text.join("\n");
|
||||||
|
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title("Configuration Help")
|
.title("Configuration Help (j/k to scroll)")
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.style(Style::default().fg(Color::White));
|
.style(Style::default().fg(Color::White));
|
||||||
|
|
||||||
let paragraph = Paragraph::new(text)
|
let paragraph = Paragraph::new(text)
|
||||||
.block(block)
|
.block(block)
|
||||||
.style(Style::default().fg(Color::White))
|
.style(Style::default().fg(Color::White))
|
||||||
|
.scroll((app.help_scroll as u16, 0))
|
||||||
.wrap(ratatui::widgets::Wrap { trim: true });
|
.wrap(ratatui::widgets::Wrap { trim: true });
|
||||||
|
|
||||||
frame.render_widget(paragraph, area);
|
frame.render_widget(paragraph, area);
|
||||||
|
|
@ -595,7 +619,7 @@ fn render_log_view(frame: &mut Frame, app: &App) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_log_view_help(frame: &mut Frame, _app: &App) {
|
fn render_log_view_help(frame: &mut Frame, app: &App) {
|
||||||
let width = frame.size().width.saturating_sub(4).min(60);
|
let width = frame.size().width.saturating_sub(4).min(60);
|
||||||
let area = centered_rect(width, frame.size().height.saturating_sub(2), frame.size());
|
let area = centered_rect(width, frame.size().height.saturating_sub(2), frame.size());
|
||||||
|
|
||||||
|
|
@ -622,34 +646,42 @@ fn render_log_view_help(frame: &mut Frame, _app: &App) {
|
||||||
" - At Entry level: Move to next/previous entry",
|
" - At Entry level: Move to next/previous entry",
|
||||||
" - At Project level: Jump to next/previous project group",
|
" - At Project level: Jump to next/previous project group",
|
||||||
" - At Day level: Jump to next/previous day",
|
" - At Day level: Jump to next/previous day",
|
||||||
"- h/l or ←/→: Change selection level (Entry ↔ Project ↔ Day)",
|
" - At All level: No navigation (entire view selected)",
|
||||||
|
"- h/l or ←/→: Change selection level",
|
||||||
|
" - l (right): Zoom in (All → Day → Project → Entry)",
|
||||||
|
" - h (left): Zoom out (Entry → Project → Day → All)",
|
||||||
"- PageUp/PageDown: Jump 10 entries (Entry level only)",
|
"- PageUp/PageDown: Jump 10 entries (Entry level only)",
|
||||||
"",
|
"",
|
||||||
"Selection Levels:",
|
"Selection Levels (use h/l to change):",
|
||||||
"- Entry: Select individual entry (can edit/delete/copy)",
|
"- Entry: Select individual entry (can edit/delete/copy)",
|
||||||
"- Project: Select whole project group (can copy only)",
|
"- Project: Select whole project group (can copy only)",
|
||||||
"- Day: Select entire day (can copy only)",
|
"- Day: Select entire day (can copy only)",
|
||||||
|
"- All: Select entire view/period (can copy only)",
|
||||||
"",
|
"",
|
||||||
"Actions:",
|
"Actions:",
|
||||||
"- e: Edit the selected entry (Entry level only)",
|
"- e: Edit the selected entry (Entry level only)",
|
||||||
"- x: Delete the selected entry (Entry level only)",
|
"- x: Delete the selected entry (Entry level only)",
|
||||||
"- c: Copy selection to clipboard (works at all levels)",
|
"- c: Copy selection to clipboard (works at all levels)",
|
||||||
|
" Copies based on current selection level",
|
||||||
"",
|
"",
|
||||||
"Other:",
|
"Other:",
|
||||||
"- ?: Show this help",
|
"- ?: Show/hide this help",
|
||||||
"- q or ESC: Return to main screen",
|
"- q or ESC: Return to main screen",
|
||||||
|
"",
|
||||||
|
"Tip: Use h/l to quickly select larger blocks for copying!",
|
||||||
];
|
];
|
||||||
|
|
||||||
let text = help_text.join("\n");
|
let text = help_text.join("\n");
|
||||||
|
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title("Log View Help")
|
.title("Log View Help (j/k to scroll)")
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.style(Style::default().fg(Color::White));
|
.style(Style::default().fg(Color::White));
|
||||||
|
|
||||||
let paragraph = Paragraph::new(text)
|
let paragraph = Paragraph::new(text)
|
||||||
.block(block)
|
.block(block)
|
||||||
.style(Style::default().fg(Color::White))
|
.style(Style::default().fg(Color::White))
|
||||||
|
.scroll((app.help_scroll as u16, 0))
|
||||||
.wrap(ratatui::widgets::Wrap { trim: true });
|
.wrap(ratatui::widgets::Wrap { trim: true });
|
||||||
|
|
||||||
frame.render_widget(paragraph, area);
|
frame.render_widget(paragraph, area);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue