package theme import ( "fmt" "os" "sync" "github.com/charmbracelet/lipgloss" ) // ColorScheme defines the color palette for the theme type ColorScheme struct { Primary lipgloss.Color Success lipgloss.Color Warning lipgloss.Color Error lipgloss.Color Muted lipgloss.Color Background lipgloss.Color } // Theme represents a color theme with its name and color scheme type Theme struct { Name string Scheme ColorScheme } // Global variables for current theme and styles var ( currentTheme *Theme once sync.Once // Global styles that can be used throughout the application StylePrimary lipgloss.Style StyleSuccess lipgloss.Style StyleWarning lipgloss.Style StyleError lipgloss.Style StyleMuted lipgloss.Style StyleTitle lipgloss.Style StyleSubtitle lipgloss.Style StyleHelpKey lipgloss.Style ) // DefaultTheme is the standard blue-based theme var DefaultTheme = &Theme{ Name: "default", Scheme: ColorScheme{ Primary: lipgloss.Color("62"), // Blue Success: lipgloss.Color("46"), // Green Warning: lipgloss.Color("208"), // Orange Error: lipgloss.Color("196"), // Red Muted: lipgloss.Color("241"), // Gray Background: lipgloss.Color(""), // Default terminal background }, } // DarkTheme is a purple-based dark theme var DarkTheme = &Theme{ Name: "dark", Scheme: ColorScheme{ Primary: lipgloss.Color("141"), // Purple Success: lipgloss.Color("51"), // Cyan Warning: lipgloss.Color("226"), // Yellow Error: lipgloss.Color("196"), // Red Muted: lipgloss.Color("245"), // Light gray Background: lipgloss.Color(""), // Default terminal background }, } // LightTheme is a green-based light theme var LightTheme = &Theme{ Name: "light", Scheme: ColorScheme{ Primary: lipgloss.Color("34"), // Green Success: lipgloss.Color("36"), // Teal Warning: lipgloss.Color("214"), // Amber Error: lipgloss.Color("196"), // Red Muted: lipgloss.Color("244"), // Gray Background: lipgloss.Color(""), // Default terminal background }, } // DraculaTheme is the popular Dracula dark color scheme var DraculaTheme = &Theme{ Name: "dracula", Scheme: ColorScheme{ Primary: lipgloss.Color("#BD93F9"), // Purple Success: lipgloss.Color("#50FA7B"), // Green Warning: lipgloss.Color("#FFB86C"), // Orange Error: lipgloss.Color("#FF5555"), // Red Muted: lipgloss.Color("#6272A4"), // Light purple-gray Background: lipgloss.Color("#282A36"), // Dark background }, } // EverforestTheme is the natural Everforest dark color scheme var EverforestTheme = &Theme{ Name: "everforest", Scheme: ColorScheme{ Primary: lipgloss.Color("#7fbbb3"), // Blue Success: lipgloss.Color("#a7c080"), // Green Warning: lipgloss.Color("#dbbc7f"), // Yellow Error: lipgloss.Color("#e67e80"), // Red Muted: lipgloss.Color("#414b50"), // Gray Background: lipgloss.Color("#272e33"), // Dark background }, } // ThemeRegistry holds all available themes var ThemeRegistry = map[string]*Theme{ "default": DefaultTheme, "dark": DarkTheme, "light": LightTheme, "dracula": DraculaTheme, "everforest": EverforestTheme, } // GetTheme loads the theme from config or environment variable // Returns the default theme if no theme is specified func GetTheme() (*Theme, error) { once.Do(func() { // Try to get theme from environment variable first themeName := os.Getenv("THEME") if themeName == "" { themeName = "everforest" } // Look up the theme in the registry if theme, ok := ThemeRegistry[themeName]; ok { currentTheme = theme } else { // If theme not found, use everforest as default currentTheme = EverforestTheme } // Apply the theme to initialize styles ApplyTheme(currentTheme) }) return currentTheme, nil } // ApplyTheme applies the given theme to all global styles func ApplyTheme(theme *Theme) { currentTheme = theme // Primary style StylePrimary = lipgloss.NewStyle(). Foreground(theme.Scheme.Primary) // Success style StyleSuccess = lipgloss.NewStyle(). Foreground(theme.Scheme.Success) // Warning style StyleWarning = lipgloss.NewStyle(). Foreground(theme.Scheme.Warning) // Error style StyleError = lipgloss.NewStyle(). Foreground(theme.Scheme.Error) // Muted style StyleMuted = lipgloss.NewStyle(). Foreground(theme.Scheme.Muted) // Title style (bold primary) StyleTitle = lipgloss.NewStyle(). Foreground(theme.Scheme.Primary). Bold(true) // Subtitle style (muted) StyleSubtitle = lipgloss.NewStyle(). Foreground(theme.Scheme.Muted) // Help key style (bold primary, slightly different shade) StyleHelpKey = lipgloss.NewStyle(). Foreground(theme.Scheme.Primary). Bold(true) } // GetThemeNames returns a list of available theme names func GetThemeNames() []string { names := make([]string, 0, len(ThemeRegistry)) for name := range ThemeRegistry { names = append(names, name) } return names } // SetTheme changes the current theme by name func SetTheme(name string) error { theme, ok := ThemeRegistry[name] if !ok { return fmt.Errorf("theme '%s' not found. Available themes: %v", name, GetThemeNames()) } ApplyTheme(theme) return nil } // GetCurrentTheme returns the currently active theme func GetCurrentTheme() *Theme { if currentTheme == nil { currentTheme = DefaultTheme ApplyTheme(currentTheme) } return currentTheme } // GetColorScheme returns the color scheme of the current theme func GetColorScheme() ColorScheme { return GetCurrentTheme().Scheme }