| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- package quit
- import (
- "github.com/charmbracelet/bubbles/v2/key"
- tea "github.com/charmbracelet/bubbletea/v2"
- "github.com/charmbracelet/crush/internal/tui/components/dialogs"
- "github.com/charmbracelet/crush/internal/tui/styles"
- "github.com/charmbracelet/crush/internal/tui/util"
- "github.com/charmbracelet/lipgloss/v2"
- )
- const (
- question = "Are you sure you want to quit?"
- QuitDialogID dialogs.DialogID = "quit"
- )
- // QuitDialog represents a confirmation dialog for quitting the application.
- type QuitDialog interface {
- dialogs.DialogModel
- }
- type quitDialogCmp struct {
- wWidth int
- wHeight int
- selectedNo bool // true if "No" button is selected
- keymap KeyMap
- }
- // NewQuitDialog creates a new quit confirmation dialog.
- func NewQuitDialog() QuitDialog {
- return &quitDialogCmp{
- selectedNo: true, // Default to "No" for safety
- keymap: DefaultKeymap(),
- }
- }
- func (q *quitDialogCmp) Init() tea.Cmd {
- return nil
- }
- // Update handles keyboard input for the quit dialog.
- func (q *quitDialogCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- q.wWidth = msg.Width
- q.wHeight = msg.Height
- case tea.KeyPressMsg:
- switch {
- case key.Matches(msg, q.keymap.LeftRight, q.keymap.Tab):
- q.selectedNo = !q.selectedNo
- return q, nil
- case key.Matches(msg, q.keymap.EnterSpace):
- if !q.selectedNo {
- return q, tea.Quit
- }
- return q, util.CmdHandler(dialogs.CloseDialogMsg{})
- case key.Matches(msg, q.keymap.Yes):
- return q, tea.Quit
- case key.Matches(msg, q.keymap.No, q.keymap.Close):
- return q, util.CmdHandler(dialogs.CloseDialogMsg{})
- }
- }
- return q, nil
- }
- // View renders the quit dialog with Yes/No buttons.
- func (q *quitDialogCmp) View() string {
- t := styles.CurrentTheme()
- baseStyle := t.S().Base
- yesStyle := t.S().Text
- noStyle := yesStyle
- if q.selectedNo {
- noStyle = noStyle.Foreground(t.White).Background(t.Secondary)
- yesStyle = yesStyle.Background(t.BgSubtle)
- } else {
- yesStyle = yesStyle.Foreground(t.White).Background(t.Secondary)
- noStyle = noStyle.Background(t.BgSubtle)
- }
- const horizontalPadding = 3
- yesButton := yesStyle.PaddingLeft(horizontalPadding).Underline(true).Render("Y") +
- yesStyle.PaddingRight(horizontalPadding).Render("ep!")
- noButton := noStyle.PaddingLeft(horizontalPadding).Underline(true).Render("N") +
- noStyle.PaddingRight(horizontalPadding).Render("ope")
- buttons := baseStyle.Width(lipgloss.Width(question)).Align(lipgloss.Right).Render(
- lipgloss.JoinHorizontal(lipgloss.Center, yesButton, " ", noButton),
- )
- content := baseStyle.Render(
- lipgloss.JoinVertical(
- lipgloss.Center,
- question,
- "",
- buttons,
- ),
- )
- quitDialogStyle := baseStyle.
- Padding(1, 2).
- Border(lipgloss.RoundedBorder()).
- BorderForeground(t.BorderFocus)
- return quitDialogStyle.Render(content)
- }
- func (q *quitDialogCmp) Position() (int, int) {
- row := q.wHeight / 2
- row -= 7 / 2
- col := q.wWidth / 2
- col -= (lipgloss.Width(question) + 4) / 2
- return row, col
- }
- func (q *quitDialogCmp) ID() dialogs.DialogID {
- return QuitDialogID
- }
|