1package dialog
2
3import (
4 "charm.land/bubbles/v2/key"
5 tea "charm.land/bubbletea/v2"
6 "charm.land/lipgloss/v2"
7 "github.com/charmbracelet/crush/internal/ui/common"
8)
9
10// QuitID is the identifier for the quit dialog.
11const QuitID = "quit"
12
13// Quit represents a confirmation dialog for quitting the application.
14type Quit struct {
15 com *common.Common
16 selectedNo bool // true if "No" button is selected
17 keyMap struct {
18 LeftRight,
19 EnterSpace,
20 Yes,
21 No,
22 Tab,
23 Close key.Binding
24 }
25}
26
27// NewQuit creates a new quit confirmation dialog.
28func NewQuit(com *common.Common) *Quit {
29 q := &Quit{
30 com: com,
31 selectedNo: true,
32 }
33 q.keyMap.LeftRight = key.NewBinding(
34 key.WithKeys("left", "right"),
35 key.WithHelp("←/→", "switch options"),
36 )
37 q.keyMap.EnterSpace = key.NewBinding(
38 key.WithKeys("enter", " "),
39 key.WithHelp("enter/space", "confirm"),
40 )
41 q.keyMap.Yes = key.NewBinding(
42 key.WithKeys("y", "Y", "ctrl+c"),
43 key.WithHelp("y/Y/ctrl+c", "yes"),
44 )
45 q.keyMap.No = key.NewBinding(
46 key.WithKeys("n", "N"),
47 key.WithHelp("n/N", "no"),
48 )
49 q.keyMap.Tab = key.NewBinding(
50 key.WithKeys("tab"),
51 key.WithHelp("tab", "switch options"),
52 )
53 q.keyMap.Close = CloseKey
54 return q
55}
56
57// ID implements [Model].
58func (*Quit) ID() string {
59 return QuitID
60}
61
62// Update implements [Model].
63func (q *Quit) Update(msg tea.Msg) tea.Msg {
64 switch msg := msg.(type) {
65 case tea.KeyPressMsg:
66 switch {
67 case key.Matches(msg, q.keyMap.Close):
68 return CloseMsg{}
69 case key.Matches(msg, q.keyMap.LeftRight, q.keyMap.Tab):
70 q.selectedNo = !q.selectedNo
71 return CloseMsg{}
72 case key.Matches(msg, q.keyMap.EnterSpace):
73 if !q.selectedNo {
74 return QuitMsg{}
75 }
76 return CloseMsg{}
77 case key.Matches(msg, q.keyMap.Yes):
78 return QuitMsg{}
79 case key.Matches(msg, q.keyMap.No, q.keyMap.Close):
80 return CloseMsg{}
81 }
82 }
83
84 return nil
85}
86
87// View implements [Dialog].
88func (q *Quit) View() string {
89 const question = "Are you sure you want to quit?"
90 baseStyle := q.com.Styles.Base
91 buttonOpts := []common.ButtonOpts{
92 {Text: "Yep!", Selected: !q.selectedNo, Padding: 3},
93 {Text: "Nope", Selected: q.selectedNo, Padding: 3},
94 }
95 buttons := common.ButtonGroup(q.com.Styles, buttonOpts, " ")
96 content := baseStyle.Render(
97 lipgloss.JoinVertical(
98 lipgloss.Center,
99 question,
100 "",
101 buttons,
102 ),
103 )
104
105 return q.com.Styles.BorderFocus.Render(content)
106}
107
108// ShortHelp implements [help.KeyMap].
109func (q *Quit) ShortHelp() []key.Binding {
110 return []key.Binding{
111 q.keyMap.LeftRight,
112 q.keyMap.EnterSpace,
113 }
114}
115
116// FullHelp implements [help.KeyMap].
117func (q *Quit) FullHelp() [][]key.Binding {
118 return [][]key.Binding{
119 {q.keyMap.LeftRight, q.keyMap.EnterSpace, q.keyMap.Yes, q.keyMap.No},
120 {q.keyMap.Tab, q.keyMap.Close},
121 }
122}