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.Cmd {
64 switch msg := msg.(type) {
65 case tea.KeyPressMsg:
66 switch {
67 case key.Matches(msg, q.keyMap.LeftRight, q.keyMap.Tab):
68 q.selectedNo = !q.selectedNo
69 return nil
70 case key.Matches(msg, q.keyMap.EnterSpace):
71 if !q.selectedNo {
72 return tea.Quit
73 }
74 return nil
75 case key.Matches(msg, q.keyMap.Yes):
76 return tea.Quit
77 case key.Matches(msg, q.keyMap.No, q.keyMap.Close):
78 return nil
79 }
80 }
81
82 return nil
83}
84
85// View implements [Dialog].
86func (q *Quit) View() string {
87 const question = "Are you sure you want to quit?"
88 baseStyle := q.com.Styles.Base
89 buttonOpts := []common.ButtonOpts{
90 {Text: "Yep!", Selected: !q.selectedNo, Padding: 3},
91 {Text: "Nope", Selected: q.selectedNo, Padding: 3},
92 }
93 buttons := common.ButtonGroup(q.com.Styles, buttonOpts, " ")
94 content := baseStyle.Render(
95 lipgloss.JoinVertical(
96 lipgloss.Center,
97 question,
98 "",
99 buttons,
100 ),
101 )
102
103 return q.com.Styles.BorderFocus.Render(content)
104}
105
106// ShortHelp implements [help.KeyMap].
107func (q *Quit) ShortHelp() []key.Binding {
108 return []key.Binding{
109 q.keyMap.LeftRight,
110 q.keyMap.EnterSpace,
111 }
112}
113
114// FullHelp implements [help.KeyMap].
115func (q *Quit) FullHelp() [][]key.Binding {
116 return [][]key.Binding{
117 {q.keyMap.LeftRight, q.keyMap.EnterSpace, q.keyMap.Yes, q.keyMap.No},
118 {q.keyMap.Tab, q.keyMap.Close},
119 }
120}