1package tabs
  2
  3import (
  4	"strings"
  5
  6	tea "github.com/charmbracelet/bubbletea"
  7	"github.com/charmbracelet/lipgloss"
  8	"github.com/charmbracelet/soft-serve/ui/common"
  9)
 10
 11// SelectTabMsg is a message that contains the index of the tab to select.
 12type SelectTabMsg int
 13
 14// ActiveTabMsg is a message that contains the index of the current active tab.
 15type ActiveTabMsg int
 16
 17// Tabs is bubbletea component that displays a list of tabs.
 18type Tabs struct {
 19	common       common.Common
 20	tabs         []string
 21	activeTab    int
 22	TabSeparator lipgloss.Style
 23	TabInactive  lipgloss.Style
 24	TabActive    lipgloss.Style
 25}
 26
 27// New creates a new Tabs component.
 28func New(c common.Common, tabs []string) *Tabs {
 29	r := &Tabs{
 30		common:       c,
 31		tabs:         tabs,
 32		activeTab:    0,
 33		TabSeparator: c.Styles.TabSeparator,
 34		TabInactive:  c.Styles.TabInactive,
 35		TabActive:    c.Styles.TabActive,
 36	}
 37	return r
 38}
 39
 40// SetSize implements common.Component.
 41func (t *Tabs) SetSize(width, height int) {
 42	t.common.SetSize(width, height)
 43}
 44
 45// Init implements tea.Model.
 46func (t *Tabs) Init() tea.Cmd {
 47	t.activeTab = 0
 48	return nil
 49}
 50
 51// Update implements tea.Model.
 52func (t *Tabs) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 53	cmds := make([]tea.Cmd, 0)
 54	switch msg := msg.(type) {
 55	case tea.KeyMsg:
 56		switch msg.String() {
 57		case "tab":
 58			t.activeTab = (t.activeTab + 1) % len(t.tabs)
 59			cmds = append(cmds, t.activeTabCmd)
 60		case "shift+tab":
 61			t.activeTab = (t.activeTab - 1 + len(t.tabs)) % len(t.tabs)
 62			cmds = append(cmds, t.activeTabCmd)
 63		}
 64	case SelectTabMsg:
 65		tab := int(msg)
 66		if tab >= 0 && tab < len(t.tabs) {
 67			t.activeTab = int(msg)
 68		}
 69	}
 70	return t, tea.Batch(cmds...)
 71}
 72
 73// View implements tea.Model.
 74func (t *Tabs) View() string {
 75	s := strings.Builder{}
 76	sep := t.TabSeparator
 77	for i, tab := range t.tabs {
 78		style := t.TabInactive.Copy()
 79		if i == t.activeTab {
 80			style = t.TabActive.Copy()
 81		}
 82		s.WriteString(style.Render(tab))
 83		if i != len(t.tabs)-1 {
 84			s.WriteString(sep.String())
 85		}
 86	}
 87	return lipgloss.NewStyle().
 88		MaxWidth(t.common.Width).
 89		Render(s.String())
 90}
 91
 92func (t *Tabs) activeTabCmd() tea.Msg {
 93	return ActiveTabMsg(t.activeTab)
 94}
 95
 96// SelectTabCmd is a bubbletea command that selects the tab at the given index.
 97func SelectTabCmd(tab int) tea.Cmd {
 98	return func() tea.Msg {
 99		return SelectTabMsg(tab)
100	}
101}