detached 1fd2245

fix(visual): center PIN dots with symmetric field padding

go-text already omits outer letter-spacing, so the asymmetric padding
shifted the dots right. The relief border width now comes from fieldEdge.
commit
1fd224555ffeefcf30c48423adfce7dcf205e9db
author
brice · · 2026-10-01 13:32 UTC
committer
brice · · 2026-10-01 16:10 UTC
parent
9e2fc29
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +5 -7
M internal/adapters/visual/view.go +5 -7
@@ -25,7 +25,6 @@ const (
2525 fieldEdge = 2 // relief width (bottom and right)
2626 passwordW = 280
2727 pinW = 160
28- pinSpacing = 6 // letter-spacing between PIN dots
2928
3029 // boxContentW is the width available to the field inside the box.
3130 boxContentW = frameW - 2*boxBorder - 2*boxPadding
@@ -42,8 +41,6 @@ const (
4241 cssClock = "color:#ffffff;text-align:right;height:24px;margin-bottom:8px"
4342 // cssBalance mirrors cssClock below the box.
4443 cssBalance = "height:24px;margin-top:8px"
45- // cssRelief is the inverted relief: bottom and right edges at 50% white.
46- cssRelief = "border-bottom:2px solid rgba(255,255,255,0.5);border-right:2px solid rgba(255,255,255,0.5)"
4744 // cssHint and cssHintBalance have the same outer height.
4845 cssHint = "color:#ffffff;margin-top:12px;height:22px;text-align:center"
4946 cssHintBalance = "margin-bottom:12px;height:22px"
@@ -52,16 +49,17 @@ const (
5249 )
5350
5451 var (
52+ // cssRelief is the inverted relief: bottom and right edges at 50% white.
53+ cssRelief = fmt.Sprintf("border-bottom:%[1]dpx solid rgba(255,255,255,0.5);"+
54+ "border-right:%[1]dpx solid rgba(255,255,255,0.5)", fieldEdge)
5555 cssFrame = fmt.Sprintf("display:flex;flex-direction:column;align-items:stretch;width:%dpx", frameW)
5656 cssBox = fmt.Sprintf("display:flex;flex-direction:column;align-items:stretch;"+
5757 "border:%dpx solid #bfbfbf;padding:%dpx;background-color:#000000", boxBorder, boxPadding)
5858 cssMask = fmt.Sprintf("color:#ffffff;height:32px;line-height:32px;width:%dpx;"+
5959 "padding:4px %dpx;margin-left:%dpx;%s", passwordW, fieldPadX, fieldMargin(passwordW), cssRelief)
60- // The PIN field shifts its padding by half the trailing letter-spacing
61- // so the dots stay optically centered.
6260 cssMaskPIN = fmt.Sprintf("color:#ffffff;height:32px;line-height:32px;width:%dpx;"+
63- "padding:4px %dpx 4px %dpx;margin-left:%dpx;font-size:24px;letter-spacing:%dpx;text-align:center;%s",
64- pinW, fieldPadX-pinSpacing/2, fieldPadX+pinSpacing/2, fieldMargin(pinW), pinSpacing, cssRelief)
61+ "padding:4px %dpx;margin-left:%dpx;font-size:24px;letter-spacing:6px;text-align:center;%s",
62+ pinW, fieldPadX, fieldMargin(pinW), cssRelief)
6563 )
6664
6765 // fieldMargin centers a field of content width w inside the box content.
@@ -25,7 +25,6 @@ const (
25 fieldEdge = 2 // relief width (bottom and right)25 fieldEdge = 2 // relief width (bottom and right)
26 passwordW = 28026 passwordW = 280
27 pinW = 16027 pinW = 160
28- pinSpacing = 6 // letter-spacing between PIN dots
29 28
30 // boxContentW is the width available to the field inside the box.29 // boxContentW is the width available to the field inside the box.
31 boxContentW = frameW - 2*boxBorder - 2*boxPadding30 boxContentW = frameW - 2*boxBorder - 2*boxPadding
@@ -42,8 +41,6 @@ const (
42 cssClock = "color:#ffffff;text-align:right;height:24px;margin-bottom:8px"41 cssClock = "color:#ffffff;text-align:right;height:24px;margin-bottom:8px"
43 // cssBalance mirrors cssClock below the box.42 // cssBalance mirrors cssClock below the box.
44 cssBalance = "height:24px;margin-top:8px"43 cssBalance = "height:24px;margin-top:8px"
45- // cssRelief is the inverted relief: bottom and right edges at 50% white.
46- cssRelief = "border-bottom:2px solid rgba(255,255,255,0.5);border-right:2px solid rgba(255,255,255,0.5)"
47 // cssHint and cssHintBalance have the same outer height.44 // cssHint and cssHintBalance have the same outer height.
48 cssHint = "color:#ffffff;margin-top:12px;height:22px;text-align:center"45 cssHint = "color:#ffffff;margin-top:12px;height:22px;text-align:center"
49 cssHintBalance = "margin-bottom:12px;height:22px"46 cssHintBalance = "margin-bottom:12px;height:22px"
@@ -52,16 +49,17 @@ const (
52 )49 )
53 50
54 var (51 var (
52+ // cssRelief is the inverted relief: bottom and right edges at 50% white.
53+ cssRelief = fmt.Sprintf("border-bottom:%[1]dpx solid rgba(255,255,255,0.5);"+
54+ "border-right:%[1]dpx solid rgba(255,255,255,0.5)", fieldEdge)
55 cssFrame = fmt.Sprintf("display:flex;flex-direction:column;align-items:stretch;width:%dpx", frameW)55 cssFrame = fmt.Sprintf("display:flex;flex-direction:column;align-items:stretch;width:%dpx", frameW)
56 cssBox = fmt.Sprintf("display:flex;flex-direction:column;align-items:stretch;"+56 cssBox = fmt.Sprintf("display:flex;flex-direction:column;align-items:stretch;"+
57 "border:%dpx solid #bfbfbf;padding:%dpx;background-color:#000000", boxBorder, boxPadding)57 "border:%dpx solid #bfbfbf;padding:%dpx;background-color:#000000", boxBorder, boxPadding)
58 cssMask = fmt.Sprintf("color:#ffffff;height:32px;line-height:32px;width:%dpx;"+58 cssMask = fmt.Sprintf("color:#ffffff;height:32px;line-height:32px;width:%dpx;"+
59 "padding:4px %dpx;margin-left:%dpx;%s", passwordW, fieldPadX, fieldMargin(passwordW), cssRelief)59 "padding:4px %dpx;margin-left:%dpx;%s", passwordW, fieldPadX, fieldMargin(passwordW), cssRelief)
60- // The PIN field shifts its padding by half the trailing letter-spacing
61- // so the dots stay optically centered.
62 cssMaskPIN = fmt.Sprintf("color:#ffffff;height:32px;line-height:32px;width:%dpx;"+60 cssMaskPIN = fmt.Sprintf("color:#ffffff;height:32px;line-height:32px;width:%dpx;"+
63- "padding:4px %dpx 4px %dpx;margin-left:%dpx;font-size:24px;letter-spacing:%dpx;text-align:center;%s",61+ "padding:4px %dpx;margin-left:%dpx;font-size:24px;letter-spacing:6px;text-align:center;%s",
64- pinW, fieldPadX-pinSpacing/2, fieldPadX+pinSpacing/2, fieldMargin(pinW), pinSpacing, cssRelief)62+ pinW, fieldPadX, fieldMargin(pinW), cssRelief)
65 )63 )
66 64
67 // fieldMargin centers a field of content width w inside the box content.65 // fieldMargin centers a field of content width w inside the box content.

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 2

Tags 9

↑↓ moveenter openesc close