detached fc90745

fix(omnibox): strengthen scalable outer borders (#439)

* fix(omnibox): strengthen scalable outer borders

* test(omnibox): verify scalable border hierarchy
commit
fc90745d39c798510bf444be79963be8f53892bf
author
bnema · · 2026-09-15 04:44 UTC
committer
GitHub · · 2026-09-15 04:44 UTC
parent
6f391e8
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
3 files · +34 -1
M CHANGELOG.md +1 -0
@@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
1313
1414 ### Changed
1515
16+- **Omnibox borders**: Outer borders scale with the configured UI size and remain more pronounced for the default `command` style.
1617 - **Omnibox status indicators**: The history-order control is now a passive status badge switched with `Ctrl+R`, and favorites use a terminal-style `*` marker.
1718 - **Favorites organization**: Favorites now use a tags-first model. Existing folder assignments are migrated into deterministic tags, with collision handling and folded-name uniqueness preserved during migration.
1819 - **Page mode configuration**: Page Mode is now called Vim Mode and uses the `workspace.vim_mode` configuration namespace for activation, timeouts, and action sequences. Existing page-mode bindings are migrated by the configuration loader.
@@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
13 13
14 ### Changed14 ### Changed
15 15
16+- **Omnibox borders**: Outer borders scale with the configured UI size and remain more pronounced for the default `command` style.
16 - **Omnibox status indicators**: The history-order control is now a passive status badge switched with `Ctrl+R`, and favorites use a terminal-style `*` marker.17 - **Omnibox status indicators**: The history-order control is now a passive status badge switched with `Ctrl+R`, and favorites use a terminal-style `*` marker.
17 - **Favorites organization**: Favorites now use a tags-first model. Existing folder assignments are migrated into deterministic tags, with collision handling and folded-name uniqueness preserved during migration.18 - **Favorites organization**: Favorites now use a tags-first model. Existing folder assignments are migrated into deterministic tags, with collision handling and folded-name uniqueness preserved during migration.
18 - **Page mode configuration**: Page Mode is now called Vim Mode and uses the `workspace.vim_mode` configuration namespace for activation, timeouts, and action sequences. Existing page-mode bindings are migrated by the configuration loader.19 - **Page mode configuration**: Page Mode is now called Vim Mode and uses the `workspace.vim_mode` configuration namespace for activation, timeouts, and action sequences. Existing page-mode bindings are migrated by the configuration loader.
M internal/ui/theme/css.go +2 -1
@@ -242,7 +242,7 @@ window.standalone-omnibox-window {
242242 .omnibox-container {
243243 background-color: var(--surface);
244244 background-image: none;
245- border: 0.0625em solid alpha(var(--border), 0.85);
245+ border: 0.09375em solid alpha(var(--border), 0.9);
246246 border-radius: 0.1875em;
247247 box-shadow: 0 0.875em 2.5em alpha(black, 0.24), 0 0.0625em 0 alpha(white, 0.05) inset;
248248 padding: 0;
@@ -577,6 +577,7 @@ entry.omnibox-entry.omnibox-entry-bang-active:focus-visible > text {
577577
578578 /* Command: a calmer command palette with a floating input and compact tabs. */
579579 .omnibox-container.omnibox-style-command {
580+ border: 0.125em solid alpha(var(--border), 0.95);
580581 border-radius: 0.625em;
581582 box-shadow: 0 1.25em 3.5em alpha(black, 0.38), 0 0 0 0.0625em alpha(white, 0.04) inset;
582583 padding: 0.375em;
@@ -242,7 +242,7 @@ window.standalone-omnibox-window {
242 .omnibox-container {242 .omnibox-container {
243 background-color: var(--surface);243 background-color: var(--surface);
244 background-image: none;244 background-image: none;
245- border: 0.0625em solid alpha(var(--border), 0.85);245+ border: 0.09375em solid alpha(var(--border), 0.9);
246 border-radius: 0.1875em;246 border-radius: 0.1875em;
247 box-shadow: 0 0.875em 2.5em alpha(black, 0.24), 0 0.0625em 0 alpha(white, 0.05) inset;247 box-shadow: 0 0.875em 2.5em alpha(black, 0.24), 0 0.0625em 0 alpha(white, 0.05) inset;
248 padding: 0;248 padding: 0;
@@ -577,6 +577,7 @@ entry.omnibox-entry.omnibox-entry-bang-active:focus-visible > text {
577 577
578 /* Command: a calmer command palette with a floating input and compact tabs. */578 /* Command: a calmer command palette with a floating input and compact tabs. */
579 .omnibox-container.omnibox-style-command {579 .omnibox-container.omnibox-style-command {
580+ border: 0.125em solid alpha(var(--border), 0.95);
580 border-radius: 0.625em;581 border-radius: 0.625em;
581 box-shadow: 0 1.25em 3.5em alpha(black, 0.38), 0 0 0 0.0625em alpha(white, 0.04) inset;582 box-shadow: 0 1.25em 3.5em alpha(black, 0.38), 0 0 0 0.0625em alpha(white, 0.04) inset;
582 padding: 0.375em;583 padding: 0.375em;
M internal/ui/theme/css_test.go +31 -0
@@ -2,6 +2,7 @@ package theme
22
33 import (
44 "regexp"
5+ "strconv"
56 "strings"
67 "testing"
78
@@ -251,6 +252,36 @@ func TestGenerateCSSWithScale_UsesMediumWeightForOmniboxSuggestionTitle(t *testi
251252 assert.NotContains(t, css, ".omnibox-suggestion-title {\n\tfont-size: 0.875em;\n\tcolor: var(--text);\n\tfont-weight: 400;")
252253 }
253254
255+func TestGenerateCSS_OmniboxOuterBordersUseScalableEmUnits(t *testing.T) {
256+ css := GenerateCSS(DefaultDarkPalette())
257+
258+ base := cssRuleBlock(t, css, ".omnibox-container")
259+ baseWidth := cssBorderWidthEm(t, base)
260+ assert.InDelta(t, 0.09375, baseWidth, 0.000001)
261+
262+ command := cssRuleBlock(t, css, ".omnibox-container.omnibox-style-command")
263+ commandWidth := cssBorderWidthEm(t, command)
264+ assert.Greater(t, commandWidth, baseWidth)
265+
266+ for _, style := range []string{"multiplexer", "minimal"} {
267+ block := cssRuleBlock(t, css, ".omnibox-container.omnibox-style-"+style)
268+ assert.NotRegexp(t, `(?m)^\s*border(?:-width)?:`, block)
269+ }
270+}
271+
272+func cssBorderWidthEm(t *testing.T, block string) float64 {
273+ t.Helper()
274+ match := regexp.MustCompile(`(?m)^\s*border:\s*([0-9.]+)em\s`).FindStringSubmatch(block)
275+ if len(match) != 2 {
276+ t.Fatalf("CSS rule does not define an em border: %s", block)
277+ }
278+ width, err := strconv.ParseFloat(match[1], 64)
279+ if err != nil {
280+ t.Fatalf("parse border width %q: %v", match[1], err)
281+ }
282+ return width
283+}
284+
254285 func TestGenerateCSS_OmniboxIncludesVisualConcepts(t *testing.T) {
255286 css := GenerateCSS(DefaultDarkPalette())
256287
@@ -2,6 +2,7 @@ package theme
2 2
3 import (3 import (
4 "regexp"4 "regexp"
5+ "strconv"
5 "strings"6 "strings"
6 "testing"7 "testing"
7 8
@@ -251,6 +252,36 @@ func TestGenerateCSSWithScale_UsesMediumWeightForOmniboxSuggestionTitle(t *testi
251 assert.NotContains(t, css, ".omnibox-suggestion-title {\n\tfont-size: 0.875em;\n\tcolor: var(--text);\n\tfont-weight: 400;")252 assert.NotContains(t, css, ".omnibox-suggestion-title {\n\tfont-size: 0.875em;\n\tcolor: var(--text);\n\tfont-weight: 400;")
252 }253 }
253 254
255+func TestGenerateCSS_OmniboxOuterBordersUseScalableEmUnits(t *testing.T) {
256+ css := GenerateCSS(DefaultDarkPalette())
257+
258+ base := cssRuleBlock(t, css, ".omnibox-container")
259+ baseWidth := cssBorderWidthEm(t, base)
260+ assert.InDelta(t, 0.09375, baseWidth, 0.000001)
261+
262+ command := cssRuleBlock(t, css, ".omnibox-container.omnibox-style-command")
263+ commandWidth := cssBorderWidthEm(t, command)
264+ assert.Greater(t, commandWidth, baseWidth)
265+
266+ for _, style := range []string{"multiplexer", "minimal"} {
267+ block := cssRuleBlock(t, css, ".omnibox-container.omnibox-style-"+style)
268+ assert.NotRegexp(t, `(?m)^\s*border(?:-width)?:`, block)
269+ }
270+}
271+
272+func cssBorderWidthEm(t *testing.T, block string) float64 {
273+ t.Helper()
274+ match := regexp.MustCompile(`(?m)^\s*border:\s*([0-9.]+)em\s`).FindStringSubmatch(block)
275+ if len(match) != 2 {
276+ t.Fatalf("CSS rule does not define an em border: %s", block)
277+ }
278+ width, err := strconv.ParseFloat(match[1], 64)
279+ if err != nil {
280+ t.Fatalf("parse border width %q: %v", match[1], err)
281+ }
282+ return width
283+}
284+
254 func TestGenerateCSS_OmniboxIncludesVisualConcepts(t *testing.T) {285 func TestGenerateCSS_OmniboxIncludesVisualConcepts(t *testing.T) {
255 css := GenerateCSS(DefaultDarkPalette())286 css := GenerateCSS(DefaultDarkPalette())
256 287

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