1package tabs23import (4 "strings"56 tea "charm.land/bubbletea/v2"7 "charm.land/lipgloss/v2"8 "github.com/charmbracelet/soft-serve/pkg/ui/common"9)1011// SelectTabMsg is a message that contains the index of the tab to select.12type SelectTabMsg int1314// ActiveTabMsg is a message that contains the index of the current active tab.15type ActiveTabMsg int1617// Tabs is bubbletea component that displays a list of tabs.18type Tabs struct {19 common common.Common20 tabs []string21 activeTab int22 TabSeparator lipgloss.Style23 TabInactive lipgloss.Style24 TabActive lipgloss.Style25 TabDot lipgloss.Style26 UseDot bool27}2829// New creates a new Tabs component.30func New(c common.Common, tabs []string) *Tabs {31 r := &Tabs{32 common: c,33 tabs: tabs,34 activeTab: 0,35 TabSeparator: c.Styles.TabSeparator,36 TabInactive: c.Styles.TabInactive,37 TabActive: c.Styles.TabActive,38 }39 return r40}4142// SetSize implements common.Component.43func (t *Tabs) SetSize(width, height int) {44 t.common.SetSize(width, height)45}4647// Init implements tea.Model.48func (t *Tabs) Init() tea.Cmd {49 t.activeTab = 050 return nil51}5253// Update implements tea.Model.54func (t *Tabs) Update(msg tea.Msg) (common.Model, tea.Cmd) {55 cmds := make([]tea.Cmd, 0)56 switch msg := msg.(type) {57 case tea.KeyPressMsg:58 switch msg.String() {59 case "tab":60 t.activeTab = (t.activeTab + 1) % len(t.tabs)61 cmds = append(cmds, t.activeTabCmd)62 case "shift+tab":63 t.activeTab = (t.activeTab - 1 + len(t.tabs)) % len(t.tabs)64 cmds = append(cmds, t.activeTabCmd)65 }66 case tea.MouseClickMsg:67 switch msg.Button {68 case tea.MouseLeft:69 for i, tab := range t.tabs {70 if t.common.Zone.Get(tab).InBounds(msg) {71 t.activeTab = i72 cmds = append(cmds, t.activeTabCmd)73 }74 }75 }76 case SelectTabMsg:77 tab := int(msg)78 if tab >= 0 && tab < len(t.tabs) {79 t.activeTab = int(msg)80 }81 }82 return t, tea.Batch(cmds...)83}8485// View implements tea.Model.86func (t *Tabs) View() string {87 s := strings.Builder{}88 sep := t.TabSeparator89 for i, tab := range t.tabs {90 style := t.TabInactive91 prefix := " "92 if i == t.activeTab {93 style = t.TabActive94 prefix = t.TabDot.Render("• ")95 }96 if t.UseDot {97 s.WriteString(prefix)98 }99 s.WriteString(100 t.common.Zone.Mark(101 tab,102 style.Render(tab),103 ),104 )105 if i != len(t.tabs)-1 {106 s.WriteString(sep.String())107 }108 }109 return lipgloss.NewStyle().110 MaxWidth(t.common.Width).111 Render(s.String())112}113114func (t *Tabs) activeTabCmd() tea.Msg {115 return ActiveTabMsg(t.activeTab)116}117118// SelectTabCmd is a bubbletea command that selects the tab at the given index.119func SelectTabCmd(tab int) tea.Cmd {120 return func() tea.Msg {121 return SelectTabMsg(tab)122 }123}