1package tui
2
3import (
4 "strings"
5
6 "charm.land/bubbles/v2/textinput"
7 tea "charm.land/bubbletea/v2"
8 "charm.land/lipgloss/v2"
9)
10
11// MailingListEditor displays the screen to add or edit a mailing list.
12type MailingListEditor struct {
13 nameInput textinput.Model
14 addrInput textinput.Model
15 focus int // 0 = name, 1 = addresses
16 width int
17 height int
18 isEditMode bool
19 editIndex int // index of the mailing list being edited
20}
21
22// NewMailingListEditor creates a new mailing list editor model.
23func NewMailingListEditor() *MailingListEditor {
24 tiStyles := ThemedTextInputStyles()
25
26 name := textinput.New()
27 name.Placeholder = "e.g., Team"
28 name.SetStyles(tiStyles)
29 name.Focus()
30
31 addr := textinput.New()
32 addr.Placeholder = "e.g., alice@example.com, bob@example.com"
33 addr.SetStyles(tiStyles)
34
35 return &MailingListEditor{
36 nameInput: name,
37 addrInput: addr,
38 focus: 0,
39 editIndex: -1,
40 }
41}
42
43// SetEditMode sets the editor to edit an existing mailing list.
44func (m *MailingListEditor) SetEditMode(index int, name, addresses string) {
45 m.isEditMode = true
46 m.editIndex = index
47 m.nameInput.SetValue(name)
48 m.addrInput.SetValue(addresses)
49}
50
51// Init initializes the mailing list editor model.
52func (m *MailingListEditor) Init() tea.Cmd {
53 return textinput.Blink
54}
55
56// Update handles messages for the mailing list editor model.
57func (m *MailingListEditor) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
58 var cmd tea.Cmd
59
60 switch msg := msg.(type) {
61 case tea.WindowSizeMsg:
62 m.width = msg.Width
63 m.height = msg.Height
64 m.nameInput.SetWidth(msg.Width - 4)
65 m.addrInput.SetWidth(msg.Width - 4)
66 return m, nil
67
68 case tea.KeyPressMsg:
69 switch msg.String() {
70 case "ctrl+c":
71 return m, tea.Quit
72 case "esc":
73 return m, func() tea.Msg { return GoToSettingsMsg{} }
74 case "tab", "shift+tab", "up", "down":
75 if m.focus == 0 {
76 m.focus = 1
77 m.nameInput.Blur()
78 m.addrInput.Focus()
79 } else {
80 m.focus = 0
81 m.addrInput.Blur()
82 m.nameInput.Focus()
83 }
84 return m, nil
85 case "enter":
86 if m.focus == 0 {
87 m.focus = 1
88 m.nameInput.Blur()
89 m.addrInput.Focus()
90 return m, nil
91 } else {
92 // Submit on second field
93 name := strings.TrimSpace(m.nameInput.Value())
94 addrs := strings.TrimSpace(m.addrInput.Value())
95 if name != "" && addrs != "" {
96 editIdx := m.editIndex
97 return m, func() tea.Msg {
98 return SaveMailingListMsg{
99 Name: name,
100 Addresses: addrs,
101 EditIndex: editIdx,
102 }
103 }
104 }
105 }
106 }
107 }
108
109 if m.focus == 0 {
110 m.nameInput, cmd = m.nameInput.Update(msg)
111 } else {
112 m.addrInput, cmd = m.addrInput.Update(msg)
113 }
114
115 return m, cmd
116}
117
118// View renders the mailing list editor screen.
119func (m *MailingListEditor) View() tea.View {
120 titleText := "Add Mailing List"
121 if m.isEditMode {
122 titleText = "Edit Mailing List"
123 }
124 title := titleStyle.Render(titleText)
125
126 var nameView, addrView string
127 if m.focus == 0 {
128 nameView = focusedStyle.Render("Name:") + "\n" + m.nameInput.View()
129 addrView = blurredStyle.Render("Addresses (comma-separated):") + "\n" + m.addrInput.View()
130 } else {
131 nameView = blurredStyle.Render("Name:") + "\n" + m.nameInput.View()
132 addrView = focusedStyle.Render("Addresses (comma-separated):") + "\n" + m.addrInput.View()
133 }
134
135 return tea.NewView(lipgloss.JoinVertical(lipgloss.Left,
136 title,
137 "",
138 nameView,
139 "",
140 addrView,
141 "",
142 helpStyle.Render("tab/↑/↓: switch fields • enter: submit • esc: back"),
143 ))
144}