From 9c1a23ae62d5cfeeeb9fc42a7d3a077760cfff5e Mon Sep 17 00:00:00 2001 From: "Vinicius C." Date: Thu, 9 Jan 2025 02:27:14 +0000 Subject: [PATCH] Move terminal colors to global constants (#913) * added new theme * change pkg to use theme colors * revert merge * revert logger * cmd utils update theme colors * list_components update theme colors * list_stacks update theme colors * terraform_clean update theme colors * atmos update theme colors * tui update theme colors * exec update theme colors * stacks update theme colors * update pkgs for new theme colors * Revert "update pkgs for new theme colors" This reverts commit 7c63ea33ff9d5796f4048232aebccb57a5704fd9. * hex colors * update internal/exec/atmos.go for new theme colors --------- Co-authored-by: Andriy Knysh --- cmd/cmd_utils.go | 6 +-- cmd/list_components.go | 9 ++-- cmd/list_stacks.go | 10 ++-- cmd/validate_component.go | 4 +- cmd/validate_stacks.go | 4 +- internal/exec/atmos.go | 6 +-- internal/exec/terraform_clean.go | 7 +-- internal/exec/vendor_model.go | 11 +++-- internal/exec/vendor_model_component.go | 4 +- internal/exec/workflow_utils.go | 8 ++-- internal/tui/atmos/column.go | 3 +- internal/tui/atmos/list_item.go | 3 +- internal/tui/templates/templater.go | 17 +++---- internal/tui/workflow/column.go | 6 +-- internal/tui/workflow/list_item.go | 3 +- pkg/config/config.go | 4 +- pkg/logger/logger.go | 13 +++-- pkg/merge/merge.go | 10 ++-- pkg/ui/theme/colors.go | 64 +++++++++++++++++++++++++ pkg/utils/log_utils.go | 35 +++++++------- pkg/utils/version_utils.go | 20 ++++---- 21 files changed, 153 insertions(+), 94 deletions(-) create mode 100644 pkg/ui/theme/colors.go diff --git a/cmd/cmd_utils.go b/cmd/cmd_utils.go index b5cfa42b6..64e7c7d1d 100644 --- a/cmd/cmd_utils.go +++ b/cmd/cmd_utils.go @@ -9,13 +9,13 @@ import ( "strings" "time" - "github.com/fatih/color" "github.com/spf13/cobra" e "github.com/cloudposse/atmos/internal/exec" tuiUtils "github.com/cloudposse/atmos/internal/tui/utils" cfg "github.com/cloudposse/atmos/pkg/config" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" "github.com/cloudposse/atmos/pkg/version" ) @@ -448,8 +448,8 @@ func checkAtmosConfig(opts ...AtmosValidateOption) { // printMessageForMissingAtmosConfig prints Atmos logo and instructions on how to configure and start using Atmos func printMessageForMissingAtmosConfig(atmosConfig schema.AtmosConfiguration) { - c1 := color.New(color.FgCyan) - c2 := color.New(color.FgGreen) + c1 := theme.Colors.Info + c2 := theme.Colors.Success fmt.Println() err := tuiUtils.PrintStyledText("ATMOS") diff --git a/cmd/list_components.go b/cmd/list_components.go index a50cca50d..4180315da 100644 --- a/cmd/list_components.go +++ b/cmd/list_components.go @@ -10,6 +10,7 @@ import ( "github.com/cloudposse/atmos/pkg/config" l "github.com/cloudposse/atmos/pkg/list" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -35,23 +36,23 @@ var listComponentsCmd = &cobra.Command{ configAndStacksInfo := schema.ConfigAndStacksInfo{} atmosConfig, err := config.InitCliConfig(configAndStacksInfo, true) if err != nil { - u.PrintMessageInColor(fmt.Sprintf("Error initializing CLI config: %v", err), color.New(color.FgRed)) + u.PrintMessageInColor(fmt.Sprintf("Error initializing CLI config: %v", err), theme.Colors.Error) return } stacksMap, err := e.ExecuteDescribeStacks(atmosConfig, "", nil, nil, nil, false, false, false) if err != nil { - u.PrintMessageInColor(fmt.Sprintf("Error describing stacks: %v", err), color.New(color.FgRed)) + u.PrintMessageInColor(fmt.Sprintf("Error describing stacks: %v", err), theme.Colors.Error) return } output, err := l.FilterAndListComponents(stackFlag, stacksMap) if err != nil { - u.PrintMessageInColor(fmt.Sprintf("Error: %v"+"\n", err), color.New(color.FgYellow)) + u.PrintMessageInColor(fmt.Sprintf("Error: %v"+"\n", err), theme.Colors.Warning) return } - u.PrintMessageInColor(output, color.New(color.FgGreen)) + u.PrintMessageInColor(output, theme.Colors.Success) }, } diff --git a/cmd/list_stacks.go b/cmd/list_stacks.go index 46e5f7687..655d83a3c 100644 --- a/cmd/list_stacks.go +++ b/cmd/list_stacks.go @@ -3,13 +3,13 @@ package cmd import ( "fmt" - "github.com/fatih/color" "github.com/spf13/cobra" e "github.com/cloudposse/atmos/internal/exec" "github.com/cloudposse/atmos/pkg/config" l "github.com/cloudposse/atmos/pkg/list" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -30,22 +30,22 @@ var listStacksCmd = &cobra.Command{ configAndStacksInfo := schema.ConfigAndStacksInfo{} atmosConfig, err := config.InitCliConfig(configAndStacksInfo, true) if err != nil { - u.PrintMessageInColor(fmt.Sprintf("Error initializing CLI config: %v", err), color.New(color.FgRed)) + u.PrintMessageInColor(fmt.Sprintf("Error initializing CLI config: %v", err), theme.Colors.Error) return } stacksMap, err := e.ExecuteDescribeStacks(atmosConfig, "", nil, nil, nil, false, false, false) if err != nil { - u.PrintMessageInColor(fmt.Sprintf("Error describing stacks: %v", err), color.New(color.FgRed)) + u.PrintMessageInColor(fmt.Sprintf("Error describing stacks: %v", err), theme.Colors.Error) return } output, err := l.FilterAndListStacks(stacksMap, componentFlag) if err != nil { - u.PrintMessageInColor(fmt.Sprintf("Error filtering stacks: %v", err), color.New(color.FgRed)) + u.PrintMessageInColor(fmt.Sprintf("Error filtering stacks: %v", err), theme.Colors.Error) return } - u.PrintMessageInColor(output, color.New(color.FgGreen)) + u.PrintMessageInColor(output, theme.Colors.Success) }, } diff --git a/cmd/validate_component.go b/cmd/validate_component.go index 20a45cd65..3b9fd4e3d 100644 --- a/cmd/validate_component.go +++ b/cmd/validate_component.go @@ -3,11 +3,11 @@ package cmd import ( "fmt" - "github.com/fatih/color" "github.com/spf13/cobra" e "github.com/cloudposse/atmos/internal/exec" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -30,7 +30,7 @@ var validateComponentCmd = &cobra.Command{ } m := fmt.Sprintf("component '%s' in stack '%s' validated successfully\n", component, stack) - u.PrintMessageInColor(m, color.New(color.FgGreen)) + u.PrintMessageInColor(m, theme.Colors.Success) }, } diff --git a/cmd/validate_stacks.go b/cmd/validate_stacks.go index 66930bb1b..872ad802d 100644 --- a/cmd/validate_stacks.go +++ b/cmd/validate_stacks.go @@ -1,11 +1,11 @@ package cmd import ( - "github.com/fatih/color" "github.com/spf13/cobra" e "github.com/cloudposse/atmos/internal/exec" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -25,7 +25,7 @@ var ValidateStacksCmd = &cobra.Command{ u.LogErrorAndExit(schema.AtmosConfiguration{}, err) } - u.PrintMessageInColor("all stacks validated successfully\n", color.New(color.FgGreen)) + u.PrintMessageInColor("all stacks validated successfully\n", theme.Colors.Success) }, } diff --git a/internal/exec/atmos.go b/internal/exec/atmos.go index 9da19bf54..f7ac4b97a 100644 --- a/internal/exec/atmos.go +++ b/internal/exec/atmos.go @@ -5,12 +5,12 @@ import ( "os" "strings" - "github.com/fatih/color" "github.com/samber/lo" tui "github.com/cloudposse/atmos/internal/tui/atmos" cfg "github.com/cloudposse/atmos/pkg/config" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -99,7 +99,7 @@ func ExecuteAtmosCmd() error { fmt.Println() u.PrintMessageInColor(fmt.Sprintf( "Executing command:\n"+os.Args[0]+" %s %s --stack %s\n", selectedCommand, selectedComponent, selectedStack), - color.New(color.FgCyan), + theme.Colors.Info, ) fmt.Println() @@ -134,7 +134,7 @@ func ExecuteAtmosCmd() error { } m := fmt.Sprintf("component '%s' in stack '%s' validated successfully\n", selectedComponent, selectedStack) - u.PrintMessageInColor(m, color.New(color.FgGreen)) + u.PrintMessageInColor(m, theme.Colors.Success) return nil } diff --git a/internal/exec/terraform_clean.go b/internal/exec/terraform_clean.go index e3b190e01..709962b19 100644 --- a/internal/exec/terraform_clean.go +++ b/internal/exec/terraform_clean.go @@ -9,6 +9,7 @@ import ( "github.com/charmbracelet/huh" "github.com/charmbracelet/lipgloss" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -256,7 +257,7 @@ func confirmDeleteTerraformLocal(message string) (confirm bool, err error) { func DeletePathTerraform(fullPath string, objectName string) error { fileInfo, err := os.Lstat(fullPath) if os.IsNotExist(err) { - xMark := lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("x") + xMark := theme.Styles.XMark fmt.Printf("%s Cannot delete %s: path does not exist", xMark, objectName) fmt.Println() return err @@ -267,12 +268,12 @@ func DeletePathTerraform(fullPath string, objectName string) error { // Proceed with deletion err = os.RemoveAll(fullPath) if err != nil { - xMark := lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("x") + xMark := theme.Styles.XMark fmt.Printf("%s Error deleting %s", xMark, objectName) fmt.Println() return err } - checkMark := lipgloss.NewStyle().Foreground(lipgloss.Color("42")).SetString("โœ“") + checkMark := theme.Styles.Checkmark fmt.Printf("%s Deleted %s", checkMark, objectName) fmt.Println() return nil diff --git a/internal/exec/vendor_model.go b/internal/exec/vendor_model.go index 1209e6805..5a09468b5 100644 --- a/internal/exec/vendor_model.go +++ b/internal/exec/vendor_model.go @@ -14,6 +14,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" "github.com/hashicorp/go-getter" cp "github.com/otiai10/copy" @@ -67,11 +68,11 @@ type modelVendor struct { } var ( - currentPkgNameStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("211")) + currentPkgNameStyle = theme.Styles.PackageName doneStyle = lipgloss.NewStyle().Margin(1, 2) - checkMark = lipgloss.NewStyle().Foreground(lipgloss.Color("42")).SetString("โœ“") - xMark = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("x") - grayColor = lipgloss.NewStyle().Foreground(lipgloss.Color("241")) + checkMark = theme.Styles.Checkmark + xMark = theme.Styles.XMark + grayColor = theme.Styles.GrayText ) func newModelAtmosVendorInternal(pkgs []pkgAtmosVendor, dryRun bool, atmosConfig schema.AtmosConfiguration) (modelVendor, error) { @@ -81,7 +82,7 @@ func newModelAtmosVendorInternal(pkgs []pkgAtmosVendor, dryRun bool, atmosConfig progress.WithoutPercentage(), ) s := spinner.New() - s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("63")) + s.Style = theme.Styles.Link if len(pkgs) == 0 { return modelVendor{done: true}, nil } diff --git a/internal/exec/vendor_model_component.go b/internal/exec/vendor_model_component.go index 38671b190..6502936d0 100644 --- a/internal/exec/vendor_model_component.go +++ b/internal/exec/vendor_model_component.go @@ -11,8 +11,8 @@ import ( "github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" "github.com/hashicorp/go-getter" cp "github.com/otiai10/copy" ) @@ -37,7 +37,7 @@ func newModelComponentVendorInternal(pkgs []pkgComponentVendor, dryRun bool, atm progress.WithoutPercentage(), ) s := spinner.New() - s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("63")) + s.Style = theme.Styles.Link if len(pkgs) == 0 { return modelVendor{done: true}, nil } diff --git a/internal/exec/workflow_utils.go b/internal/exec/workflow_utils.go index 06fdd53fa..971a06396 100644 --- a/internal/exec/workflow_utils.go +++ b/internal/exec/workflow_utils.go @@ -7,12 +7,12 @@ import ( "sort" "strings" - "github.com/fatih/color" "github.com/pkg/errors" "github.com/samber/lo" w "github.com/cloudposse/atmos/internal/tui/workflow" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -109,12 +109,12 @@ func ExecuteWorkflow( workflowFileName := filepath.Base(workflowPath) workflowFileName = strings.TrimSuffix(workflowFileName, filepath.Ext(workflowFileName)) - failedMsg := color.New(color.FgRed).Sprintf("\nStep '%s' failed!", step.Name) + failedMsg := theme.Colors.Error.Sprintf("\nStep '%s' failed!", step.Name) u.LogDebug(atmosConfig, fmt.Sprintf("\nCommand failed: %s", command)) u.LogDebug(atmosConfig, fmt.Sprintf("Error: %v", err)) - resumeMsg := color.New(color.FgGreen).Sprintf( + resumeMsg := theme.Colors.Success.Sprintf( "\nTo resume the workflow from this step, run:\natmos workflow %s -f %s --from-step %s", workflow, workflowFileName, @@ -256,7 +256,7 @@ func ExecuteWorkflowUI(atmosConfig schema.AtmosConfiguration) (string, string, s fmt.Println() u.PrintMessageInColor(fmt.Sprintf( "Executing command:\n"+os.Args[0]+" workflow %s --file %s --from-step \"%s\"\n", selectedWorkflow, selectedWorkflowFile, selectedWorkflowStep), - color.New(color.FgCyan), + theme.Colors.Info, ) fmt.Println() diff --git a/internal/tui/atmos/column.go b/internal/tui/atmos/column.go index 59cc80611..7af21d203 100644 --- a/internal/tui/atmos/column.go +++ b/internal/tui/atmos/column.go @@ -4,6 +4,7 @@ import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/cloudposse/atmos/pkg/ui/theme" mouseZone "github.com/lrstanley/bubblezone" ) @@ -72,7 +73,7 @@ func (c *columnView) getStyle() lipgloss.Style { s := lipgloss.NewStyle().Padding(1, 2).Height(c.height).Width(c.width) if c.Focused() { - s = s.Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("62")) + s = s.Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(theme.ColorBorder)) } else { s = s.Border(lipgloss.HiddenBorder()) } diff --git a/internal/tui/atmos/list_item.go b/internal/tui/atmos/list_item.go index d62deaae5..998cd656f 100644 --- a/internal/tui/atmos/list_item.go +++ b/internal/tui/atmos/list_item.go @@ -8,11 +8,12 @@ import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/cloudposse/atmos/pkg/ui/theme" ) var ( itemStyle = lipgloss.NewStyle().PaddingLeft(4) - selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("#10ff10")) + selectedItemStyle = theme.Styles.SelectedItem ) type listItem string diff --git a/internal/tui/templates/templater.go b/internal/tui/templates/templater.go index 705dede61..c4539a6ea 100644 --- a/internal/tui/templates/templater.go +++ b/internal/tui/templates/templater.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/charmbracelet/lipgloss" + "github.com/cloudposse/atmos/pkg/ui/theme" "github.com/spf13/cobra" "github.com/spf13/pflag" "golang.org/x/term" @@ -19,18 +20,14 @@ type Templater struct { // commandStyle defines the styles for command formatting var ( - commandNameStyle = lipgloss.NewStyle(). - Foreground(lipgloss.Color("2")). // Green color for command name - Bold(true) + commandNameStyle = theme.Styles.CommandName + commandDescStyle = theme.Styles.Description - commandDescStyle = lipgloss.NewStyle(). - Foreground(lipgloss.Color("7")) // White color for description - - commandUnsupportedNameStyle = lipgloss.NewStyle(). - Foreground(lipgloss.Color("8")). + commandUnsupportedNameStyle = theme.Styles.CommandName. + Foreground(lipgloss.Color(theme.ColorGray)). Bold(true) - commandUnsupportedDescStyle = lipgloss.NewStyle(). - Foreground(lipgloss.Color("8")) + commandUnsupportedDescStyle = theme.Styles.Description. + Foreground(lipgloss.Color(theme.ColorGray)) ) // formatCommand returns a styled string for a command and its description diff --git a/internal/tui/workflow/column.go b/internal/tui/workflow/column.go index 2f5094f2b..485c3ee97 100644 --- a/internal/tui/workflow/column.go +++ b/internal/tui/workflow/column.go @@ -4,9 +4,9 @@ import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" - mouseZone "github.com/lrstanley/bubblezone" - codeview "github.com/cloudposse/atmos/internal/tui/components/code_view" + "github.com/cloudposse/atmos/pkg/ui/theme" + mouseZone "github.com/lrstanley/bubblezone" ) const ( @@ -142,7 +142,7 @@ func (c *columnView) getStyle() lipgloss.Style { s := lipgloss.NewStyle().Padding(0).Margin(2).Height(c.height).Width(c.width) if c.Focused() { - s = s.Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("62")) + s = s.Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(theme.ColorBorder)) } else { s = s.Border(lipgloss.HiddenBorder()) } diff --git a/internal/tui/workflow/list_item.go b/internal/tui/workflow/list_item.go index a6e5b81f4..adb25bcb0 100644 --- a/internal/tui/workflow/list_item.go +++ b/internal/tui/workflow/list_item.go @@ -8,11 +8,12 @@ import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/cloudposse/atmos/pkg/ui/theme" ) var ( itemStyle = lipgloss.NewStyle().PaddingLeft(4) - selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("#10ff10")) + selectedItemStyle = theme.Styles.SelectedItem ) type listItem struct { diff --git a/pkg/config/config.go b/pkg/config/config.go index df60ff8d5..8b552b0e0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -8,12 +8,12 @@ import ( "path/filepath" "runtime" - "github.com/fatih/color" "github.com/mitchellh/go-homedir" "github.com/pkg/errors" "github.com/spf13/viper" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" "github.com/cloudposse/atmos/pkg/version" ) @@ -206,7 +206,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks if logsLevelEnvVar == u.LogLevelDebug || logsLevelEnvVar == u.LogLevelTrace { u.PrintMessageInColor("'atmos.yaml' CLI config was not found in any of the searched paths: system dir, home dir, current dir, ENV vars.\n"+ "Refer to https://atmos.tools/cli/configuration for details on how to configure 'atmos.yaml'.\n"+ - "Using the default CLI config:\n\n", color.New(color.FgCyan)) + "Using the default CLI config:\n\n", theme.Colors.Info) err = u.PrintAsYAMLToFileDescriptor(atmosConfig, defaultCliConfig) if err != nil { diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 648641325..833885f6f 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -7,6 +7,7 @@ import ( "github.com/fatih/color" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" ) type LogLevel string @@ -104,8 +105,7 @@ func (l *Logger) SetLogLevel(logLevel LogLevel) error { func (l *Logger) Error(err error) { if err != nil { - c := color.New(color.FgRed) - _, err2 := c.Fprintln(color.Error, err.Error()+"\n") + _, err2 := theme.Colors.Error.Fprintln(color.Error, err.Error()+"\n") if err2 != nil { color.Red("Error logging the error:") color.Red("%s\n", err2) @@ -117,7 +117,7 @@ func (l *Logger) Error(err error) { func (l *Logger) Trace(message string) { if l.LogLevel == LogLevelTrace { - l.log(color.New(color.FgCyan), message) + l.log(theme.Colors.Info, message) } } @@ -125,17 +125,16 @@ func (l *Logger) Debug(message string) { if l.LogLevel == LogLevelTrace || l.LogLevel == LogLevelDebug { - l.log(color.New(color.FgCyan), message) + l.log(theme.Colors.Info, message) } } func (l *Logger) Info(message string) { - if l.LogLevel == LogLevelTrace || l.LogLevel == LogLevelDebug || l.LogLevel == LogLevelInfo { - l.log(color.New(color.Reset), message) + l.log(theme.Colors.Default, message) } } @@ -145,6 +144,6 @@ func (l *Logger) Warning(message string) { l.LogLevel == LogLevelInfo || l.LogLevel == LogLevelWarning { - l.log(color.New(color.FgYellow), message) + l.log(theme.Colors.Warning, message) } } diff --git a/pkg/merge/merge.go b/pkg/merge/merge.go index 937e06cc3..dd7f9c25d 100644 --- a/pkg/merge/merge.go +++ b/pkg/merge/merge.go @@ -7,6 +7,7 @@ import ( "github.com/fatih/color" "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" u "github.com/cloudposse/atmos/pkg/utils" ) @@ -39,15 +40,13 @@ func MergeWithOptions( // so `mergo` does not have access to the original pointers yamlCurrent, err := u.ConvertToYAML(current) if err != nil { - c := color.New(color.FgRed) - _, _ = c.Fprintln(color.Error, err.Error()+"\n") + _, _ = theme.Colors.Error.Fprintln(color.Error, err.Error()+"\n") return nil, err } dataCurrent, err := u.UnmarshalYAML[any](yamlCurrent) if err != nil { - c := color.New(color.FgRed) - _, _ = c.Fprintln(color.Error, err.Error()+"\n") + _, _ = theme.Colors.Error.Fprintln(color.Error, err.Error()+"\n") return nil, err } @@ -66,8 +65,7 @@ func MergeWithOptions( } if err = mergo.Merge(&merged, dataCurrent, opts...); err != nil { - c := color.New(color.FgRed) - _, _ = c.Fprintln(color.Error, err.Error()+"\n") + _, _ = theme.Colors.Error.Fprintln(color.Error, err.Error()+"\n") return nil, err } } diff --git a/pkg/ui/theme/colors.go b/pkg/ui/theme/colors.go new file mode 100644 index 000000000..aba957436 --- /dev/null +++ b/pkg/ui/theme/colors.go @@ -0,0 +1,64 @@ +package theme + +import ( + "github.com/charmbracelet/lipgloss" + "github.com/fatih/color" +) + +const ( + // Base colors + ColorGray = "#808080" // Version number + ColorGreen = "#00FF00" // Success, new version + ColorCyan = "#00FFFF" // Links, info + ColorPink = "#FF69B4" // Package names + ColorBlue = "#5F5FFF" // UI elements + ColorDarkGray = "#626262" // Subtle text + ColorRed = "#FF0000" // Errors, x mark + ColorCheckmark = "#00D700" // Checkmark + ColorWhite = "#FFFFFF" // Default text + + ColorSelectedItem = "#10ff10" // Selected items in lists + ColorBorder = "#5F5FD7" // UI borders +) + +// Styles provides pre-configured lipgloss styles for common UI elements +var Styles = struct { + VersionNumber lipgloss.Style + NewVersion lipgloss.Style + Link lipgloss.Style + PackageName lipgloss.Style + Checkmark lipgloss.Style + XMark lipgloss.Style + GrayText lipgloss.Style + SelectedItem lipgloss.Style + CommandName lipgloss.Style + Description lipgloss.Style + Border lipgloss.Style +}{ + VersionNumber: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGray)), + NewVersion: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen)), + Link: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCyan)), + PackageName: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorPink)), + Checkmark: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorCheckmark)).SetString("โœ“"), + XMark: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorRed)).SetString("x"), + GrayText: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorDarkGray)), + SelectedItem: lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color(ColorSelectedItem)), + CommandName: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorGreen)), + Description: lipgloss.NewStyle().Foreground(lipgloss.Color(ColorWhite)), + Border: lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(ColorBorder)), +} + +// Colors provides color.Attribute mappings for the old color.New style +var Colors = struct { + Error *color.Color + Info *color.Color + Success *color.Color + Warning *color.Color + Default *color.Color +}{ + Error: color.New(color.FgRed), + Info: color.New(color.FgCyan), + Success: color.New(color.FgGreen), + Warning: color.New(color.FgYellow), + Default: color.New(color.Reset), +} diff --git a/pkg/utils/log_utils.go b/pkg/utils/log_utils.go index fd6463691..af3007f18 100644 --- a/pkg/utils/log_utils.go +++ b/pkg/utils/log_utils.go @@ -7,9 +7,9 @@ import ( "os/exec" "runtime/debug" - "github.com/fatih/color" - "github.com/cloudposse/atmos/pkg/schema" + "github.com/cloudposse/atmos/pkg/ui/theme" + "github.com/fatih/color" ) const ( @@ -48,13 +48,12 @@ func LogErrorAndExit(atmosConfig schema.AtmosConfiguration, err error) { // LogError logs errors to std.Error func LogError(atmosConfig schema.AtmosConfiguration, err error) { if err != nil { - c := color.New(color.FgRed) - _, printErr := c.Fprintln(color.Error, err.Error()+"\n") + _, printErr := theme.Colors.Error.Fprintln(color.Error, err.Error()+"\n") if printErr != nil { - color.Red("Error logging the error:") - color.Red("%s\n", printErr) - color.Red("Original error:") - color.Red("%s\n", err) + theme.Colors.Error.Println("Error logging the error:") + theme.Colors.Error.Printf("%s\n", printErr) + theme.Colors.Error.Println("Original error:") + theme.Colors.Error.Printf("%s\n", err) } // Print stack trace @@ -67,7 +66,7 @@ func LogError(atmosConfig schema.AtmosConfiguration, err error) { // LogTrace logs the provided trace message func LogTrace(atmosConfig schema.AtmosConfiguration, message string) { if atmosConfig.Logs.Level == LogLevelTrace { - log(atmosConfig, color.New(color.FgCyan), message) + log(atmosConfig, theme.Colors.Info, message) } } @@ -76,7 +75,7 @@ func LogDebug(atmosConfig schema.AtmosConfiguration, message string) { if atmosConfig.Logs.Level == LogLevelTrace || atmosConfig.Logs.Level == LogLevelDebug { - log(atmosConfig, color.New(color.FgCyan), message) + log(atmosConfig, theme.Colors.Info, message) } } @@ -88,7 +87,7 @@ func LogInfo(atmosConfig schema.AtmosConfiguration, message string) { atmosConfig.Logs.Level == LogLevelDebug || atmosConfig.Logs.Level == LogLevelInfo { - log(atmosConfig, color.New(color.Reset), message) + log(atmosConfig, theme.Colors.Default, message) } } @@ -99,7 +98,7 @@ func LogWarning(atmosConfig schema.AtmosConfiguration, message string) { atmosConfig.Logs.Level == LogLevelInfo || atmosConfig.Logs.Level == LogLevelWarning { - log(atmosConfig, color.New(color.FgYellow), message) + log(atmosConfig, theme.Colors.Warning, message) } } @@ -108,36 +107,36 @@ func log(atmosConfig schema.AtmosConfiguration, logColor *color.Color, message s if atmosConfig.Logs.File == "/dev/stdout" { _, err := logColor.Fprintln(os.Stdout, message) if err != nil { - color.Red("%s\n", err) + theme.Colors.Error.Printf("%s\n", err) } } else if atmosConfig.Logs.File == "/dev/stderr" { _, err := logColor.Fprintln(os.Stderr, message) if err != nil { - color.Red("%s\n", err) + theme.Colors.Error.Printf("%s\n", err) } } else { f, err := os.OpenFile(atmosConfig.Logs.File, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) if err != nil { - color.Red("%s\n", err) + theme.Colors.Error.Printf("%s\n", err) return } defer func(f *os.File) { err = f.Close() if err != nil { - color.Red("%s\n", err) + theme.Colors.Error.Printf("%s\n", err) } }(f) _, err = f.Write([]byte(fmt.Sprintf("%s\n", message))) if err != nil { - color.Red("%s\n", err) + theme.Colors.Error.Printf("%s\n", err) } } } else { _, err := logColor.Fprintln(os.Stdout, message) if err != nil { - color.Red("%s\n", err) + theme.Colors.Error.Printf("%s\n", err) } } } diff --git a/pkg/utils/version_utils.go b/pkg/utils/version_utils.go index f179da4d8..a4712ef63 100644 --- a/pkg/utils/version_utils.go +++ b/pkg/utils/version_utils.go @@ -5,38 +5,34 @@ import ( "strings" "github.com/charmbracelet/lipgloss" + "github.com/cloudposse/atmos/pkg/ui/theme" "github.com/cloudposse/atmos/pkg/version" ) // PrintMessageToUpgradeToAtmosLatestRelease prints info on how to upgrade Atmos to the latest version func PrintMessageToUpgradeToAtmosLatestRelease(latestVersion string) { - // Define colors - c1 := lipgloss.NewStyle().Foreground(lipgloss.Color("8")) - c2 := lipgloss.NewStyle().Foreground(lipgloss.Color("10")) - c3 := lipgloss.NewStyle().Foreground(lipgloss.Color("14")) - // Define content message := lipgloss.NewStyle(). Render(fmt.Sprintf("Update available! %s ยป %s", - c1.Render(version.Version), - c2.Render(latestVersion))) + theme.Styles.VersionNumber.Render(version.Version), + theme.Styles.NewVersion.Render(latestVersion))) - links := []string{lipgloss.NewStyle().Render(fmt.Sprintf("Atmos Releases: %s", c3.Render("https://github.com/cloudposse/atmos/releases"))), - lipgloss.NewStyle().Render(fmt.Sprintf("Install Atmos: %s", c3.Render("https://atmos.tools/install"))), + links := []string{lipgloss.NewStyle().Render(fmt.Sprintf("Atmos Releases: %s", theme.Styles.Link.Render("https://github.com/cloudposse/atmos/releases"))), + lipgloss.NewStyle().Render(fmt.Sprintf("Install Atmos: %s", theme.Styles.Link.Render("https://atmos.tools/install"))), } messageLines := append([]string{message}, links...) messageContent := strings.Join(messageLines, "\n") // Define box - boxStyle := lipgloss.NewStyle(). + style := lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("10")). + BorderForeground(lipgloss.Color(theme.ColorGreen)). Padding(0, 1). Align(lipgloss.Center) // Render the box - box := boxStyle.Render(messageContent) + box := style.Render(messageContent) // Print the box fmt.Println(box)