item.go

  1package selector
  2
  3import (
  4	"fmt"
  5	"io"
  6	"strings"
  7	"time"
  8
  9	"github.com/charmbracelet/bubbles/list"
 10	tea "github.com/charmbracelet/bubbletea"
 11	"github.com/charmbracelet/lipgloss"
 12	"github.com/charmbracelet/soft-serve/ui/components/yankable"
 13	"github.com/charmbracelet/soft-serve/ui/styles"
 14	"github.com/dustin/go-humanize"
 15)
 16
 17type Item struct {
 18	Title       string
 19	Name        string
 20	Description string
 21	LastUpdate  time.Time
 22	URL         *yankable.Yankable
 23}
 24
 25func (i *Item) Init() tea.Cmd {
 26	return nil
 27}
 28
 29func (i *Item) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 30	return i, nil
 31}
 32
 33func (i *Item) View() string {
 34	return ""
 35}
 36
 37func (i Item) FilterValue() string { return i.Title }
 38
 39type ItemDelegate struct {
 40	styles *styles.Styles
 41}
 42
 43func (d ItemDelegate) Width() int {
 44	width := d.styles.MenuItem.GetHorizontalFrameSize() + d.styles.MenuItem.GetWidth()
 45	return width
 46}
 47func (d ItemDelegate) Height() int {
 48	height := d.styles.MenuItem.GetVerticalFrameSize() + d.styles.MenuItem.GetHeight()
 49	return height
 50}
 51func (d ItemDelegate) Spacing() int { return 1 }
 52func (d ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
 53	cmds := make([]tea.Cmd, 0)
 54	for i, item := range m.VisibleItems() {
 55		itm, ok := item.(Item)
 56		if !ok {
 57			continue
 58		}
 59		// FIXME check if X & Y are within the item box
 60		switch msg := msg.(type) {
 61		case tea.MouseMsg:
 62			x := msg.X
 63			y := msg.Y
 64			minX := (i * d.Width())
 65			maxX := minX + d.Width()
 66			minY := (i * d.Height())
 67			maxY := minY + d.Height()
 68			// log.Printf("i: %d, x: %d, y: %d", i, x, y)
 69			if y < minY || y > maxY || x < minX || x > maxX {
 70				continue
 71			}
 72		}
 73		y, cmd := itm.URL.Update(msg)
 74		itm.URL = y.(*yankable.Yankable)
 75		if cmd != nil {
 76			cmds = append(cmds, cmd)
 77		}
 78	}
 79	return tea.Batch(cmds...)
 80}
 81func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
 82	i := listItem.(Item)
 83	s := strings.Builder{}
 84	style := d.styles.MenuItem.Copy()
 85	if index == m.Index() {
 86		style = d.styles.SelectedMenuItem.Copy()
 87	}
 88	style.Width(m.Width() - 2) // FIXME figure out where this "2" comes from
 89	titleStr := i.Title
 90	updatedStr := fmt.Sprintf(" Updated %s", humanize.Time(i.LastUpdate))
 91	updated := d.styles.MenuLastUpdate.
 92		Copy().
 93		Width(m.Width() - style.GetHorizontalFrameSize() - lipgloss.Width(titleStr)).
 94		Render(updatedStr)
 95	title := lipgloss.NewStyle().
 96		Align(lipgloss.Left).
 97		Width(m.Width() - style.GetHorizontalFrameSize() - lipgloss.Width(updated)).
 98		Render(titleStr)
 99
100	s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, updated))
101	s.WriteString("\n")
102	s.WriteString(i.Description)
103	s.WriteString("\n\n")
104	s.WriteString(i.URL.View())
105	w.Write([]byte(style.Render(s.String())))
106}