1package core
2
3import (
4 "github.com/charmbracelet/bubbles/key"
5 tea "github.com/charmbracelet/bubbletea"
6 "github.com/charmbracelet/lipgloss"
7 "github.com/kujtimiihoxha/termai/internal/tui/layout"
8 "github.com/kujtimiihoxha/termai/internal/tui/util"
9)
10
11type SizeableModel interface {
12 tea.Model
13 layout.Sizeable
14}
15
16type DialogMsg struct {
17 Content SizeableModel
18 WidthRatio float64
19 HeightRatio float64
20
21 MinWidth int
22 MinHeight int
23}
24
25type DialogCloseMsg struct{}
26
27type KeyBindings struct {
28 Return key.Binding
29}
30
31var keys = KeyBindings{
32 Return: key.NewBinding(
33 key.WithKeys("esc"),
34 key.WithHelp("esc", "close"),
35 ),
36}
37
38type DialogCmp interface {
39 tea.Model
40 layout.Bindings
41}
42
43type dialogCmp struct {
44 content SizeableModel
45 screenWidth int
46 screenHeight int
47
48 widthRatio float64
49 heightRatio float64
50
51 minWidth int
52 minHeight int
53
54 width int
55 height int
56}
57
58func (d *dialogCmp) Init() tea.Cmd {
59 return nil
60}
61
62func (d *dialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
63 switch msg := msg.(type) {
64 case tea.WindowSizeMsg:
65 d.screenWidth = msg.Width
66 d.screenHeight = msg.Height
67 d.width = max(int(float64(d.screenWidth)*d.widthRatio), d.minWidth)
68 d.height = max(int(float64(d.screenHeight)*d.heightRatio), d.minHeight)
69 if d.content != nil {
70 d.content.SetSize(d.width, d.height)
71 }
72 return d, nil
73 case DialogMsg:
74 d.content = msg.Content
75 d.widthRatio = msg.WidthRatio
76 d.heightRatio = msg.HeightRatio
77 d.minWidth = msg.MinWidth
78 d.minHeight = msg.MinHeight
79 d.width = max(int(float64(d.screenWidth)*d.widthRatio), d.minWidth)
80 d.height = max(int(float64(d.screenHeight)*d.heightRatio), d.minHeight)
81 if d.content != nil {
82 d.content.SetSize(d.width, d.height)
83 }
84 case DialogCloseMsg:
85 d.content = nil
86 return d, nil
87 case tea.KeyMsg:
88 if key.Matches(msg, keys.Return) {
89 return d, util.CmdHandler(DialogCloseMsg{})
90 }
91 }
92 if d.content != nil {
93 u, cmd := d.content.Update(msg)
94 d.content = u.(SizeableModel)
95 return d, cmd
96 }
97 return d, nil
98}
99
100func (d *dialogCmp) BindingKeys() []key.Binding {
101 bindings := []key.Binding{keys.Return}
102 if d.content == nil {
103 return bindings
104 }
105 if c, ok := d.content.(layout.Bindings); ok {
106 return append(bindings, c.BindingKeys()...)
107 }
108 return bindings
109}
110
111func (d *dialogCmp) View() string {
112 return lipgloss.NewStyle().Width(d.width).Height(d.height).Render(d.content.View())
113}
114
115func NewDialogCmp() DialogCmp {
116 return &dialogCmp{}
117}