mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-08-21 20:15:49 +02:00
5f99fa7521
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
110 lines
3.1 KiB
Go
110 lines
3.1 KiB
Go
// Package router owns every page's own layout.Model for the lifetime of
|
|
// the whole app, so switching pages never discards their state - only
|
|
// which one is currently active/rendered changes. It slots into the root
|
|
// tree's "router" leaf exactly like a single nested layout.Model would
|
|
// (see examples/layout/nested), because Model implements layout.Navigable
|
|
// itself on top of layout.Pane, delegating everything to whichever page is
|
|
// active: ctrl+hjkl, the help bar, and SendMsg/RequestFocusMsg addressed to
|
|
// ids inside that page all keep working transparently.
|
|
package router
|
|
|
|
import (
|
|
"charm.land/bubbles/v2/key"
|
|
tea "charm.land/bubbletea/v2"
|
|
|
|
"github.com/anotherhadi/ilovetui/examples/layout/fullapp/first"
|
|
"github.com/anotherhadi/ilovetui/examples/layout/fullapp/second"
|
|
"github.com/anotherhadi/ilovetui/examples/layout/fullapp/third"
|
|
"github.com/anotherhadi/ilovetui/layout"
|
|
)
|
|
|
|
// SelectMsg asks Model to switch its active page, by id ("first", "second"
|
|
// or "third"). Sent by the sidebar via layout.SendMsg{Target: "router"} -
|
|
// it never holds a reference to Model either.
|
|
type SelectMsg struct{ Page string }
|
|
|
|
type Model struct {
|
|
active string
|
|
pages map[string]layout.Model
|
|
}
|
|
|
|
func New() *Model {
|
|
return &Model{
|
|
active: "first",
|
|
pages: map[string]layout.Model{
|
|
"first": first.NewWorkspace(),
|
|
"second": second.NewWorkspace(),
|
|
"third": third.NewWorkspace(),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (m *Model) current() layout.Model { return m.pages[m.active] }
|
|
|
|
func (m *Model) Init() tea.Cmd {
|
|
var cmds []tea.Cmd
|
|
for _, p := range m.pages {
|
|
if cmd := p.Init(); cmd != nil {
|
|
cmds = append(cmds, cmd)
|
|
}
|
|
}
|
|
return tea.Batch(cmds...)
|
|
}
|
|
|
|
func (m *Model) Update(msg tea.Msg) (layout.Pane, tea.Cmd) {
|
|
if sel, ok := msg.(SelectMsg); ok {
|
|
if _, exists := m.pages[sel.Page]; exists {
|
|
m.active = sel.Page
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
if size, ok := msg.(layout.SizeMsg); ok {
|
|
// Every page needs to stay correctly sized even while hidden - the
|
|
// outer tree only re-sends SizeMsg when the "router" leaf's own
|
|
// Rect changes, never on a plain page switch, so a page that was
|
|
// inactive during a resize must still learn about it here, or it
|
|
// renders at a stale size whenever it becomes active again.
|
|
var cmds []tea.Cmd
|
|
for id, p := range m.pages {
|
|
updated, cmd := p.Update(size)
|
|
m.pages[id] = updated.(layout.Model)
|
|
if cmd != nil {
|
|
cmds = append(cmds, cmd)
|
|
}
|
|
}
|
|
return m, tea.Batch(cmds...)
|
|
}
|
|
|
|
updated, cmd := m.current().Update(msg)
|
|
m.pages[m.active] = updated.(layout.Model)
|
|
return m, cmd
|
|
}
|
|
|
|
func (m *Model) View() string {
|
|
return m.current().View()
|
|
}
|
|
|
|
// Leaves, MoveFocus, Route, Focus and FocusedHelp implement
|
|
// layout.Navigable, delegating to whichever page is currently active.
|
|
|
|
func (m *Model) Leaves() []layout.LeafRect {
|
|
return m.current().Leaves()
|
|
}
|
|
|
|
func (m *Model) MoveFocus(dir layout.FocusDirection) bool {
|
|
return m.current().MoveFocus(dir)
|
|
}
|
|
|
|
func (m *Model) Route(target string, msg tea.Msg) (bool, tea.Cmd) {
|
|
return m.current().Route(target, msg)
|
|
}
|
|
|
|
func (m *Model) Focus(id string) (bool, tea.Cmd) {
|
|
return m.current().Focus(id)
|
|
}
|
|
|
|
func (m *Model) FocusedHelp() []key.Binding {
|
|
return m.current().FocusedHelp()
|
|
}
|