From eb24e66b3d9188e40d3efbaaabdde3182b28f583 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 29 Jan 2026 11:38:48 -0500 Subject: [PATCH] wip(spinner): rework and simplify --- internal/ui/spinner/spinner.go | 59 ++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/internal/ui/spinner/spinner.go b/internal/ui/spinner/spinner.go index 281673c68d7ebd2424ccc97d3b66a34b239bbbb3..eb3817acf1b7acd445606985a766e4ed20eebaa5 100644 --- a/internal/ui/spinner/spinner.go +++ b/internal/ui/spinner/spinner.go @@ -2,32 +2,23 @@ package spinner import ( - "log" + "image/color" "strings" "sync/atomic" "time" tea "charm.land/bubbletea/v2" + "github.com/charmbracelet/x/exp/charmtone" ) const ( fps = 24 - pauseSteps = 72 + pauseSteps = 48 width = 12 + lowChar = '•' + highChar = '│' ) -var blocks = []rune{ - ' ', - '▁', - '▂', - '▃', - '▄', - '▅', - '▆', - '▇', - '█', -} - // Internal ID management. Used during animating to ensure that frame messages // are received only by spinner components that sent them. var lastID int64 @@ -36,23 +27,36 @@ func nextID() int { return int(atomic.AddInt64(&lastID, 1)) } +type Config struct { + LowColor color.Color + PeakColor color.Color +} + type StepMsg struct { ID int tag int } type Spinner struct { - id int - tag int - index int - pause int - cells []int + Config Config + id int + tag int + index int + pause int + cells []int + maxAt []int // frame when cell reached max height } func NewSpinner() Spinner { return Spinner{ + Config: Config{ + PeakColor: charmtone.Charple, + LowColor: charmtone.Blush, + }, id: nextID(), + index: -1, cells: make([]int, width), + maxAt: make([]int, width), } } @@ -69,20 +73,23 @@ func (s Spinner) Update(msg tea.Msg) (Spinner, tea.Cmd) { if s.pause > 0 { s.pause-- - log.Println("pausing", s.pause) } else { s.index++ if s.index > width { s.pause = pauseSteps - s.index = 0 + s.index = -1 } } for i, c := range s.cells { if s.index == i { - s.cells[i] = len(blocks) - 1 + s.cells[i] = width - 1 + s.maxAt[i] = s.tag } else { + if s.maxAt[i] >= 0 && s.tag-s.maxAt[i] < 8 { + continue + } s.cells[i] = max(0, c-1) } } @@ -100,13 +107,17 @@ func (s Spinner) Step() tea.Cmd { } func (s Spinner) View() string { - if len(blocks) == 0 { + if width == 0 { return "" } var b strings.Builder for i := range s.cells { - b.WriteRune(blocks[s.cells[i]]) + if s.cells[i] == 0 { + b.WriteRune(lowChar) + continue + } + b.WriteRune(highChar) } return b.String()