- Add DraculaTheme with official Dracula color palette - Add EverforestTheme with natural Everforest dark color scheme - Set Everforest as default theme (was 'default') - Update README with theming documentation and THEME env var usage - Build verified successfully
214 lines
5.5 KiB
Go
214 lines
5.5 KiB
Go
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
|
|
}
|