| 13 | ) |
| 14 | |
| 15 | func (m RootModel) updateDashboard(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { |
| 16 | |
| 17 | // Handle search input FIRST when active (intercepts ALL keys) |
| 18 | if m.searchActive { |
| 19 | switch msg.String() { |
| 20 | case "esc": |
| 21 | // Cancel search and clear query |
| 22 | m.searchActive = false |
| 23 | m.searchInput.Blur() |
| 24 | m.searchQuery = "" |
| 25 | m.searchInput.SetValue("") |
| 26 | m.UpdateListItems() |
| 27 | return m, nil |
| 28 | case "enter": |
| 29 | // Commit search (keep filter applied) |
| 30 | m.searchActive = false |
| 31 | m.searchInput.Blur() |
| 32 | return m, nil |
| 33 | default: |
| 34 | // All other keys go to search input |
| 35 | var cmd tea.Cmd |
| 36 | m.searchInput, cmd = m.searchInput.Update(msg) |
| 37 | m.searchQuery = m.searchInput.Value() |
| 38 | m.UpdateListItems() |
| 39 | return m, cmd |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | // Toggle search with F |
| 44 | if key.Matches(msg, m.keys.Dashboard.Search) { |
| 45 | if m.searchQuery != "" { |
| 46 | // Clear existing search |
| 47 | m.searchQuery = "" |
| 48 | m.searchInput.SetValue("") |
| 49 | m.UpdateListItems() |
| 50 | } else { |
| 51 | // Start new search |
| 52 | m.searchActive = true |
| 53 | m.searchInput.Focus() |
| 54 | } |
| 55 | return m, nil |
| 56 | } |
| 57 | |
| 58 | // Tab switching |
| 59 | pinnedGuard := func() bool { |
| 60 | if m.pinnedTab != -1 { |
| 61 | m.addLogEntry(LogStyleError.Render("\u25c6 Tab is pinned \u2014 press t to unpin")) |
| 62 | return true |
| 63 | } |
| 64 | return false |
| 65 | } |
| 66 | |
| 67 | switchTab := func(tab int) (tea.Model, tea.Cmd) { |
| 68 | m.activeTab = tab |
| 69 | m.ManualTabSwitch = true |
| 70 | m.UpdateListItems() |
| 71 | return m, nil |
| 72 | } |