Help hints in UI
This commit is contained in:
parent
ead09c4a80
commit
811743e1e4
2 changed files with 127 additions and 29 deletions
|
|
@ -5,16 +5,23 @@ use std::path::PathBuf;
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[serde(default = "default_show_help_hint")]
|
#[serde(default = "default_show_help_hint")]
|
||||||
pub show_help_hint: bool,
|
pub show_help_hint: bool,
|
||||||
|
#[serde(default = "default_show_command_hints")]
|
||||||
|
pub show_command_hints: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_show_help_hint() -> bool {
|
fn default_show_help_hint() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_show_command_hints() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
show_help_hint: true,
|
show_help_hint: default_show_help_hint(),
|
||||||
|
show_command_hints: default_show_command_hints(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
147
src/ui.rs
147
src/ui.rs
|
|
@ -14,24 +14,53 @@ const INACTIVE_COLOR: Color = Color::Yellow;
|
||||||
pub fn render(frame: &mut Frame, app: &App) {
|
pub fn render(frame: &mut Frame, app: &App) {
|
||||||
match app.current_screen {
|
match app.current_screen {
|
||||||
Screen::Main => render_main(frame, app),
|
Screen::Main => render_main(frame, app),
|
||||||
Screen::Help => render_help(frame),
|
Screen::Help => render_help(frame, app),
|
||||||
Screen::ConfigHelp => render_config_help(frame),
|
Screen::ConfigHelp => render_config_help(frame, app),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_main(frame: &mut Frame, app: &App) {
|
fn render_main(frame: &mut Frame, app: &App) {
|
||||||
|
// Calculate layout - accounting for bottom bar if needed
|
||||||
|
let show_bottom_bar = app.config.show_help_hint || app.config.show_command_hints;
|
||||||
|
let constraints = if show_bottom_bar {
|
||||||
|
vec![
|
||||||
|
Constraint::Min(3), // At least 3 lines for each section
|
||||||
|
Constraint::Min(3),
|
||||||
|
Constraint::Min(3),
|
||||||
|
Constraint::Length(1), // Command bar
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
Constraint::Min(3),
|
||||||
|
Constraint::Min(3),
|
||||||
|
Constraint::Min(3),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([
|
.constraints(constraints)
|
||||||
Constraint::Ratio(1, 3),
|
|
||||||
Constraint::Ratio(1, 3),
|
|
||||||
Constraint::Ratio(1, 3),
|
|
||||||
])
|
|
||||||
.split(frame.size());
|
.split(frame.size());
|
||||||
|
|
||||||
|
let main_height = if show_bottom_bar {
|
||||||
|
chunks[0].height + chunks[1].height + chunks[2].height
|
||||||
|
} else {
|
||||||
|
frame.size().height
|
||||||
|
};
|
||||||
|
|
||||||
|
let section_height = main_height / 3;
|
||||||
|
|
||||||
|
// Create sections with equal height
|
||||||
|
let sections = vec![
|
||||||
|
Rect::new(0, 0, frame.size().width, section_height),
|
||||||
|
Rect::new(0, section_height, frame.size().width, section_height),
|
||||||
|
Rect::new(0, section_height * 2, frame.size().width, section_height),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Render main sections
|
||||||
render_section(
|
render_section(
|
||||||
frame,
|
frame,
|
||||||
chunks[0],
|
sections[0],
|
||||||
"Permanent Items",
|
"Permanent Items",
|
||||||
&app.state.permanent_items,
|
&app.state.permanent_items,
|
||||||
app.state.current_pane == 0,
|
app.state.current_pane == 0,
|
||||||
|
|
@ -41,7 +70,7 @@ fn render_main(frame: &mut Frame, app: &App) {
|
||||||
|
|
||||||
render_section(
|
render_section(
|
||||||
frame,
|
frame,
|
||||||
chunks[1],
|
sections[1],
|
||||||
"Recurring Items",
|
"Recurring Items",
|
||||||
&app.state.recurring_items,
|
&app.state.recurring_items,
|
||||||
app.state.current_pane == 1,
|
app.state.current_pane == 1,
|
||||||
|
|
@ -51,7 +80,7 @@ fn render_main(frame: &mut Frame, app: &App) {
|
||||||
|
|
||||||
render_section(
|
render_section(
|
||||||
frame,
|
frame,
|
||||||
chunks[2],
|
sections[2],
|
||||||
"Recent Items",
|
"Recent Items",
|
||||||
&app.state.recent_items,
|
&app.state.recent_items,
|
||||||
app.state.current_pane == 2,
|
app.state.current_pane == 2,
|
||||||
|
|
@ -59,22 +88,85 @@ fn render_main(frame: &mut Frame, app: &App) {
|
||||||
&app.state,
|
&app.state,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Render bottom bar if needed
|
||||||
|
if show_bottom_bar {
|
||||||
|
let bottom_area = Rect::new(
|
||||||
|
0,
|
||||||
|
frame.size().height - 1,
|
||||||
|
frame.size().width,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
render_bottom_bar(frame, bottom_area, app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_bottom_bar(frame: &mut Frame, area: Rect, app: &App) {
|
||||||
|
if app.config.show_command_hints {
|
||||||
|
let commands = vec![
|
||||||
|
("c", "config"),
|
||||||
|
("q", "quit"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let command_text = format!(" {}", commands.iter()
|
||||||
|
.map(|(key, desc)| format!("{} ({})", key, desc))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" · "));
|
||||||
|
|
||||||
|
let command_area = if app.config.show_help_hint {
|
||||||
|
// Leave space for help hint
|
||||||
|
Rect::new(area.x, area.y, area.width.saturating_sub(12), area.height)
|
||||||
|
} else {
|
||||||
|
area
|
||||||
|
};
|
||||||
|
|
||||||
|
let command_bar = Paragraph::new(command_text)
|
||||||
|
.style(Style::default().fg(Color::White))
|
||||||
|
.alignment(Alignment::Left);
|
||||||
|
|
||||||
|
frame.render_widget(command_bar, command_area);
|
||||||
|
}
|
||||||
|
|
||||||
if app.config.show_help_hint {
|
if app.config.show_help_hint {
|
||||||
let help_hint = Paragraph::new("(?) for help")
|
let help_hint = Paragraph::new("(?) for help")
|
||||||
.alignment(Alignment::Right)
|
.alignment(Alignment::Right)
|
||||||
.style(Style::default().fg(Color::DarkGray));
|
.style(Style::default().fg(Color::DarkGray));
|
||||||
|
|
||||||
let help_area = Rect {
|
let help_area = Rect::new(
|
||||||
x: frame.size().width.saturating_sub(12),
|
area.width.saturating_sub(12),
|
||||||
y: frame.size().height.saturating_sub(1),
|
area.y,
|
||||||
width: 12,
|
12,
|
||||||
height: 1,
|
1,
|
||||||
};
|
);
|
||||||
|
|
||||||
frame.render_widget(help_hint, help_area);
|
frame.render_widget(help_hint, help_area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_help_command_bar(frame: &mut Frame) {
|
||||||
|
let commands = vec![
|
||||||
|
("c", "configuration help"),
|
||||||
|
("q/ESC", "back"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let command_text = format!(" {}", commands.iter()
|
||||||
|
.map(|(key, desc)| format!("{} ({})", key, desc))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" · "));
|
||||||
|
|
||||||
|
let bar_area = Rect::new(
|
||||||
|
0,
|
||||||
|
frame.size().height.saturating_sub(1),
|
||||||
|
frame.size().width,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let command_bar = Paragraph::new(command_text)
|
||||||
|
.style(Style::default().fg(Color::White))
|
||||||
|
.alignment(Alignment::Left);
|
||||||
|
|
||||||
|
frame.render_widget(command_bar, bar_area);
|
||||||
|
}
|
||||||
|
|
||||||
fn render_section(
|
fn render_section(
|
||||||
frame: &mut Frame,
|
frame: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
|
|
@ -124,8 +216,8 @@ fn render_section(
|
||||||
frame.render_widget(list, area);
|
frame.render_widget(list, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_help(frame: &mut Frame) {
|
fn render_help(frame: &mut Frame, _app: &App) {
|
||||||
let area = centered_rect(60, 20, frame.size());
|
let area = centered_rect(60, frame.size().height.saturating_sub(2), frame.size());
|
||||||
|
|
||||||
frame.render_widget(Clear, area);
|
frame.render_widget(Clear, area);
|
||||||
|
|
||||||
|
|
@ -144,9 +236,6 @@ fn render_help(frame: &mut Frame) {
|
||||||
"- Use h/l or ←/→ to switch between panes",
|
"- Use h/l or ←/→ to switch between panes",
|
||||||
"- Press Enter to start/stop time tracking",
|
"- Press Enter to start/stop time tracking",
|
||||||
"",
|
"",
|
||||||
"Help Pages:",
|
|
||||||
"c - Configuration help",
|
|
||||||
"",
|
|
||||||
"Main Commands:",
|
"Main Commands:",
|
||||||
"j/k, arrows - Navigate",
|
"j/k, arrows - Navigate",
|
||||||
"h/l, arrows - Switch panes",
|
"h/l, arrows - Switch panes",
|
||||||
|
|
@ -169,10 +258,11 @@ fn render_help(frame: &mut Frame) {
|
||||||
.style(Style::default().fg(Color::White));
|
.style(Style::default().fg(Color::White));
|
||||||
|
|
||||||
frame.render_widget(paragraph, area);
|
frame.render_widget(paragraph, area);
|
||||||
|
render_help_command_bar(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_config_help(frame: &mut Frame) {
|
fn render_config_help(frame: &mut Frame, _app: &App) {
|
||||||
let area = centered_rect(60, 15, frame.size());
|
let area = centered_rect(60, frame.size().height.saturating_sub(2), frame.size());
|
||||||
|
|
||||||
frame.render_widget(Clear, area);
|
frame.render_widget(Clear, area);
|
||||||
|
|
||||||
|
|
@ -182,14 +272,14 @@ fn render_config_help(frame: &mut Frame) {
|
||||||
"The configuration file is in YAML format and supports these options:",
|
"The configuration file is in YAML format and supports these options:",
|
||||||
"",
|
"",
|
||||||
"show_help_hint: true/false",
|
"show_help_hint: true/false",
|
||||||
" Controls visibility of the help hint in the main interface",
|
" Controls visibility of the help hint in the bottom bar",
|
||||||
|
"",
|
||||||
|
"show_command_hints: true/false",
|
||||||
|
" Controls visibility of command hints in the bottom bar",
|
||||||
"",
|
"",
|
||||||
"Example configuration:",
|
"Example configuration:",
|
||||||
"show_help_hint: true",
|
"show_help_hint: true",
|
||||||
"",
|
"show_command_hints: true",
|
||||||
"",
|
|
||||||
"Commands:",
|
|
||||||
"q (or ESC) - Return to main help",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let text = help_text.join("\n");
|
let text = help_text.join("\n");
|
||||||
|
|
@ -204,6 +294,7 @@ fn render_config_help(frame: &mut Frame) {
|
||||||
.style(Style::default().fg(Color::White));
|
.style(Style::default().fg(Color::White));
|
||||||
|
|
||||||
frame.render_widget(paragraph, area);
|
frame.render_widget(paragraph, area);
|
||||||
|
render_help_command_bar(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn centered_rect(width: u16, height: u16, r: Rect) -> Rect {
|
fn centered_rect(width: u16, height: u16, r: Rect) -> Rect {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue