Files
Samuel Enocsson 2555afce19 Initial commit: Azure DevOps TUI client
A terminal-based user interface for browsing and managing Azure DevOps
work items. Features include:

- Browse work items with filtering by area, iteration, state, and type
- View work item details with markdown rendering
- Open work items in browser
- Create git branches from work items
- Update work item state
- Keyboard-driven navigation

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 09:56:11 +01:00

174 lines
3.4 KiB
Go

package components
import (
"strings"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/lipgloss"
"github.com/samuelenocsson/devops-tui/internal/ui/theme"
)
// HelpPanel displays keyboard shortcuts
type HelpPanel struct {
keys theme.KeyMap
styles theme.Styles
visible bool
width int
height int
}
// NewHelpPanel creates a new help panel
func NewHelpPanel(keys theme.KeyMap, styles theme.Styles) HelpPanel {
return HelpPanel{
keys: keys,
styles: styles,
}
}
// View renders the help panel
func (h HelpPanel) View() string {
if !h.visible {
return ""
}
var b strings.Builder
title := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#F9FAFB")).
MarginBottom(1).
Render("Keyboard Shortcuts")
b.WriteString(title)
b.WriteString("\n\n")
// Group shortcuts by category
sections := []struct {
title string
bindings []key.Binding
}{
{
title: "Navigation",
bindings: []key.Binding{
h.keys.Up,
h.keys.Down,
h.keys.Top,
h.keys.Bottom,
h.keys.NextPanel,
h.keys.PrevPanel,
},
},
{
title: "Actions",
bindings: []key.Binding{
h.keys.Select,
h.keys.Open,
h.keys.View,
h.keys.Search,
h.keys.Refresh,
},
},
{
title: "General",
bindings: []key.Binding{
h.keys.Help,
h.keys.Back,
h.keys.Quit,
},
},
}
for i, section := range sections {
// Section title
sectionTitle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#7C3AED")).
Render(section.title)
b.WriteString(sectionTitle)
b.WriteString("\n")
// Key bindings
for _, binding := range section.bindings {
keyStyle := h.styles.HelpKey.Width(12)
descStyle := h.styles.HelpDesc
help := binding.Help()
line := keyStyle.Render(help.Key) + descStyle.Render(help.Desc)
b.WriteString(line)
b.WriteString("\n")
}
// Add spacing between sections
if i < len(sections)-1 {
b.WriteString("\n")
}
}
// Footer
b.WriteString("\n")
footer := lipgloss.NewStyle().
Foreground(lipgloss.Color("#6B7280")).
Italic(true).
Render("Press ? or Esc to close")
b.WriteString(footer)
content := b.String()
// Center the help panel
helpWidth := 40
helpHeight := 25
panel := h.styles.HelpPanel.
Width(helpWidth).
Height(helpHeight).
Background(lipgloss.Color("#1F2937")).
Render(content)
// Create overlay positioning
return lipgloss.Place(
h.width,
h.height,
lipgloss.Center,
lipgloss.Center,
panel,
lipgloss.WithWhitespaceChars(" "),
lipgloss.WithWhitespaceForeground(lipgloss.Color("#000000")),
)
}
// SetVisible sets whether the help panel is visible
func (h *HelpPanel) SetVisible(visible bool) {
h.visible = visible
}
// IsVisible returns whether the help panel is visible
func (h *HelpPanel) IsVisible() bool {
return h.visible
}
// Toggle toggles the visibility of the help panel
func (h *HelpPanel) Toggle() {
h.visible = !h.visible
}
// SetSize sets the size of the help panel
func (h *HelpPanel) SetSize(width, height int) {
h.width = width
h.height = height
}
// ShortHelp returns a short help string for the status bar
func ShortHelp(keys theme.KeyMap, styles theme.Styles) string {
bindings := keys.ShortHelp()
var parts []string
for _, b := range bindings {
help := b.Help()
key := styles.HelpKey.Render(help.Key)
desc := styles.HelpDesc.Render(help.Desc)
parts = append(parts, key+" "+desc)
}
return strings.Join(parts, " ")
}