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. This function was missing.
 16func NewLogin() tea.Model {
 17	m := Login{
 18		inputs: make([]textinput.Model, 2),
 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 = "Email"
 30			t.Focus()
 31			t.Prompt = "✉️ > "
 32		case 1:
 33			t.Placeholder = "Password"
 34			t.EchoMode = textinput.EchoPassword
 35			t.Prompt = "🔑 > "
 36		}
 37		m.inputs[i] = t
 38	}
 39
 40	return m
 41}
 42
 43// Init initializes the login model.
 44func (m Login) Init() tea.Cmd {
 45	return textinput.Blink
 46}
 47
 48// Update handles messages for the login model.
 49func (m Login) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 50	switch msg := msg.(type) {
 51	case tea.KeyMsg:
 52		switch msg.Type {
 53		// On Enter, if we are on the last field, submit the credentials.
 54		case tea.KeyEnter:
 55			if m.focusIndex == len(m.inputs)-1 {
 56				return m, func() tea.Msg {
 57					return Credentials{
 58						Email:    m.inputs[0].Value(),
 59						Password: m.inputs[1].Value(),
 60					}
 61				}
 62			}
 63			fallthrough
 64		// Cycle focus between inputs.
 65		case tea.KeyTab, tea.KeyShiftTab, tea.KeyUp, tea.KeyDown:
 66			s := msg.String()
 67			if s == "up" || s == "shift+tab" {
 68				m.focusIndex--
 69			} else {
 70				m.focusIndex++
 71			}
 72
 73			if m.focusIndex >= len(m.inputs) {
 74				m.focusIndex = 0
 75			} else if m.focusIndex < 0 {
 76				m.focusIndex = len(m.inputs) - 1
 77			}
 78
 79			cmds := make([]tea.Cmd, len(m.inputs))
 80			for i := 0; i < len(m.inputs); i++ {
 81				if i == m.focusIndex {
 82					cmds[i] = m.inputs[i].Focus()
 83				} else {
 84					m.inputs[i].Blur()
 85				}
 86			}
 87			return m, tea.Batch(cmds...)
 88		}
 89	}
 90
 91	// Update the focused input field.
 92	var cmds = make([]tea.Cmd, len(m.inputs))
 93	for i := range m.inputs {
 94		m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
 95	}
 96	return m, tea.Batch(cmds...)
 97}
 98
 99// View renders the login form.
100func (m Login) View() string {
101	return lipgloss.JoinVertical(lipgloss.Left,
102		titleStyle.Render("Welcome to Email CLI"),
103		"Please enter your credentials.",
104		m.inputs[0].View(),
105		m.inputs[1].View(),
106		helpStyle.Render("\nenter: submit • tab: next field • esc: quit"),
107	)
108}