Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a router bubble for navigation #326

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 71 additions & 0 deletions router/router.go
@@ -0,0 +1,71 @@
package router

import (
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
)

// Screen represents a model with a particular binding to trigger it
type Screen struct {
model tea.Model
binding key.Binding
KaviiSuri marked this conversation as resolved.
Show resolved Hide resolved
}

// Model stores different screens and the currently focused screens
type Model struct {
screens []Screen
current int
}

// New creates a new empty Model
func New() Model {
return Model{}
}

// NewWithScreens creates a new model with an array of Screen
func NewWithScreens(screens []Screen) Model {
current := 0
return Model{
screens,
current,
}
}

func (m Model) updateCurrent(msg tea.Msg) (Model, tea.Cmd) {
if len(m.screens) <= m.current {
return m, nil
}
var cmd tea.Cmd
m.screens[m.current].model, cmd = m.screens[m.current].model.Update(msg)
return m, cmd
}

// AddScreen adds a new screen to the router
func (m *Model) AddScreen(model tea.Model, binding key.Binding) {
m.screens = append(m.screens, Screen{model, binding})
}

// Init implements tea.Model
func (Model) Init() tea.Cmd {
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should Init all the screens here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, makes sense, will do!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maaslalani I was wondering if I should only init the current screen or all of them.

Because in case we do all of them, how do we handle the return messages?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you're right, It probably makes sense to Init the current screen, we should probably keep track of whether the screen has been initialized and do that on first load (we should check this every time the navigator switches screens).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, so it'll be kind of lazily executed Init. If there's a need for something to be executed right away in the future, we can extend the api to accomodate

}

// Update implements tea.Model
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
for i, screen := range m.screens {
if key.Matches(msg, screen.binding) {
m.current = i
break
}
}
}

return m.updateCurrent(msg)
}

// View implements tea.Model
func (m Model) View() string {
return m.screens[m.current].model.View()
}