detached bc5cb18

feat(config): add configurable default zoom level

Added default_zoom config option to set the default zoom level for pages without saved zoom preferences. Defaults to 1.2 (120%) for better readability. Per-domain zoom settings still override this default.
commit
bc5cb18cc7b3ad7165f86cbd9ee72464ea609cb6
author
bamen · · 2025-10-06 16:56 UTC
committer
bamen · · 2025-10-06 17:30 UTC
parent
43d9ee2
signature
unsigned
5 files · +38 -5
M CHANGELOG.md +1 -0
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
55 ## [Unreleased]
66
77 ### Added
8+- **Configurable default zoom**: Added `default_zoom` config (defaults to 1.2/120%). Per-domain zoom still overrides this
89 - **Pin/favorite sites**: Pin websites from history or quick access to prioritize them in "Jump back in" section. Uses localStorage persistence with star icons for pin/unpin actions
910 - **Zellij-style stacked panes**: Added Ctrl+P → 's' to stack panes instead of splitting, with Alt+Up/Down navigation between stacked panes. Features collapsed page title bars showing for inactive panes and full WebView interaction for the active pane. Includes GTK4 CSS styling for proper visual feedback
1011 - **Stacked pane favicons**: Title bars display site favicons with async caching. Click title bars to switch between stacked panes
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
5 ## [Unreleased]5 ## [Unreleased]
6 6
7 ### Added7 ### Added
8+- **Configurable default zoom**: Added `default_zoom` config (defaults to 1.2/120%). Per-domain zoom still overrides this
8 - **Pin/favorite sites**: Pin websites from history or quick access to prioritize them in "Jump back in" section. Uses localStorage persistence with star icons for pin/unpin actions9 - **Pin/favorite sites**: Pin websites from history or quick access to prioritize them in "Jump back in" section. Uses localStorage persistence with star icons for pin/unpin actions
9 - **Zellij-style stacked panes**: Added Ctrl+P → 's' to stack panes instead of splitting, with Alt+Up/Down navigation between stacked panes. Features collapsed page title bars showing for inactive panes and full WebView interaction for the active pane. Includes GTK4 CSS styling for proper visual feedback10 - **Zellij-style stacked panes**: Added Ctrl+P → 's' to stack panes instead of splitting, with Alt+Up/Down navigation between stacked panes. Features collapsed page title bars showing for inactive panes and full WebView interaction for the active pane. Includes GTK4 CSS styling for proper visual feedback
10 - **Stacked pane favicons**: Title bars display site favicons with async caching. Click title bars to switch between stacked panes11 - **Stacked pane favicons**: Title bars display site favicons with async caching. Click title bars to switch between stacked panes
M internal/app/browser/webview.go +1 -1
@@ -86,7 +86,7 @@ func (app *BrowserApp) buildWebkitConfig() (*webkit.Config, error) {
8686 cfg := &webkit.Config{
8787 Assets: app.assets,
8888 InitialURL: "dumb://homepage",
89- ZoomDefault: 1.0,
89+ ZoomDefault: app.config.DefaultZoom,
9090 EnableDeveloperExtras: true,
9191 DataDir: webkitData,
9292 CacheDir: webkitCache,
@@ -86,7 +86,7 @@ func (app *BrowserApp) buildWebkitConfig() (*webkit.Config, error) {
86 cfg := &webkit.Config{86 cfg := &webkit.Config{
87 Assets: app.assets,87 Assets: app.assets,
88 InitialURL: "dumb://homepage",88 InitialURL: "dumb://homepage",
89- ZoomDefault: 1.0,89+ ZoomDefault: app.config.DefaultZoom,
90 EnableDeveloperExtras: true,90 EnableDeveloperExtras: true,
91 DataDir: webkitData,91 DataDir: webkitData,
92 CacheDir: webkitCache,92 CacheDir: webkitCache,
M internal/config/config.go +31 -0
@@ -40,6 +40,8 @@ type Config struct {
4040 RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"`
4141 // UseDomZoom toggles DOM-based zoom instead of native WebKit zoom.
4242 UseDomZoom bool `mapstructure:"use_dom_zoom" yaml:"use_dom_zoom"`
43+ // DefaultZoom sets the default zoom level for pages without saved zoom settings (1.0 = 100%, 1.2 = 120%)
44+ DefaultZoom float64 `mapstructure:"default_zoom" yaml:"default_zoom"`
4345 // Workspace defines workspace, pane, and tab handling behaviour.
4446 Workspace WorkspaceConfig `mapstructure:"workspace" yaml:"workspace"`
4547 }
@@ -381,6 +383,9 @@ func NewManager() (*Manager, error) {
381383 if err := v.BindEnv("use_dom_zoom", "DUMBER_USE_DOM_ZOOM"); err != nil {
382384 return nil, fmt.Errorf("failed to bind DUMBER_USE_DOM_ZOOM: %w", err)
383385 }
386+ if err := v.BindEnv("default_zoom", "DUMBER_DEFAULT_ZOOM"); err != nil {
387+ return nil, fmt.Errorf("failed to bind DUMBER_DEFAULT_ZOOM: %w", err)
388+ }
384389
385390 // Video acceleration environment variable bindings
386391 videoAccelEnvBindings := map[string]string{
@@ -716,6 +721,7 @@ func (m *Manager) setDefaults() {
716721 // Rendering defaults
717722 m.viper.SetDefault("rendering_mode", string(RenderingModeGPU))
718723 m.viper.SetDefault("use_dom_zoom", defaults.UseDomZoom)
724+ m.viper.SetDefault("default_zoom", defaults.DefaultZoom)
719725
720726 // Workspace defaults
721727 m.viper.SetDefault("workspace.enable_zellij_controls", defaults.Workspace.EnableZellijControls)
@@ -767,6 +773,31 @@ func (m *Manager) ensurePersistedDefaults(cfg *Config) {
767773 logging.Info(fmt.Sprintf("Config: persisted missing use_dom_zoom default (%v) to %s", cfg.UseDomZoom, cfgFile))
768774 }
769775
776+// persistDefaultZoomIfMissing persists the default_zoom value to the config file if it's not already set.
777+func (m *Manager) persistDefaultZoomIfMissing(cfg *Config) {
778+ if cfg == nil {
779+ return
780+ }
781+
782+ // Only persist when the key is missing from the user config file.
783+ if m.viper.InConfig("default_zoom") {
784+ return
785+ }
786+
787+ cfgFile := m.viper.ConfigFileUsed()
788+ if cfgFile == "" {
789+ return
790+ }
791+
792+ m.viper.Set("default_zoom", cfg.DefaultZoom)
793+ if err := m.viper.WriteConfig(); err != nil {
794+ logging.Warn(fmt.Sprintf("Config: failed to persist default_zoom default to %s: %v", cfgFile, err))
795+ return
796+ }
797+
798+ logging.Info(fmt.Sprintf("Config: persisted missing default_zoom default (%.2f) to %s", cfg.DefaultZoom, cfgFile))
799+}
800+
770801 // createDefaultConfig creates a default configuration file.
771802 func (m *Manager) createDefaultConfig() error {
772803 configFile, err := GetConfigFile()
@@ -40,6 +40,8 @@ type Config struct {
40 RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"`40 RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"`
41 // UseDomZoom toggles DOM-based zoom instead of native WebKit zoom.41 // UseDomZoom toggles DOM-based zoom instead of native WebKit zoom.
42 UseDomZoom bool `mapstructure:"use_dom_zoom" yaml:"use_dom_zoom"`42 UseDomZoom bool `mapstructure:"use_dom_zoom" yaml:"use_dom_zoom"`
43+ // DefaultZoom sets the default zoom level for pages without saved zoom settings (1.0 = 100%, 1.2 = 120%)
44+ DefaultZoom float64 `mapstructure:"default_zoom" yaml:"default_zoom"`
43 // Workspace defines workspace, pane, and tab handling behaviour.45 // Workspace defines workspace, pane, and tab handling behaviour.
44 Workspace WorkspaceConfig `mapstructure:"workspace" yaml:"workspace"`46 Workspace WorkspaceConfig `mapstructure:"workspace" yaml:"workspace"`
45 }47 }
@@ -381,6 +383,9 @@ func NewManager() (*Manager, error) {
381 if err := v.BindEnv("use_dom_zoom", "DUMBER_USE_DOM_ZOOM"); err != nil {383 if err := v.BindEnv("use_dom_zoom", "DUMBER_USE_DOM_ZOOM"); err != nil {
382 return nil, fmt.Errorf("failed to bind DUMBER_USE_DOM_ZOOM: %w", err)384 return nil, fmt.Errorf("failed to bind DUMBER_USE_DOM_ZOOM: %w", err)
383 }385 }
386+ if err := v.BindEnv("default_zoom", "DUMBER_DEFAULT_ZOOM"); err != nil {
387+ return nil, fmt.Errorf("failed to bind DUMBER_DEFAULT_ZOOM: %w", err)
388+ }
384 389
385 // Video acceleration environment variable bindings390 // Video acceleration environment variable bindings
386 videoAccelEnvBindings := map[string]string{391 videoAccelEnvBindings := map[string]string{
@@ -716,6 +721,7 @@ func (m *Manager) setDefaults() {
716 // Rendering defaults721 // Rendering defaults
717 m.viper.SetDefault("rendering_mode", string(RenderingModeGPU))722 m.viper.SetDefault("rendering_mode", string(RenderingModeGPU))
718 m.viper.SetDefault("use_dom_zoom", defaults.UseDomZoom)723 m.viper.SetDefault("use_dom_zoom", defaults.UseDomZoom)
724+ m.viper.SetDefault("default_zoom", defaults.DefaultZoom)
719 725
720 // Workspace defaults726 // Workspace defaults
721 m.viper.SetDefault("workspace.enable_zellij_controls", defaults.Workspace.EnableZellijControls)727 m.viper.SetDefault("workspace.enable_zellij_controls", defaults.Workspace.EnableZellijControls)
@@ -767,6 +773,31 @@ func (m *Manager) ensurePersistedDefaults(cfg *Config) {
767 logging.Info(fmt.Sprintf("Config: persisted missing use_dom_zoom default (%v) to %s", cfg.UseDomZoom, cfgFile))773 logging.Info(fmt.Sprintf("Config: persisted missing use_dom_zoom default (%v) to %s", cfg.UseDomZoom, cfgFile))
768 }774 }
769 775
776+// persistDefaultZoomIfMissing persists the default_zoom value to the config file if it's not already set.
777+func (m *Manager) persistDefaultZoomIfMissing(cfg *Config) {
778+ if cfg == nil {
779+ return
780+ }
781+
782+ // Only persist when the key is missing from the user config file.
783+ if m.viper.InConfig("default_zoom") {
784+ return
785+ }
786+
787+ cfgFile := m.viper.ConfigFileUsed()
788+ if cfgFile == "" {
789+ return
790+ }
791+
792+ m.viper.Set("default_zoom", cfg.DefaultZoom)
793+ if err := m.viper.WriteConfig(); err != nil {
794+ logging.Warn(fmt.Sprintf("Config: failed to persist default_zoom default to %s: %v", cfgFile, err))
795+ return
796+ }
797+
798+ logging.Info(fmt.Sprintf("Config: persisted missing default_zoom default (%.2f) to %s", cfg.DefaultZoom, cfgFile))
799+}
800+
770 // createDefaultConfig creates a default configuration file.801 // createDefaultConfig creates a default configuration file.
771 func (m *Manager) createDefaultConfig() error {802 func (m *Manager) createDefaultConfig() error {
772 configFile, err := GetConfigFile()803 configFile, err := GetConfigFile()
M internal/config/defaults.go +1 -0
@@ -164,6 +164,7 @@ func DefaultConfig() *Config {
164164 },
165165 RenderingMode: RenderingModeGPU,
166166 UseDomZoom: false,
167+ DefaultZoom: 1.2, // 120% default zoom for better readability
167168 Workspace: WorkspaceConfig{
168169 EnableZellijControls: true,
169170 PaneMode: PaneModeConfig{
@@ -164,6 +164,7 @@ func DefaultConfig() *Config {
164 },164 },
165 RenderingMode: RenderingModeGPU,165 RenderingMode: RenderingModeGPU,
166 UseDomZoom: false,166 UseDomZoom: false,
167+ DefaultZoom: 1.2, // 120% default zoom for better readability
167 Workspace: WorkspaceConfig{168 Workspace: WorkspaceConfig{
168 EnableZellijControls: true,169 EnableZellijControls: true,
169 PaneMode: PaneModeConfig{170 PaneMode: PaneModeConfig{
M internal/services/browser.go +4 -4
@@ -446,7 +446,7 @@ func (s *BrowserService) ResetZoom(ctx context.Context, url string) (float64, er
446446 // GetZoomLevel retrieves the saved zoom level for a URL.
447447 func (s *BrowserService) GetZoomLevel(ctx context.Context, url string) (float64, error) {
448448 if url == "" {
449- return 1.0, nil
449+ return s.config.DefaultZoom, nil
450450 }
451451
452452 key := zoomKeyFromURL(url)
@@ -458,10 +458,10 @@ func (s *BrowserService) GetZoomLevel(ctx context.Context, url string) (float64,
458458 if err2 == nil {
459459 return zl, nil
460460 }
461- // No zoom setting found, return default
462- return 1.0, nil
461+ // No zoom setting found, return configured default
462+ return s.config.DefaultZoom, nil
463463 }
464- return 1.0, err
464+ return s.config.DefaultZoom, err
465465 }
466466
467467 return zoomLevel, nil
@@ -446,7 +446,7 @@ func (s *BrowserService) ResetZoom(ctx context.Context, url string) (float64, er
446 // GetZoomLevel retrieves the saved zoom level for a URL.446 // GetZoomLevel retrieves the saved zoom level for a URL.
447 func (s *BrowserService) GetZoomLevel(ctx context.Context, url string) (float64, error) {447 func (s *BrowserService) GetZoomLevel(ctx context.Context, url string) (float64, error) {
448 if url == "" {448 if url == "" {
449- return 1.0, nil449+ return s.config.DefaultZoom, nil
450 }450 }
451 451
452 key := zoomKeyFromURL(url)452 key := zoomKeyFromURL(url)
@@ -458,10 +458,10 @@ func (s *BrowserService) GetZoomLevel(ctx context.Context, url string) (float64,
458 if err2 == nil {458 if err2 == nil {
459 return zl, nil459 return zl, nil
460 }460 }
461- // No zoom setting found, return default461+ // No zoom setting found, return configured default
462- return 1.0, nil462+ return s.config.DefaultZoom, nil
463 }463 }
464- return 1.0, err464+ return s.config.DefaultZoom, err
465 }465 }
466 466
467 return zoomLevel, nil467 return zoomLevel, nil

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