login.go

  1package tui
  2
  3import (
  4	"github.com/charmbracelet/bubbles/textinput"
  5	tea "github.com/charmbracelet/bubbletea"
  6	"github.com/charmbracelet/lipgloss"
  7)
  8
  9// Login holds the state for the login form.
 10type Login struct {
 11	focusIndex int
 12	inputs     []textinput.Model
 13}
 14
 15// NewLogin creates a new login model.
 16func NewLogin() tea.Model {
 17	m := Login{
 18		inputs: make([]textinput.Model, 4), // Increased to 4 for provider, name, email, and password
 19	}
 20
 21	var t textinput.Model
 22	for i := range m.inputs {
 23		t = textinput.New()
 24		t.Cursor.Style = focusedStyle
 25		t.CharLimit = 64
 26
 27		switch i {
 28		case 0:
 29			t.Placeholder = "Provider (gmail or icloud)"
 30			t.Focus()
 31			t.Prompt = "☁️ > "
 32		case 1:
 33			t.Placeholder = "Name"
 34			t.Prompt = "👤 > "
 35		case 2:
 36			t.Placeholder = "Email"
 37			t.Prompt = "✉️ > "
 38		case 3:
 39			t.Placeholder = "Password"
 40			t.EchoMode = textinput.EchoPassword
 41			t.Prompt = "🔑 > "
 42		}
 43		m.inputs[i] = t
 44	}
 45
 46	return m
 47}
 48
 49// Init initializes the login model.
 50func (m Login) Init() tea.Cmd {
 51	return textinput.Blink
 52}
 53
 54// Update handles messages for the login model.
 55func (m Login) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 56	switch msg := msg.(type) {
 57	case tea.KeyMsg:
 58		switch msg.Type {
 59		// On Enter, if we are on the last field, submit the credentials.
 60		case tea.KeyEnter:
 61			if m.focusIndex == len(m.inputs)-1 {
 62				return m, func() tea.Msg {
 63					return Credentials{
 64						Provider: m.inputs[0].Value(),
 65						Name:     m.inputs[1].Value(),
 66						Email:    m.inputs[2].Value(),
 67						Password: m.inputs[3].Value(),
 68					}
 69				}
 70			}
 71			fallthrough
 72		// Cycle focus between inputs.
 73		case tea.KeyTab, tea.KeyShiftTab, tea.KeyUp, tea.KeyDown:
 74			s := msg.String()
 75			if s == "up" || s == "shift+tab" {
 76				m.focusIndex--
 77			} else {
 78				m.focusIndex++
 79			}
 80
 81			if m.focusIndex >= len(m.inputs) {
 82				m.focusIndex = 0
 83			} else if m.focusIndex < 0 {
 84				m.focusIndex = len(m.inputs) - 1
 85			}
 86
 87			cmds := make([]tea.Cmd, len(m.inputs))
 88			for i := 0; i < len(m.inputs); i++ {
 89				if i == m.focusIndex {
 90					cmds[i] = m.inputs[i].Focus()
 91				} else {
 92					m.inputs[i].Blur()
 93				}
 94			}
 95			return m, tea.Batch(cmds...)
 96		}
 97	}
 98
 99	// Update the focused input field.
100	var cmds = make([]tea.Cmd, len(m.inputs))
101	for i := range m.inputs {
102		m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
103	}
104	return m, tea.Batch(cmds...)
105}
106
107// View renders the login form.
108func (m Login) View() string {
109	return lipgloss.JoinVertical(lipgloss.Left,
110		titleStyle.Render("Account Settings"),
111		"Update your credentials.",
112		m.inputs[0].View(),
113		m.inputs[1].View(),
114		m.inputs[2].View(),
115		m.inputs[3].View(),
116		helpStyle.Render("\nenter: save • tab: next field • esc: back to menu"),
117	)
118}