mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-08-22 12:35:48 +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,101 @@
|
||||
package sidebar
|
||||
|
||||
import (
|
||||
"charm.land/bubbles/v2/key"
|
||||
bubbleslist "charm.land/bubbles/v2/list"
|
||||
|
||||
tea "charm.land/bubbletea/v2"
|
||||
|
||||
"github.com/anotherhadi/ilovetui/bubbles"
|
||||
"github.com/anotherhadi/ilovetui/examples/layout/fullapp/router"
|
||||
"github.com/anotherhadi/ilovetui/layout"
|
||||
)
|
||||
|
||||
// page is a sidebar entry: just an id (matching one of router.Model's
|
||||
// own page keys) and a label. Model has no idea what a page actually is or
|
||||
// how it's built - that's router's business entirely, this only needs
|
||||
// to name it.
|
||||
type page struct {
|
||||
id string
|
||||
title string
|
||||
}
|
||||
|
||||
func (p page) Title() string { return p.title }
|
||||
func (p page) Description() string { return "" }
|
||||
func (p page) FilterValue() string { return p.title }
|
||||
|
||||
type Model struct {
|
||||
id string // learned from SizeMsg.ID, needed as RequestFocusMsg.Source
|
||||
list bubbleslist.Model
|
||||
w, h int
|
||||
focused bool
|
||||
}
|
||||
|
||||
func New() *Model {
|
||||
items := []bubbleslist.Item{
|
||||
page{id: "first", title: "First"},
|
||||
page{id: "second", title: "Second"},
|
||||
page{id: "third", title: "Third"},
|
||||
}
|
||||
list := bubbles.NewList(items, 0, 0)
|
||||
list.Title = "Sidebar"
|
||||
// list's own built-in help footer is redundant - Model already feeds
|
||||
// layout's single centralized help bar via HelpBindings below - and at
|
||||
// a narrow sidebar width it word-wraps onto multiple lines, which
|
||||
// list.SetSize doesn't account for: list.View() ends up taller than
|
||||
// the height it was given, breaking layout's "render exactly h" rule
|
||||
// and pushing the border past the bottom of the pane.
|
||||
list.SetShowHelp(false)
|
||||
return &Model{list: list}
|
||||
}
|
||||
|
||||
func (m *Model) Init() tea.Cmd { return nil }
|
||||
|
||||
func (m *Model) Update(msg tea.Msg) (layout.Pane, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case layout.SizeMsg:
|
||||
m.id, m.w, m.h = msg.ID, msg.Width, msg.Height
|
||||
m.list.SetSize(m.w-2, m.h-2)
|
||||
case layout.FocusMsg:
|
||||
m.focused = true
|
||||
case layout.BlurMsg:
|
||||
m.focused = false
|
||||
}
|
||||
|
||||
if !m.focused {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if key, ok := msg.(tea.KeyPressMsg); ok && key.String() == "enter" {
|
||||
if selected, ok := m.list.SelectedItem().(page); ok {
|
||||
// tea.Sequence, not tea.Batch: the page switch must land
|
||||
// before the focus jump, or RequestFocusMsg could cascade
|
||||
// into router while it's still showing the previous page
|
||||
// (Batch runs both concurrently with no ordering guarantee).
|
||||
return m, tea.Sequence(
|
||||
func() tea.Msg {
|
||||
return layout.SendMsg{Target: "router", Msg: router.SelectMsg{Page: selected.id}}
|
||||
},
|
||||
func() tea.Msg {
|
||||
return layout.RequestFocusMsg{Source: m.id, Target: "router"}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
m.list, cmd = m.list.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m *Model) View() string {
|
||||
return layout.Bordered(m.focused, m.w, m.h, m.list.View())
|
||||
}
|
||||
|
||||
func (m *Model) HelpBindings() []key.Binding {
|
||||
return []key.Binding{
|
||||
key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "open page")),
|
||||
key.NewBinding(key.WithKeys("j"), key.WithHelp("j", "go down")),
|
||||
key.NewBinding(key.WithKeys("k"), key.WithHelp("k", "go up")),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user