detached 5cd9158

feat(config): add configurable border styling for inactive panes

commit
5cd91588685a5721a41dfd17fb7e1cb31258ac81
author
bnema · · 2025-11-15 16:20 UTC
parent
e4a335a
signature
unsigned
4 files · +88 -37
M docs/CONFIG.md +7 -4
@@ -251,11 +251,14 @@ The schema is automatically generated when you first create a config file.
251251
252252 | Key | Type | Default | Description |
253253 |-----|------|---------|-------------|
254-| `workspace.styling.border_width` | int | `2` | Border width in pixels |
255-| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Border color (CSS or theme var) |
254+| `workspace.styling.border_width` | int | `1` | Active pane border width (px) |
255+| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Active pane border color |
256+| `workspace.styling.inactive_border_width` | int | `1` | Inactive pane border width (px) |
257+| `workspace.styling.inactive_border_color` | string | `"@theme_unfocused_bg_color"` | Inactive pane border color |
258+| `workspace.styling.show_stacked_title_border` | bool | `false` | Show separator on stacked pane titles |
256259 | `workspace.styling.pane_mode_border_color` | string | `"#FFA500"` | Pane mode border color (orange) |
257-| `workspace.styling.transition_duration` | int | `120` | Transition duration (ms) |
258-| `workspace.styling.border_radius` | int | `0` | Border radius in pixels |
260+| `workspace.styling.transition_duration` | int | `120` | Border transition duration (ms) |
261+| `workspace.styling.border_radius` | int | `0` | Border radius (px) |
259262
260263 ## Content Filtering
261264
@@ -251,11 +251,14 @@ The schema is automatically generated when you first create a config file.
251 251
252 | Key | Type | Default | Description |252 | Key | Type | Default | Description |
253 |-----|------|---------|-------------|253 |-----|------|---------|-------------|
254-| `workspace.styling.border_width` | int | `2` | Border width in pixels |254+| `workspace.styling.border_width` | int | `1` | Active pane border width (px) |
255-| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Border color (CSS or theme var) |255+| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Active pane border color |
256+| `workspace.styling.inactive_border_width` | int | `1` | Inactive pane border width (px) |
257+| `workspace.styling.inactive_border_color` | string | `"@theme_unfocused_bg_color"` | Inactive pane border color |
258+| `workspace.styling.show_stacked_title_border` | bool | `false` | Show separator on stacked pane titles |
256 | `workspace.styling.pane_mode_border_color` | string | `"#FFA500"` | Pane mode border color (orange) |259 | `workspace.styling.pane_mode_border_color` | string | `"#FFA500"` | Pane mode border color (orange) |
257-| `workspace.styling.transition_duration` | int | `120` | Transition duration (ms) |260+| `workspace.styling.transition_duration` | int | `120` | Border transition duration (ms) |
258-| `workspace.styling.border_radius` | int | `0` | Border radius in pixels |261+| `workspace.styling.border_radius` | int | `0` | Border radius (px) |
259 262
260 ## Content Filtering263 ## Content Filtering
261 264
M internal/app/browser/workspace_css.go +55 -22
@@ -55,23 +55,41 @@ func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool
5555 return "#87CEEB" // Sky blue pastel for light theme
5656 }
5757
58+// getInactivePaneBorderColor returns the border color for inactive panes based on config and theme
59+func getInactivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool) string {
60+ // Use configured border color if set
61+ if styling.InactiveBorderColor != "" {
62+ // Check if it's a GTK theme variable (starts with @)
63+ if strings.HasPrefix(styling.InactiveBorderColor, "@") {
64+ return styling.InactiveBorderColor
65+ }
66+ // Return the configured color as-is (could be hex, rgb, etc.)
67+ return styling.InactiveBorderColor
68+ }
69+
70+ // Fallback to hardcoded colors based on theme
71+ if isDark {
72+ return "#333333" // Dark border for dark theme
73+ }
74+ return "#dddddd" // Light border for light theme
75+}
76+
5877 // generateWorkspaceCSS generates the complete CSS for workspace panes and stacked panes
5978 func (wm *WorkspaceManager) generateWorkspaceCSS() string {
6079 cfg := config.Get()
6180 styling := cfg.Workspace.Styling
6281
6382 // Get appropriate colors based on GTK theme preference
64- var inactiveBorderColor, windowBackgroundColor string
83+ var windowBackgroundColor string
6584 isDark := webkit.PrefersDarkTheme()
6685 if isDark {
67- inactiveBorderColor = "#333333" // Dark border for dark theme
6886 windowBackgroundColor = "#2b2b2b" // Dark window background
6987 } else {
70- inactiveBorderColor = "#dddddd" // Light border for light theme
7188 windowBackgroundColor = "#ffffff" // Light window background
7289 }
7390
7491 activeBorderColor := getActivePaneBorderColor(styling, isDark)
92+ inactiveBorderColor := getInactivePaneBorderColor(styling, isDark)
7593
7694 // Pane mode border color - use configured value or fallback to orange
7795 paneModeColor := styling.PaneModeBorderColor
@@ -79,6 +97,12 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
7997 paneModeColor = "#FFA500" // Fallback to orange if not configured
8098 }
8199
100+ // Stacked title border - conditional based on config
101+ stackedTitleBorder := "0"
102+ if styling.ShowStackedTitleBorder {
103+ stackedTitleBorder = fmt.Sprintf("1px solid %s", inactiveBorderColor)
104+ }
105+
82106 css := fmt.Sprintf(`window {
83107 background-color: %s;
84108 padding: 0;
@@ -96,16 +120,21 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
96120 transition: margin 150ms ease-in-out;
97121 }
98122
99- /* Base pane styling - subtle border for inactive panes */
123+ /* Base pane styling - configurable inactive borders */
100124 .workspace-pane, .stacked-pane-container {
101- border: 2px solid %s;
125+ border-width: %dpx;
126+ border-style: solid;
127+ border-color: %s;
102128 border-radius: %dpx;
103- transition: border-color %dms ease-in-out;
104129 margin: 0;
130+ transition-property: border-color;
131+ transition-duration: %dms;
132+ transition-timing-function: ease-in-out;
105133 }
106134
107135 /* Active pane border styling */
108136 .workspace-pane-active {
137+ border-width: %dpx;
109138 border-color: %s;
110139 }
111140
@@ -114,14 +143,15 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
114143 background-color: %s;
115144 }
116145
117- /* Stacked pane containers never get active border - focus is shown via WebKit */
146+ /* Stacked pane containers keep inactive border when active */
118147 .stacked-pane-container.workspace-pane-active {
148+ border-width: %dpx;
119149 border-color: %s;
120150 }
121151
122152 .stacked-pane-title {
123153 background-color: %s;
124- border-bottom: 1px solid %s;
154+ border-bottom: %s;
125155 padding: 4px 8px;
126156 min-height: 24px;
127157 transition: background-color %dms ease-in-out;
@@ -148,20 +178,23 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
148178 .stacked-pane-collapsed {
149179 /* Collapsed panes are hidden - handled in code via widget visibility */
150180 }`,
151- windowBackgroundColor, // window background
152- paneModeColor, // window.pane-mode-active background (border color)
153- windowBackgroundColor, // paned, box background
154- inactiveBorderColor, // base pane border color (inactive)
155- styling.BorderRadius, // base pane border radius
156- styling.TransitionDuration, // base pane border transition
157- activeBorderColor, // workspace-pane-active border color
158- windowBackgroundColor, // stacked-pane-container background
159- inactiveBorderColor, // stacked-pane-container.workspace-pane-active border color (keep subtle)
160- getStackTitleBg(isDark), // stacked-pane-title background
161- inactiveBorderColor, // stacked-pane-title border-bottom
162- styling.TransitionDuration, // stacked-pane-title transition
163- getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
164- getStackTitleTextColor(isDark), // stacked-pane-title-text color
181+ windowBackgroundColor, // window background
182+ paneModeColor, // window.pane-mode-active background (border color)
183+ windowBackgroundColor, // paned, box background
184+ styling.InactiveBorderWidth, // base pane border-width (inactive)
185+ inactiveBorderColor, // base pane border-color (inactive)
186+ styling.BorderRadius, // base pane border radius
187+ styling.TransitionDuration, // transition-duration
188+ styling.BorderWidth, // workspace-pane-active border-width
189+ activeBorderColor, // workspace-pane-active border color
190+ windowBackgroundColor, // stacked-pane-container background
191+ styling.InactiveBorderWidth, // stacked-pane-container.active border-width
192+ inactiveBorderColor, // stacked-pane-container.active border-color
193+ getStackTitleBg(isDark), // stacked-pane-title background
194+ stackedTitleBorder, // stacked-pane-title border-bottom
195+ styling.TransitionDuration, // stacked-pane-title transition
196+ getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
197+ getStackTitleTextColor(isDark), // stacked-pane-title-text color
165198 )
166199
167200 return css
@@ -55,23 +55,41 @@ func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool
55 return "#87CEEB" // Sky blue pastel for light theme55 return "#87CEEB" // Sky blue pastel for light theme
56 }56 }
57 57
58+// getInactivePaneBorderColor returns the border color for inactive panes based on config and theme
59+func getInactivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool) string {
60+ // Use configured border color if set
61+ if styling.InactiveBorderColor != "" {
62+ // Check if it's a GTK theme variable (starts with @)
63+ if strings.HasPrefix(styling.InactiveBorderColor, "@") {
64+ return styling.InactiveBorderColor
65+ }
66+ // Return the configured color as-is (could be hex, rgb, etc.)
67+ return styling.InactiveBorderColor
68+ }
69+
70+ // Fallback to hardcoded colors based on theme
71+ if isDark {
72+ return "#333333" // Dark border for dark theme
73+ }
74+ return "#dddddd" // Light border for light theme
75+}
76+
58 // generateWorkspaceCSS generates the complete CSS for workspace panes and stacked panes77 // generateWorkspaceCSS generates the complete CSS for workspace panes and stacked panes
59 func (wm *WorkspaceManager) generateWorkspaceCSS() string {78 func (wm *WorkspaceManager) generateWorkspaceCSS() string {
60 cfg := config.Get()79 cfg := config.Get()
61 styling := cfg.Workspace.Styling80 styling := cfg.Workspace.Styling
62 81
63 // Get appropriate colors based on GTK theme preference82 // Get appropriate colors based on GTK theme preference
64- var inactiveBorderColor, windowBackgroundColor string83+ var windowBackgroundColor string
65 isDark := webkit.PrefersDarkTheme()84 isDark := webkit.PrefersDarkTheme()
66 if isDark {85 if isDark {
67- inactiveBorderColor = "#333333" // Dark border for dark theme
68 windowBackgroundColor = "#2b2b2b" // Dark window background86 windowBackgroundColor = "#2b2b2b" // Dark window background
69 } else {87 } else {
70- inactiveBorderColor = "#dddddd" // Light border for light theme
71 windowBackgroundColor = "#ffffff" // Light window background88 windowBackgroundColor = "#ffffff" // Light window background
72 }89 }
73 90
74 activeBorderColor := getActivePaneBorderColor(styling, isDark)91 activeBorderColor := getActivePaneBorderColor(styling, isDark)
92+ inactiveBorderColor := getInactivePaneBorderColor(styling, isDark)
75 93
76 // Pane mode border color - use configured value or fallback to orange94 // Pane mode border color - use configured value or fallback to orange
77 paneModeColor := styling.PaneModeBorderColor95 paneModeColor := styling.PaneModeBorderColor
@@ -79,6 +97,12 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
79 paneModeColor = "#FFA500" // Fallback to orange if not configured97 paneModeColor = "#FFA500" // Fallback to orange if not configured
80 }98 }
81 99
100+ // Stacked title border - conditional based on config
101+ stackedTitleBorder := "0"
102+ if styling.ShowStackedTitleBorder {
103+ stackedTitleBorder = fmt.Sprintf("1px solid %s", inactiveBorderColor)
104+ }
105+
82 css := fmt.Sprintf(`window {106 css := fmt.Sprintf(`window {
83 background-color: %s;107 background-color: %s;
84 padding: 0;108 padding: 0;
@@ -96,16 +120,21 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
96 transition: margin 150ms ease-in-out;120 transition: margin 150ms ease-in-out;
97 }121 }
98 122
99- /* Base pane styling - subtle border for inactive panes */123+ /* Base pane styling - configurable inactive borders */
100 .workspace-pane, .stacked-pane-container {124 .workspace-pane, .stacked-pane-container {
101- border: 2px solid %s;125+ border-width: %dpx;
126+ border-style: solid;
127+ border-color: %s;
102 border-radius: %dpx;128 border-radius: %dpx;
103- transition: border-color %dms ease-in-out;
104 margin: 0;129 margin: 0;
130+ transition-property: border-color;
131+ transition-duration: %dms;
132+ transition-timing-function: ease-in-out;
105 }133 }
106 134
107 /* Active pane border styling */135 /* Active pane border styling */
108 .workspace-pane-active {136 .workspace-pane-active {
137+ border-width: %dpx;
109 border-color: %s;138 border-color: %s;
110 }139 }
111 140
@@ -114,14 +143,15 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
114 background-color: %s;143 background-color: %s;
115 }144 }
116 145
117- /* Stacked pane containers never get active border - focus is shown via WebKit */146+ /* Stacked pane containers keep inactive border when active */
118 .stacked-pane-container.workspace-pane-active {147 .stacked-pane-container.workspace-pane-active {
148+ border-width: %dpx;
119 border-color: %s;149 border-color: %s;
120 }150 }
121 151
122 .stacked-pane-title {152 .stacked-pane-title {
123 background-color: %s;153 background-color: %s;
124- border-bottom: 1px solid %s;154+ border-bottom: %s;
125 padding: 4px 8px;155 padding: 4px 8px;
126 min-height: 24px;156 min-height: 24px;
127 transition: background-color %dms ease-in-out;157 transition: background-color %dms ease-in-out;
@@ -148,20 +178,23 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
148 .stacked-pane-collapsed {178 .stacked-pane-collapsed {
149 /* Collapsed panes are hidden - handled in code via widget visibility */179 /* Collapsed panes are hidden - handled in code via widget visibility */
150 }`,180 }`,
151- windowBackgroundColor, // window background181+ windowBackgroundColor, // window background
152- paneModeColor, // window.pane-mode-active background (border color)182+ paneModeColor, // window.pane-mode-active background (border color)
153- windowBackgroundColor, // paned, box background183+ windowBackgroundColor, // paned, box background
154- inactiveBorderColor, // base pane border color (inactive)184+ styling.InactiveBorderWidth, // base pane border-width (inactive)
155- styling.BorderRadius, // base pane border radius185+ inactiveBorderColor, // base pane border-color (inactive)
156- styling.TransitionDuration, // base pane border transition186+ styling.BorderRadius, // base pane border radius
157- activeBorderColor, // workspace-pane-active border color187+ styling.TransitionDuration, // transition-duration
158- windowBackgroundColor, // stacked-pane-container background188+ styling.BorderWidth, // workspace-pane-active border-width
159- inactiveBorderColor, // stacked-pane-container.workspace-pane-active border color (keep subtle)189+ activeBorderColor, // workspace-pane-active border color
160- getStackTitleBg(isDark), // stacked-pane-title background190+ windowBackgroundColor, // stacked-pane-container background
161- inactiveBorderColor, // stacked-pane-title border-bottom191+ styling.InactiveBorderWidth, // stacked-pane-container.active border-width
162- styling.TransitionDuration, // stacked-pane-title transition192+ inactiveBorderColor, // stacked-pane-container.active border-color
163- getStackTitleHoverBg(isDark), // stacked-pane-title:hover background193+ getStackTitleBg(isDark), // stacked-pane-title background
164- getStackTitleTextColor(isDark), // stacked-pane-title-text color194+ stackedTitleBorder, // stacked-pane-title border-bottom
195+ styling.TransitionDuration, // stacked-pane-title transition
196+ getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
197+ getStackTitleTextColor(isDark), // stacked-pane-title-text color
165 )198 )
166 199
167 return css200 return css
M internal/config/config.go +10 -1
@@ -283,10 +283,16 @@ type PopupBehaviorConfig struct {
283283
284284 // WorkspaceStylingConfig defines visual styling for workspace panes.
285285 type WorkspaceStylingConfig struct {
286- // BorderWidth in pixels for pane borders
286+ // BorderWidth in pixels for active pane borders
287287 BorderWidth int `mapstructure:"border_width" yaml:"border_width" json:"border_width"`
288288 // BorderColor for focused panes (CSS color value or theme variable)
289289 BorderColor string `mapstructure:"border_color" yaml:"border_color" json:"border_color"`
290+ // InactiveBorderWidth in pixels for inactive pane borders (0 = hidden)
291+ InactiveBorderWidth int `mapstructure:"inactive_border_width" yaml:"inactive_border_width" json:"inactive_border_width"`
292+ // InactiveBorderColor for unfocused panes (CSS color value or theme variable)
293+ InactiveBorderColor string `mapstructure:"inactive_border_color" yaml:"inactive_border_color" json:"inactive_border_color"`
294+ // ShowStackedTitleBorder enables the separator line below stacked pane titles
295+ ShowStackedTitleBorder bool `mapstructure:"show_stacked_title_border" yaml:"show_stacked_title_border" json:"show_stacked_title_border"`
290296 // PaneModeBorderColor for the pane mode indicator border (CSS color value or theme variable)
291297 // Defaults to "#FFA500" (orange) if not set
292298 PaneModeBorderColor string `mapstructure:"pane_mode_border_color" yaml:"pane_mode_border_color" json:"pane_mode_border_color"`
@@ -692,6 +698,9 @@ func (m *Manager) setDefaults() {
692698 m.viper.SetDefault("workspace.popups.oauth_auto_close", defaults.Workspace.Popups.OAuthAutoClose)
693699 m.viper.SetDefault("workspace.styling.border_width", defaults.Workspace.Styling.BorderWidth)
694700 m.viper.SetDefault("workspace.styling.border_color", defaults.Workspace.Styling.BorderColor)
701+ m.viper.SetDefault("workspace.styling.inactive_border_width", defaults.Workspace.Styling.InactiveBorderWidth)
702+ m.viper.SetDefault("workspace.styling.inactive_border_color", defaults.Workspace.Styling.InactiveBorderColor)
703+ m.viper.SetDefault("workspace.styling.show_stacked_title_border", defaults.Workspace.Styling.ShowStackedTitleBorder)
695704 m.viper.SetDefault("workspace.styling.pane_mode_border_color", defaults.Workspace.Styling.PaneModeBorderColor)
696705 m.viper.SetDefault("workspace.styling.transition_duration", defaults.Workspace.Styling.TransitionDuration)
697706 m.viper.SetDefault("workspace.styling.border_radius", defaults.Workspace.Styling.BorderRadius)
@@ -283,10 +283,16 @@ type PopupBehaviorConfig struct {
283 283
284 // WorkspaceStylingConfig defines visual styling for workspace panes.284 // WorkspaceStylingConfig defines visual styling for workspace panes.
285 type WorkspaceStylingConfig struct {285 type WorkspaceStylingConfig struct {
286- // BorderWidth in pixels for pane borders286+ // BorderWidth in pixels for active pane borders
287 BorderWidth int `mapstructure:"border_width" yaml:"border_width" json:"border_width"`287 BorderWidth int `mapstructure:"border_width" yaml:"border_width" json:"border_width"`
288 // BorderColor for focused panes (CSS color value or theme variable)288 // BorderColor for focused panes (CSS color value or theme variable)
289 BorderColor string `mapstructure:"border_color" yaml:"border_color" json:"border_color"`289 BorderColor string `mapstructure:"border_color" yaml:"border_color" json:"border_color"`
290+ // InactiveBorderWidth in pixels for inactive pane borders (0 = hidden)
291+ InactiveBorderWidth int `mapstructure:"inactive_border_width" yaml:"inactive_border_width" json:"inactive_border_width"`
292+ // InactiveBorderColor for unfocused panes (CSS color value or theme variable)
293+ InactiveBorderColor string `mapstructure:"inactive_border_color" yaml:"inactive_border_color" json:"inactive_border_color"`
294+ // ShowStackedTitleBorder enables the separator line below stacked pane titles
295+ ShowStackedTitleBorder bool `mapstructure:"show_stacked_title_border" yaml:"show_stacked_title_border" json:"show_stacked_title_border"`
290 // PaneModeBorderColor for the pane mode indicator border (CSS color value or theme variable)296 // PaneModeBorderColor for the pane mode indicator border (CSS color value or theme variable)
291 // Defaults to "#FFA500" (orange) if not set297 // Defaults to "#FFA500" (orange) if not set
292 PaneModeBorderColor string `mapstructure:"pane_mode_border_color" yaml:"pane_mode_border_color" json:"pane_mode_border_color"`298 PaneModeBorderColor string `mapstructure:"pane_mode_border_color" yaml:"pane_mode_border_color" json:"pane_mode_border_color"`
@@ -692,6 +698,9 @@ func (m *Manager) setDefaults() {
692 m.viper.SetDefault("workspace.popups.oauth_auto_close", defaults.Workspace.Popups.OAuthAutoClose)698 m.viper.SetDefault("workspace.popups.oauth_auto_close", defaults.Workspace.Popups.OAuthAutoClose)
693 m.viper.SetDefault("workspace.styling.border_width", defaults.Workspace.Styling.BorderWidth)699 m.viper.SetDefault("workspace.styling.border_width", defaults.Workspace.Styling.BorderWidth)
694 m.viper.SetDefault("workspace.styling.border_color", defaults.Workspace.Styling.BorderColor)700 m.viper.SetDefault("workspace.styling.border_color", defaults.Workspace.Styling.BorderColor)
701+ m.viper.SetDefault("workspace.styling.inactive_border_width", defaults.Workspace.Styling.InactiveBorderWidth)
702+ m.viper.SetDefault("workspace.styling.inactive_border_color", defaults.Workspace.Styling.InactiveBorderColor)
703+ m.viper.SetDefault("workspace.styling.show_stacked_title_border", defaults.Workspace.Styling.ShowStackedTitleBorder)
695 m.viper.SetDefault("workspace.styling.pane_mode_border_color", defaults.Workspace.Styling.PaneModeBorderColor)704 m.viper.SetDefault("workspace.styling.pane_mode_border_color", defaults.Workspace.Styling.PaneModeBorderColor)
696 m.viper.SetDefault("workspace.styling.transition_duration", defaults.Workspace.Styling.TransitionDuration)705 m.viper.SetDefault("workspace.styling.transition_duration", defaults.Workspace.Styling.TransitionDuration)
697 m.viper.SetDefault("workspace.styling.border_radius", defaults.Workspace.Styling.BorderRadius)706 m.viper.SetDefault("workspace.styling.border_radius", defaults.Workspace.Styling.BorderRadius)
M internal/config/defaults.go +16 -10
@@ -24,11 +24,14 @@ const (
2424 defaultPopupPlacement = "right"
2525
2626 // Workspace styling defaults
27- defaultBorderWidth = 2
28- defaultBorderColor = "@theme_selected_bg_color"
29- defaultPaneModeBorderColor = "#FFA500" // Orange for pane mode indicator
30- defaultTransitionDuration = 120
31- defaultBorderRadius = 0
27+ defaultBorderWidth = 1
28+ defaultBorderColor = "@theme_selected_bg_color"
29+ defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift
30+ defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable
31+ defaultShowStackedTitleBorder = false // Hidden by default
32+ defaultPaneModeBorderColor = "#FFA500" // Orange for pane mode indicator
33+ defaultTransitionDuration = 120
34+ defaultBorderRadius = 0
3235 )
3336
3437 // getDefaultLogDir returns the default log directory, falls back to empty string on error
@@ -176,11 +179,14 @@ func DefaultConfig() *Config {
176179 OAuthAutoClose: true, // Auto-close OAuth popups on success
177180 },
178181 Styling: WorkspaceStylingConfig{
179- BorderWidth: defaultBorderWidth,
180- BorderColor: defaultBorderColor,
181- PaneModeBorderColor: defaultPaneModeBorderColor,
182- TransitionDuration: defaultTransitionDuration,
183- BorderRadius: defaultBorderRadius,
182+ BorderWidth: defaultBorderWidth,
183+ BorderColor: defaultBorderColor,
184+ InactiveBorderWidth: defaultInactiveBorderWidth,
185+ InactiveBorderColor: defaultInactiveBorderColor,
186+ ShowStackedTitleBorder: defaultShowStackedTitleBorder,
187+ PaneModeBorderColor: defaultPaneModeBorderColor,
188+ TransitionDuration: defaultTransitionDuration,
189+ BorderRadius: defaultBorderRadius,
184190 },
185191 },
186192 ContentFilteringWhitelist: []string{
@@ -24,11 +24,14 @@ const (
24 defaultPopupPlacement = "right"24 defaultPopupPlacement = "right"
25 25
26 // Workspace styling defaults26 // Workspace styling defaults
27- defaultBorderWidth = 227+ defaultBorderWidth = 1
28- defaultBorderColor = "@theme_selected_bg_color"28+ defaultBorderColor = "@theme_selected_bg_color"
29- defaultPaneModeBorderColor = "#FFA500" // Orange for pane mode indicator29+ defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift
30- defaultTransitionDuration = 12030+ defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable
31- defaultBorderRadius = 031+ defaultShowStackedTitleBorder = false // Hidden by default
32+ defaultPaneModeBorderColor = "#FFA500" // Orange for pane mode indicator
33+ defaultTransitionDuration = 120
34+ defaultBorderRadius = 0
32 )35 )
33 36
34 // getDefaultLogDir returns the default log directory, falls back to empty string on error37 // getDefaultLogDir returns the default log directory, falls back to empty string on error
@@ -176,11 +179,14 @@ func DefaultConfig() *Config {
176 OAuthAutoClose: true, // Auto-close OAuth popups on success179 OAuthAutoClose: true, // Auto-close OAuth popups on success
177 },180 },
178 Styling: WorkspaceStylingConfig{181 Styling: WorkspaceStylingConfig{
179- BorderWidth: defaultBorderWidth,182+ BorderWidth: defaultBorderWidth,
180- BorderColor: defaultBorderColor,183+ BorderColor: defaultBorderColor,
181- PaneModeBorderColor: defaultPaneModeBorderColor,184+ InactiveBorderWidth: defaultInactiveBorderWidth,
182- TransitionDuration: defaultTransitionDuration,185+ InactiveBorderColor: defaultInactiveBorderColor,
183- BorderRadius: defaultBorderRadius,186+ ShowStackedTitleBorder: defaultShowStackedTitleBorder,
187+ PaneModeBorderColor: defaultPaneModeBorderColor,
188+ TransitionDuration: defaultTransitionDuration,
189+ BorderRadius: defaultBorderRadius,
184 },190 },
185 },191 },
186 ContentFilteringWhitelist: []string{192 ContentFilteringWhitelist: []string{

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