diff options
Diffstat (limited to 'makima/src/daemon/tui/widgets')
| -rw-r--r-- | makima/src/daemon/tui/widgets/list_view.rs | 127 | ||||
| -rw-r--r-- | makima/src/daemon/tui/widgets/mod.rs | 4 | ||||
| -rw-r--r-- | makima/src/daemon/tui/widgets/preview_pane.rs | 21 | ||||
| -rw-r--r-- | makima/src/daemon/tui/widgets/search_input.rs | 82 | ||||
| -rw-r--r-- | makima/src/daemon/tui/widgets/status_bar.rs | 19 |
5 files changed, 0 insertions, 253 deletions
diff --git a/makima/src/daemon/tui/widgets/list_view.rs b/makima/src/daemon/tui/widgets/list_view.rs deleted file mode 100644 index ff8269a..0000000 --- a/makima/src/daemon/tui/widgets/list_view.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! List view widget with fuzzy match highlighting. - -use std::collections::HashSet; - -use ratatui::{ - prelude::*, - widgets::{Block, Borders, List, ListItem, ListState}, -}; - -use crate::daemon::tui::app::{App, ViewMode}; - -/// Style for matched characters in search results -const MATCH_HIGHLIGHT_COLOR: Color = Color::Yellow; -const MATCH_HIGHLIGHT_MODIFIER: Modifier = Modifier::BOLD; - -/// Build a Line with highlighted characters based on matched indices -fn build_highlighted_name(name: &str, matched_indices: &[usize]) -> Vec<Span<'static>> { - if matched_indices.is_empty() { - return vec![Span::raw(name.to_string())]; - } - - let matched_set: HashSet<usize> = matched_indices.iter().cloned().collect(); - let mut spans = Vec::new(); - let mut current_run = String::new(); - let mut is_highlighted = false; - - for (byte_idx, ch) in name.char_indices() { - let should_highlight = matched_set.contains(&byte_idx); - - if should_highlight != is_highlighted { - // Flush current run - if !current_run.is_empty() { - if is_highlighted { - spans.push(Span::styled( - current_run.clone(), - Style::default() - .fg(MATCH_HIGHLIGHT_COLOR) - .add_modifier(MATCH_HIGHLIGHT_MODIFIER), - )); - } else { - spans.push(Span::raw(current_run.clone())); - } - current_run.clear(); - } - is_highlighted = should_highlight; - } - - current_run.push(ch); - } - - // Flush remaining - if !current_run.is_empty() { - if is_highlighted { - spans.push(Span::styled( - current_run, - Style::default() - .fg(MATCH_HIGHLIGHT_COLOR) - .add_modifier(MATCH_HIGHLIGHT_MODIFIER), - )); - } else { - spans.push(Span::raw(current_run)); - } - } - - spans -} - -/// Get status icon and color for an item -fn get_status_display(status: Option<&str>) -> (&'static str, Color) { - match status { - Some("running") => ("▸", Color::Green), - Some("done") => ("✓", Color::Blue), - Some("failed") => ("✗", Color::Red), - Some("pending") => ("○", Color::Yellow), - Some("paused") => ("⏸", Color::Cyan), - _ => (" ", Color::Gray), - } -} - -pub fn render(f: &mut Frame, area: Rect, app: &mut App) { - let items: Vec<ListItem> = app - .filtered_items - .iter() - .map(|filtered_item| { - let item = &app.items[filtered_item.index]; - let (status_icon, status_color) = get_status_display(item.status.as_deref()); - - // Build spans with highlighted matched characters - let mut spans = vec![Span::styled( - format!("{} ", status_icon), - Style::default().fg(status_color), - )]; - - // Add name with match highlighting - spans.extend(build_highlighted_name(&item.name, &filtered_item.matched_indices)); - - ListItem::new(Line::from(spans)) - }) - .collect(); - - let view_label = match app.view_mode { - ViewMode::Tasks => "Tasks", - ViewMode::Contracts => "Contracts", - ViewMode::Files => "Files", - }; - - let title = format!( - " {} ({}{}) ", - view_label, - app.filtered_items.len(), - if app.filtered_items.len() != app.items.len() { - format!("/{}", app.items.len()) - } else { - String::new() - } - ); - - let list = List::new(items) - .block(Block::default().title(title).borders(Borders::ALL)) - .highlight_style(Style::default().add_modifier(Modifier::REVERSED)) - .highlight_symbol("> "); - - let mut state = ListState::default(); - state.select(Some(app.selected_index)); - - f.render_stateful_widget(list, area, &mut state); -} diff --git a/makima/src/daemon/tui/widgets/mod.rs b/makima/src/daemon/tui/widgets/mod.rs deleted file mode 100644 index ddea546..0000000 --- a/makima/src/daemon/tui/widgets/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod list_view; -pub mod preview_pane; -pub mod search_input; -pub mod status_bar; diff --git a/makima/src/daemon/tui/widgets/preview_pane.rs b/makima/src/daemon/tui/widgets/preview_pane.rs deleted file mode 100644 index 84095d0..0000000 --- a/makima/src/daemon/tui/widgets/preview_pane.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Preview pane widget. - -use ratatui::{ - prelude::*, - widgets::{Block, Borders, Paragraph, Wrap}, -}; - -use crate::daemon::tui::app::App; - -pub fn render(f: &mut Frame, area: Rect, app: &App) { - let content = app - .preview_content - .as_deref() - .unwrap_or("No preview available"); - - let preview = Paragraph::new(content) - .block(Block::default().title(" Preview ").borders(Borders::ALL)) - .wrap(Wrap { trim: true }); - - f.render_widget(preview, area); -} diff --git a/makima/src/daemon/tui/widgets/search_input.rs b/makima/src/daemon/tui/widgets/search_input.rs deleted file mode 100644 index 311b4f0..0000000 --- a/makima/src/daemon/tui/widgets/search_input.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Search input widget with match count and visual feedback. - -use ratatui::{ - prelude::*, - widgets::{Block, Borders, Paragraph}, -}; - -use crate::daemon::tui::app::{App, InputMode, ViewMode}; - -/// Color for the search bar when there are no matches -const NO_MATCH_COLOR: Color = Color::Red; -/// Color for the search bar when actively searching -const SEARCH_ACTIVE_COLOR: Color = Color::Yellow; - -pub fn render(f: &mut Frame, area: Rect, app: &App) { - let view_label = match app.view_mode { - ViewMode::Tasks => "Tasks", - ViewMode::Contracts => "Contracts", - ViewMode::Files => "Files", - }; - - let (matched, total) = app.match_count(); - let has_no_matches = app.has_no_matches(); - let is_searching = matches!(app.input_mode, InputMode::Search); - let has_query = !app.search_query.is_empty(); - - // Determine border style based on state - let border_style = if has_no_matches { - Style::default().fg(NO_MATCH_COLOR) - } else if is_searching { - Style::default().fg(SEARCH_ACTIVE_COLOR) - } else { - Style::default() - }; - - // Build the search input content - let search_text = if app.search_query.is_empty() { - if is_searching { - " Type to search...".to_string() - } else { - " Press / to search".to_string() - } - } else { - format!(" {}", app.search_query) - }; - - // Build the title with match count - let title = if has_query { - if has_no_matches { - format!(" 🔍 Search [{}] - No matches ", view_label) - } else { - format!(" 🔍 Search [{}] - {}/{} matches ", view_label, matched, total) - } - } else { - format!(" 🔍 Search [{}] ", view_label) - }; - - // Create input text with appropriate style - let text_style = if app.search_query.is_empty() && !is_searching { - Style::default().fg(Color::DarkGray) - } else if has_no_matches { - Style::default().fg(NO_MATCH_COLOR) - } else { - Style::default() - }; - - let input = Paragraph::new(Span::styled(search_text, text_style)).block( - Block::default() - .title(title) - .borders(Borders::ALL) - .border_style(border_style), - ); - - f.render_widget(input, area); - - // Show cursor in search mode - if is_searching { - // Calculate cursor position based on actual search query length - let cursor_x = area.x + app.search_query.len() as u16 + 2; - f.set_cursor_position(Position::new(cursor_x, area.y + 1)); - } -} diff --git a/makima/src/daemon/tui/widgets/status_bar.rs b/makima/src/daemon/tui/widgets/status_bar.rs deleted file mode 100644 index 3357c58..0000000 --- a/makima/src/daemon/tui/widgets/status_bar.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Status bar widget. - -use ratatui::{prelude::*, widgets::Paragraph}; - -use crate::daemon::tui::app::{App, InputMode}; - -pub fn render(f: &mut Frame, area: Rect, app: &App) { - let keybindings = match app.input_mode { - InputMode::Normal => { - "↑↓:Navigate Enter:View e:Edit d:Delete Tab:Preview /:Search q:Quit" - } - InputMode::Search => "Type to search Enter:Select Esc:Cancel", - InputMode::Confirm => "y:Confirm n:Cancel", - }; - - let status = Paragraph::new(keybindings).style(Style::default().bg(Color::DarkGray)); - - f.render_widget(status, area); -} |
