detached 135779d

feat(config): add color palettes and update default search shortcuts

- Add ColorPalette struct with semantic color tokens (background, surface, text, muted, accent, border)
- Add light and dark palette configurations to AppearanceConfig
- Refactor search shortcuts to use GetDefaultSearchShortcuts() function
- Update default shortcuts: add ddg, go, mdn, npm, remove/reorder others
- Update Chrome user agent to version 141.0.0.0
- Set viper defaults for new palette configurations
commit
135779d50057193fc4b08aab140790b8b209d2ed
author
bamen · · 2025-10-06 17:02 UTC
committer
bamen · · 2025-10-06 16:13 UTC
parent
a36e3e7
signature
unsigned
2 files · +59 -42
M internal/config/config.go +17 -1
@@ -118,7 +118,20 @@ type AppearanceConfig struct {
118118 SerifFont string `mapstructure:"serif_font" yaml:"serif_font"`
119119 MonospaceFont string `mapstructure:"monospace_font" yaml:"monospace_font"`
120120 // Default font size in CSS pixels (approx).
121- DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`
121+ DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`
122+ LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"`
123+ DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"`
124+}
125+
126+// ColorPalette contains semantic color tokens for light/dark themes.
127+type ColorPalette struct {
128+ Background string `mapstructure:"background" yaml:"background" json:"background"`
129+ Surface string `mapstructure:"surface" yaml:"surface" json:"surface"`
130+ SurfaceVariant string `mapstructure:"surface_variant" yaml:"surface_variant" json:"surface_variant"`
131+ Text string `mapstructure:"text" yaml:"text" json:"text"`
132+ Muted string `mapstructure:"muted" yaml:"muted" json:"muted"`
133+ Accent string `mapstructure:"accent" yaml:"accent" json:"accent"`
134+ Border string `mapstructure:"border" yaml:"border" json:"border"`
122135 }
123136
124137 // VideoAccelerationConfig holds video hardware acceleration preferences.
@@ -665,6 +678,8 @@ func (m *Manager) setDefaults() {
665678 m.viper.SetDefault("appearance.serif_font", defaults.Appearance.SerifFont)
666679 m.viper.SetDefault("appearance.monospace_font", defaults.Appearance.MonospaceFont)
667680 m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize)
681+ m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette)
682+ m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette)
668683
669684 // Video acceleration defaults
670685 m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI)
@@ -768,6 +783,7 @@ func (m *Manager) createDefaultConfig() error {
768783 defaultConfig := DefaultConfig()
769784
770785 // Marshal to JSON with proper indentation
786+ // Note: Go 1.20+ automatically sorts map keys in JSON output
771787 configData, err := json.MarshalIndent(defaultConfig, "", " ")
772788 if err != nil {
773789 return fmt.Errorf("failed to marshal default config: %w", err)
@@ -118,7 +118,20 @@ type AppearanceConfig struct {
118 SerifFont string `mapstructure:"serif_font" yaml:"serif_font"`118 SerifFont string `mapstructure:"serif_font" yaml:"serif_font"`
119 MonospaceFont string `mapstructure:"monospace_font" yaml:"monospace_font"`119 MonospaceFont string `mapstructure:"monospace_font" yaml:"monospace_font"`
120 // Default font size in CSS pixels (approx).120 // Default font size in CSS pixels (approx).
121- DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`121+ DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"`
122+ LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"`
123+ DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"`
124+}
125+
126+// ColorPalette contains semantic color tokens for light/dark themes.
127+type ColorPalette struct {
128+ Background string `mapstructure:"background" yaml:"background" json:"background"`
129+ Surface string `mapstructure:"surface" yaml:"surface" json:"surface"`
130+ SurfaceVariant string `mapstructure:"surface_variant" yaml:"surface_variant" json:"surface_variant"`
131+ Text string `mapstructure:"text" yaml:"text" json:"text"`
132+ Muted string `mapstructure:"muted" yaml:"muted" json:"muted"`
133+ Accent string `mapstructure:"accent" yaml:"accent" json:"accent"`
134+ Border string `mapstructure:"border" yaml:"border" json:"border"`
122 }135 }
123 136
124 // VideoAccelerationConfig holds video hardware acceleration preferences.137 // VideoAccelerationConfig holds video hardware acceleration preferences.
@@ -665,6 +678,8 @@ func (m *Manager) setDefaults() {
665 m.viper.SetDefault("appearance.serif_font", defaults.Appearance.SerifFont)678 m.viper.SetDefault("appearance.serif_font", defaults.Appearance.SerifFont)
666 m.viper.SetDefault("appearance.monospace_font", defaults.Appearance.MonospaceFont)679 m.viper.SetDefault("appearance.monospace_font", defaults.Appearance.MonospaceFont)
667 m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize)680 m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize)
681+ m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette)
682+ m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette)
668 683
669 // Video acceleration defaults684 // Video acceleration defaults
670 m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI)685 m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI)
@@ -768,6 +783,7 @@ func (m *Manager) createDefaultConfig() error {
768 defaultConfig := DefaultConfig()783 defaultConfig := DefaultConfig()
769 784
770 // Marshal to JSON with proper indentation785 // Marshal to JSON with proper indentation
786+ // Note: Go 1.20+ automatically sorts map keys in JSON output
771 configData, err := json.MarshalIndent(defaultConfig, "", " ")787 configData, err := json.MarshalIndent(defaultConfig, "", " ")
772 if err != nil {788 if err != nil {
773 return fmt.Errorf("failed to marshal default config: %w", err)789 return fmt.Errorf("failed to marshal default config: %w", err)
M internal/config/defaults.go +42 -41
@@ -60,24 +60,7 @@ func DefaultConfig() *Config {
6060 RetentionPeriodDays: defaultRetentionDays, // 1 year
6161 CleanupIntervalDays: 1, // daily cleanup
6262 },
63- SearchShortcuts: map[string]SearchShortcut{
64- "g": {
65- URL: "https://www.google.com/search?q=%s",
66- Description: "Google search",
67- },
68- "gh": {
69- URL: "https://github.com/search?q=%s",
70- Description: "GitHub search",
71- },
72- "yt": {
73- URL: "https://www.youtube.com/results?search_query=%s",
74- Description: "YouTube search",
75- },
76- "w": {
77- URL: "https://en.wikipedia.org/wiki/%s",
78- Description: "Wikipedia search",
79- },
80- },
63+ SearchShortcuts: GetDefaultSearchShortcuts(),
8164 Dmenu: DmenuConfig{
8265 MaxHistoryItems: defaultMaxHistoryItems,
8366 ShowVisitCount: true,
@@ -110,6 +93,24 @@ func DefaultConfig() *Config {
11093 SerifFont: "Fira Sans",
11194 MonospaceFont: "Fira Code",
11295 DefaultFontSize: defaultFontSize,
96+ LightPalette: ColorPalette{
97+ Background: "#f8f8f8",
98+ Surface: "#f2f2f2",
99+ SurfaceVariant: "#ececec",
100+ Text: "#1a1a1a",
101+ Muted: "#6e6e6e",
102+ Accent: "#404040",
103+ Border: "#d2d2d2",
104+ },
105+ DarkPalette: ColorPalette{
106+ Background: "#0e0e0e",
107+ Surface: "#1a1a1a",
108+ SurfaceVariant: "#141414",
109+ Text: "#e4e4e4",
110+ Muted: "#848484",
111+ Accent: "#a8a8a8",
112+ Border: "#363636",
113+ },
113114 },
114115 VideoAcceleration: VideoAccelerationConfig{
115116 EnableVAAPI: true,
@@ -127,7 +128,7 @@ func DefaultConfig() *Config {
127128 DisableVP9Hardware: false, // Allow VP9 hardware for high res content
128129 VideoBufferSizeMB: 16, // Larger buffer for AV1 streams
129130 QueueBufferTimeSec: 10, // More buffering time for smooth playback
130- CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", // Chrome UA with AV1 support
131+ CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", // Chrome UA with AV1 support
131132 AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res
132133 DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)
133134 },
@@ -209,6 +210,10 @@ func DefaultConfig() *Config {
209210 // GetDefaultSearchShortcuts returns the default search shortcuts.
210211 func GetDefaultSearchShortcuts() map[string]SearchShortcut {
211212 return map[string]SearchShortcut{
213+ "ddg": {
214+ URL: "https://duckduckgo.com/?q=%s",
215+ Description: "DuckDuckGo search",
216+ },
212217 "g": {
213218 URL: "https://www.google.com/search?q=%s",
214219 Description: "Google search",
@@ -217,37 +222,33 @@ func GetDefaultSearchShortcuts() map[string]SearchShortcut {
217222 URL: "https://github.com/search?q=%s",
218223 Description: "GitHub search",
219224 },
220- "yt": {
221- URL: "https://www.youtube.com/results?search_query=%s",
222- Description: "YouTube search",
223- },
224- "w": {
225- URL: "https://en.wikipedia.org/wiki/%s",
226- Description: "Wikipedia search",
225+ "go": {
226+ URL: "https://pkg.go.dev/search?q=%s",
227+ Description: "Go package search",
227228 },
228- "ddg": {
229- URL: "https://duckduckgo.com/?q=%s",
230- Description: "DuckDuckGo search",
229+ "mdn": {
230+ URL: "https://developer.mozilla.org/en-US/search?q=%s",
231+ Description: "MDN Web Docs search",
231232 },
232- "so": {
233- URL: "https://stackoverflow.com/search?q=%s",
234- Description: "Stack Overflow search",
233+ "npm": {
234+ URL: "https://www.npmjs.com/search?q=%s",
235+ Description: "npm package search",
235236 },
236237 "r": {
237238 URL: "https://www.reddit.com/search?q=%s",
238239 Description: "Reddit search",
239240 },
240- "npm": {
241- URL: "https://www.npmjs.com/search?q=%s",
242- Description: "npm package search",
241+ "so": {
242+ URL: "https://stackoverflow.com/search?q=%s",
243+ Description: "Stack Overflow search",
243244 },
244- "go": {
245- URL: "https://pkg.go.dev/search?q=%s",
246- Description: "Go package search",
245+ "w": {
246+ URL: "https://en.wikipedia.org/wiki/%s",
247+ Description: "Wikipedia search",
247248 },
248- "mdn": {
249- URL: "https://developer.mozilla.org/en-US/search?q=%s",
250- Description: "MDN Web Docs search",
249+ "yt": {
250+ URL: "https://www.youtube.com/results?search_query=%s",
251+ Description: "YouTube search",
251252 },
252253 }
253254 }
@@ -60,24 +60,7 @@ func DefaultConfig() *Config {
60 RetentionPeriodDays: defaultRetentionDays, // 1 year60 RetentionPeriodDays: defaultRetentionDays, // 1 year
61 CleanupIntervalDays: 1, // daily cleanup61 CleanupIntervalDays: 1, // daily cleanup
62 },62 },
63- SearchShortcuts: map[string]SearchShortcut{63+ SearchShortcuts: GetDefaultSearchShortcuts(),
64- "g": {
65- URL: "https://www.google.com/search?q=%s",
66- Description: "Google search",
67- },
68- "gh": {
69- URL: "https://github.com/search?q=%s",
70- Description: "GitHub search",
71- },
72- "yt": {
73- URL: "https://www.youtube.com/results?search_query=%s",
74- Description: "YouTube search",
75- },
76- "w": {
77- URL: "https://en.wikipedia.org/wiki/%s",
78- Description: "Wikipedia search",
79- },
80- },
81 Dmenu: DmenuConfig{64 Dmenu: DmenuConfig{
82 MaxHistoryItems: defaultMaxHistoryItems,65 MaxHistoryItems: defaultMaxHistoryItems,
83 ShowVisitCount: true,66 ShowVisitCount: true,
@@ -110,6 +93,24 @@ func DefaultConfig() *Config {
110 SerifFont: "Fira Sans",93 SerifFont: "Fira Sans",
111 MonospaceFont: "Fira Code",94 MonospaceFont: "Fira Code",
112 DefaultFontSize: defaultFontSize,95 DefaultFontSize: defaultFontSize,
96+ LightPalette: ColorPalette{
97+ Background: "#f8f8f8",
98+ Surface: "#f2f2f2",
99+ SurfaceVariant: "#ececec",
100+ Text: "#1a1a1a",
101+ Muted: "#6e6e6e",
102+ Accent: "#404040",
103+ Border: "#d2d2d2",
104+ },
105+ DarkPalette: ColorPalette{
106+ Background: "#0e0e0e",
107+ Surface: "#1a1a1a",
108+ SurfaceVariant: "#141414",
109+ Text: "#e4e4e4",
110+ Muted: "#848484",
111+ Accent: "#a8a8a8",
112+ Border: "#363636",
113+ },
113 },114 },
114 VideoAcceleration: VideoAccelerationConfig{115 VideoAcceleration: VideoAccelerationConfig{
115 EnableVAAPI: true,116 EnableVAAPI: true,
@@ -127,7 +128,7 @@ func DefaultConfig() *Config {
127 DisableVP9Hardware: false, // Allow VP9 hardware for high res content128 DisableVP9Hardware: false, // Allow VP9 hardware for high res content
128 VideoBufferSizeMB: 16, // Larger buffer for AV1 streams129 VideoBufferSizeMB: 16, // Larger buffer for AV1 streams
129 QueueBufferTimeSec: 10, // More buffering time for smooth playback130 QueueBufferTimeSec: 10, // More buffering time for smooth playback
130- CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", // Chrome UA with AV1 support131+ CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", // Chrome UA with AV1 support
131 AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res132 AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res
132 DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)133 DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing)
133 },134 },
@@ -209,6 +210,10 @@ func DefaultConfig() *Config {
209 // GetDefaultSearchShortcuts returns the default search shortcuts.210 // GetDefaultSearchShortcuts returns the default search shortcuts.
210 func GetDefaultSearchShortcuts() map[string]SearchShortcut {211 func GetDefaultSearchShortcuts() map[string]SearchShortcut {
211 return map[string]SearchShortcut{212 return map[string]SearchShortcut{
213+ "ddg": {
214+ URL: "https://duckduckgo.com/?q=%s",
215+ Description: "DuckDuckGo search",
216+ },
212 "g": {217 "g": {
213 URL: "https://www.google.com/search?q=%s",218 URL: "https://www.google.com/search?q=%s",
214 Description: "Google search",219 Description: "Google search",
@@ -217,37 +222,33 @@ func GetDefaultSearchShortcuts() map[string]SearchShortcut {
217 URL: "https://github.com/search?q=%s",222 URL: "https://github.com/search?q=%s",
218 Description: "GitHub search",223 Description: "GitHub search",
219 },224 },
220- "yt": {225+ "go": {
221- URL: "https://www.youtube.com/results?search_query=%s",226+ URL: "https://pkg.go.dev/search?q=%s",
222- Description: "YouTube search",227+ Description: "Go package search",
223- },
224- "w": {
225- URL: "https://en.wikipedia.org/wiki/%s",
226- Description: "Wikipedia search",
227 },228 },
228- "ddg": {229+ "mdn": {
229- URL: "https://duckduckgo.com/?q=%s",230+ URL: "https://developer.mozilla.org/en-US/search?q=%s",
230- Description: "DuckDuckGo search",231+ Description: "MDN Web Docs search",
231 },232 },
232- "so": {233+ "npm": {
233- URL: "https://stackoverflow.com/search?q=%s",234+ URL: "https://www.npmjs.com/search?q=%s",
234- Description: "Stack Overflow search",235+ Description: "npm package search",
235 },236 },
236 "r": {237 "r": {
237 URL: "https://www.reddit.com/search?q=%s",238 URL: "https://www.reddit.com/search?q=%s",
238 Description: "Reddit search",239 Description: "Reddit search",
239 },240 },
240- "npm": {241+ "so": {
241- URL: "https://www.npmjs.com/search?q=%s",242+ URL: "https://stackoverflow.com/search?q=%s",
242- Description: "npm package search",243+ Description: "Stack Overflow search",
243 },244 },
244- "go": {245+ "w": {
245- URL: "https://pkg.go.dev/search?q=%s",246+ URL: "https://en.wikipedia.org/wiki/%s",
246- Description: "Go package search",247+ Description: "Wikipedia search",
247 },248 },
248- "mdn": {249+ "yt": {
249- URL: "https://developer.mozilla.org/en-US/search?q=%s",250+ URL: "https://www.youtube.com/results?search_query=%s",
250- Description: "MDN Web Docs search",251+ Description: "YouTube search",
251 },252 },
252 }253 }
253 }254 }

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