mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-08-21 12:05:49 +02:00
init layout, notifications, tabs & more
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
// Command fullapp demonstrates a more realistic app shell: the sidebar
|
||||
// leaf isn't a plain placeholder pane, it's a full layout.Model of its own
|
||||
// (sidebar.New(), a themed list, see sidebar/sidebar.go) embedded exactly
|
||||
// like the "router" one below - layout.Model implements Pane, so any
|
||||
// package can hand back one to be wrapped in a Leaf, no adapter needed.
|
||||
package first
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"charm.land/bubbles/v2/key"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
|
||||
"github.com/anotherhadi/ilovetui/layout"
|
||||
)
|
||||
|
||||
type pane struct {
|
||||
id string
|
||||
w, h int
|
||||
focused bool
|
||||
}
|
||||
|
||||
func newPane(id string) *pane { return &pane{id: id} }
|
||||
|
||||
func (p *pane) Init() tea.Cmd { return nil }
|
||||
|
||||
func (p *pane) Update(msg tea.Msg) (layout.Pane, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case layout.SizeMsg:
|
||||
p.w, p.h = msg.Width, msg.Height
|
||||
case layout.FocusMsg:
|
||||
p.focused = true
|
||||
case layout.BlurMsg:
|
||||
p.focused = false
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *pane) View() string {
|
||||
content := lipgloss.NewStyle().
|
||||
Width(p.w - 2).Height(p.h - 2).
|
||||
AlignHorizontal(lipgloss.Center).AlignVertical(lipgloss.Center).
|
||||
Render(p.id)
|
||||
return layout.Bordered(p.focused, p.w, p.h, content)
|
||||
}
|
||||
|
||||
// HelpBindings implements layout.HelpProvider, so every pane - at the top
|
||||
// level or nested three levels deep, doesn't matter - shows up correctly
|
||||
// in the single, outer help bar.
|
||||
func (p *pane) HelpBindings() []key.Binding {
|
||||
return []key.Binding{key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "use "+p.id))}
|
||||
}
|
||||
|
||||
// editorPane keeps a counter (press +) that's otherwise irrelevant to the
|
||||
// app but proves the point of router.Model owning pages permanently:
|
||||
// switch to "Second" and back, and it's still there. A plain pane (like
|
||||
// terminal below) would just get reconstructed from scratch every time if
|
||||
// something recreated it on each switch instead of keeping it alive.
|
||||
type editorPane struct {
|
||||
w, h int
|
||||
focused bool
|
||||
count int
|
||||
}
|
||||
|
||||
func newEditorPane() *editorPane { return &editorPane{} }
|
||||
|
||||
func (p *editorPane) Init() tea.Cmd { return nil }
|
||||
|
||||
func (p *editorPane) Update(msg tea.Msg) (layout.Pane, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case layout.SizeMsg:
|
||||
p.w, p.h = msg.Width, msg.Height
|
||||
case layout.FocusMsg:
|
||||
p.focused = true
|
||||
case layout.BlurMsg:
|
||||
p.focused = false
|
||||
case tea.KeyPressMsg:
|
||||
if msg.String() == "+" {
|
||||
p.count++
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *editorPane) View() string {
|
||||
content := lipgloss.NewStyle().
|
||||
Width(p.w - 2).Height(p.h - 2).
|
||||
AlignHorizontal(lipgloss.Center).AlignVertical(lipgloss.Center).
|
||||
Render(fmt.Sprintf("editor\n\npress + to increment: %d", p.count))
|
||||
return layout.Bordered(p.focused, p.w, p.h, content)
|
||||
}
|
||||
|
||||
// HelpBindings implements layout.HelpProvider.
|
||||
func (p *editorPane) HelpBindings() []key.Binding {
|
||||
return []key.Binding{key.NewBinding(key.WithKeys("+"), key.WithHelp("+", "increment"))}
|
||||
}
|
||||
|
||||
// NewWorkspace builds the "First" page's own nested layout.Model: note the
|
||||
// lack of layout.AsRoot() here - only the outermost Model (see main) should
|
||||
// render a help bar, or focused help would show up twice. second.
|
||||
// NewWorkspace and sidebar.New() below are built the same way, same reason.
|
||||
//
|
||||
// This Model is built exactly once, by router.New(), and kept alive for
|
||||
// the whole app's lifetime - router.Model just changes which page is
|
||||
// rendered/routed to, it never reconstructs one. That's what lets
|
||||
// editorPane's counter above survive switching to "Second" and back; see
|
||||
// package router's own doc comment for why that ownership lives there
|
||||
// and not in the sidebar.
|
||||
func NewWorkspace() layout.Model {
|
||||
root := layout.VSplit(0.7,
|
||||
layout.Leaf("editor", newEditorPane()),
|
||||
layout.Leaf("terminal", newPane("terminal")),
|
||||
)
|
||||
return layout.New(root)
|
||||
}
|
||||
Reference in New Issue
Block a user