fix(theme): keep stacked title bars compact (#443)
- commit
- fdc7e51fc3a80e811c9711152a040666fe12c4c9
- author
- bnema · · 2026-09-20 17:05 UTC
- committer
- GitHub · · 2026-09-20 17:05 UTC
- parent
- b79d993
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
2 files · +28 -8
M internal/ui/theme/css.go +8 -7
| @@ -948,7 +948,7 @@ func generatePaneCSS(p Palette) string { | |||
| 948 | 948 | } | |
| 949 | 949 | ||
| 950 | 950 | // generateStackedPaneCSS creates stacked pane (Zellij-style tabs within panes) styles. | |
| 951 | - | // Uses em units for scalable UI. | |
| 951 | + | // Text uses scalable units while vertical chrome stays compact in device pixels. | |
| 952 | 952 | func generateStackedPaneCSS(p Palette) string { | |
| 953 | 953 | return `/* ===== Stacked Pane Styling ===== */ | |
| 954 | 954 | ||
| @@ -958,8 +958,8 @@ func generateStackedPaneCSS(p Palette) string { | |||
| 958 | 958 | background-color: var(--surface-variant); | |
| 959 | 959 | color: var(--control-text); | |
| 960 | 960 | border-bottom: 0.0625em solid var(--border); | |
| 961 | - | padding: 0.25em 0.5em; | |
| 962 | - | min-height: 1.5em; | |
| 961 | + | padding: 4px 0.5em; | |
| 962 | + | min-height: 24px; | |
| 963 | 963 | } | |
| 964 | 964 | ||
| 965 | 965 | /* Keep the background stable so --control-text retains its contrast. | |
| @@ -988,15 +988,16 @@ func generateStackedPaneCSS(p Palette) string { | |||
| 988 | 988 | text-decoration-line: underline; | |
| 989 | 989 | } | |
| 990 | 990 | ||
| 991 | - | /* Close button in stacked pane title bar */ | |
| 991 | + | /* Close button in stacked pane title bar. | |
| 992 | + | * Its vertical footprint is intentionally smaller than the original scale-1 baseline. */ | |
| 992 | 993 | .stacked-pane-close-button { | |
| 993 | 994 | background: transparent; | |
| 994 | 995 | border: none; | |
| 995 | 996 | border-radius: 0.2727em; | |
| 996 | - | padding: 0.2727em; | |
| 997 | - | margin: 0 0.1364em; | |
| 997 | + | padding: 3px; | |
| 998 | + | margin: 0 2px; | |
| 998 | 999 | min-width: 1.3636em; | |
| 999 | - | min-height: 1.3636em; | |
| 1000 | + | min-height: 15px; | |
| 1000 | 1001 | opacity: 0.4; | |
| 1001 | 1002 | transition: opacity 100ms ease-in-out, background-color 100ms ease-in-out; | |
| 1002 | 1003 | } | |
| @@ -948,7 +948,7 @@ func generatePaneCSS(p Palette) string { | |||||
| 948 | } | 948 | } | ||
| 949 | 949 | ||||
| 950 | // generateStackedPaneCSS creates stacked pane (Zellij-style tabs within panes) styles. | 950 | // generateStackedPaneCSS creates stacked pane (Zellij-style tabs within panes) styles. | ||
| 951 | - | // Uses em units for scalable UI. | 951 | + | // Text uses scalable units while vertical chrome stays compact in device pixels. |
| 952 | func generateStackedPaneCSS(p Palette) string { | 952 | func generateStackedPaneCSS(p Palette) string { | ||
| 953 | return `/* ===== Stacked Pane Styling ===== */ | 953 | return `/* ===== Stacked Pane Styling ===== */ | ||
| 954 | 954 | ||||
| @@ -958,8 +958,8 @@ func generateStackedPaneCSS(p Palette) string { | |||||
| 958 | background-color: var(--surface-variant); | 958 | background-color: var(--surface-variant); | ||
| 959 | color: var(--control-text); | 959 | color: var(--control-text); | ||
| 960 | border-bottom: 0.0625em solid var(--border); | 960 | border-bottom: 0.0625em solid var(--border); | ||
| 961 | - | padding: 0.25em 0.5em; | 961 | + | padding: 4px 0.5em; |
| 962 | - | min-height: 1.5em; | 962 | + | min-height: 24px; |
| 963 | } | 963 | } | ||
| 964 | 964 | ||||
| 965 | /* Keep the background stable so --control-text retains its contrast. | 965 | /* Keep the background stable so --control-text retains its contrast. | ||
| @@ -988,15 +988,16 @@ func generateStackedPaneCSS(p Palette) string { | |||||
| 988 | text-decoration-line: underline; | 988 | text-decoration-line: underline; | ||
| 989 | } | 989 | } | ||
| 990 | 990 | ||||
| 991 | - | /* Close button in stacked pane title bar */ | 991 | + | /* Close button in stacked pane title bar. |
| 992 | + | * Its vertical footprint is intentionally smaller than the original scale-1 baseline. */ | |||
| 992 | .stacked-pane-close-button { | 993 | .stacked-pane-close-button { | ||
| 993 | background: transparent; | 994 | background: transparent; | ||
| 994 | border: none; | 995 | border: none; | ||
| 995 | border-radius: 0.2727em; | 996 | border-radius: 0.2727em; | ||
| 996 | - | padding: 0.2727em; | 997 | + | padding: 3px; |
| 997 | - | margin: 0 0.1364em; | 998 | + | margin: 0 2px; |
| 998 | min-width: 1.3636em; | 999 | min-width: 1.3636em; | ||
| 999 | - | min-height: 1.3636em; | 1000 | + | min-height: 15px; |
| 1000 | opacity: 0.4; | 1001 | opacity: 0.4; | ||
| 1001 | transition: opacity 100ms ease-in-out, background-color 100ms ease-in-out; | 1002 | transition: opacity 100ms ease-in-out, background-color 100ms ease-in-out; | ||
| 1002 | } | 1003 | } | ||
M internal/ui/theme/css_test.go +20 -1
| @@ -259,7 +259,6 @@ func TestGenerateCSS_AuxiliaryWidgetDimensionsUseScalableUnits(t *testing.T) { | |||
| 259 | 259 | ".loading-skeleton-spinner", | |
| 260 | 260 | ".loading-skeleton-logo", | |
| 261 | 261 | ".loading-skeleton-version", | |
| 262 | - | ".stacked-pane-close-button", | |
| 263 | 262 | "progressbar.osd", | |
| 264 | 263 | "progressbar.osd trough", | |
| 265 | 264 | "progressbar.osd progress", | |
| @@ -272,6 +271,26 @@ func TestGenerateCSS_AuxiliaryWidgetDimensionsUseScalableUnits(t *testing.T) { | |||
| 272 | 271 | } | |
| 273 | 272 | } | |
| 274 | 273 | ||
| 274 | + | func TestGenerateCSS_StackedPaneTitlebarKeepsCompactVerticalChrome(t *testing.T) { | |
| 275 | + | css := GenerateCSS(DefaultDarkPalette()) | |
| 276 | + | ||
| 277 | + | titlebar := cssRuleBlock(t, css, ".stacked-pane-titlebar") | |
| 278 | + | assert.Contains(t, titlebar, "padding: 4px 0.5em;") | |
| 279 | + | assert.Contains(t, titlebar, "min-height: 24px;") | |
| 280 | + | assert.NotRegexp(t, `(?m)^\s*(?:padding-(?:top|bottom)|min-height):[^;]*em`, titlebar) | |
| 281 | + | ||
| 282 | + | closeButton := cssRuleBlock(t, css, ".stacked-pane-close-button") | |
| 283 | + | assert.Contains(t, closeButton, "padding: 3px;") | |
| 284 | + | assert.Contains(t, closeButton, "margin: 0 2px;") | |
| 285 | + | assert.Contains(t, closeButton, "min-height: 15px;") | |
| 286 | + | assert.NotRegexp(t, `(?m)^\s*(?:padding|margin|min-height):[^;]*em`, closeButton) | |
| 287 | + | ||
| 288 | + | // Text and horizontal sizing still follow GTK font scaling. | |
| 289 | + | label := cssRuleBlock(t, css, ".stacked-pane-titlebar label") | |
| 290 | + | assert.Contains(t, label, "font-size: 0.75em;") | |
| 291 | + | assert.Contains(t, closeButton, "min-width: 1.3636em;") | |
| 292 | + | } | |
| 293 | + | ||
| 275 | 294 | func TestGenerateCSS_OmniboxOuterBordersUseScalableEmUnits(t *testing.T) { | |
| 276 | 295 | css := GenerateCSS(DefaultDarkPalette()) | |
| 277 | 296 | ||
| @@ -259,7 +259,6 @@ func TestGenerateCSS_AuxiliaryWidgetDimensionsUseScalableUnits(t *testing.T) { | |||||
| 259 | ".loading-skeleton-spinner", | 259 | ".loading-skeleton-spinner", | ||
| 260 | ".loading-skeleton-logo", | 260 | ".loading-skeleton-logo", | ||
| 261 | ".loading-skeleton-version", | 261 | ".loading-skeleton-version", | ||
| 262 | - | ".stacked-pane-close-button", | |||
| 263 | "progressbar.osd", | 262 | "progressbar.osd", | ||
| 264 | "progressbar.osd trough", | 263 | "progressbar.osd trough", | ||
| 265 | "progressbar.osd progress", | 264 | "progressbar.osd progress", | ||
| @@ -272,6 +271,26 @@ func TestGenerateCSS_AuxiliaryWidgetDimensionsUseScalableUnits(t *testing.T) { | |||||
| 272 | } | 271 | } | ||
| 273 | } | 272 | } | ||
| 274 | 273 | ||||
| 274 | + | func TestGenerateCSS_StackedPaneTitlebarKeepsCompactVerticalChrome(t *testing.T) { | |||
| 275 | + | css := GenerateCSS(DefaultDarkPalette()) | |||
| 276 | + | ||||
| 277 | + | titlebar := cssRuleBlock(t, css, ".stacked-pane-titlebar") | |||
| 278 | + | assert.Contains(t, titlebar, "padding: 4px 0.5em;") | |||
| 279 | + | assert.Contains(t, titlebar, "min-height: 24px;") | |||
| 280 | + | assert.NotRegexp(t, `(?m)^\s*(?:padding-(?:top|bottom)|min-height):[^;]*em`, titlebar) | |||
| 281 | + | ||||
| 282 | + | closeButton := cssRuleBlock(t, css, ".stacked-pane-close-button") | |||
| 283 | + | assert.Contains(t, closeButton, "padding: 3px;") | |||
| 284 | + | assert.Contains(t, closeButton, "margin: 0 2px;") | |||
| 285 | + | assert.Contains(t, closeButton, "min-height: 15px;") | |||
| 286 | + | assert.NotRegexp(t, `(?m)^\s*(?:padding|margin|min-height):[^;]*em`, closeButton) | |||
| 287 | + | ||||
| 288 | + | // Text and horizontal sizing still follow GTK font scaling. | |||
| 289 | + | label := cssRuleBlock(t, css, ".stacked-pane-titlebar label") | |||
| 290 | + | assert.Contains(t, label, "font-size: 0.75em;") | |||
| 291 | + | assert.Contains(t, closeButton, "min-width: 1.3636em;") | |||
| 292 | + | } | |||
| 293 | + | ||||
| 275 | func TestGenerateCSS_OmniboxOuterBordersUseScalableEmUnits(t *testing.T) { | 294 | func TestGenerateCSS_OmniboxOuterBordersUseScalableEmUnits(t *testing.T) { | ||
| 276 | css := GenerateCSS(DefaultDarkPalette()) | 295 | css := GenerateCSS(DefaultDarkPalette()) | ||
| 277 | 296 | ||||