diff --git a/go.mod b/go.mod index 84c87c8..01df893 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/atotto/clipboard v0.1.2 github.com/charmbracelet/bubbletea v0.12.2 + github.com/lucasb-eyer/go-colorful v1.0.3 github.com/mattn/go-runewidth v0.0.9 github.com/muesli/termenv v0.7.4 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect diff --git a/progress/progress.go b/progress/progress.go new file mode 100644 index 0000000..c364eeb --- /dev/null +++ b/progress/progress.go @@ -0,0 +1,91 @@ +package progress + +import ( + "strings" + + tea "github.com/charmbracelet/bubbletea" + "github.com/lucasb-eyer/go-colorful" + "github.com/muesli/termenv" +) + +// Value is explicit type of, you know, progression. Can be 0.0 < x < 1.0 +type Value float64 + +type Model struct { + // Left side color of progress bar. By default, it's #00dbde + StartColor colorful.Color + + // Left side color of progress bar. By default, it's #fc00ff + EndColor colorful.Color + + // Length of progress bar in symbols. + Length int + + // Which part of bar need to visualise. Can be 0.0 < Progress < 1.0, if value is bigger or smaller, it'll + // be mapped to this values + Progress float64 + + // filament rune of done part of progress bar. it's █ by default + FilamentSymbol rune + + // empty rune of pending part of progress bar. it's ░ by default + EmptySymbol rune + + // if true, gradient will be setted from start to end of filled part. Instead, it'll work + // on all proggress bar length + FullGradientMode bool +} + +// NewModel returns a model with default values. +func NewModel(size int) *Model { + startColor, _ := colorful.Hex("#00dbde") + endColor, _ := colorful.Hex("#fc00ff") + return &Model{ + StartColor: startColor, + EndColor: endColor, + Length: size, + FilamentSymbol: '█', + EmptySymbol: '░', + } +} + +func (m *Model) Init() tea.Cmd { + return nil +} + +func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch cmd := msg.(type) { + case Value: + if cmd > 1 { + cmd = 1 + } + if cmd < 0 { + cmd = 0 + } + + m.Progress = float64(cmd) + } + + return m, nil +} + +func (m *Model) View() string { + ramp := make([]string, int(float64(m.Length)*m.Progress)) + for i := 0; i < len(ramp); i++ { + gradientPart := float64(m.Length) + if m.FullGradientMode { + gradientPart = float64(len(ramp)) + } + percent := float64(i) / gradientPart + c := m.StartColor.BlendLuv(m.EndColor, percent) + ramp[i] = c.Hex() + } + + var fullCells string + for i := 0; i < len(ramp); i++ { + fullCells += termenv.String(string(m.FilamentSymbol)).Foreground(termenv.ColorProfile().Color(ramp[i])).String() + } + + fullCells += strings.Repeat(string(m.EmptySymbol), m.Length-len(ramp)) + return fullCells +}