update
This commit is contained in:
72
internal/tui/cmdlist.go
Normal file
72
internal/tui/cmdlist.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// screen length of the list
|
||||
const listHeight = 10
|
||||
|
||||
// item is the object that will appear in our list
|
||||
type item struct {
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func (i item) FilterValue() string { return i.cmd.Name() }
|
||||
|
||||
// itemDelegate encapsulates the general functionality for all list items
|
||||
type itemDelegate struct {
|
||||
styles *Styles
|
||||
}
|
||||
|
||||
func (d itemDelegate) Height() int { return 1 }
|
||||
func (d itemDelegate) Spacing() int { return 0 }
|
||||
func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
|
||||
func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
|
||||
i, ok := listItem.(item)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
str := i.cmd.Name() + lipgloss.NewStyle().Bold(true).
|
||||
PaddingLeft(i.cmd.NamePadding()-len(i.cmd.Name())+1).Render(i.cmd.Short)
|
||||
|
||||
fn := d.styles.Item.Render
|
||||
if index == m.Index() {
|
||||
fn = func(strs ...string) string {
|
||||
return d.styles.SelectedItem.Render("> " + fmt.Sprint(strs))
|
||||
}
|
||||
}
|
||||
fmt.Fprint(w, fn(str))
|
||||
}
|
||||
|
||||
// newSubCmdsList returns a new list.Model filled with the values in []list.Items
|
||||
func newSubCmdsList(styles *Styles, items []list.Item) list.Model {
|
||||
l := list.New(items, itemDelegate{styles: styles}, 0, listHeight)
|
||||
l.Styles.TitleBar.Padding(0, 0)
|
||||
l.Styles.Title = styles.Section
|
||||
l.Title = "Available Sub Commands:"
|
||||
l.SetShowHelp(false)
|
||||
l.SetShowStatusBar(false)
|
||||
l.SetShowPagination(false)
|
||||
return l
|
||||
}
|
||||
|
||||
// getSubCommands returns a []list.Item filled with any available sub command from the supplied *cobra.Command.
|
||||
// This does not follow the command chain past a depth of 1.
|
||||
func getSubCommands(c *cobra.Command) []list.Item {
|
||||
subs := make([]list.Item, 0)
|
||||
if c.HasAvailableSubCommands() {
|
||||
for _, subcmd := range c.Commands() {
|
||||
if subcmd.Name() == "help" || subcmd.IsAvailableCommand() {
|
||||
subs = append(subs, item{cmd: subcmd})
|
||||
}
|
||||
}
|
||||
}
|
||||
return subs
|
||||
}
|
||||
44
internal/tui/helper.go
Normal file
44
internal/tui/helper.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type Boa struct {
|
||||
options *options
|
||||
}
|
||||
|
||||
// Create a new instance of Boa with custom Options
|
||||
func New(options ...Options) *Boa {
|
||||
opts := defaultOptions()
|
||||
for _, opt := range options {
|
||||
opt.apply(opts)
|
||||
}
|
||||
return &Boa{
|
||||
options: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Boa) HelpFunc(cmd *cobra.Command, s []string) {
|
||||
model := newCmdModel(b.options, cmd)
|
||||
p := tea.NewProgram(model, b.options.altScreen, b.options.mouseCellMotion)
|
||||
p.Run()
|
||||
|
||||
if model.print {
|
||||
fmt.Println(b.options.styles.Border.Render(b.options.styles.CmdPrint.Render(model.cmdChain)))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Boa) UsageFunc(cmd *cobra.Command) error {
|
||||
model := newCmdModel(b.options, cmd)
|
||||
p := tea.NewProgram(model, b.options.altScreen, b.options.mouseCellMotion)
|
||||
p.Run()
|
||||
|
||||
if model.print {
|
||||
fmt.Println(b.options.styles.Border.Render(b.options.styles.CmdPrint.Render(model.cmdChain)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
77
internal/tui/initprompt.go
Normal file
77
internal/tui/initprompt.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
cursor int
|
||||
choices []string
|
||||
selected map[int]struct{}
|
||||
}
|
||||
|
||||
func InitialModel() model {
|
||||
return model{
|
||||
choices: []string{"Buy carrots", "Buy celery", "Buy kohlrabi"},
|
||||
|
||||
// A map which indicates which choices are selected. We're using
|
||||
// the map like a mathematical set. The keys refer to the indexes
|
||||
// of the `choices` slice, above.
|
||||
selected: make(map[int]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return tea.SetWindowTitle("Grocery List")
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
return m, tea.Quit
|
||||
case "up", "k":
|
||||
if m.cursor > 0 {
|
||||
m.cursor--
|
||||
}
|
||||
case "down", "j":
|
||||
if m.cursor < len(m.choices)-1 {
|
||||
m.cursor++
|
||||
}
|
||||
case "enter", " ":
|
||||
_, ok := m.selected[m.cursor]
|
||||
if ok {
|
||||
delete(m.selected, m.cursor)
|
||||
} else {
|
||||
m.selected[m.cursor] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
s := "What should we buy at the market?\n\n"
|
||||
|
||||
for i, choice := range m.choices {
|
||||
cursor := " "
|
||||
if m.cursor == i {
|
||||
cursor = ">"
|
||||
}
|
||||
|
||||
checked := " "
|
||||
if _, ok := m.selected[i]; ok {
|
||||
checked = "x"
|
||||
}
|
||||
|
||||
s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
|
||||
}
|
||||
|
||||
s += "\nPress q to quit.\n"
|
||||
|
||||
return s
|
||||
}
|
||||
246
internal/tui/model.go
Normal file
246
internal/tui/model.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
spacebar = " "
|
||||
)
|
||||
|
||||
// cmdModel Implements tea.Model. It provides an interactive
|
||||
// help and usage tui component for bubbletea programs.
|
||||
type cmdModel struct {
|
||||
styles *Styles
|
||||
list list.Model
|
||||
viewport *viewport.Model
|
||||
cmd *cobra.Command
|
||||
subCmds []list.Item
|
||||
print bool
|
||||
cmdChain string
|
||||
// Store window height to adjust viewport on command selection changes
|
||||
windowHeight int
|
||||
// Store full height of content for given view, updated on command change
|
||||
contentHeight int
|
||||
errorWriter *bytes.Buffer
|
||||
}
|
||||
|
||||
// newCmdModel initializes a based on values supplied from cmd *cobra.Command
|
||||
func newCmdModel(options *options, cmd *cobra.Command) *cmdModel {
|
||||
subCmds := getSubCommands(cmd)
|
||||
l := newSubCmdsList(options.styles, subCmds)
|
||||
vp := viewport.New(0, 0)
|
||||
vp.KeyMap = viewPortKeyMap()
|
||||
m := &cmdModel{
|
||||
styles: options.styles,
|
||||
cmd: cmd,
|
||||
subCmds: subCmds,
|
||||
list: l,
|
||||
viewport: &vp,
|
||||
errorWriter: options.errorWriter,
|
||||
}
|
||||
m.contentHeight = lipgloss.Height(m.usage())
|
||||
return m
|
||||
}
|
||||
|
||||
// Init is the initial cmd to be executed which is nil for this component.
|
||||
func (m *cmdModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update is called when a message is received.
|
||||
func (m *cmdModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
var listCmd tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
m.windowHeight = msg.Height
|
||||
m.viewport.Width = msg.Width
|
||||
m.viewport.Height = m.windowHeight - lipgloss.Height(m.footer())
|
||||
if m.viewport.Height > m.contentHeight {
|
||||
m.viewport.Height = m.contentHeight
|
||||
}
|
||||
// Scroll viewport back to top for new screen
|
||||
m.viewport.SetYOffset(0)
|
||||
return m, nil
|
||||
case tea.KeyMsg:
|
||||
switch keypress := msg.String(); keypress {
|
||||
case "q", "ctrl+c":
|
||||
return m, tea.Quit
|
||||
case "enter":
|
||||
i, ok := m.list.SelectedItem().(item)
|
||||
if ok {
|
||||
m.cmd = i.cmd
|
||||
subCmds := getSubCommands(m.cmd)
|
||||
m.list = newSubCmdsList(m.styles, subCmds)
|
||||
m.viewport.Height = m.windowHeight - lipgloss.Height(m.footer())
|
||||
// Update new content height and check viewport size
|
||||
m.contentHeight = lipgloss.Height(m.usage())
|
||||
if m.viewport.Height > m.contentHeight {
|
||||
m.viewport.Height = m.contentHeight
|
||||
}
|
||||
// Scroll viewport back to top for new screen
|
||||
m.viewport.SetYOffset(0)
|
||||
}
|
||||
return m, nil
|
||||
case "b":
|
||||
if m.cmd.HasParent() {
|
||||
m.cmd = m.cmd.Parent()
|
||||
subCmds := getSubCommands(m.cmd)
|
||||
m.list = newSubCmdsList(m.styles, subCmds)
|
||||
m.viewport.Height = m.windowHeight - lipgloss.Height(m.footer())
|
||||
// Update new content height and check viewport size
|
||||
m.contentHeight = lipgloss.Height(m.usage())
|
||||
if m.viewport.Height > m.contentHeight {
|
||||
m.viewport.Height = m.contentHeight
|
||||
}
|
||||
// Scroll viewport back to top for new screen
|
||||
m.viewport.SetYOffset(0)
|
||||
}
|
||||
return m, nil
|
||||
case "p":
|
||||
m.print = true
|
||||
m.cmdChain = print("", m.cmd)
|
||||
return m, tea.Quit
|
||||
}
|
||||
}
|
||||
|
||||
m.list, listCmd = m.list.Update(msg)
|
||||
newViewport, viewPortCmd := m.viewport.Update(msg)
|
||||
// point to new viewport
|
||||
m.viewport = &newViewport
|
||||
m.viewport.KeyMap = viewPortKeyMap()
|
||||
if m.viewport.Height > m.contentHeight {
|
||||
m.viewport.Height = m.contentHeight
|
||||
}
|
||||
cmds = append(cmds, listCmd, viewPortCmd)
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
// View renders the program's UI, which is just a string.
|
||||
func (m *cmdModel) View() string {
|
||||
m.viewport.SetContent(m.usage())
|
||||
return lipgloss.JoinVertical(lipgloss.Top, m.viewport.View(), m.footer())
|
||||
}
|
||||
|
||||
// usage builds the usage body from a cobra command
|
||||
func (m *cmdModel) usage() string {
|
||||
usageText := strings.Builder{}
|
||||
|
||||
if m.errorWriter != nil && m.errorWriter.Len() > 0 {
|
||||
usageText.WriteString(m.styles.ErrorText.Render(m.errorWriter.String() + "\n"))
|
||||
}
|
||||
|
||||
cmdTitle := ""
|
||||
cmdName := m.cmd.Name()
|
||||
if m.cmd.Version != "" {
|
||||
cmdName += " " + m.cmd.Version
|
||||
}
|
||||
cmdName = m.styles.Section.Render(cmdName)
|
||||
cmdLong := m.styles.SubTitle.Render(m.cmd.Long)
|
||||
cmdTitle = m.styles.Title.Foreground(lipgloss.AdaptiveColor{Light: darkGrey, Dark: white}).
|
||||
Render(lipgloss.JoinVertical(lipgloss.Center, cmdName, cmdLong))
|
||||
usageText.WriteString(cmdTitle + "\n")
|
||||
|
||||
cmdSection := m.styles.Section.Render("Cmd Description:")
|
||||
short := m.styles.Text.Render(m.cmd.Short)
|
||||
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, cmdSection, short) + "\n")
|
||||
|
||||
if m.cmd.Runnable() {
|
||||
usage := m.styles.Section.Render("Usage:")
|
||||
useLine := m.styles.Text.Render(m.cmd.UseLine())
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, usage, useLine) + "\n")
|
||||
if m.cmd.HasAvailableSubCommands() {
|
||||
commandPath := m.styles.Text.Render(m.cmd.CommandPath() + " [command]")
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, commandPath) + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.cmd.Aliases) > 0 {
|
||||
aliases := m.styles.Section.Render("Aliases:")
|
||||
nameAndAlias := m.styles.Text.Render(m.cmd.NameAndAliases())
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, aliases, nameAndAlias) + "\n")
|
||||
}
|
||||
|
||||
if m.cmd.HasAvailableLocalFlags() {
|
||||
localFlags := m.styles.Section.Render("Flags:")
|
||||
flagUsage := m.styles.Text.Render(strings.TrimRightFunc(m.cmd.LocalFlags().FlagUsages(), unicode.IsSpace))
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, localFlags, flagUsage) + "\n")
|
||||
}
|
||||
if m.cmd.HasAvailableInheritedFlags() {
|
||||
globalFlags := m.styles.Section.Render("Global Flags:")
|
||||
flagUsage := m.styles.Text.Render(strings.TrimRightFunc(m.cmd.InheritedFlags().FlagUsages(), unicode.IsSpace))
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, globalFlags, flagUsage) + "\n")
|
||||
}
|
||||
|
||||
if m.cmd.HasExample() {
|
||||
examples := m.styles.Section.Render("Examples:")
|
||||
example := m.styles.Text.Render(m.cmd.Example)
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, examples, example) + "\n")
|
||||
}
|
||||
|
||||
if m.cmd.HasAvailableSubCommands() {
|
||||
usageText.WriteString(lipgloss.JoinVertical(lipgloss.Left, m.list.View()))
|
||||
}
|
||||
|
||||
return m.styles.Border.Render(usageText.String() + "\n")
|
||||
}
|
||||
|
||||
// footer outputs the footer of the viewport and contains help text.
|
||||
func (m *cmdModel) footer() string {
|
||||
var help, scroll string
|
||||
help = m.styles.Info.Render("↑/k up • ↓/j down • / to filter • p to print • b to go back • enter to select • q, ctrl+c to quit")
|
||||
// If content is larger than the window minus the size of the necessary footer then it will be in a scrollable viewport
|
||||
if m.contentHeight > m.windowHeight-2 {
|
||||
scroll = m.styles.Info.Render("ctrl+k up • ctrl+j down • mouse to scroll")
|
||||
}
|
||||
return lipgloss.JoinVertical(lipgloss.Left, help, scroll)
|
||||
}
|
||||
|
||||
// print outputs the command chain for a given cobra command.
|
||||
func print(v string, cmd *cobra.Command) string {
|
||||
if cmd != nil {
|
||||
v = cmd.Name() + " " + v
|
||||
if !cmd.HasParent() {
|
||||
// final result
|
||||
return "Command: " + v
|
||||
}
|
||||
// recursively walk cmd chain
|
||||
return print(v, cmd.Parent())
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func viewPortKeyMap() viewport.KeyMap {
|
||||
return viewport.KeyMap{
|
||||
PageDown: key.NewBinding(
|
||||
key.WithKeys("pgdown", spacebar, "f"),
|
||||
),
|
||||
PageUp: key.NewBinding(
|
||||
key.WithKeys("pgup", "v"),
|
||||
),
|
||||
HalfPageUp: key.NewBinding(
|
||||
key.WithKeys("u", "ctrl+u"),
|
||||
),
|
||||
HalfPageDown: key.NewBinding(
|
||||
key.WithKeys("d", "ctrl+d"),
|
||||
),
|
||||
Up: key.NewBinding(
|
||||
key.WithKeys("ctrl+k"),
|
||||
),
|
||||
Down: key.NewBinding(
|
||||
key.WithKeys("ctrl+j"),
|
||||
),
|
||||
}
|
||||
}
|
||||
71
internal/tui/options.go
Normal file
71
internal/tui/options.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
var ErrorWriter = &bytes.Buffer{}
|
||||
|
||||
type options struct {
|
||||
// public
|
||||
altScreen tea.ProgramOption
|
||||
styles *Styles
|
||||
// private (not capable of being set)
|
||||
mouseCellMotion tea.ProgramOption
|
||||
errorWriter *bytes.Buffer
|
||||
}
|
||||
|
||||
type Options interface {
|
||||
apply(*options)
|
||||
}
|
||||
|
||||
type funcOption struct {
|
||||
f func(*options)
|
||||
}
|
||||
|
||||
func (fo *funcOption) apply(opt *options) {
|
||||
fo.f(opt)
|
||||
}
|
||||
|
||||
func newFuncOption(f func(*options)) *funcOption {
|
||||
return &funcOption{f: f}
|
||||
}
|
||||
|
||||
func WithAltScreen(b bool) Options {
|
||||
return newFuncOption(func(opt *options) {
|
||||
if !b {
|
||||
opt.altScreen = noOpt
|
||||
return
|
||||
}
|
||||
opt.altScreen = tea.WithAltScreen()
|
||||
})
|
||||
}
|
||||
|
||||
func WithStyles(styles *Styles) Options {
|
||||
return newFuncOption(func(opt *options) {
|
||||
if styles != nil {
|
||||
opt.styles = styles
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func WithErrWriter(b *bytes.Buffer) Options {
|
||||
return newFuncOption(func(opt *options) {
|
||||
if b != nil {
|
||||
opt.errorWriter = b
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func defaultOptions() *options {
|
||||
return &options{
|
||||
altScreen: tea.WithAltScreen(),
|
||||
styles: DefaultStyles(),
|
||||
mouseCellMotion: tea.WithMouseCellMotion(),
|
||||
errorWriter: ErrorWriter,
|
||||
}
|
||||
}
|
||||
|
||||
func noOpt(*tea.Program) {}
|
||||
83
internal/tui/styles.go
Normal file
83
internal/tui/styles.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultWidth = 100
|
||||
|
||||
//default colors
|
||||
purple = `#7e2fcc`
|
||||
darkGrey = `#353C3B`
|
||||
lightTeal = `#03DAC5`
|
||||
darkTeal = `#01A299`
|
||||
white = `#e5e5e5`
|
||||
red = `#FF3333`
|
||||
)
|
||||
|
||||
type Styles struct {
|
||||
Border lipgloss.Style
|
||||
Title lipgloss.Style
|
||||
SubTitle lipgloss.Style
|
||||
Section lipgloss.Style
|
||||
Text lipgloss.Style
|
||||
ErrorText lipgloss.Style
|
||||
SelectedItem lipgloss.Style
|
||||
Item lipgloss.Style
|
||||
Info lipgloss.Style
|
||||
CmdPrint lipgloss.Style
|
||||
}
|
||||
|
||||
func DefaultStyles() *Styles {
|
||||
s := &Styles{}
|
||||
|
||||
// Style of the border
|
||||
s.Border = lipgloss.NewStyle().
|
||||
Padding(0, 1, 0, 1).
|
||||
Width(defaultWidth).
|
||||
BorderForeground(lipgloss.AdaptiveColor{Light: darkTeal, Dark: lightTeal}).
|
||||
Border(lipgloss.ThickBorder())
|
||||
|
||||
// Style of the title
|
||||
s.Title = lipgloss.NewStyle().Bold(true).
|
||||
Border(lipgloss.DoubleBorder()).
|
||||
BorderForeground(lipgloss.AdaptiveColor{Light: purple, Dark: purple}).
|
||||
Width(defaultWidth - 4).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
// Style of the SubTitle
|
||||
s.SubTitle = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: white, Dark: white}).Align(lipgloss.Center)
|
||||
|
||||
// Style of the individual help sections (Exaple, Usage, Flags etc.. )
|
||||
s.Section = lipgloss.NewStyle().Bold(true).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: darkTeal, Dark: lightTeal}).
|
||||
Underline(true).
|
||||
BorderBottom(true).
|
||||
Margin(1, 0, 1, 0).
|
||||
Padding(0, 1, 0, 1).Align(lipgloss.Center)
|
||||
|
||||
// Style of the text output
|
||||
s.Text = lipgloss.NewStyle().Bold(true).Padding(0, 0, 0, 5).Align(lipgloss.Left).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: darkGrey, Dark: white})
|
||||
|
||||
s.ErrorText = lipgloss.NewStyle().Underline(true).Bold(true).Align(lipgloss.Center).Width(defaultWidth - 4).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: red, Dark: red})
|
||||
|
||||
// Style of the selection list items
|
||||
s.SelectedItem = lipgloss.NewStyle().PaddingLeft(2).Background(lipgloss.AdaptiveColor{Light: purple, Dark: purple}).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: white, Dark: white})
|
||||
|
||||
// Style of the list items
|
||||
s.Item = lipgloss.NewStyle().PaddingLeft(2).Bold(true).Foreground(lipgloss.AdaptiveColor{Light: white, Dark: white})
|
||||
|
||||
// Style of the info text
|
||||
s.Info = lipgloss.NewStyle().Bold(true).Width(defaultWidth).Align(lipgloss.Center).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: darkGrey, Dark: white})
|
||||
|
||||
// Style of the Cmd Print text
|
||||
s.CmdPrint = lipgloss.NewStyle().Bold(true).Width(defaultWidth).Margin(1).Align(lipgloss.Center).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: darkGrey, Dark: white})
|
||||
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user