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. | |||
| 251 | 251 | ||
| 252 | 252 | | Key | Type | Default | Description | | |
| 253 | 253 | |-----|------|---------|-------------| | |
| 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 | | |
| 256 | 259 | | `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) | | |
| 259 | 262 | ||
| 260 | 263 | ## Content Filtering | |
| 261 | 264 | ||
| @@ -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 Filtering | 263 | ## Content Filtering | ||
| 261 | 264 | ||||
M internal/app/browser/workspace_css.go +55 -22
| @@ -55,23 +55,41 @@ func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool | |||
| 55 | 55 | 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 | 77 | // generateWorkspaceCSS generates the complete CSS for workspace panes and stacked panes | |
| 59 | 78 | func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |
| 60 | 79 | cfg := config.Get() | |
| 61 | 80 | styling := cfg.Workspace.Styling | |
| 62 | 81 | ||
| 63 | 82 | // Get appropriate colors based on GTK theme preference | |
| 64 | - | var inactiveBorderColor, windowBackgroundColor string | |
| 83 | + | var windowBackgroundColor string | |
| 65 | 84 | isDark := webkit.PrefersDarkTheme() | |
| 66 | 85 | if isDark { | |
| 67 | - | inactiveBorderColor = "#333333" // Dark border for dark theme | |
| 68 | 86 | windowBackgroundColor = "#2b2b2b" // Dark window background | |
| 69 | 87 | } else { | |
| 70 | - | inactiveBorderColor = "#dddddd" // Light border for light theme | |
| 71 | 88 | windowBackgroundColor = "#ffffff" // Light window background | |
| 72 | 89 | } | |
| 73 | 90 | ||
| 74 | 91 | activeBorderColor := getActivePaneBorderColor(styling, isDark) | |
| 92 | + | inactiveBorderColor := getInactivePaneBorderColor(styling, isDark) | |
| 75 | 93 | ||
| 76 | 94 | // Pane mode border color - use configured value or fallback to orange | |
| 77 | 95 | paneModeColor := styling.PaneModeBorderColor | |
| @@ -79,6 +97,12 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||
| 79 | 97 | 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 | 106 | css := fmt.Sprintf(`window { | |
| 83 | 107 | background-color: %s; | |
| 84 | 108 | padding: 0; | |
| @@ -96,16 +120,21 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||
| 96 | 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 | 124 | .workspace-pane, .stacked-pane-container { | |
| 101 | - | border: 2px solid %s; | |
| 125 | + | border-width: %dpx; | |
| 126 | + | border-style: solid; | |
| 127 | + | border-color: %s; | |
| 102 | 128 | border-radius: %dpx; | |
| 103 | - | transition: border-color %dms ease-in-out; | |
| 104 | 129 | margin: 0; | |
| 130 | + | transition-property: border-color; | |
| 131 | + | transition-duration: %dms; | |
| 132 | + | transition-timing-function: ease-in-out; | |
| 105 | 133 | } | |
| 106 | 134 | ||
| 107 | 135 | /* Active pane border styling */ | |
| 108 | 136 | .workspace-pane-active { | |
| 137 | + | border-width: %dpx; | |
| 109 | 138 | border-color: %s; | |
| 110 | 139 | } | |
| 111 | 140 | ||
| @@ -114,14 +143,15 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||
| 114 | 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 | 147 | .stacked-pane-container.workspace-pane-active { | |
| 148 | + | border-width: %dpx; | |
| 119 | 149 | border-color: %s; | |
| 120 | 150 | } | |
| 121 | 151 | ||
| 122 | 152 | .stacked-pane-title { | |
| 123 | 153 | background-color: %s; | |
| 124 | - | border-bottom: 1px solid %s; | |
| 154 | + | border-bottom: %s; | |
| 125 | 155 | padding: 4px 8px; | |
| 126 | 156 | min-height: 24px; | |
| 127 | 157 | transition: background-color %dms ease-in-out; | |
| @@ -148,20 +178,23 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||
| 148 | 178 | .stacked-pane-collapsed { | |
| 149 | 179 | /* Collapsed panes are hidden - handled in code via widget visibility */ | |
| 150 | 180 | }`, | |
| 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 | |
| 165 | 198 | ) | |
| 166 | 199 | ||
| 167 | 200 | return css | |
| @@ -55,23 +55,41 @@ func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool | |||||
| 55 | return "#87CEEB" // Sky blue pastel for light theme | 55 | 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 panes | 77 | // 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.Styling | 80 | styling := cfg.Workspace.Styling | ||
| 62 | 81 | ||||
| 63 | // Get appropriate colors based on GTK theme preference | 82 | // Get appropriate colors based on GTK theme preference | ||
| 64 | - | var inactiveBorderColor, windowBackgroundColor string | 83 | + | 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 background | 86 | windowBackgroundColor = "#2b2b2b" // Dark window background | ||
| 69 | } else { | 87 | } else { | ||
| 70 | - | inactiveBorderColor = "#dddddd" // Light border for light theme | |||
| 71 | windowBackgroundColor = "#ffffff" // Light window background | 88 | 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 orange | 94 | // Pane mode border color - use configured value or fallback to orange | ||
| 77 | paneModeColor := styling.PaneModeBorderColor | 95 | paneModeColor := styling.PaneModeBorderColor | ||
| @@ -79,6 +97,12 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string { | |||||
| 79 | paneModeColor = "#FFA500" // Fallback to orange if not configured | 97 | 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 background | 181 | + | 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 background | 183 | + | 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 radius | 185 | + | inactiveBorderColor, // base pane border-color (inactive) |
| 156 | - | styling.TransitionDuration, // base pane border transition | 186 | + | styling.BorderRadius, // base pane border radius |
| 157 | - | activeBorderColor, // workspace-pane-active border color | 187 | + | styling.TransitionDuration, // transition-duration |
| 158 | - | windowBackgroundColor, // stacked-pane-container background | 188 | + | 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 background | 190 | + | windowBackgroundColor, // stacked-pane-container background |
| 161 | - | inactiveBorderColor, // stacked-pane-title border-bottom | 191 | + | styling.InactiveBorderWidth, // stacked-pane-container.active border-width |
| 162 | - | styling.TransitionDuration, // stacked-pane-title transition | 192 | + | inactiveBorderColor, // stacked-pane-container.active border-color |
| 163 | - | getStackTitleHoverBg(isDark), // stacked-pane-title:hover background | 193 | + | getStackTitleBg(isDark), // stacked-pane-title background |
| 164 | - | getStackTitleTextColor(isDark), // stacked-pane-title-text color | 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 | |||
| 165 | ) | 198 | ) | ||
| 166 | 199 | ||||
| 167 | return css | 200 | return css | ||
M internal/config/config.go +10 -1
| @@ -283,10 +283,16 @@ type PopupBehaviorConfig struct { | |||
| 283 | 283 | ||
| 284 | 284 | // WorkspaceStylingConfig defines visual styling for workspace panes. | |
| 285 | 285 | type WorkspaceStylingConfig struct { | |
| 286 | - | // BorderWidth in pixels for pane borders | |
| 286 | + | // BorderWidth in pixels for active pane borders | |
| 287 | 287 | BorderWidth int `mapstructure:"border_width" yaml:"border_width" json:"border_width"` | |
| 288 | 288 | // BorderColor for focused panes (CSS color value or theme variable) | |
| 289 | 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 | 296 | // PaneModeBorderColor for the pane mode indicator border (CSS color value or theme variable) | |
| 291 | 297 | // Defaults to "#FFA500" (orange) if not set | |
| 292 | 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 | 698 | m.viper.SetDefault("workspace.popups.oauth_auto_close", defaults.Workspace.Popups.OAuthAutoClose) | |
| 693 | 699 | m.viper.SetDefault("workspace.styling.border_width", defaults.Workspace.Styling.BorderWidth) | |
| 694 | 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 | 704 | m.viper.SetDefault("workspace.styling.pane_mode_border_color", defaults.Workspace.Styling.PaneModeBorderColor) | |
| 696 | 705 | m.viper.SetDefault("workspace.styling.transition_duration", defaults.Workspace.Styling.TransitionDuration) | |
| 697 | 706 | 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 borders | 286 | + | // 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 set | 297 | // 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 ( | |||
| 24 | 24 | defaultPopupPlacement = "right" | |
| 25 | 25 | ||
| 26 | 26 | // 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 | |
| 32 | 35 | ) | |
| 33 | 36 | ||
| 34 | 37 | // getDefaultLogDir returns the default log directory, falls back to empty string on error | |
| @@ -176,11 +179,14 @@ func DefaultConfig() *Config { | |||
| 176 | 179 | OAuthAutoClose: true, // Auto-close OAuth popups on success | |
| 177 | 180 | }, | |
| 178 | 181 | 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, | |
| 184 | 190 | }, | |
| 185 | 191 | }, | |
| 186 | 192 | ContentFilteringWhitelist: []string{ | |
| @@ -24,11 +24,14 @@ const ( | |||||
| 24 | defaultPopupPlacement = "right" | 24 | defaultPopupPlacement = "right" | ||
| 25 | 25 | ||||
| 26 | // Workspace styling defaults | 26 | // Workspace styling defaults | ||
| 27 | - | defaultBorderWidth = 2 | 27 | + | defaultBorderWidth = 1 |
| 28 | - | defaultBorderColor = "@theme_selected_bg_color" | 28 | + | defaultBorderColor = "@theme_selected_bg_color" |
| 29 | - | defaultPaneModeBorderColor = "#FFA500" // Orange for pane mode indicator | 29 | + | defaultInactiveBorderWidth = 1 // Same width as active to prevent layout shift |
| 30 | - | defaultTransitionDuration = 120 | 30 | + | defaultInactiveBorderColor = "@theme_unfocused_bg_color" // GTK theme variable |
| 31 | - | defaultBorderRadius = 0 | 31 | + | 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 error | 37 | // 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 success | 179 | 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{ | ||