diff --git a/internal/dynamo-browse/ui/model.go b/internal/dynamo-browse/ui/model.go index e16ed4e..4cefc0e 100644 --- a/internal/dynamo-browse/ui/model.go +++ b/internal/dynamo-browse/ui/model.go @@ -5,6 +5,7 @@ import ( "github.com/lmika/awstools/internal/common/ui/commandctrl" "github.com/lmika/awstools/internal/common/ui/events" "github.com/lmika/awstools/internal/dynamo-browse/controllers" + "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dialogprompt" "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamoitemview" "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamotableview" "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout" @@ -31,7 +32,8 @@ func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteCon dtv := dynamotableview.New(uiStyles) div := dynamoitemview.New(uiStyles) statusAndPrompt := statusandprompt.New(layout.NewVBox(layout.LastChildFixedAt(17), dtv, div), "", uiStyles.StatusAndPrompt) - tableSelect := tableselect.New(statusAndPrompt, uiStyles) + dialogPrompt := dialogprompt.New(statusAndPrompt) + tableSelect := tableselect.New(dialogPrompt, uiStyles) cc.AddCommands(&commandctrl.CommandContext{ Commands: map[string]commandctrl.Command{ @@ -73,7 +75,8 @@ func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteCon }, }) - root := layout.FullScreen(tableSelect) + //root := layout.FullScreen(tableSelect) + root := layout.FullScreen(dialogPrompt) return Model{ tableReadController: rc, diff --git a/internal/dynamo-browse/ui/teamodels/dialogprompt/dialogmodel.go b/internal/dynamo-browse/ui/teamodels/dialogprompt/dialogmodel.go new file mode 100644 index 0000000..326e9a9 --- /dev/null +++ b/internal/dynamo-browse/ui/teamodels/dialogprompt/dialogmodel.go @@ -0,0 +1,33 @@ +package dialogprompt + +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout" +) + +var style = lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("63")) + +type dialogModel struct { + w, h int + borderStyle lipgloss.Style +} + +func (d *dialogModel) Init() tea.Cmd { + return nil +} + +func (d *dialogModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + return d, nil +} + +func (d *dialogModel) View() string { + return style.Width(d.w).Height(d.h).Render("Hello this is a test of some content") +} + +func (d *dialogModel) Resize(w, h int) layout.ResizingModel { + d.w, d.h = w-2, h-2 + return d +} diff --git a/internal/dynamo-browse/ui/teamodels/dialogprompt/model.go b/internal/dynamo-browse/ui/teamodels/dialogprompt/model.go new file mode 100644 index 0000000..3f8c1fd --- /dev/null +++ b/internal/dynamo-browse/ui/teamodels/dialogprompt/model.go @@ -0,0 +1,38 @@ +package dialogprompt + +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout" +) + +type Model struct { + compositor *layout.Compositor +} + +func New(model layout.ResizingModel) *Model { + m := &Model{ + compositor: layout.NewCompositor(model), + } + // TEMP + m.compositor.SetOverlay(&dialogModel{}, 5, 5, 30, 12) + return m +} + +func (m *Model) Init() tea.Cmd { + return m.compositor.Init() +} + +func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + newModel, cmd := m.compositor.Update(msg) + m.compositor = newModel.(*layout.Compositor) + return m, cmd +} + +func (m *Model) View() string { + return m.compositor.View() +} + +func (m *Model) Resize(w, h int) layout.ResizingModel { + m.compositor = m.compositor.Resize(w, h).(*layout.Compositor) + return m +} diff --git a/internal/dynamo-browse/ui/teamodels/layout/composit.go b/internal/dynamo-browse/ui/teamodels/layout/composit.go new file mode 100644 index 0000000..055521f --- /dev/null +++ b/internal/dynamo-browse/ui/teamodels/layout/composit.go @@ -0,0 +1,85 @@ +package layout + +import ( + "bufio" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "strings" +) + +type Compositor struct { + background ResizingModel + + foreground ResizingModel + foreX, foreY int + foreW, foreH int +} + +func NewCompositor(background ResizingModel) *Compositor { + return &Compositor{ + background: background, + } +} + +func (c *Compositor) Init() tea.Cmd { + return c.background.Init() +} + +func (c *Compositor) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + // TODO: allow the compositor the + newM, cmd := c.background.Update(msg) + c.background = newM.(ResizingModel) + return c, cmd +} + +func (c *Compositor) SetOverlay(m ResizingModel, x, y, w, h int) { + c.foreground = m + c.foreX, c.foreY = x, y + c.foreW, c.foreH = w, h +} + +func (c *Compositor) View() string { + if c.foreground == nil { + return c.background.View() + } + + // Need to compose + backgroundView := c.background.View() + foregroundViewLines := strings.Split(c.foreground.View(), "\n") + + backgroundScanner := bufio.NewScanner(strings.NewReader(backgroundView)) + compositeOutput := new(strings.Builder) + + r := 0 + for backgroundScanner.Scan() { + if r > 0 { + compositeOutput.WriteRune('\n') + } + + line := backgroundScanner.Text() + if r >= c.foreY && r < c.foreY+c.foreH { + compositeOutput.WriteString(line[:c.foreX]) + + foregroundScanPos := r - c.foreY + if foregroundScanPos < len(foregroundViewLines) { + displayLine := foregroundViewLines[foregroundScanPos] + compositeOutput.WriteString(lipgloss.PlaceHorizontal(c.foreW, lipgloss.Left, displayLine, lipgloss.WithWhitespaceChars(" "))) + } + + compositeOutput.WriteString(line[c.foreX+c.foreW:]) + } else { + compositeOutput.WriteString(line) + } + r++ + } + + return compositeOutput.String() +} + +func (c *Compositor) Resize(w, h int) ResizingModel { + c.background = c.background.Resize(w, h) + if c.foreground != nil { + c.foreground = c.foreground.Resize(c.foreW, c.foreH) + } + return c +}