@young1lin/dsh-ui-gitworkbench 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +28 -0
- package/CHANGELOG_EN.md +28 -0
- package/README.md +100 -50
- package/README_EN.md +2 -1
- package/lib/client.js +6902 -6256
- package/package.json +1 -1
- package/src/client/ChangesFileTree.tsx +550 -0
- package/src/client/ChromeGlyph.tsx +27 -0
- package/src/client/CodeEditor.tsx +129 -3
- package/src/client/CommitHistory.tsx +1001 -0
- package/src/client/DiffViews.tsx +1070 -0
- package/src/client/GitWorkbenchPanel.module.css +15 -2513
- package/src/client/GitWorkbenchPanel.tsx +37 -3959
- package/src/client/PaneDivider.tsx +74 -0
- package/src/client/WorkbenchControls.tsx +1047 -0
- package/src/client/WorktreeGlyph.tsx +24 -0
- package/src/client/cm-search-theme.ts +250 -0
- package/src/client/diff-nav.ts +59 -0
- package/src/client/git-workbench-types.ts +252 -0
- package/src/client/locales.ts +14 -8
- package/src/client/row-window.ts +23 -0
- package/src/client/search-count.ts +125 -0
- package/src/client/side-rows.ts +66 -0
- package/src/client/styles/changes.css +505 -0
- package/src/client/styles/controls.css +236 -0
- package/src/client/styles/environment.css +89 -0
- package/src/client/styles/files.css +113 -0
- package/src/client/styles/history-filters.css +400 -0
- package/src/client/styles/history.css +276 -0
- package/src/client/styles/image.css +67 -0
- package/src/client/styles/operations.css +179 -0
- package/src/client/styles/shell.css +431 -0
- package/src/client/styles/themes.css +224 -0
- package/src/client/use-change-nav.ts +6 -5
- package/src/client/use-row-window.ts +55 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/* ============================ one button vocabulary ============================
|
|
2
|
+
*
|
|
3
|
+
* Every clickable control in the drawer is one of two shapes, and which one it
|
|
4
|
+
* gets is decided by WHERE IT LIVES, never by what it does: drawer-level chrome
|
|
5
|
+
* (header actions, ref chips, menu triggers) is a PILL, and anything inside a
|
|
6
|
+
* panel or pane is a ROUNDED RECT. They differ in shape and nothing else — same
|
|
7
|
+
* height, same type size, same hover, same focus ring, same transition.
|
|
8
|
+
*
|
|
9
|
+
* Grouping the selectors is what enforces that. Each class used to spell out
|
|
10
|
+
* its own padding, radius and font-size, and the same "small secondary button"
|
|
11
|
+
* had drifted to four heights and three radii across one screen.
|
|
12
|
+
*/
|
|
13
|
+
.btn, .miniBtn, .treeIcon, .commitCopy, .scopeBtn, .refButton, .funnelButton, .funnelPreset, .layoutButton {
|
|
14
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
flex: none;
|
|
17
|
+
height: var(--gs-h-control);
|
|
18
|
+
padding: var(--gs-pad-control);
|
|
19
|
+
border: 1px solid var(--gs-border);
|
|
20
|
+
border-radius: var(--gs-r-control);
|
|
21
|
+
background: transparent;
|
|
22
|
+
color: var(--gs-fg-dim);
|
|
23
|
+
font-family: inherit;
|
|
24
|
+
font-size: var(--gs-t-ui);
|
|
25
|
+
line-height: 1;
|
|
26
|
+
white-space: nowrap;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
|
|
29
|
+
}
|
|
30
|
+
.btn:hover, .miniBtn:hover, .treeIcon:hover, .commitCopy:hover,
|
|
31
|
+
.scopeBtn:hover, .refButton:hover, .funnelButton:hover, .funnelPreset:hover, .layoutButton:hover {
|
|
32
|
+
background: var(--gs-raise);
|
|
33
|
+
color: var(--gs-fg);
|
|
34
|
+
border-color: var(--gs-fg-fainter);
|
|
35
|
+
}
|
|
36
|
+
.btn:focus-visible, .miniBtn:focus-visible, .treeIcon:focus-visible,
|
|
37
|
+
.commitCopy:focus-visible, .scopeBtn:focus-visible, .refButton:focus-visible,
|
|
38
|
+
.funnelPreset:focus-visible, .layoutButton:focus-visible {
|
|
39
|
+
outline: 2px solid var(--gs-accent);
|
|
40
|
+
outline-offset: 1px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Pills are for drawer-level chrome: the header's actions, the ref chips, and
|
|
44
|
+
anything that opens a menu — dsh spells its own dropdown triggers
|
|
45
|
+
("Code mode ⌄", "glm-5.3 ⌄") as pills, so a trigger that is not one reads as
|
|
46
|
+
foreign. Controls that live INSIDE a panel or pane stay 8px rects. */
|
|
47
|
+
.btn, .refButton { border-radius: var(--gs-r-pill); }
|
|
48
|
+
|
|
49
|
+
/* Pane tools give their vertical space back to the diff; the date presets sit
|
|
50
|
+
inside a 320px popover, so they take the compact height too. */
|
|
51
|
+
.treeIcon, .commitCopy, .funnelPreset, .layoutButton {
|
|
52
|
+
height: var(--gs-h-compact);
|
|
53
|
+
padding: var(--gs-pad-compact);
|
|
54
|
+
font-size: var(--gs-t-dense);
|
|
55
|
+
}
|
|
56
|
+
/* Expand / collapse all are the tree's own chevron at its two angles: the
|
|
57
|
+
button shows the state it puts every row into. Icon-only because at the 170px
|
|
58
|
+
the pane drags down to, two more text buttons cannot share a row with the
|
|
59
|
+
count — and these two are the pair a tree header always carries. */
|
|
60
|
+
.treeIcon { width: var(--gs-h-compact); padding: 0; }
|
|
61
|
+
/* The arrangement switch: two square icon buttons at the end of the commit
|
|
62
|
+
list's head, side by side with no gap so they read as one control. Icon-only
|
|
63
|
+
for the same reason the tree's are — the head already carries a title, a
|
|
64
|
+
funnel and a search box, and at the 190px the pane drags down to there is no
|
|
65
|
+
room for two more words. */
|
|
66
|
+
/* Pushed to the far end of History's toolbar row, away from the ref picker:
|
|
67
|
+
one changes WHAT is listed, the other only where it is drawn. */
|
|
68
|
+
.layoutSwitch { display: inline-flex; flex: none; gap: 2px; margin-left: auto; }
|
|
69
|
+
.layoutButton { width: var(--gs-h-compact); padding: 0; }
|
|
70
|
+
/* Qualified, like `.treeIconOn`: the shared vocabulary sets `color` at the
|
|
71
|
+
same specificity a few rules above. */
|
|
72
|
+
.layoutButton.layoutButtonOn { color: var(--gs-accent); border-color: var(--gs-accent); }
|
|
73
|
+
.layoutGlyph { display: block; }
|
|
74
|
+
/* Qualified, like `.funnelButtonActive`: this sits inside the shared button
|
|
75
|
+
vocabulary, which sets `color` at the same specificity a few lines above. */
|
|
76
|
+
.treeIcon.treeIconOn { color: var(--gs-accent); border-color: var(--gs-accent); }
|
|
77
|
+
.treeIconGlyph { display: block; font-size: var(--gs-t-meta); line-height: 1; }
|
|
78
|
+
.treeIconDown { transform: rotate(90deg); }
|
|
79
|
+
|
|
80
|
+
/* The scope toggle splits its row in two equal halves, so it opts out of the
|
|
81
|
+
vocabulary's `flex: none`. Declared here rather than beside `.scopeRow`
|
|
82
|
+
because it has to win against the grouped rule above by source order. */
|
|
83
|
+
.scopeBtn { flex: 1 1 0; }
|
|
84
|
+
|
|
85
|
+
/* The single "this one is selected" idiom: accent text, in an accent tint,
|
|
86
|
+
inside an accent border. Everything that can be the chosen one is here — a
|
|
87
|
+
tree leaf, a commit, a ref, a palette, a segment, a funnel tab, a date
|
|
88
|
+
bound, a preset — because the drawer had reached three spellings of one
|
|
89
|
+
meaning (this chip, a filled panel, a left accent bar) and showed two of
|
|
90
|
+
them at once whenever the Changes tree sat beside the history.
|
|
91
|
+
|
|
92
|
+
A modifier applied as `${css.base} ${css.mod}` carries the SAME specificity
|
|
93
|
+
as its base, so source order decides. Every base named here is declared
|
|
94
|
+
above this rule; `.fbRow.fbRowActive` is the one exception and is written
|
|
95
|
+
qualified, because `files.css` is imported after this file. */
|
|
96
|
+
.scopeBtnActive, .miniBtnPrimary, .segmentActive, .refRowActive, .paletteRowActive,
|
|
97
|
+
.fileActive, .commitActive, .funnelTabActive, .funnelBoundBtnActive, .funnelPresetActive,
|
|
98
|
+
.fbRow.fbRowActive {
|
|
99
|
+
border-color: var(--gs-accent-border);
|
|
100
|
+
background: var(--gs-accent-bg);
|
|
101
|
+
color: var(--gs-accent);
|
|
102
|
+
font-weight: 600;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Icon-only chrome: square, so four of them read as a control cluster rather
|
|
106
|
+
than four pills of drifting width. Height, border, radius and hover still
|
|
107
|
+
come from the vocabulary — only the box changes shape. */
|
|
108
|
+
.btnIcon { width: var(--gs-h-control); padding: 0; }
|
|
109
|
+
.btnIcon svg { display: block; }
|
|
110
|
+
/* Close is the one destructive control in the row, and every window on the
|
|
111
|
+
machine says so with red on hover. Quiet until then: a permanently red X in
|
|
112
|
+
a header would read as an error state. */
|
|
113
|
+
.btnClose:hover:not(:disabled) {
|
|
114
|
+
border-color: var(--gs-del); background: var(--gs-del-bg); color: var(--gs-del);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Sync actions that have something to report.
|
|
118
|
+
*
|
|
119
|
+
* These three variants set COLOUR ONLY — height, padding, radius and type size
|
|
120
|
+
* still come from the vocabulary above, so a loud Push is the same object as a
|
|
121
|
+
* quiet one and not a second button that happens to look similar.
|
|
122
|
+
*
|
|
123
|
+
* Fetch deliberately has no variant. It writes nothing, so it has no state to
|
|
124
|
+
* announce, and leaving one of the three permanently quiet is what makes the
|
|
125
|
+
* other two register as signal rather than decoration. */
|
|
126
|
+
.btnBehind {
|
|
127
|
+
border-color: var(--gs-warn); background: var(--gs-warn-bg); color: var(--gs-warn);
|
|
128
|
+
font-weight: 600;
|
|
129
|
+
}
|
|
130
|
+
.btnBehind:hover:not(:disabled) { background: var(--gs-warn-bg); color: var(--gs-warn); border-color: var(--gs-warn); }
|
|
131
|
+
.btnAhead {
|
|
132
|
+
border-color: var(--gs-add); background: var(--gs-add-bg); color: var(--gs-add);
|
|
133
|
+
font-weight: 600;
|
|
134
|
+
}
|
|
135
|
+
.btnAhead:hover:not(:disabled) { background: var(--gs-add-bg); color: var(--gs-add); border-color: var(--gs-add); }
|
|
136
|
+
/* Publishing a branch that exists nowhere else is the one moment this bar has a
|
|
137
|
+
primary action, so it gets the solid fill Commit uses — and only then. */
|
|
138
|
+
.btnPrimary {
|
|
139
|
+
border-color: var(--gs-accent); background: var(--gs-accent); color: var(--gs-on-accent);
|
|
140
|
+
font-weight: 600;
|
|
141
|
+
}
|
|
142
|
+
.btnPrimary:hover:not(:disabled) { background: var(--gs-accent); color: var(--gs-on-accent); border-color: var(--gs-accent); }
|
|
143
|
+
|
|
144
|
+
/* The count riding inside Pull / Push. Reads as part of the label rather than a
|
|
145
|
+
badge stuck on it: same colour, tabular, just set apart by a hairline. */
|
|
146
|
+
.btnCount {
|
|
147
|
+
margin-left: 1px; padding-left: 6px;
|
|
148
|
+
border-left: 1px solid currentColor;
|
|
149
|
+
font-variant-numeric: tabular-nums;
|
|
150
|
+
opacity: 0.85;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Pull and its strategy are one control. The picker is Pull's argument, not a
|
|
154
|
+
third action, so the two are welded: shared border, one outer radius. */
|
|
155
|
+
.pullGroup { display: inline-flex; flex: none; align-items: center; }
|
|
156
|
+
.pullGroup > .refPicker > .refButton {
|
|
157
|
+
border-top-right-radius: 0; border-bottom-right-radius: 0;
|
|
158
|
+
border-right-color: transparent;
|
|
159
|
+
}
|
|
160
|
+
.pullGroup > .btn {
|
|
161
|
+
margin-left: -1px;
|
|
162
|
+
border-top-left-radius: 0; border-bottom-left-radius: 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* Scrollbars inside the drawer.
|
|
166
|
+
Listing the scrolling panes by name is what let the file tree keep the
|
|
167
|
+
platform's own wide light scrollbar after that pane was renamed, so this
|
|
168
|
+
matches every descendant instead: nothing to keep in step as panes change.
|
|
169
|
+
`scrollbar-*` inherit, which covers Firefox from the same declaration. */
|
|
170
|
+
.drawer { scrollbar-width: thin; scrollbar-color: var(--gs-border) transparent; }
|
|
171
|
+
.drawer ::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
172
|
+
.drawer ::-webkit-scrollbar-track, .drawer ::-webkit-scrollbar-corner { background: transparent; }
|
|
173
|
+
.drawer ::-webkit-scrollbar-thumb {
|
|
174
|
+
/* Painted inside a transparent border so the thumb reads as a floating pill
|
|
175
|
+
rather than a bar welded to the pane edge. */
|
|
176
|
+
background: var(--gs-border);
|
|
177
|
+
background-clip: padding-box;
|
|
178
|
+
border: 3px solid transparent;
|
|
179
|
+
border-radius: var(--gs-r-pill);
|
|
180
|
+
}
|
|
181
|
+
.drawer ::-webkit-scrollbar-thumb:hover { background: var(--gs-fg-faint); background-clip: padding-box; }
|
|
182
|
+
|
|
183
|
+
/* Overflow counter for a commit carrying more refs than the row can show. */
|
|
184
|
+
.commitRefMore {
|
|
185
|
+
flex: none;
|
|
186
|
+
padding: 0 5px;
|
|
187
|
+
border-radius: var(--gs-r-pill);
|
|
188
|
+
background: var(--gs-neutral-bg);
|
|
189
|
+
color: var(--gs-fg-dim);
|
|
190
|
+
font-size: var(--gs-t-meta); line-height: 15px;
|
|
191
|
+
cursor: default;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* ---- the roll-back confirmation ----
|
|
195
|
+
*
|
|
196
|
+
* Scoped to the drawer rather than the viewport: `.drawer` is the positioned
|
|
197
|
+
* ancestor, so the scrim dims the thing the question is about and leaves the
|
|
198
|
+
* session behind it alone. It is also the only modal surface in this plugin —
|
|
199
|
+
* everything else the drawer does can be done again.
|
|
200
|
+
*/
|
|
201
|
+
.confirmScrim {
|
|
202
|
+
/* `position`, `inset` and the stacking rank live with the drawer's other
|
|
203
|
+
child ranks — see `.drawer > .confirmScrim`. */
|
|
204
|
+
display: flex; align-items: center; justify-content: center;
|
|
205
|
+
padding: 24px;
|
|
206
|
+
background: var(--gs-backdrop);
|
|
207
|
+
animation: gsFade 120ms ease-out;
|
|
208
|
+
}
|
|
209
|
+
.confirmBox {
|
|
210
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
211
|
+
box-sizing: border-box;
|
|
212
|
+
width: min(440px, 100%);
|
|
213
|
+
padding: 18px;
|
|
214
|
+
border: 1px solid var(--gs-border); border-radius: var(--gs-r-drawer);
|
|
215
|
+
background: var(--gs-bg);
|
|
216
|
+
box-shadow: 0 18px 48px var(--gs-shadow);
|
|
217
|
+
}
|
|
218
|
+
.confirmTitle { color: var(--gs-fg); font-size: var(--gs-t-ui); font-weight: 600; }
|
|
219
|
+
/* The body carries a path, which is the one string here that can be long and
|
|
220
|
+
has no sensible break points of its own. */
|
|
221
|
+
.confirmBody {
|
|
222
|
+
color: var(--gs-fg-dim);
|
|
223
|
+
font-size: var(--gs-t-dense); line-height: 1.55;
|
|
224
|
+
overflow-wrap: anywhere;
|
|
225
|
+
}
|
|
226
|
+
/* Cancel first in the DOM so it takes focus and the Tab order starts on the
|
|
227
|
+
harmless answer; `row-reverse` puts the destructive one where the eye ends. */
|
|
228
|
+
.confirmActions { display: flex; flex-direction: row-reverse; gap: 8px; margin-top: 2px; }
|
|
229
|
+
/* Qualified rather than a bare modifier: written this way it out-specifies
|
|
230
|
+
`.btn` wherever either rule sits, which is the failure the drawer already
|
|
231
|
+
shipped once. */
|
|
232
|
+
.btn.btnDanger {
|
|
233
|
+
border-color: var(--gs-del); background: var(--gs-del); color: var(--gs-on-accent);
|
|
234
|
+
font-weight: 600;
|
|
235
|
+
}
|
|
236
|
+
.btn.btnDanger:hover:not(:disabled) { border-color: var(--gs-del); background: var(--gs-del); color: var(--gs-on-accent); }
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* Change inspector.
|
|
2
|
+
*
|
|
3
|
+
* The session-header card lives in dsh chrome and keeps dsh's own --dsw-* tokens,
|
|
4
|
+
* so it is themed by the app and needs nothing here. The DRAWER paints its own
|
|
5
|
+
* surface — a diff needs an add/delete/word-level/syntax palette dsh does not
|
|
6
|
+
* define — so it carries a self-contained palette instead.
|
|
7
|
+
*
|
|
8
|
+
* Every drawer colour resolves through a --gs-* token. The palettes below are the
|
|
9
|
+
* only place a literal colour appears; each theme sets the same token names, so a
|
|
10
|
+
* theme is a palette swap and nothing else. `data-gs-theme` on the overlay picks
|
|
11
|
+
* one, and the panel computes it from the theme setting (`system` follows dsh's
|
|
12
|
+
* `body[data-ds-dark-theme]`; light/dark pin the drawer).
|
|
13
|
+
*
|
|
14
|
+
* One exception is deliberate: the mode picker's own light/dark chips are fixed
|
|
15
|
+
* white and near-black, because those buttons name colours rather than wear them.
|
|
16
|
+
*
|
|
17
|
+
* `data-gs-part` attributes on the overlay, card, header, tabs and three panes are
|
|
18
|
+
* the stable hooks user CSS targets — class names are hashed by CSS Modules and
|
|
19
|
+
* change on every build, so they are not addressable from outside.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/* ---- environment card (lives in dsh chrome — keep dsw tokens) ---- */
|
|
23
|
+
.card {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 7px;
|
|
27
|
+
min-height: 28px;
|
|
28
|
+
padding: 3px 10px;
|
|
29
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
30
|
+
border-radius: 8px;
|
|
31
|
+
background: transparent;
|
|
32
|
+
color: var(--dsw-alias-label-secondary);
|
|
33
|
+
font-size: 12px;
|
|
34
|
+
line-height: 18px;
|
|
35
|
+
font-variant-numeric: tabular-nums;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
transition: background 120ms ease, border-color 120ms ease;
|
|
38
|
+
}
|
|
39
|
+
.card:hover, .card:focus-visible {
|
|
40
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
41
|
+
border-color: var(--dsw-alias-border-l3);
|
|
42
|
+
}
|
|
43
|
+
.cardBranch {
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: 4px;
|
|
47
|
+
max-width: 220px;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
color: var(--dsw-alias-label-primary);
|
|
50
|
+
font-weight: 550;
|
|
51
|
+
}
|
|
52
|
+
.cardBranchName { min-width: 0; overflow: hidden; }
|
|
53
|
+
.cardGlyph { flex: none; opacity: 0.7; }
|
|
54
|
+
.cardDetached {
|
|
55
|
+
padding: 0 6px;
|
|
56
|
+
border-radius: 999px;
|
|
57
|
+
background: var(--dsw-alias-state-warning-bg, rgba(187, 128, 9, 0.15));
|
|
58
|
+
color: var(--dsw-alias-state-warning-primary, #d29922);
|
|
59
|
+
font-size: 10px;
|
|
60
|
+
line-height: 16px;
|
|
61
|
+
letter-spacing: 0.02em;
|
|
62
|
+
}
|
|
63
|
+
/* Bound-worktree badge: the session is attached to an agent worktree. */
|
|
64
|
+
.cardWt {
|
|
65
|
+
display: inline-flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 3px;
|
|
68
|
+
max-width: 150px;
|
|
69
|
+
overflow: hidden;
|
|
70
|
+
padding: 0 6px;
|
|
71
|
+
border-radius: 999px;
|
|
72
|
+
background: var(--dsw-alias-state-business-bg, rgba(56, 139, 253, 0.16));
|
|
73
|
+
color: var(--dsw-alias-state-business-primary, #58a6ff);
|
|
74
|
+
font-size: 10px;
|
|
75
|
+
line-height: 16px;
|
|
76
|
+
letter-spacing: 0.02em;
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
text-overflow: ellipsis;
|
|
79
|
+
}
|
|
80
|
+
.cardAhead, .cardBehind {
|
|
81
|
+
color: var(--dsw-alias-label-tertiary);
|
|
82
|
+
font-size: 11px;
|
|
83
|
+
}
|
|
84
|
+
.cardAhead { color: var(--dsw-alias-state-success-primary); }
|
|
85
|
+
.cardBehind { color: var(--dsw-alias-state-attention-primary, #d29922); }
|
|
86
|
+
.cardSep { width: 1px; height: 14px; background: var(--dsw-alias-border-l2); }
|
|
87
|
+
.cardAdded { color: var(--dsw-alias-state-success-primary); }
|
|
88
|
+
.cardDeleted { color: var(--dsw-alias-state-error-primary); }
|
|
89
|
+
.cardFiles { color: var(--dsw-alias-label-tertiary); }
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/* Files tab: the repository browser's tree, and the pane that opens a file.
|
|
2
|
+
Modifier rules stay BELOW the base rule they narrow — a modifier declared
|
|
3
|
+
first loses the cascade, which the drawer-chrome test checks for. */
|
|
4
|
+
.fbTree {
|
|
5
|
+
flex: none;
|
|
6
|
+
min-width: var(--gs-min-tree);
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: 4px;
|
|
10
|
+
padding: 6px;
|
|
11
|
+
overflow: auto;
|
|
12
|
+
background: var(--gs-surface-2);
|
|
13
|
+
}
|
|
14
|
+
.fbSearch {
|
|
15
|
+
flex: none;
|
|
16
|
+
width: 100%;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
padding: 4px 6px;
|
|
19
|
+
font: inherit;
|
|
20
|
+
font-size: var(--gs-t-meta);
|
|
21
|
+
color: var(--gs-fg);
|
|
22
|
+
background: var(--gs-surface);
|
|
23
|
+
border: 1px solid var(--gs-border);
|
|
24
|
+
border-radius: var(--gs-r-control);
|
|
25
|
+
}
|
|
26
|
+
.fbSearch:focus { outline: none; border-color: var(--gs-accent); }
|
|
27
|
+
.fbNote { flex: none; font-size: var(--gs-t-meta); color: var(--gs-fg-dim); padding: 2px 4px; }
|
|
28
|
+
.fbList { list-style: none; margin: 0; padding: 0; }
|
|
29
|
+
.fbRow {
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: 4px;
|
|
33
|
+
width: 100%;
|
|
34
|
+
padding: 2px 6px 2px 4px;
|
|
35
|
+
font: inherit;
|
|
36
|
+
font-size: var(--gs-t-dense);
|
|
37
|
+
color: var(--gs-fg-dim);
|
|
38
|
+
text-align: left;
|
|
39
|
+
background: none;
|
|
40
|
+
border: 0;
|
|
41
|
+
border-radius: var(--gs-r-control);
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
white-space: nowrap;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
text-overflow: ellipsis;
|
|
46
|
+
}
|
|
47
|
+
.fbRow:hover { background: var(--gs-raise); }
|
|
48
|
+
/* .fbRowActive: see the shared selected-state rule in controls.css. It is
|
|
49
|
+
written there qualified, because this file is imported after that one and a
|
|
50
|
+
bare modifier declared above its base loses the cascade. */
|
|
51
|
+
.fbDirName { overflow: hidden; text-overflow: ellipsis; }
|
|
52
|
+
.fbFileName { overflow: hidden; text-overflow: ellipsis; }
|
|
53
|
+
.fbMain {
|
|
54
|
+
flex: 1 1 0;
|
|
55
|
+
min-width: var(--gs-min-diff);
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
min-height: 0;
|
|
59
|
+
background: var(--gs-surface);
|
|
60
|
+
}
|
|
61
|
+
.fbHeader {
|
|
62
|
+
flex: none;
|
|
63
|
+
display: flex;
|
|
64
|
+
align-items: flex-start;
|
|
65
|
+
gap: 8px;
|
|
66
|
+
padding: 4px 8px 0;
|
|
67
|
+
border-bottom: 1px solid var(--gs-border);
|
|
68
|
+
}
|
|
69
|
+
.fbPath {
|
|
70
|
+
font-size: var(--gs-t-meta);
|
|
71
|
+
color: var(--gs-fg-dim);
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
text-overflow: ellipsis;
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
padding: 4px 0;
|
|
76
|
+
}
|
|
77
|
+
/* The editor scrolls inside this, so the header and the notices above stay
|
|
78
|
+
put — the same reason the side pane's toolbar is pinned. */
|
|
79
|
+
.fbBody { flex: 1 1 0; min-height: 0; overflow: auto; padding: 4px 8px; }
|
|
80
|
+
|
|
81
|
+
/* The commit behind the picked blame line. A strip rather than a floating
|
|
82
|
+
popup: it never covers the code it is about, and it survives a scroll. */
|
|
83
|
+
.fbCommit {
|
|
84
|
+
flex: none;
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: baseline;
|
|
87
|
+
gap: 8px;
|
|
88
|
+
padding: 4px 8px;
|
|
89
|
+
font-size: var(--gs-t-meta);
|
|
90
|
+
color: var(--gs-fg-dim);
|
|
91
|
+
background: var(--gs-surface-2);
|
|
92
|
+
border-bottom: 1px solid var(--gs-border);
|
|
93
|
+
}
|
|
94
|
+
.fbCommitLine { flex: none; color: var(--gs-fg-faint); font-variant-numeric: tabular-nums; }
|
|
95
|
+
.fbCommitWho { flex: none; color: var(--gs-fg); font-weight: 600; }
|
|
96
|
+
.fbCommitWhen { flex: none; font-variant-numeric: tabular-nums; }
|
|
97
|
+
.fbCommitHash { flex: none; font-family: inherit; color: var(--gs-fg-faint); }
|
|
98
|
+
.fbCommitWhat {
|
|
99
|
+
flex: 1 1 auto;
|
|
100
|
+
min-width: 0;
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
text-overflow: ellipsis;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
color: var(--gs-fg);
|
|
105
|
+
}
|
|
106
|
+
.fbCommitHint { color: var(--gs-fg-faint); }
|
|
107
|
+
.fbMore {
|
|
108
|
+
display: block;
|
|
109
|
+
padding: 2px 6px 4px 4px;
|
|
110
|
+
font-size: var(--gs-t-meta);
|
|
111
|
+
color: var(--gs-fg-faint);
|
|
112
|
+
font-style: italic;
|
|
113
|
+
}
|