package ui import ( "fmt" "strings" "github.com/charmbracelet/bubbles/key" ) // HelpModel is the help overlay model. type HelpModel struct { visible bool } // NewHelp creates a new help model. func NewHelp() HelpModel { return HelpModel{ visible: false, } } // Show displays the help overlay. func (m *HelpModel) Show() { m.visible = true } // Hide hides the help overlay. func (m *HelpModel) Hide() { m.visible = false } // Toggle toggles the help overlay visibility. func (m *HelpModel) Toggle() { m.visible = !m.visible } // IsVisible returns true if the help overlay is visible. func (m HelpModel) IsVisible() bool { return m.visible } // Render renders the help overlay. func (m HelpModel) Render(keys KeyMap, styles Styles) string { if !m.visible { return "" } var b strings.Builder // Title title := styles.HeaderBar.Render("Keybindings - Press ? or esc to close") b.WriteString(title) b.WriteString("\n\n") // Define keybinding groups groups := []struct { name string binds []keyHelp }{ { name: "Global", binds: []keyHelp{ {keys.Help, "Show/hide this help"}, {keys.Quit, "Quit the application"}, {keys.RefreshNow, "Refresh data now"}, }, }, { name: "Filters", binds: []keyHelp{ {keys.Search, "Search by title/details"}, {keys.Priority, "Cycle priority filter"}, {keys.Category, "Cycle category filter"}, }, }, { name: "Navigation", binds: []keyHelp{ {keys.FocusNext, "Toggle focus (table/details)"}, {keys.Sort, "Cycle sort order"}, {keys.JumpToTop, "Jump to top (g)"}, {keys.JumpToBottom, "Jump to bottom (G)"}, {keys.Down, "Move down (j)"}, {keys.Up, "Move up (k)"}, }, }, { name: "Actions", binds: []keyHelp{ {keys.AckToggle, "Acknowledge/unacknowledge issue"}, {keys.Export, "Export issues to JSON"}, }, }, } // Render each group for i, group := range groups { if i > 0 { b.WriteString("\n") } // Group header groupTitle := styles.HeaderKey.Render(group.name + ":") b.WriteString(groupTitle) b.WriteString("\n") // Keybindings in this group for _, kb := range group.binds { line := renderKeyHelp(kb, styles) b.WriteString(line) b.WriteString("\n") } } // Render collector health icon legend b.WriteString("\n") legendTitle := styles.HeaderKey.Render("Legend:") b.WriteString(legendTitle) b.WriteString("\n") legendText := styles.HeaderVal.Render(" Collector health: ✓ (OK), ⚠ (DEGRADED), ✗ (ERROR)") b.WriteString(legendText) b.WriteString("\n") return b.String() } type keyHelp struct { binding key.Binding help string } func renderKeyHelp(kb keyHelp, styles Styles) string { // Get key names from the binding keys := kb.binding.Keys() if len(keys) == 0 { return "" } // Format key names keyStr := strings.Join(keys, ", ") keyStyled := styles.HeaderVal.Render(keyStr) // Format help text helpStyled := styles.HeaderVal.Render(kb.help) // Combine with padding padding := "" if needed := 10 - len(keyStr); needed > 0 { padding = strings.Repeat(" ", needed) } return fmt.Sprintf(" %s%s%s", keyStyled, padding, helpStyled) }