main
6d86999 · 6 months ago 26 commits
  1// internal/ui/menu.go
  2package ui
  3
  4import (
  5	"strings"
  6	"github.com/The-Robin-Hood/ufWall/internal/keys"
  7
  8	"github.com/charmbracelet/bubbles/key"
  9	tea "github.com/charmbracelet/bubbletea"
 10)
 11
 12type MenuItem struct {
 13	Label  string
 14	Action func() tea.Cmd
 15}
 16
 17type Menu struct {
 18	Options  []MenuItem
 19	Selected int
 20	styles   Styles
 21}
 22
 23func NewMenu(options []MenuItem, styles Styles) Menu {
 24	return Menu{
 25		Options:  options,
 26		Selected: 0,
 27		styles:   styles,
 28	}
 29}
 30
 31func (m *Menu) Up() {
 32	if m.Selected > 0 {
 33		m.Selected--
 34	}
 35}
 36
 37func (m *Menu) Down() {
 38	if m.Selected < len(m.Options)-1 {
 39		m.Selected++
 40	}
 41}
 42
 43func (m Menu) ExecuteSelected() tea.Cmd {
 44	if m.Selected >= 0 && m.Selected < len(m.Options) {
 45		if m.Options[m.Selected].Action != nil {
 46			return m.Options[m.Selected].Action()
 47		}
 48	}
 49	return nil
 50}
 51
 52func (m Menu) View(styles Styles) string {
 53	var lines []string
 54
 55	for i, option := range m.Options {
 56		prefix := "  "
 57		style := m.styles.Value
 58
 59		if i == m.Selected {
 60			prefix = "▶ "
 61			style = m.styles.ActiveStatus.Bold(true)
 62		}
 63
 64		lines = append(lines, prefix+style.Render(option.Label))
 65	}
 66
 67	content := strings.Join(lines, "\n")
 68
 69	return styles.Menu.Render(content)
 70}
 71
 72func (m *Menu) Update(msg tea.Msg) (bool) {
 73	switch msg := msg.(type) {
 74
 75	case tea.KeyMsg:
 76		switch {
 77		case key.Matches(msg, keys.Bindings.CursorUp):
 78			m.Up()
 79		case key.Matches(msg, keys.Bindings.CursorDown):
 80			m.Down()
 81		case key.Matches(msg, keys.Bindings.Execute):
 82			m.ExecuteSelected()
 83			return true
 84		case key.Matches(msg, keys.Bindings.Quit):
 85			return true
 86		}
 87	}
 88	return false
 89}
 90
 91func MakeMenuItems(labels []string, handler func(string) tea.Cmd) []MenuItem {
 92	items := make([]MenuItem, len(labels))
 93
 94	for i, label := range labels {
 95		l := label // capture loop variable!
 96		items[i] = MenuItem{
 97			Label: l,
 98			Action: func() tea.Cmd {
 99				return handler(l)
100			},
101		}
102	}
103
104	return items
105}