charmbracelet / bubbletea

A powerful little TUI framework 🏗
MIT License
27.94k stars 806 forks source link

model with two lists #644

Closed horseinthesky closed 1 year ago

horseinthesky commented 1 year ago

Hello. I try to create a model with two lists and the ability to toggle between them

I've changed list-default example but got into an issue: the second list shows the number of its items but not showing the items themselves.

The first list is fine image

The Second has amount of items and a counter below but items are hidden somehow image

Could you please help me to fix it?

Here is the code:

package main

import (
        "fmt"
        "os"

        "github.com/charmbracelet/bubbles/key"
        "github.com/charmbracelet/bubbles/list"
        tea "github.com/charmbracelet/bubbletea"
        "github.com/charmbracelet/lipgloss"
)

type keymap struct {
        Toggle key.Binding
}

var keyMap = keymap{
        Toggle: key.NewBinding(
                key.WithKeys("T"),
                key.WithHelp("T", "toggle"),
        ),
}

var docStyle = lipgloss.NewStyle().Margin(1, 2)

type item struct {
        title, desc string
}

func (i item) Title() string       { return i.title }
func (i item) Description() string { return i.desc }
func (i item) FilterValue() string { return i.title }

type mode int

const (
        one mode = iota
        two
)

type model struct {
        mode    mode
        list    list.Model
        listTwo list.Model
}

func (m model) Init() tea.Cmd {
        return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
        switch msg := msg.(type) {
        case tea.WindowSizeMsg:
                h, v := docStyle.GetFrameSize()
                m.list.SetSize(msg.Width-h, msg.Height-v)
        case tea.KeyMsg:
                if msg.String() == "ctrl+c" {
                        return m, tea.Quit
                }

                switch m.mode {
                case one:
                        switch {
                        case key.Matches(msg, keyMap.Toggle):
                                m.mode = two
                        }
                case two:
                        switch {
                        case key.Matches(msg, keyMap.Toggle):
                                m.mode = one
                        }
                }
        }

        var cmd tea.Cmd
        var cmds []tea.Cmd

        m.list, cmd = m.list.Update(msg)
        cmds = append(cmds, cmd)
        m.listTwo, cmd = m.listTwo.Update(msg)
        cmds = append(cmds, cmd)
        return m, tea.Batch(cmds...)
}

func (m model) View() string {
        if m.mode == two {
                return docStyle.Render(m.listTwo.View())
        }
        return docStyle.Render(m.list.View())
}

func main() {
        items := []list.Item{
                item{title: "Raspberry Pi’s", desc: "I have ’em all over my house"},
                item{title: "Nutella", desc: "It's good on toast"},
                item{title: "Bitter melon", desc: "It cools you down"},
                item{title: "Nice socks", desc: "And by that I mean socks without holes"},
                item{title: "Eight hours of sleep", desc: "I had this once"},
                item{title: "Cats", desc: "Usually"},
                item{title: "Plantasia, the album", desc: "My plants love it too"},
                item{title: "Pour over coffee", desc: "It takes forever to make though"},
                item{title: "VR", desc: "Virtual reality...what is there to say?"},
                item{title: "Noguchi Lamps", desc: "Such pleasing organic forms"},
                item{title: "Linux", desc: "Pretty much the best OS"},
        }

        items2 := []list.Item{
                item{title: "Business school", desc: "Just kidding"},
                item{title: "Pottery", desc: "Wet clay is a great feeling"},
                item{title: "Shampoo", desc: "Nothing like clean hair"},
                item{title: "Table tennis", desc: "It’s surprisingly exhausting"},
                item{title: "Milk crates", desc: "Great for packing in your extra stuff"},
                item{title: "Afternoon tea", desc: "Especially the tea sandwich part"},
                item{title: "Stickers", desc: "The thicker the vinyl the better"},
                item{title: "20° Weather", desc: "Celsius, not Fahrenheit"},
                item{title: "Warm light", desc: "Like around 2700 Kelvin"},
                item{title: "The vernal equinox", desc: "The autumnal equinox is pretty good too"},
                item{title: "Gaffer’s tape", desc: "Basically sticky fabric"},
                item{title: "Terrycloth", desc: "In other words, towel fabric"},
        }

        m := model{
                list:    list.New(items, list.NewDefaultDelegate(), 0, 0),
                listTwo: list.New(items2, list.NewDefaultDelegate(), 0, 0),
        }
        m.list.Title = "My Fave Things"
        m.listTwo.Title = "My Fave Things Two"
        m.list.AdditionalShortHelpKeys = func() []key.Binding {
                return []key.Binding{
                        keyMap.Toggle,
                }
        }
        m.listTwo.AdditionalShortHelpKeys = func() []key.Binding {
                return []key.Binding{
                        keyMap.Toggle,
                }
        }

        p := tea.NewProgram(m, tea.WithAltScreen())

        if _, err := p.Run(); err != nil {
                fmt.Println("Error running program:", err)
                os.Exit(1)
        }
}
horseinthesky commented 1 year ago

@bashbunni Hi. I've watched a couple of your vids and CLI Kanban Board playlist on youtube. I just don't see any examples using two lists in one model so can't figure out what is my mistake here. Could you pls help we with this?

bashbunni commented 1 year ago

Ah that's because you need to set the height and width on both lists to see the items. It looks like it's missing for listTwo. That should fix it!

horseinthesky commented 1 year ago

@bashbunni Thank you. It somehow wants me to set height/width only on second list. It is perfectly fine with 0, 0 on the first one. Anyway it works =)