From 77971756e51c2c217aecde49f6774470686119ad Mon Sep 17 00:00:00 2001 From: Florian Rey Date: Tue, 28 May 2024 10:19:14 +0200 Subject: [PATCH 1/2] fix: form and group styles --- form.go | 15 +++++++++++++-- group.go | 15 ++++++++++++++- theme.go | 2 ++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/form.go b/form.go index 76e27889..7bdba6bf 100644 --- a/form.go +++ b/form.go @@ -11,6 +11,7 @@ import ( "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/paginator" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" ) const defaultWidth = 80 @@ -65,6 +66,7 @@ type Form struct { // options width int height int + theme *Theme keymap *KeyMap timeout time.Duration teaOptions []tea.ProgramOption @@ -240,9 +242,10 @@ func (f *Form) WithShowErrors(v bool) *Form { // can be applied to each group and field individually for more granular // control. func (f *Form) WithTheme(theme *Theme) *Form { - if theme == nil { + if f.theme != nil { return f } + f.theme = theme for _, group := range f.groups { group.WithTheme(theme) } @@ -575,13 +578,21 @@ func (f *Form) isGroupHidden(page int) bool { return hide() } +func (f *Form) style() lipgloss.Style { + theme := f.theme + if theme == nil { + theme = ThemeCharm() + } + return theme.Form +} + // View renders the form. func (f *Form) View() string { if f.quitting { return "" } - return f.layout.View(f) + return f.style().Render(f.layout.View(f)) } // Run runs the form. diff --git a/group.go b/group.go index d9ef2c08..8a63f959 100644 --- a/group.go +++ b/group.go @@ -38,6 +38,7 @@ type Group struct { // group options width int height int + theme *Theme keymap *KeyMap hide func() bool active bool @@ -92,6 +93,10 @@ func (g *Group) WithShowErrors(show bool) *Group { // WithTheme sets the theme on a group. func (g *Group) WithTheme(t *Theme) *Group { + if g.theme != nil { + return g + } + g.theme = t g.help.Styles = t.Help for _, field := range g.fields { field.WithTheme(t) @@ -265,6 +270,14 @@ func (g *Group) fullHeight() int { return height } +func (g *Group) style() lipgloss.Style { + theme := g.theme + if theme == nil { + theme = ThemeCharm() + } + return theme.Group +} + func (g *Group) getContent() (int, string) { var fields strings.Builder offset := 0 @@ -323,5 +336,5 @@ func (g *Group) Footer() string { view.WriteString(ThemeCharm().Focused.ErrorMessage.Render(err.Error())) } } - return view.String() + return g.style().Render(view.String()) } diff --git a/theme.go b/theme.go index 32982a1b..7db054ad 100644 --- a/theme.go +++ b/theme.go @@ -74,6 +74,8 @@ const ( func ThemeBase() *Theme { var t Theme + t.Form = lipgloss.NewStyle() + t.Group = lipgloss.NewStyle() t.FieldSeparator = lipgloss.NewStyle().SetString("\n\n") button := lipgloss.NewStyle(). From 5ca34a5862d9e221703b04aa7e5ffc45ba82a7aa Mon Sep 17 00:00:00 2001 From: Florian Rey Date: Tue, 28 May 2024 10:39:30 +0200 Subject: [PATCH 2/2] misc: define form and group dedicated styles --- form.go | 9 +++++---- group.go | 10 ++++++---- theme.go | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/form.go b/form.go index 7bdba6bf..9e50e5f4 100644 --- a/form.go +++ b/form.go @@ -11,7 +11,6 @@ import ( "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/paginator" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) const defaultWidth = 80 @@ -578,12 +577,12 @@ func (f *Form) isGroupHidden(page int) bool { return hide() } -func (f *Form) style() lipgloss.Style { +func (f *Form) styles() *FormStyles { theme := f.theme if theme == nil { theme = ThemeCharm() } - return theme.Form + return &theme.Form } // View renders the form. @@ -592,7 +591,9 @@ func (f *Form) View() string { return "" } - return f.style().Render(f.layout.View(f)) + styles := f.styles() + + return styles.Base.Render(f.layout.View(f)) } // Run runs the form. diff --git a/group.go b/group.go index 8a63f959..b9e361e9 100644 --- a/group.go +++ b/group.go @@ -270,12 +270,12 @@ func (g *Group) fullHeight() int { return height } -func (g *Group) style() lipgloss.Style { +func (g *Group) styles() *GroupStyles { theme := g.theme if theme == nil { theme = ThemeCharm() } - return theme.Group + return &theme.Group } func (g *Group) getContent() (int, string) { @@ -325,6 +325,8 @@ func (g *Group) Content() string { // Footer renders the group's footer only (no content). func (g *Group) Footer() string { + styles := g.styles() + var view strings.Builder view.WriteRune('\n') errors := g.Errors() @@ -333,8 +335,8 @@ func (g *Group) Footer() string { } if g.showErrors { for _, err := range errors { - view.WriteString(ThemeCharm().Focused.ErrorMessage.Render(err.Error())) + view.WriteString(styles.ErrorMessage.Render(err.Error())) } } - return g.style().Render(view.String()) + return styles.Base.Render(view.String()) } diff --git a/theme.go b/theme.go index 7db054ad..35403fdd 100644 --- a/theme.go +++ b/theme.go @@ -9,21 +9,31 @@ import ( // Theme is a collection of styles for components of the form. // Themes can be applied to a form using the WithTheme option. type Theme struct { - Form lipgloss.Style - Group lipgloss.Style + Form FormStyles + Group GroupStyles FieldSeparator lipgloss.Style Blurred FieldStyles Focused FieldStyles Help help.Styles } +// FormStyles are the styles for form. +type FormStyles struct { + Base lipgloss.Style +} + +// GroupStyles are the styles for form groups. +type GroupStyles struct { + Base lipgloss.Style + ErrorMessage lipgloss.Style +} + // FieldStyles are the styles for input fields. type FieldStyles struct { Base lipgloss.Style Title lipgloss.Style Description lipgloss.Style ErrorIndicator lipgloss.Style - ErrorMessage lipgloss.Style // Select styles. SelectSelector lipgloss.Style // Selection indicator @@ -74,8 +84,13 @@ const ( func ThemeBase() *Theme { var t Theme - t.Form = lipgloss.NewStyle() - t.Group = lipgloss.NewStyle() + // Form styles. + t.Form.Base = lipgloss.NewStyle() + + // Group styles. + t.Group.Base = lipgloss.NewStyle() + t.Group.ErrorMessage = lipgloss.NewStyle().SetString(" *") + t.FieldSeparator = lipgloss.NewStyle().SetString("\n\n") button := lipgloss.NewStyle(). @@ -86,7 +101,6 @@ func ThemeBase() *Theme { t.Focused.Base = lipgloss.NewStyle().PaddingLeft(1).BorderStyle(lipgloss.ThickBorder()).BorderLeft(true) t.Focused.Card = lipgloss.NewStyle().PaddingLeft(1) t.Focused.ErrorIndicator = lipgloss.NewStyle().SetString(" *") - t.Focused.ErrorMessage = lipgloss.NewStyle().SetString(" *") t.Focused.SelectSelector = lipgloss.NewStyle().SetString("> ") t.Focused.NextIndicator = lipgloss.NewStyle().MarginLeft(1).SetString("→") t.Focused.PrevIndicator = lipgloss.NewStyle().MarginRight(1).SetString("←") @@ -122,13 +136,14 @@ func ThemeCharm() *Theme { red = lipgloss.AdaptiveColor{Light: "#FF4672", Dark: "#ED567A"} ) + t.Group.ErrorMessage = t.Group.ErrorMessage.Foreground(red) + t.Focused.Base = t.Focused.Base.BorderForeground(lipgloss.Color("238")) t.Focused.Title = t.Focused.Title.Foreground(indigo).Bold(true) t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(indigo).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(fuchsia) t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(fuchsia) t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(fuchsia) @@ -169,6 +184,8 @@ func ThemeDracula() *Theme { yellow = lipgloss.AdaptiveColor{Dark: "#f1fa8c"} ) + t.Group.ErrorMessage = t.Group.ErrorMessage.Foreground(red) + t.Focused.Base = t.Focused.Base.BorderForeground(selection) t.Focused.Title = t.Focused.Title.Foreground(purple) t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(purple) @@ -176,7 +193,6 @@ func ThemeDracula() *Theme { t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(red) t.Focused.Directory = t.Focused.Directory.Foreground(purple) t.Focused.File = t.Focused.File.Foreground(foreground) - t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(red) t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(yellow) t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(yellow) t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(yellow) @@ -205,13 +221,14 @@ func ThemeDracula() *Theme { func ThemeBase16() *Theme { t := ThemeBase() + t.Group.ErrorMessage = t.Group.ErrorMessage.Foreground(lipgloss.Color("9")) + t.Focused.Base = t.Focused.Base.BorderForeground(lipgloss.Color("8")) t.Focused.Title = t.Focused.Title.Foreground(lipgloss.Color("6")) t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(lipgloss.Color("6")) t.Focused.Directory = t.Focused.Directory.Foreground(lipgloss.Color("6")) t.Focused.Description = t.Focused.Description.Foreground(lipgloss.Color("8")) t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(lipgloss.Color("9")) - t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(lipgloss.Color("9")) t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(lipgloss.Color("3")) t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(lipgloss.Color("3")) t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(lipgloss.Color("3")) @@ -261,13 +278,14 @@ func ThemeCatppuccin() *Theme { cursor = lipgloss.AdaptiveColor{Light: light.Rosewater().Hex, Dark: dark.Rosewater().Hex} ) + t.Group.ErrorMessage = t.Group.ErrorMessage.Foreground(red) + t.Focused.Base = t.Focused.Base.BorderForeground(subtext1) t.Focused.Title = t.Focused.Title.Foreground(mauve) t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(mauve) t.Focused.Directory = t.Focused.Directory.Foreground(mauve) t.Focused.Description = t.Focused.Description.Foreground(subtext0) t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(red) - t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(red) t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(pink) t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(pink) t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(pink)