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() *Login {
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.WindowSizeMsg:
58 // When the window is resized, update the width of the inputs.
59 for i := range m.inputs {
60 m.inputs[i].Width = msg.Width - 6 // Subtract for padding and prompt
61 }
62
63 case tea.KeyMsg:
64 switch msg.Type {
65 // On Enter, if we are on the last field, submit the credentials.
66 case tea.KeyEnter:
67 if m.focusIndex == len(m.inputs)-1 {
68 return m, func() tea.Msg {
69 return Credentials{
70 Provider: m.inputs[0].Value(),
71 Name: m.inputs[1].Value(),
72 Email: m.inputs[2].Value(),
73 Password: m.inputs[3].Value(),
74 }
75 }
76 }
77 fallthrough
78 // Cycle focus between inputs.
79 case tea.KeyTab, tea.KeyShiftTab, tea.KeyUp, tea.KeyDown:
80 s := msg.String()
81 if s == "up" || s == "shift+tab" {
82 m.focusIndex--
83 } else {
84 m.focusIndex++
85 }
86
87 if m.focusIndex >= len(m.inputs) {
88 m.focusIndex = 0
89 } else if m.focusIndex < 0 {
90 m.focusIndex = len(m.inputs) - 1
91 }
92
93 cmds := make([]tea.Cmd, len(m.inputs))
94 for i := 0; i < len(m.inputs); i++ {
95 if i == m.focusIndex {
96 cmds[i] = m.inputs[i].Focus()
97 } else {
98 m.inputs[i].Blur()
99 }
100 }
101 return m, tea.Batch(cmds...)
102 }
103 }
104
105 // Update the focused input field.
106 var cmds = make([]tea.Cmd, len(m.inputs))
107 for i := range m.inputs {
108 m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
109 }
110 return m, tea.Batch(cmds...)
111}
112
113// View renders the login form.
114func (m *Login) View() string {
115 return lipgloss.JoinVertical(lipgloss.Left,
116 titleStyle.Render("Account Settings"),
117 "Update your credentials.",
118 m.inputs[0].View(),
119 m.inputs[1].View(),
120 m.inputs[2].View(),
121 m.inputs[3].View(),
122 helpStyle.Render("\nenter: save • tab: next field • esc: back to menu"),
123 )
124}