detached 98b0069

feat(config): add color_scheme setting to appearance config

commit
98b0069696cbe5cabf561864d9958ef1f3af6ef9
author
bnema · · 2025-10-23 20:56 UTC
parent
2d1ce89
signature
unsigned
2 files · +28 -0
M internal/config/config.go +27 -0
@@ -124,6 +124,8 @@ type AppearanceConfig struct {
124124 DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`
125125 LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"`
126126 DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"`
127+ // ColorScheme controls the initial theme preference: "prefer-dark", "prefer-light", or "default" (follows system)
128+ ColorScheme string `mapstructure:"color_scheme" yaml:"color_scheme"`
127129 }
128130
129131 // ColorPalette contains semantic color tokens for light/dark themes.
@@ -545,6 +547,9 @@ func (m *Manager) Load() error {
545547 // Validate and configure codec preferences
546548 config = m.validateAndConfigureCodecPreferences(config)
547549
550+ // Validate ColorScheme setting
551+ m.validateColorScheme(config)
552+
548553 m.config = config
549554 return nil
550555 }
@@ -643,6 +648,9 @@ func (m *Manager) reload() error {
643648 // Validate and configure codec preferences
644649 config = m.validateAndConfigureCodecPreferences(config)
645650
651+ // Validate ColorScheme setting
652+ m.validateColorScheme(config)
653+
646654 m.config = config
647655 return nil
648656 }
@@ -713,6 +721,7 @@ func (m *Manager) setDefaults() {
713721 m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize)
714722 m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette)
715723 m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette)
724+ m.viper.SetDefault("appearance.color_scheme", defaults.Appearance.ColorScheme)
716725
717726 // Video acceleration defaults
718727 m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI)
@@ -894,3 +903,21 @@ func (m *Manager) validateAndConfigureCodecPreferences(config *Config) *Config {
894903
895904 return config
896905 }
906+
907+// validateColorScheme validates and normalizes the ColorScheme setting
908+func (m *Manager) validateColorScheme(config *Config) {
909+ switch config.Appearance.ColorScheme {
910+ case "prefer-dark", "prefer-light", "default", "":
911+ // Valid values - no changes needed
912+ // Empty string is treated the same as "default"
913+ if config.Appearance.ColorScheme == "" {
914+ config.Appearance.ColorScheme = "default"
915+ logging.Info("Config: ColorScheme not set, defaulting to 'default' (follows system)")
916+ }
917+ default:
918+ // Invalid value - warn and reset to default
919+ logging.Info(fmt.Sprintf("Config: Invalid color_scheme value '%s', valid values are: 'prefer-dark', 'prefer-light', 'default'. Resetting to 'default'",
920+ config.Appearance.ColorScheme))
921+ config.Appearance.ColorScheme = "default"
922+ }
923+}
@@ -124,6 +124,8 @@ type AppearanceConfig struct {
124 DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`124 DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`
125 LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"`125 LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"`
126 DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"`126 DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"`
127+ // ColorScheme controls the initial theme preference: "prefer-dark", "prefer-light", or "default" (follows system)
128+ ColorScheme string `mapstructure:"color_scheme" yaml:"color_scheme"`
127 }129 }
128 130
129 // ColorPalette contains semantic color tokens for light/dark themes.131 // ColorPalette contains semantic color tokens for light/dark themes.
@@ -545,6 +547,9 @@ func (m *Manager) Load() error {
545 // Validate and configure codec preferences547 // Validate and configure codec preferences
546 config = m.validateAndConfigureCodecPreferences(config)548 config = m.validateAndConfigureCodecPreferences(config)
547 549
550+ // Validate ColorScheme setting
551+ m.validateColorScheme(config)
552+
548 m.config = config553 m.config = config
549 return nil554 return nil
550 }555 }
@@ -643,6 +648,9 @@ func (m *Manager) reload() error {
643 // Validate and configure codec preferences648 // Validate and configure codec preferences
644 config = m.validateAndConfigureCodecPreferences(config)649 config = m.validateAndConfigureCodecPreferences(config)
645 650
651+ // Validate ColorScheme setting
652+ m.validateColorScheme(config)
653+
646 m.config = config654 m.config = config
647 return nil655 return nil
648 }656 }
@@ -713,6 +721,7 @@ func (m *Manager) setDefaults() {
713 m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize)721 m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize)
714 m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette)722 m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette)
715 m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette)723 m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette)
724+ m.viper.SetDefault("appearance.color_scheme", defaults.Appearance.ColorScheme)
716 725
717 // Video acceleration defaults726 // Video acceleration defaults
718 m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI)727 m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI)
@@ -894,3 +903,21 @@ func (m *Manager) validateAndConfigureCodecPreferences(config *Config) *Config {
894 903
895 return config904 return config
896 }905 }
906+
907+// validateColorScheme validates and normalizes the ColorScheme setting
908+func (m *Manager) validateColorScheme(config *Config) {
909+ switch config.Appearance.ColorScheme {
910+ case "prefer-dark", "prefer-light", "default", "":
911+ // Valid values - no changes needed
912+ // Empty string is treated the same as "default"
913+ if config.Appearance.ColorScheme == "" {
914+ config.Appearance.ColorScheme = "default"
915+ logging.Info("Config: ColorScheme not set, defaulting to 'default' (follows system)")
916+ }
917+ default:
918+ // Invalid value - warn and reset to default
919+ logging.Info(fmt.Sprintf("Config: Invalid color_scheme value '%s', valid values are: 'prefer-dark', 'prefer-light', 'default'. Resetting to 'default'",
920+ config.Appearance.ColorScheme))
921+ config.Appearance.ColorScheme = "default"
922+ }
923+}
M internal/config/defaults.go +1 -0
@@ -112,6 +112,7 @@ func DefaultConfig() *Config {
112112 Accent: "#a8a8a8",
113113 Border: "#363636",
114114 },
115+ ColorScheme: "default", // default follows system theme
115116 },
116117 VideoAcceleration: VideoAccelerationConfig{
117118 EnableVAAPI: true,
@@ -112,6 +112,7 @@ func DefaultConfig() *Config {
112 Accent: "#a8a8a8",112 Accent: "#a8a8a8",
113 Border: "#363636",113 Border: "#363636",
114 },114 },
115+ ColorScheme: "default", // default follows system theme
115 },116 },
116 VideoAcceleration: VideoAccelerationConfig{117 VideoAcceleration: VideoAccelerationConfig{
117 EnableVAAPI: true,118 EnableVAAPI: true,

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close