detached 92941be

feat(stacked-panes): add visual enhancements to title bars

- Add subtle 1px border separator between stacked pane titles
- Border color is theme-aware (darker in light mode, lighter in dark mode)
- Implement UI scaling for all title bar elements (font, padding, height, favicon)
- Base scale is 1.0 (100%), configurable via workspace.styling.ui_scale
- Scales apply to: font size (12px), padding (4px/8px), height (24px), favicon (16px)
commit
92941be09ef4f888987e385245e732c0dbfa8810
author
bnema · · 2025-11-16 22:41 UTC
committer
bnema · · 2025-11-16 20:05 UTC
parent
524e65e
signature
unsigned
1 file · +29 -8
M internal/app/browser/workspace_css.go +29 -8
@@ -36,6 +36,14 @@ func getStackTitleTextColor(isDark bool) string {
3636 return "#333333"
3737 }
3838
39+// getStackTitleBorderColor returns a subtle border color slightly darker than the title background
40+func getStackTitleBorderColor(isDark bool) string {
41+ if isDark {
42+ return "#353535" // Slightly darker than #404040
43+ }
44+ return "#e5e5e5" // Slightly darker than #f0f0f0
45+}
46+
3947 // getActivePaneBorderColor returns the border color for active panes based on config and theme
4048 func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool) string {
4149 // Use configured border color if set
@@ -97,11 +105,19 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
97105 paneModeColor = "#FFA500" // Fallback to orange if not configured
98106 }
99107
100- // Stacked title border - conditional based on config
101- stackedTitleBorder := "0"
102- if styling.ShowStackedTitleBorder {
103- stackedTitleBorder = fmt.Sprintf("1px solid %s", inactiveBorderColor)
108+ // Stacked title border - subtle separator between titles
109+ stackedTitleBorder := fmt.Sprintf("1px solid %s", getStackTitleBorderColor(isDark))
110+
111+ // UI Scale calculations for title bar elements (base values at 1.0 scale)
112+ uiScale := styling.UIScale
113+ if uiScale <= 0 {
114+ uiScale = 1.0 // Fallback to default if invalid
104115 }
116+ titleFontSize := int(12 * uiScale) // Base: 12px
117+ titlePaddingVertical := int(4 * uiScale) // Base: 4px
118+ titlePaddingHorizontal := int(8 * uiScale) // Base: 8px
119+ titleMinHeight := int(24 * uiScale) // Base: 24px
120+ faviconMargin := int(4 * uiScale) // Base: 4px
105121
106122 css := fmt.Sprintf(`window {
107123 background-color: %s;
@@ -152,8 +168,8 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
152168 .stacked-pane-title {
153169 background-color: %s;
154170 border-bottom: %s;
155- padding: 4px 8px;
156- min-height: 24px;
171+ padding: %dpx %dpx;
172+ min-height: %dpx;
157173 transition: background-color %dms ease-in-out;
158174 }
159175
@@ -162,13 +178,13 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
162178 }
163179
164180 .stacked-pane-title-text {
165- font-size: 12px;
181+ font-size: %dpx;
166182 color: %s;
167183 font-weight: 500;
168184 }
169185
170186 .stacked-pane-favicon {
171- margin-right: 4px;
187+ margin-right: %dpx;
172188 }
173189
174190 .stacked-pane-active {
@@ -192,9 +208,14 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
192208 inactiveBorderColor, // stacked-pane-container.active border-color
193209 getStackTitleBg(isDark), // stacked-pane-title background
194210 stackedTitleBorder, // stacked-pane-title border-bottom
211+ titlePaddingVertical, // stacked-pane-title padding vertical
212+ titlePaddingHorizontal, // stacked-pane-title padding horizontal
213+ titleMinHeight, // stacked-pane-title min-height
195214 styling.TransitionDuration, // stacked-pane-title transition
196215 getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
216+ titleFontSize, // stacked-pane-title-text font-size
197217 getStackTitleTextColor(isDark), // stacked-pane-title-text color
218+ faviconMargin, // stacked-pane-favicon margin-right
198219 )
199220
200221 return css
@@ -36,6 +36,14 @@ func getStackTitleTextColor(isDark bool) string {
36 return "#333333"36 return "#333333"
37 }37 }
38 38
39+// getStackTitleBorderColor returns a subtle border color slightly darker than the title background
40+func getStackTitleBorderColor(isDark bool) string {
41+ if isDark {
42+ return "#353535" // Slightly darker than #404040
43+ }
44+ return "#e5e5e5" // Slightly darker than #f0f0f0
45+}
46+
39 // getActivePaneBorderColor returns the border color for active panes based on config and theme47 // getActivePaneBorderColor returns the border color for active panes based on config and theme
40 func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool) string {48 func getActivePaneBorderColor(styling config.WorkspaceStylingConfig, isDark bool) string {
41 // Use configured border color if set49 // Use configured border color if set
@@ -97,11 +105,19 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
97 paneModeColor = "#FFA500" // Fallback to orange if not configured105 paneModeColor = "#FFA500" // Fallback to orange if not configured
98 }106 }
99 107
100- // Stacked title border - conditional based on config108+ // Stacked title border - subtle separator between titles
101- stackedTitleBorder := "0"109+ stackedTitleBorder := fmt.Sprintf("1px solid %s", getStackTitleBorderColor(isDark))
102- if styling.ShowStackedTitleBorder {110+
103- stackedTitleBorder = fmt.Sprintf("1px solid %s", inactiveBorderColor)111+ // UI Scale calculations for title bar elements (base values at 1.0 scale)
112+ uiScale := styling.UIScale
113+ if uiScale <= 0 {
114+ uiScale = 1.0 // Fallback to default if invalid
104 }115 }
116+ titleFontSize := int(12 * uiScale) // Base: 12px
117+ titlePaddingVertical := int(4 * uiScale) // Base: 4px
118+ titlePaddingHorizontal := int(8 * uiScale) // Base: 8px
119+ titleMinHeight := int(24 * uiScale) // Base: 24px
120+ faviconMargin := int(4 * uiScale) // Base: 4px
105 121
106 css := fmt.Sprintf(`window {122 css := fmt.Sprintf(`window {
107 background-color: %s;123 background-color: %s;
@@ -152,8 +168,8 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
152 .stacked-pane-title {168 .stacked-pane-title {
153 background-color: %s;169 background-color: %s;
154 border-bottom: %s;170 border-bottom: %s;
155- padding: 4px 8px;171+ padding: %dpx %dpx;
156- min-height: 24px;172+ min-height: %dpx;
157 transition: background-color %dms ease-in-out;173 transition: background-color %dms ease-in-out;
158 }174 }
159 175
@@ -162,13 +178,13 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
162 }178 }
163 179
164 .stacked-pane-title-text {180 .stacked-pane-title-text {
165- font-size: 12px;181+ font-size: %dpx;
166 color: %s;182 color: %s;
167 font-weight: 500;183 font-weight: 500;
168 }184 }
169 185
170 .stacked-pane-favicon {186 .stacked-pane-favicon {
171- margin-right: 4px;187+ margin-right: %dpx;
172 }188 }
173 189
174 .stacked-pane-active {190 .stacked-pane-active {
@@ -192,9 +208,14 @@ func (wm *WorkspaceManager) generateWorkspaceCSS() string {
192 inactiveBorderColor, // stacked-pane-container.active border-color208 inactiveBorderColor, // stacked-pane-container.active border-color
193 getStackTitleBg(isDark), // stacked-pane-title background209 getStackTitleBg(isDark), // stacked-pane-title background
194 stackedTitleBorder, // stacked-pane-title border-bottom210 stackedTitleBorder, // stacked-pane-title border-bottom
211+ titlePaddingVertical, // stacked-pane-title padding vertical
212+ titlePaddingHorizontal, // stacked-pane-title padding horizontal
213+ titleMinHeight, // stacked-pane-title min-height
195 styling.TransitionDuration, // stacked-pane-title transition214 styling.TransitionDuration, // stacked-pane-title transition
196 getStackTitleHoverBg(isDark), // stacked-pane-title:hover background215 getStackTitleHoverBg(isDark), // stacked-pane-title:hover background
216+ titleFontSize, // stacked-pane-title-text font-size
197 getStackTitleTextColor(isDark), // stacked-pane-title-text color217 getStackTitleTextColor(isDark), // stacked-pane-title-text color
218+ faviconMargin, // stacked-pane-favicon margin-right
198 )219 )
199 220
200 return css221 return css

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