@@ -4,6 +4,8 @@ import (
4 "charm.land/bubbles/v2/key"
4 "charm.land/bubbles/v2/key"
5 tea "charm.land/bubbletea/v2"
5 tea "charm.land/bubbletea/v2"
6 "charm.land/lipgloss/v2"
6 "charm.land/lipgloss/v2"
7+ "github.com/charmbracelet/crush/internal/ui/common"
8+ uv "github.com/charmbracelet/ultraviolet"
9// CloseKey is the default key binding to close dialogs.
11// CloseKey is the default key binding to close dialogs.
@@ -12,35 +14,11 @@ var CloseKey = key.NewBinding(
12 key.WithHelp("esc", "exit"),
14 key.WithHelp("esc", "exit"),
15−// OverlayKeyMap defines key bindings for dialogs.
16−type OverlayKeyMap struct {
20−// ActionType represents the type of action taken by a dialog.
24− // ActionNone indicates no action.
25− ActionNone ActionType = iota
26− // ActionClose indicates that the dialog should be closed.
28− // ActionSelect indicates that an item has been selected.
32−// Action represents an action taken by a dialog.
33−// It can be used to signal closing or other operations.
39// Dialog is a component that can be displayed on top of the UI.
17// Dialog is a component that can be displayed on top of the UI.
40type Dialog interface {
18type Dialog interface {
41 ID() string
19 ID() string
42− Update(msg tea.Msg) (Action, tea.Cmd)
20+ Update(msg tea.Msg) tea.Cmd
43− Layer() *lipgloss.Layer
21+ View() string
46// Overlay manages multiple dialogs as an overlay.
24// Overlay manages multiple dialogs as an overlay.
@@ -122,27 +100,26 @@ func (d *Overlay) Update(msg tea.Msg) (*Overlay, tea.Cmd) {
125− action, cmd := dialog.Update(msg)
103+ if cmd := dialog.Update(msg); cmd != nil {
126− switch action.Type {
128 // Close the current dialog
104 // Close the current dialog
129 d.removeDialog(idx)
105 d.removeDialog(idx)
130 return d, cmd
106 return d, cmd
132− // Pass the action up (without modifying the dialog stack)
136− return d, cmd
109+ return d, nil
139−// Layers returns the current stack of dialogs as lipgloss layers.
112+// Draw renders the overlay and its dialogs.
140−func (d *Overlay) Layers() []*lipgloss.Layer {
113+func (d *Overlay) Draw(scr uv.Screen, area uv.Rectangle) {
141− layers := make([]*lipgloss.Layer, len(d.dialogs))
142− for i, dialog := range d.dialogs {
114+ for _, dialog := range d.dialogs {
143− layers[i] = dialog.Layer()
115+ view := dialog.View()
116+ viewWidth := lipgloss.Width(view)
117+ viewHeight := lipgloss.Height(view)
118+ center := common.CenterRect(area, viewWidth, viewHeight)
119+ if area.Overlaps(center) {
120+ uv.NewStyledString(view).Draw(scr, center)
148// removeDialog removes a dialog from the stack.
125// removeDialog removes a dialog from the stack.