summaryrefslogtreecommitdiff
path: root/makima/src/daemon/tui/widgets/search_input.rs
blob: 311b4f023e17bd9572a90025788f2ba82dbaf494 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! 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));
    }
}