dialog.go

  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}