mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-08-21 03:55:48 +02:00
5f99fa7521
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
102 lines
2.9 KiB
Go
102 lines
2.9 KiB
Go
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")),
|
|
}
|
|
}
|