167 lines
4.8 KiB
Go
167 lines
4.8 KiB
Go
|
package ui
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strconv"
|
||
|
|
||
|
"github.com/charmbracelet/lipgloss"
|
||
|
|
||
|
"github.com/charmbracelet/huh"
|
||
|
log "github.com/sirupsen/logrus"
|
||
|
)
|
||
|
|
||
|
type FormBuilder struct {
|
||
|
widgets []huh.Field
|
||
|
form huh.Form
|
||
|
}
|
||
|
|
||
|
func NewForm() *FormBuilder {
|
||
|
return &FormBuilder{}
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) AddWidget(w huh.Field) {
|
||
|
f.widgets = append(f.widgets, w)
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) Group(w ...huh.Field) *huh.Group {
|
||
|
group := huh.NewGroup(w...)
|
||
|
return group
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) BuildGroups(g ...*huh.Group) *huh.Form {
|
||
|
form := huh.NewForm(g...)
|
||
|
return form
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) Build() *huh.Form {
|
||
|
form := huh.NewForm(huh.NewGroup(f.widgets...)).WithTheme(ThemeCustom())
|
||
|
return form
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) GetString(key string) string {
|
||
|
fmt.Println(f.form.GetString(key))
|
||
|
return f.form.GetString(key)
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) GetBool(key string) bool {
|
||
|
fmt.Println(f.form.GetString(key))
|
||
|
return f.form.GetBool(key)
|
||
|
}
|
||
|
|
||
|
func (f *FormBuilder) GetInt(key string) int64 {
|
||
|
v := f.form.GetString(key)
|
||
|
fmt.Println(v)
|
||
|
value, err := strconv.Atoi(v)
|
||
|
if err != nil {
|
||
|
log.WithError(err).Fatalf(fmt.Sprintf("failed to convert value %s to integer", v))
|
||
|
return 0
|
||
|
}
|
||
|
return int64(value)
|
||
|
}
|
||
|
|
||
|
func MultiSelect(title, key string, options []string) *huh.MultiSelect[string] {
|
||
|
s := huh.NewMultiSelect[string]().
|
||
|
Title(title).
|
||
|
Options(huh.NewOptions[string](options...)...).
|
||
|
Key(key)
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
func InteractiveList(title, key string, opts map[string]string) *huh.Select[string] {
|
||
|
var pick string
|
||
|
var options []huh.Option[string]
|
||
|
s := huh.NewSelect[string]().
|
||
|
Title(title).
|
||
|
Key(key).
|
||
|
Value(&pick)
|
||
|
if opts != nil {
|
||
|
for k, v := range opts {
|
||
|
options = append(options, huh.Option[string]{Key: k, Value: v})
|
||
|
}
|
||
|
|
||
|
s.Options(options...)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
func Input(question string, key string) *huh.Input {
|
||
|
var answer string
|
||
|
input := huh.NewInput().
|
||
|
Title(fmt.Sprintf("%s", question)).
|
||
|
Prompt("> ").
|
||
|
Validate(ValidateString).
|
||
|
Key(key).
|
||
|
Value(&answer)
|
||
|
return input
|
||
|
}
|
||
|
|
||
|
func Confirm(question string, key string) *huh.Confirm {
|
||
|
var happy bool
|
||
|
confirm := huh.NewConfirm().
|
||
|
Title(question).
|
||
|
Affirmative("Yes").
|
||
|
Negative("No").
|
||
|
Value(&happy).
|
||
|
Key(key)
|
||
|
|
||
|
return confirm
|
||
|
}
|
||
|
|
||
|
func Text(title, desc string) *huh.Note {
|
||
|
t := huh.NewNote().
|
||
|
Title(title).
|
||
|
Description(desc)
|
||
|
return t
|
||
|
}
|
||
|
|
||
|
func TextField(title, key string) *huh.Text {
|
||
|
t := huh.NewText().
|
||
|
Title(title).Key(key).ShowLineNumbers(true).Editor("vim")
|
||
|
return t
|
||
|
}
|
||
|
|
||
|
func ThemeCustom() *huh.Theme {
|
||
|
t := huh.ThemeBase()
|
||
|
|
||
|
var (
|
||
|
normalFg = lipgloss.AdaptiveColor{Light: "235", Dark: "252"}
|
||
|
// indigo = lipgloss.AdaptiveColor{Light: "#5A56E0", Dark: "#7571F9"}
|
||
|
indigo = lipgloss.AdaptiveColor{Light: "32", Dark: "33"}
|
||
|
cream = lipgloss.AdaptiveColor{Light: "#FFFDF5", Dark: "#FFFDF5"}
|
||
|
// fuchsia = lipgloss.Color("#F780E2")
|
||
|
green = lipgloss.AdaptiveColor{Light: "#02BA84", Dark: "#02BF87"}
|
||
|
red = lipgloss.AdaptiveColor{Light: "#FF4672", Dark: "#ED567A"}
|
||
|
)
|
||
|
|
||
|
t.Focused.Base = t.Focused.Base.BorderForeground(lipgloss.Color("238"))
|
||
|
t.Focused.Title = t.Focused.Title.Foreground(White).Bold(true)
|
||
|
t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(White).Bold(true).MarginBottom(1)
|
||
|
t.Focused.Directory = t.Focused.Directory.Foreground(indigo)
|
||
|
t.Focused.Description = t.Focused.Description.Foreground(lipgloss.AdaptiveColor{Light: "", Dark: "243"})
|
||
|
t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(red)
|
||
|
t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(red)
|
||
|
t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(green)
|
||
|
t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(indigo)
|
||
|
t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(indigo)
|
||
|
t.Focused.Option = t.Focused.Option.Foreground(normalFg)
|
||
|
t.Focused.MultiSelectSelector = t.Focused.MultiSelectSelector.Foreground(green)
|
||
|
t.Focused.SelectedOption = t.Focused.SelectedOption.Foreground(green)
|
||
|
t.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(green).SetString("✓ ")
|
||
|
t.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "", Dark: "243"}).SetString("• ")
|
||
|
t.Focused.UnselectedOption = t.Focused.UnselectedOption.Foreground(normalFg)
|
||
|
t.Focused.FocusedButton = t.Focused.FocusedButton.Foreground(cream).Background(indigo)
|
||
|
t.Focused.Next = t.Focused.FocusedButton
|
||
|
t.Focused.BlurredButton = t.Focused.BlurredButton.Foreground(normalFg).Background(lipgloss.AdaptiveColor{Light: "252", Dark: "237"})
|
||
|
|
||
|
t.Focused.TextInput.Cursor = t.Focused.TextInput.Cursor.Foreground(Gray)
|
||
|
t.Focused.TextInput.Placeholder = t.Focused.TextInput.Placeholder.Foreground(lipgloss.AdaptiveColor{Light: "248", Dark: "238"})
|
||
|
t.Focused.TextInput.Prompt = t.Focused.TextInput.Prompt.Foreground(green)
|
||
|
|
||
|
t.Blurred = t.Focused
|
||
|
t.Blurred.Base = t.Focused.Base.BorderStyle(lipgloss.HiddenBorder())
|
||
|
t.Blurred.NextIndicator = lipgloss.NewStyle()
|
||
|
t.Blurred.PrevIndicator = lipgloss.NewStyle()
|
||
|
|
||
|
return t
|
||
|
}
|