fix(ui): implement reactive font configuration and improve workspace styling
- commit
- 202ebb859df33479b45596b50197f990dcb4f928
- author
- brice · · 2025-12-22 20:12 UTC
- committer
- brice · · 2025-12-22 19:10 UTC
- parent
- a6d8f47
- signature
- unsigned
4 files · +80 -12
M internal/ui/component/workspace_view_test.go +2 -0
| @@ -147,6 +147,7 @@ func TestSetWorkspace_SinglePane_CreatesPaneView(t *testing.T) { | |||
| 147 | 147 | ||
| 148 | 148 | mockStackBox.EXPECT().SetVisible(true).Once() | |
| 149 | 149 | mockBox.EXPECT().Append(mockStackBox).Once() | |
| 150 | + | mockBox.EXPECT().AddCssClass("single-pane").Once() | |
| 150 | 151 | mockBorderBox.EXPECT().AddCssClass("pane-active").Once() | |
| 151 | 152 | ||
| 152 | 153 | pane := entity.NewPane(entity.PaneID("pane-1")) | |
| @@ -204,6 +205,7 @@ func TestSetActivePaneID_UpdatesStyling(t *testing.T) { | |||
| 204 | 205 | mockBox.EXPECT().Append(mockPaned).Once() | |
| 205 | 206 | ||
| 206 | 207 | // Initial active pane is pane-1 | |
| 208 | + | mockBox.EXPECT().RemoveCssClass("single-pane").Once() | |
| 207 | 209 | mockBorderBox1.EXPECT().AddCssClass("pane-active").Once() | |
| 208 | 210 | ||
| 209 | 211 | splitNode := &entity.PaneNode{ | |
| @@ -147,6 +147,7 @@ func TestSetWorkspace_SinglePane_CreatesPaneView(t *testing.T) { | |||||
| 147 | 147 | ||||
| 148 | mockStackBox.EXPECT().SetVisible(true).Once() | 148 | mockStackBox.EXPECT().SetVisible(true).Once() | ||
| 149 | mockBox.EXPECT().Append(mockStackBox).Once() | 149 | mockBox.EXPECT().Append(mockStackBox).Once() | ||
| 150 | + | mockBox.EXPECT().AddCssClass("single-pane").Once() | |||
| 150 | mockBorderBox.EXPECT().AddCssClass("pane-active").Once() | 151 | mockBorderBox.EXPECT().AddCssClass("pane-active").Once() | ||
| 151 | 152 | ||||
| 152 | pane := entity.NewPane(entity.PaneID("pane-1")) | 153 | pane := entity.NewPane(entity.PaneID("pane-1")) | ||
| @@ -204,6 +205,7 @@ func TestSetActivePaneID_UpdatesStyling(t *testing.T) { | |||||
| 204 | mockBox.EXPECT().Append(mockPaned).Once() | 205 | mockBox.EXPECT().Append(mockPaned).Once() | ||
| 205 | 206 | ||||
| 206 | // Initial active pane is pane-1 | 207 | // Initial active pane is pane-1 | ||
| 208 | + | mockBox.EXPECT().RemoveCssClass("single-pane").Once() | |||
| 207 | mockBorderBox1.EXPECT().AddCssClass("pane-active").Once() | 209 | mockBorderBox1.EXPECT().AddCssClass("pane-active").Once() | ||
| 208 | 210 | ||||
| 209 | splitNode := &entity.PaneNode{ | 211 | splitNode := &entity.PaneNode{ | ||
M internal/ui/theme/css.go +49 -1
| @@ -14,18 +14,66 @@ func GenerateCSS(p Palette) string { | |||
| 14 | 14 | // GenerateCSSWithScale creates GTK4 CSS using the provided palette and UI scale factor. | |
| 15 | 15 | // Scale affects font sizes and widget padding/margins proportionally. | |
| 16 | 16 | func GenerateCSSWithScale(p Palette, scale float64) string { | |
| 17 | + | return GenerateCSSWithScaleAndFonts(p, scale, DefaultFontConfig()) | |
| 18 | + | } | |
| 19 | + | ||
| 20 | + | // FontConfig holds font settings for CSS generation. | |
| 21 | + | type FontConfig struct { | |
| 22 | + | SansFont string | |
| 23 | + | MonospaceFont string | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | // DefaultFontConfig returns safe font fallbacks. | |
| 27 | + | func DefaultFontConfig() FontConfig { | |
| 28 | + | return FontConfig{ | |
| 29 | + | SansFont: "sans-serif", | |
| 30 | + | MonospaceFont: "monospace", | |
| 31 | + | } | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | // FontCSSVars generates CSS custom properties for fonts. | |
| 35 | + | func FontCSSVars(fonts FontConfig) string { | |
| 36 | + | var sb strings.Builder | |
| 37 | + | // Quote the configured family; include generic fallback. | |
| 38 | + | sb.WriteString(fmt.Sprintf(" --font-sans: \"%s\", sans-serif;\n", fonts.SansFont)) | |
| 39 | + | sb.WriteString(fmt.Sprintf(" --font-mono: \"%s\", monospace;\n", fonts.MonospaceFont)) | |
| 40 | + | return sb.String() | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | func generateFontCSS() string { | |
| 44 | + | return `/* Font styling */ | |
| 45 | + | window, tooltip, popover { | |
| 46 | + | font-family: var(--font-sans); | |
| 47 | + | } | |
| 48 | + | ` | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // GenerateCSSWithScaleAndFonts creates GTK4 CSS using the provided palette, UI scale factor and fonts. | |
| 52 | + | // Scale affects font sizes and widget padding/margins proportionally. | |
| 53 | + | func GenerateCSSWithScaleAndFonts(p Palette, scale float64, fonts FontConfig) string { | |
| 17 | 54 | if scale <= 0 { | |
| 18 | 55 | scale = 1.0 | |
| 19 | 56 | } | |
| 20 | 57 | ||
| 58 | + | defaults := DefaultFontConfig() | |
| 59 | + | fonts = FontConfig{ | |
| 60 | + | SansFont: Coalesce(fonts.SansFont, defaults.SansFont), | |
| 61 | + | MonospaceFont: Coalesce(fonts.MonospaceFont, defaults.MonospaceFont), | |
| 62 | + | } | |
| 63 | + | ||
| 21 | 64 | var sb strings.Builder | |
| 22 | 65 | ||
| 23 | 66 | // CSS custom properties (variables) - GTK4 uses :root selector | |
| 24 | 67 | sb.WriteString("/* Theme variables */\n") | |
| 25 | 68 | sb.WriteString(":root {\n") | |
| 26 | 69 | sb.WriteString(p.ToCSSVars()) | |
| 70 | + | sb.WriteString(FontCSSVars(fonts)) | |
| 27 | 71 | sb.WriteString("}\n\n") | |
| 28 | 72 | ||
| 73 | + | // Global font styling | |
| 74 | + | sb.WriteString(generateFontCSS()) | |
| 75 | + | sb.WriteString("\n") | |
| 76 | + | ||
| 29 | 77 | // Global UI scaling via font-size on all widgets | |
| 30 | 78 | if scale != 1.0 { | |
| 31 | 79 | sb.WriteString(generateScalingCSS(scale)) | |
| @@ -274,7 +322,7 @@ entry.omnibox-entry > *:focus-visible { | |||
| 274 | 322 | padding: 0.125em 0.375em; | |
| 275 | 323 | font-size: 0.625em; | |
| 276 | 324 | font-weight: 500; | |
| 277 | - | font-family: monospace; | |
| 325 | + | font-family: var(--font-mono); | |
| 278 | 326 | margin-left: 0.5em; | |
| 279 | 327 | } | |
| 280 | 328 | ||
| @@ -14,18 +14,66 @@ func GenerateCSS(p Palette) string { | |||||
| 14 | // GenerateCSSWithScale creates GTK4 CSS using the provided palette and UI scale factor. | 14 | // GenerateCSSWithScale creates GTK4 CSS using the provided palette and UI scale factor. | ||
| 15 | // Scale affects font sizes and widget padding/margins proportionally. | 15 | // Scale affects font sizes and widget padding/margins proportionally. | ||
| 16 | func GenerateCSSWithScale(p Palette, scale float64) string { | 16 | func GenerateCSSWithScale(p Palette, scale float64) string { | ||
| 17 | + | return GenerateCSSWithScaleAndFonts(p, scale, DefaultFontConfig()) | |||
| 18 | + | } | |||
| 19 | + | ||||
| 20 | + | // FontConfig holds font settings for CSS generation. | |||
| 21 | + | type FontConfig struct { | |||
| 22 | + | SansFont string | |||
| 23 | + | MonospaceFont string | |||
| 24 | + | } | |||
| 25 | + | ||||
| 26 | + | // DefaultFontConfig returns safe font fallbacks. | |||
| 27 | + | func DefaultFontConfig() FontConfig { | |||
| 28 | + | return FontConfig{ | |||
| 29 | + | SansFont: "sans-serif", | |||
| 30 | + | MonospaceFont: "monospace", | |||
| 31 | + | } | |||
| 32 | + | } | |||
| 33 | + | ||||
| 34 | + | // FontCSSVars generates CSS custom properties for fonts. | |||
| 35 | + | func FontCSSVars(fonts FontConfig) string { | |||
| 36 | + | var sb strings.Builder | |||
| 37 | + | // Quote the configured family; include generic fallback. | |||
| 38 | + | sb.WriteString(fmt.Sprintf(" --font-sans: \"%s\", sans-serif;\n", fonts.SansFont)) | |||
| 39 | + | sb.WriteString(fmt.Sprintf(" --font-mono: \"%s\", monospace;\n", fonts.MonospaceFont)) | |||
| 40 | + | return sb.String() | |||
| 41 | + | } | |||
| 42 | + | ||||
| 43 | + | func generateFontCSS() string { | |||
| 44 | + | return `/* Font styling */ | |||
| 45 | + | window, tooltip, popover { | |||
| 46 | + | font-family: var(--font-sans); | |||
| 47 | + | } | |||
| 48 | + | ` | |||
| 49 | + | } | |||
| 50 | + | ||||
| 51 | + | // GenerateCSSWithScaleAndFonts creates GTK4 CSS using the provided palette, UI scale factor and fonts. | |||
| 52 | + | // Scale affects font sizes and widget padding/margins proportionally. | |||
| 53 | + | func GenerateCSSWithScaleAndFonts(p Palette, scale float64, fonts FontConfig) string { | |||
| 17 | if scale <= 0 { | 54 | if scale <= 0 { | ||
| 18 | scale = 1.0 | 55 | scale = 1.0 | ||
| 19 | } | 56 | } | ||
| 20 | 57 | ||||
| 58 | + | defaults := DefaultFontConfig() | |||
| 59 | + | fonts = FontConfig{ | |||
| 60 | + | SansFont: Coalesce(fonts.SansFont, defaults.SansFont), | |||
| 61 | + | MonospaceFont: Coalesce(fonts.MonospaceFont, defaults.MonospaceFont), | |||
| 62 | + | } | |||
| 63 | + | ||||
| 21 | var sb strings.Builder | 64 | var sb strings.Builder | ||
| 22 | 65 | ||||
| 23 | // CSS custom properties (variables) - GTK4 uses :root selector | 66 | // CSS custom properties (variables) - GTK4 uses :root selector | ||
| 24 | sb.WriteString("/* Theme variables */\n") | 67 | sb.WriteString("/* Theme variables */\n") | ||
| 25 | sb.WriteString(":root {\n") | 68 | sb.WriteString(":root {\n") | ||
| 26 | sb.WriteString(p.ToCSSVars()) | 69 | sb.WriteString(p.ToCSSVars()) | ||
| 70 | + | sb.WriteString(FontCSSVars(fonts)) | |||
| 27 | sb.WriteString("}\n\n") | 71 | sb.WriteString("}\n\n") | ||
| 28 | 72 | ||||
| 73 | + | // Global font styling | |||
| 74 | + | sb.WriteString(generateFontCSS()) | |||
| 75 | + | sb.WriteString("\n") | |||
| 76 | + | ||||
| 29 | // Global UI scaling via font-size on all widgets | 77 | // Global UI scaling via font-size on all widgets | ||
| 30 | if scale != 1.0 { | 78 | if scale != 1.0 { | ||
| 31 | sb.WriteString(generateScalingCSS(scale)) | 79 | sb.WriteString(generateScalingCSS(scale)) | ||
| @@ -274,7 +322,7 @@ entry.omnibox-entry > *:focus-visible { | |||||
| 274 | padding: 0.125em 0.375em; | 322 | padding: 0.125em 0.375em; | ||
| 275 | font-size: 0.625em; | 323 | font-size: 0.625em; | ||
| 276 | font-weight: 500; | 324 | font-weight: 500; | ||
| 277 | - | font-family: monospace; | 325 | + | font-family: var(--font-mono); |
| 278 | margin-left: 0.5em; | 326 | margin-left: 0.5em; | ||
| 279 | } | 327 | } | ||
| 280 | 328 | ||||
M internal/ui/theme/manager.go +20 -2
| @@ -17,6 +17,7 @@ type Manager struct { | |||
| 17 | 17 | lightPalette Palette // Light theme colors | |
| 18 | 18 | darkPalette Palette // Dark theme colors | |
| 19 | 19 | uiScale float64 // UI scaling factor (1.0 = 100%) | |
| 20 | + | fonts FontConfig | |
| 20 | 21 | cssProvider *gtk.CssProvider | |
| 21 | 22 | } | |
| 22 | 23 | ||
| @@ -49,10 +50,18 @@ func NewManager(ctx context.Context, cfg *config.Config) *Manager { | |||
| 49 | 50 | uiScale = cfg.DefaultUIScale | |
| 50 | 51 | } | |
| 51 | 52 | ||
| 53 | + | fonts := DefaultFontConfig() | |
| 54 | + | if cfg != nil { | |
| 55 | + | fonts.SansFont = Coalesce(cfg.Appearance.SansFont, fonts.SansFont) | |
| 56 | + | fonts.MonospaceFont = Coalesce(cfg.Appearance.MonospaceFont, fonts.MonospaceFont) | |
| 57 | + | } | |
| 58 | + | ||
| 52 | 59 | log.Debug(). | |
| 53 | 60 | Str("scheme", scheme). | |
| 54 | 61 | Bool("prefers_dark", prefersDark). | |
| 55 | 62 | Float64("ui_scale", uiScale). | |
| 63 | + | Str("sans_font", fonts.SansFont). | |
| 64 | + | Str("monospace_font", fonts.MonospaceFont). | |
| 56 | 65 | Msg("theme manager initialized") | |
| 57 | 66 | ||
| 58 | 67 | return &Manager{ | |
| @@ -61,6 +70,7 @@ func NewManager(ctx context.Context, cfg *config.Config) *Manager { | |||
| 61 | 70 | lightPalette: lightPalette, | |
| 62 | 71 | darkPalette: darkPalette, | |
| 63 | 72 | uiScale: uiScale, | |
| 73 | + | fonts: fonts, | |
| 64 | 74 | } | |
| 65 | 75 | } | |
| 66 | 76 | ||
| @@ -104,9 +114,9 @@ func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) { | |||
| 104 | 114 | return | |
| 105 | 115 | } | |
| 106 | 116 | ||
| 107 | - | // Generate CSS with current palette and UI scale | |
| 117 | + | // Generate CSS with current palette, UI scale and fonts | |
| 108 | 118 | palette := m.GetCurrentPalette() | |
| 109 | - | css := GenerateCSSWithScale(palette, m.uiScale) | |
| 119 | + | css := GenerateCSSWithScaleAndFonts(palette, m.uiScale, m.fonts) | |
| 110 | 120 | ||
| 111 | 121 | // Create CSS provider if needed | |
| 112 | 122 | if m.cssProvider == nil { | |
| @@ -174,10 +184,18 @@ func (m *Manager) UpdateFromConfig(ctx context.Context, cfg *config.Config, disp | |||
| 174 | 184 | m.uiScale = cfg.DefaultUIScale | |
| 175 | 185 | } | |
| 176 | 186 | ||
| 187 | + | defaults := DefaultFontConfig() | |
| 188 | + | m.fonts = FontConfig{ | |
| 189 | + | SansFont: Coalesce(cfg.Appearance.SansFont, defaults.SansFont), | |
| 190 | + | MonospaceFont: Coalesce(cfg.Appearance.MonospaceFont, defaults.MonospaceFont), | |
| 191 | + | } | |
| 192 | + | ||
| 177 | 193 | log.Info(). | |
| 178 | 194 | Str("scheme", m.scheme). | |
| 179 | 195 | Bool("prefers_dark", m.prefersDark). | |
| 180 | 196 | Float64("ui_scale", m.uiScale). | |
| 197 | + | Str("sans_font", m.fonts.SansFont). | |
| 198 | + | Str("monospace_font", m.fonts.MonospaceFont). | |
| 181 | 199 | Msg("theme manager updated from config") | |
| 182 | 200 | ||
| 183 | 201 | // Re-apply CSS if display is available | |
| @@ -17,6 +17,7 @@ type Manager struct { | |||||
| 17 | lightPalette Palette // Light theme colors | 17 | lightPalette Palette // Light theme colors | ||
| 18 | darkPalette Palette // Dark theme colors | 18 | darkPalette Palette // Dark theme colors | ||
| 19 | uiScale float64 // UI scaling factor (1.0 = 100%) | 19 | uiScale float64 // UI scaling factor (1.0 = 100%) | ||
| 20 | + | fonts FontConfig | |||
| 20 | cssProvider *gtk.CssProvider | 21 | cssProvider *gtk.CssProvider | ||
| 21 | } | 22 | } | ||
| 22 | 23 | ||||
| @@ -49,10 +50,18 @@ func NewManager(ctx context.Context, cfg *config.Config) *Manager { | |||||
| 49 | uiScale = cfg.DefaultUIScale | 50 | uiScale = cfg.DefaultUIScale | ||
| 50 | } | 51 | } | ||
| 51 | 52 | ||||
| 53 | + | fonts := DefaultFontConfig() | |||
| 54 | + | if cfg != nil { | |||
| 55 | + | fonts.SansFont = Coalesce(cfg.Appearance.SansFont, fonts.SansFont) | |||
| 56 | + | fonts.MonospaceFont = Coalesce(cfg.Appearance.MonospaceFont, fonts.MonospaceFont) | |||
| 57 | + | } | |||
| 58 | + | ||||
| 52 | log.Debug(). | 59 | log.Debug(). | ||
| 53 | Str("scheme", scheme). | 60 | Str("scheme", scheme). | ||
| 54 | Bool("prefers_dark", prefersDark). | 61 | Bool("prefers_dark", prefersDark). | ||
| 55 | Float64("ui_scale", uiScale). | 62 | Float64("ui_scale", uiScale). | ||
| 63 | + | Str("sans_font", fonts.SansFont). | |||
| 64 | + | Str("monospace_font", fonts.MonospaceFont). | |||
| 56 | Msg("theme manager initialized") | 65 | Msg("theme manager initialized") | ||
| 57 | 66 | ||||
| 58 | return &Manager{ | 67 | return &Manager{ | ||
| @@ -61,6 +70,7 @@ func NewManager(ctx context.Context, cfg *config.Config) *Manager { | |||||
| 61 | lightPalette: lightPalette, | 70 | lightPalette: lightPalette, | ||
| 62 | darkPalette: darkPalette, | 71 | darkPalette: darkPalette, | ||
| 63 | uiScale: uiScale, | 72 | uiScale: uiScale, | ||
| 73 | + | fonts: fonts, | |||
| 64 | } | 74 | } | ||
| 65 | } | 75 | } | ||
| 66 | 76 | ||||
| @@ -104,9 +114,9 @@ func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) { | |||||
| 104 | return | 114 | return | ||
| 105 | } | 115 | } | ||
| 106 | 116 | ||||
| 107 | - | // Generate CSS with current palette and UI scale | 117 | + | // Generate CSS with current palette, UI scale and fonts |
| 108 | palette := m.GetCurrentPalette() | 118 | palette := m.GetCurrentPalette() | ||
| 109 | - | css := GenerateCSSWithScale(palette, m.uiScale) | 119 | + | css := GenerateCSSWithScaleAndFonts(palette, m.uiScale, m.fonts) |
| 110 | 120 | ||||
| 111 | // Create CSS provider if needed | 121 | // Create CSS provider if needed | ||
| 112 | if m.cssProvider == nil { | 122 | if m.cssProvider == nil { | ||
| @@ -174,10 +184,18 @@ func (m *Manager) UpdateFromConfig(ctx context.Context, cfg *config.Config, disp | |||||
| 174 | m.uiScale = cfg.DefaultUIScale | 184 | m.uiScale = cfg.DefaultUIScale | ||
| 175 | } | 185 | } | ||
| 176 | 186 | ||||
| 187 | + | defaults := DefaultFontConfig() | |||
| 188 | + | m.fonts = FontConfig{ | |||
| 189 | + | SansFont: Coalesce(cfg.Appearance.SansFont, defaults.SansFont), | |||
| 190 | + | MonospaceFont: Coalesce(cfg.Appearance.MonospaceFont, defaults.MonospaceFont), | |||
| 191 | + | } | |||
| 192 | + | ||||
| 177 | log.Info(). | 193 | log.Info(). | ||
| 178 | Str("scheme", m.scheme). | 194 | Str("scheme", m.scheme). | ||
| 179 | Bool("prefers_dark", m.prefersDark). | 195 | Bool("prefers_dark", m.prefersDark). | ||
| 180 | Float64("ui_scale", m.uiScale). | 196 | Float64("ui_scale", m.uiScale). | ||
| 197 | + | Str("sans_font", m.fonts.SansFont). | |||
| 198 | + | Str("monospace_font", m.fonts.MonospaceFont). | |||
| 181 | Msg("theme manager updated from config") | 199 | Msg("theme manager updated from config") | ||
| 182 | 200 | ||||
| 183 | // Re-apply CSS if display is available | 201 | // Re-apply CSS if display is available | ||
M internal/ui/theme/palette.go +9 -9
| @@ -70,13 +70,13 @@ func PaletteFromConfig(cfg *config.ColorPalette, isDark bool) Palette { | |||
| 70 | 70 | } | |
| 71 | 71 | ||
| 72 | 72 | return Palette{ | |
| 73 | - | Background: coalesce(cfg.Background, defaults.Background), | |
| 74 | - | Surface: coalesce(cfg.Surface, defaults.Surface), | |
| 75 | - | SurfaceVariant: coalesce(cfg.SurfaceVariant, defaults.SurfaceVariant), | |
| 76 | - | Text: coalesce(cfg.Text, defaults.Text), | |
| 77 | - | Muted: coalesce(cfg.Muted, defaults.Muted), | |
| 78 | - | Accent: coalesce(cfg.Accent, defaults.Accent), | |
| 79 | - | Border: coalesce(cfg.Border, defaults.Border), | |
| 73 | + | Background: Coalesce(cfg.Background, defaults.Background), | |
| 74 | + | Surface: Coalesce(cfg.Surface, defaults.Surface), | |
| 75 | + | SurfaceVariant: Coalesce(cfg.SurfaceVariant, defaults.SurfaceVariant), | |
| 76 | + | Text: Coalesce(cfg.Text, defaults.Text), | |
| 77 | + | Muted: Coalesce(cfg.Muted, defaults.Muted), | |
| 78 | + | Accent: Coalesce(cfg.Accent, defaults.Accent), | |
| 79 | + | Border: Coalesce(cfg.Border, defaults.Border), | |
| 80 | 80 | // Semantic colors always use defaults (not user-editable) | |
| 81 | 81 | Success: defaults.Success, | |
| 82 | 82 | Warning: defaults.Warning, | |
| @@ -84,8 +84,8 @@ func PaletteFromConfig(cfg *config.ColorPalette, isDark bool) Palette { | |||
| 84 | 84 | } | |
| 85 | 85 | } | |
| 86 | 86 | ||
| 87 | - | // coalesce returns the first non-empty string. | |
| 88 | - | func coalesce(values ...string) string { | |
| 87 | + | // Coalesce returns the first non-empty string. | |
| 88 | + | func Coalesce(values ...string) string { | |
| 89 | 89 | for _, v := range values { | |
| 90 | 90 | if v != "" { | |
| 91 | 91 | return v | |
| @@ -70,13 +70,13 @@ func PaletteFromConfig(cfg *config.ColorPalette, isDark bool) Palette { | |||||
| 70 | } | 70 | } | ||
| 71 | 71 | ||||
| 72 | return Palette{ | 72 | return Palette{ | ||
| 73 | - | Background: coalesce(cfg.Background, defaults.Background), | 73 | + | Background: Coalesce(cfg.Background, defaults.Background), |
| 74 | - | Surface: coalesce(cfg.Surface, defaults.Surface), | 74 | + | Surface: Coalesce(cfg.Surface, defaults.Surface), |
| 75 | - | SurfaceVariant: coalesce(cfg.SurfaceVariant, defaults.SurfaceVariant), | 75 | + | SurfaceVariant: Coalesce(cfg.SurfaceVariant, defaults.SurfaceVariant), |
| 76 | - | Text: coalesce(cfg.Text, defaults.Text), | 76 | + | Text: Coalesce(cfg.Text, defaults.Text), |
| 77 | - | Muted: coalesce(cfg.Muted, defaults.Muted), | 77 | + | Muted: Coalesce(cfg.Muted, defaults.Muted), |
| 78 | - | Accent: coalesce(cfg.Accent, defaults.Accent), | 78 | + | Accent: Coalesce(cfg.Accent, defaults.Accent), |
| 79 | - | Border: coalesce(cfg.Border, defaults.Border), | 79 | + | Border: Coalesce(cfg.Border, defaults.Border), |
| 80 | // Semantic colors always use defaults (not user-editable) | 80 | // Semantic colors always use defaults (not user-editable) | ||
| 81 | Success: defaults.Success, | 81 | Success: defaults.Success, | ||
| 82 | Warning: defaults.Warning, | 82 | Warning: defaults.Warning, | ||
| @@ -84,8 +84,8 @@ func PaletteFromConfig(cfg *config.ColorPalette, isDark bool) Palette { | |||||
| 84 | } | 84 | } | ||
| 85 | } | 85 | } | ||
| 86 | 86 | ||||
| 87 | - | // coalesce returns the first non-empty string. | 87 | + | // Coalesce returns the first non-empty string. |
| 88 | - | func coalesce(values ...string) string { | 88 | + | func Coalesce(values ...string) string { |
| 89 | for _, v := range values { | 89 | for _, v := range values { | ||
| 90 | if v != "" { | 90 | if v != "" { | ||
| 91 | return v | 91 | return v | ||