Implement complete keyboard navigation and UI enhancement
Phase 1 - Panel Navigation: - Add PanelType enum and panel focus state management - Implement Shift+Tab cycling between panels (System → Services → Backup → Network) - Add visual focus indicators with blue borders for focused panels - Preserve existing Tab behavior for host switching Phase 2 - Dynamic Statusbar: - Add bottom statusbar with context-aware shortcuts - Display different shortcuts based on focused panel - Global shortcuts: Tab, Shift+Tab, Up/Down arrows, Q - Panel-specific shortcuts: R (Rebuild), Space/R (Services), B (Backup), N (Network) Phase 3 - Scrolling Support: - Add scroll state management per host and panel type - Implement Up/Down arrow key scrolling within focused panels - Smart scrolling that activates only when content exceeds panel height - Scroll bounds checking to prevent over-scrolling Complete keyboard navigation experience with visual feedback and contextual help.
This commit is contained in:
@@ -308,7 +308,18 @@ impl Widget for ServicesWidget {
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &mut Frame, area: Rect) {
|
||||
let services_block = Components::widget_block("services");
|
||||
self.render_with_focus(frame, area, false);
|
||||
}
|
||||
}
|
||||
|
||||
impl ServicesWidget {
|
||||
/// Render with optional focus indicator
|
||||
pub fn render_with_focus(&mut self, frame: &mut Frame, area: Rect, is_focused: bool) {
|
||||
let services_block = if is_focused {
|
||||
Components::focused_widget_block("services")
|
||||
} else {
|
||||
Components::widget_block("services")
|
||||
};
|
||||
let inner_area = services_block.inner(area);
|
||||
frame.render_widget(services_block, area);
|
||||
|
||||
|
||||
@@ -399,6 +399,13 @@ impl Widget for SystemWidget {
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &mut Frame, area: Rect) {
|
||||
self.render_with_scroll(frame, area, 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemWidget {
|
||||
/// Render with scroll offset support
|
||||
pub fn render_with_scroll(&mut self, frame: &mut Frame, area: Rect, scroll_offset: usize) {
|
||||
let mut lines = Vec::new();
|
||||
|
||||
// NixOS section
|
||||
@@ -509,7 +516,28 @@ impl Widget for SystemWidget {
|
||||
}
|
||||
}
|
||||
|
||||
let paragraph = Paragraph::new(Text::from(lines));
|
||||
frame.render_widget(paragraph, area);
|
||||
// Apply scroll offset
|
||||
let total_lines = lines.len();
|
||||
let available_height = area.height as usize;
|
||||
|
||||
if total_lines > available_height {
|
||||
// Content is larger than area, apply scrolling
|
||||
let max_scroll = total_lines.saturating_sub(available_height);
|
||||
let effective_scroll = scroll_offset.min(max_scroll);
|
||||
|
||||
// Take only the visible portion after scrolling
|
||||
let visible_lines: Vec<Line> = lines
|
||||
.into_iter()
|
||||
.skip(effective_scroll)
|
||||
.take(available_height)
|
||||
.collect();
|
||||
|
||||
let paragraph = Paragraph::new(Text::from(visible_lines));
|
||||
frame.render_widget(paragraph, area);
|
||||
} else {
|
||||
// All content fits, render normally
|
||||
let paragraph = Paragraph::new(Text::from(lines));
|
||||
frame.render_widget(paragraph, area);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user