mbeditor 0.12.9 → 0.13.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +216 -1
- data/app/assets/javascripts/mbeditor/application.js +6 -1
- data/app/assets/javascripts/mbeditor/collaboration_service.js +52 -1
- data/app/assets/javascripts/mbeditor/color_provider.js +5 -0
- data/app/assets/javascripts/mbeditor/components/CollapsibleSection.js +3 -1
- data/app/assets/javascripts/mbeditor/components/EditorPanel.js +104 -103
- data/app/assets/javascripts/mbeditor/components/FileTree.js +6 -1
- data/app/assets/javascripts/mbeditor/components/GitPanel.js +10 -1
- data/app/assets/javascripts/mbeditor/components/ImportConflictModal.js +15 -8
- data/app/assets/javascripts/mbeditor/components/ImportDialog.js +224 -0
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +704 -270
- data/app/assets/javascripts/mbeditor/components/ModelGraph.js +25 -6
- data/app/assets/javascripts/mbeditor/components/ProblemsPanel.js +193 -9
- data/app/assets/javascripts/mbeditor/components/QuickOpenDialog.js +105 -77
- data/app/assets/javascripts/mbeditor/components/TabBar.js +11 -2
- data/app/assets/javascripts/mbeditor/editor_plugins.js +434 -112
- data/app/assets/javascripts/mbeditor/file_import.js +78 -0
- data/app/assets/javascripts/mbeditor/file_service.js +112 -18
- data/app/assets/javascripts/mbeditor/git_service.js +130 -8
- data/app/assets/javascripts/mbeditor/history_service.js +33 -38
- data/app/assets/javascripts/mbeditor/log_service.js +4 -0
- data/app/assets/javascripts/mbeditor/search_service.js +50 -4
- data/app/assets/javascripts/mbeditor/tab_manager.js +66 -10
- data/app/assets/javascripts/mbeditor/websocket_service.js +88 -4
- data/app/assets/stylesheets/mbeditor/editor.css +389 -103
- data/app/channels/mbeditor/channel_authentication.rb +7 -0
- data/app/channels/mbeditor/collaboration_channel.rb +8 -2
- data/app/channels/mbeditor/editor_channel.rb +6 -3
- data/app/controllers/mbeditor/application_controller.rb +5 -0
- data/app/controllers/mbeditor/editors_controller.rb +155 -29
- data/app/controllers/mbeditor/git_controller.rb +3 -3
- data/app/controllers/mbeditor/logs_controller.rb +3 -1
- data/app/services/mbeditor/collaboration_doc_store.rb +49 -3
- data/app/services/mbeditor/duplicate_content_scanner.rb +105 -0
- data/app/services/mbeditor/editor_state_service.rb +36 -26
- data/app/services/mbeditor/exclusion_matcher.rb +12 -10
- data/app/services/mbeditor/file_operation_service.rb +38 -3
- data/app/services/mbeditor/file_tree_service.rb +30 -2
- data/app/services/mbeditor/git_combined_diff_service.rb +13 -3
- data/app/services/mbeditor/git_commit_detail_service.rb +20 -16
- data/app/services/mbeditor/git_diff_service.rb +5 -1
- data/app/services/mbeditor/git_info_service.rb +20 -8
- data/app/services/mbeditor/git_line_diff_service.rb +6 -2
- data/app/services/mbeditor/git_service.rb +65 -15
- data/app/services/mbeditor/js_definition_service.rb +3 -1
- data/app/services/mbeditor/js_globals_service.rb +18 -4
- data/app/services/mbeditor/js_members_service.rb +3 -2
- data/app/services/mbeditor/js_program_service.rb +15 -5
- data/app/services/mbeditor/js_syntax_check_service.rb +15 -4
- data/app/services/mbeditor/process_runner.rb +42 -12
- data/app/services/mbeditor/ri_definition_service.rb +8 -1
- data/app/services/mbeditor/route_service.rb +45 -8
- data/app/services/mbeditor/rubocop_run_service.rb +98 -0
- data/app/services/mbeditor/ruby_definition_service.rb +23 -4
- data/app/services/mbeditor/schema_service.rb +73 -66
- data/app/services/mbeditor/search_replace_service.rb +42 -7
- data/app/services/mbeditor/test_runner_service.rb +45 -10
- data/lib/mbeditor/cable_log_filter.rb +8 -2
- data/lib/mbeditor/configuration.rb +4 -1
- data/lib/mbeditor/editor_bootstrap.rb +18 -12
- data/lib/mbeditor/engine.rb +22 -3
- data/lib/mbeditor/exception_log.rb +2 -2
- data/lib/mbeditor/pending_migrations.rb +33 -0
- data/lib/mbeditor/rack/handle_pending_migrations.rb +25 -15
- data/lib/mbeditor/rack/pending_migration_bypass.rb +104 -0
- data/lib/mbeditor/rack/silence_ping_request.rb +10 -2
- data/lib/mbeditor/route_map.rb +1 -0
- data/lib/mbeditor/ruby_lsp_client.rb +71 -12
- data/lib/mbeditor/version.rb +1 -1
- data/lib/tasks/mbeditor.rake +23 -0
- metadata +8 -2
|
@@ -8,10 +8,86 @@
|
|
|
8
8
|
box-shadow: none !important;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
/* ── Pico containment ──────────────────────────────────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* The host app's stylesheet loads alongside this one, and when it is Pico (the
|
|
14
|
+
* dummy app's is) it styles bare element and ARIA selectors — `button`,
|
|
15
|
+
* `[role=button]`, `[role=group]`, `[disabled]` — every one of which matches
|
|
16
|
+
* this UI's markup. Two shipped bugs came from exactly that: `[role=button]`
|
|
17
|
+
* painted the tab close buttons as filled primary squares, and
|
|
18
|
+
* `[disabled] { pointer-events: none }` stopped disabled toolbar buttons from
|
|
19
|
+
* receiving hover at all, so their tooltips never appeared.
|
|
20
|
+
*
|
|
21
|
+
* The technique is to zero Pico's own custom properties: every Pico button
|
|
22
|
+
* declaration reads from them, so neutralising the variables disarms the whole
|
|
23
|
+
* ruleset at once, which beats fighting each declaration on specificity. Only
|
|
24
|
+
* the few properties Pico hard-codes need explicit overrides.
|
|
25
|
+
*
|
|
26
|
+
* Two things make this safe to widen, and both depend on where the block sits:
|
|
27
|
+
*
|
|
28
|
+
* - The root is wrapped in :where(), so these rules carry exactly Pico's own
|
|
29
|
+
* specificity, no more. They win over Pico only because the whole of
|
|
30
|
+
* editor.css is bundled after the whole of Pico.
|
|
31
|
+
* - The block lives at the TOP of this file, so every component rule below —
|
|
32
|
+
* .statusbar-btn, .project-actions, .tab-close — is later at equal or
|
|
33
|
+
* greater specificity and still wins.
|
|
34
|
+
*
|
|
35
|
+
* That combination is what makes this a floor rather than a new source of
|
|
36
|
+
* truth: it can only remove Pico's opinions, never override this file's own.
|
|
37
|
+
* Moving it further down would silently invert that.
|
|
38
|
+
*
|
|
39
|
+
* Deliberately NOT reset: Pico's `*` box-sizing and background-repeat rules
|
|
40
|
+
* (this UI assumes border-box, which is what Pico sets), and `position` on
|
|
41
|
+
* [role=group] (Pico's `relative` is the safer value for any absolutely
|
|
42
|
+
* positioned descendant, and nothing here needs it to be static).
|
|
43
|
+
*
|
|
44
|
+
* Monaco is listed separately because its widgets portal out of the shell to
|
|
45
|
+
* document.body (.context-view, .action-widget), so a #mbeditor-root scope
|
|
46
|
+
* would miss them. Monaco renders its own actions as <a role="button">.
|
|
47
|
+
*/
|
|
48
|
+
:where(#mbeditor-root) :is(button, [type="button"], [type="submit"], [type="reset"], [role="button"], [role="group"]),
|
|
49
|
+
.monaco-hover [role=button],
|
|
50
|
+
.action-widget [role=button],
|
|
51
|
+
.context-view [role=button],
|
|
52
|
+
.monaco-editor [role=button],
|
|
53
|
+
.monaco-diff-editor [role=button] {
|
|
54
|
+
--pico-background-color: transparent;
|
|
55
|
+
--pico-border-color: transparent;
|
|
56
|
+
--pico-color: inherit;
|
|
57
|
+
--pico-box-shadow: none;
|
|
58
|
+
--pico-form-element-spacing-vertical: 0;
|
|
59
|
+
--pico-form-element-spacing-horizontal: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Properties Pico hard-codes, which the variable reset above cannot reach. */
|
|
63
|
+
|
|
64
|
+
/* Pico's `[disabled] { pointer-events: none }` means a disabled control never
|
|
65
|
+
* receives hover, so neither a title attribute nor a CSS hover tooltip can
|
|
66
|
+
* fire on it — and a disabled button is exactly when a user most wants to be
|
|
67
|
+
* told what it is. */
|
|
68
|
+
:where(#mbeditor-root) [disabled],
|
|
69
|
+
:where(#mbeditor-root) [aria-disabled="true"] {
|
|
70
|
+
pointer-events: auto;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Pico lays [role=group] out as a full-width bordered input group. It is used
|
|
74
|
+
* here only to label toolbars for screen readers. */
|
|
75
|
+
:where(#mbeditor-root) [role="group"] {
|
|
76
|
+
display: inline-flex;
|
|
77
|
+
width: auto;
|
|
78
|
+
margin-bottom: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Pico gives every button a bottom margin to space form controls. */
|
|
82
|
+
:where(#mbeditor-root) :is(button, [type="button"], [type="submit"], [type="reset"]) {
|
|
83
|
+
margin: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Pico's focus/active state sets its primary blue on --pico-background-color
|
|
87
|
+
and --pico-border-color, which bleeds through as a blue tint on any button
|
|
88
|
+
not overriding its background with a literal value. Kept separate from the
|
|
89
|
+
block above: this one is intentionally more specific than a component rule,
|
|
90
|
+
because no component should be able to opt back into a Pico focus colour. */
|
|
15
91
|
#mbeditor-root button:not(.pico-btn):focus,
|
|
16
92
|
#mbeditor-root button:not(.pico-btn):focus-visible,
|
|
17
93
|
#mbeditor-root button:not(.pico-btn):active {
|
|
@@ -129,57 +205,66 @@ html, body, #mbeditor-root {
|
|
|
129
205
|
|
|
130
206
|
/* ── Activity Bar (VSCode-style, always visible) ───────── */
|
|
131
207
|
.ide-activity-bar {
|
|
132
|
-
width:
|
|
133
|
-
min-width:
|
|
208
|
+
width: 40px;
|
|
209
|
+
min-width: 40px;
|
|
134
210
|
flex-shrink: 0;
|
|
135
211
|
background: var(--ide-panel-bg);
|
|
136
212
|
border-right: 1px solid var(--ide-border);
|
|
137
213
|
display: flex;
|
|
138
214
|
flex-direction: column;
|
|
139
|
-
|
|
140
|
-
|
|
215
|
+
/* stretch, not center: the buttons fill the bar edge to edge so the active
|
|
216
|
+
indicator can sit flush against the left of the screen. Centering them
|
|
217
|
+
left a gutter the indicator was inset by. */
|
|
218
|
+
align-items: stretch;
|
|
219
|
+
padding: 0;
|
|
141
220
|
z-index: 10;
|
|
142
221
|
}
|
|
143
222
|
|
|
144
223
|
.ide-activity-bar-top {
|
|
145
224
|
display: flex;
|
|
146
225
|
flex-direction: column;
|
|
147
|
-
align-items:
|
|
148
|
-
gap:
|
|
226
|
+
align-items: stretch;
|
|
227
|
+
gap: 0;
|
|
149
228
|
flex: 1;
|
|
150
229
|
}
|
|
151
230
|
|
|
152
231
|
.ide-activity-bar-bottom {
|
|
153
232
|
display: flex;
|
|
154
233
|
flex-direction: column;
|
|
155
|
-
align-items:
|
|
156
|
-
gap:
|
|
157
|
-
padding-bottom: 4px;
|
|
234
|
+
align-items: stretch;
|
|
235
|
+
gap: 0;
|
|
158
236
|
}
|
|
159
237
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
238
|
+
/* Scoped through the bar so the glyph size outranks the global
|
|
239
|
+
`button:not(.pico-btn) { font-size: 12px }` reset, which is more specific
|
|
240
|
+
than a bare class and was silently winning. */
|
|
241
|
+
.ide-activity-bar .ide-activity-btn {
|
|
242
|
+
width: 100%;
|
|
243
|
+
height: 40px;
|
|
163
244
|
background: transparent;
|
|
164
245
|
border: none;
|
|
246
|
+
/* Always reserve the indicator's width so the glyph does not shift sideways
|
|
247
|
+
by a pixel the moment a panel is opened. */
|
|
248
|
+
border-left: 2px solid transparent;
|
|
165
249
|
border-radius: 0;
|
|
166
250
|
color: var(--ide-text-muted);
|
|
167
251
|
display: flex;
|
|
168
252
|
align-items: center;
|
|
169
253
|
justify-content: center;
|
|
170
254
|
cursor: pointer;
|
|
171
|
-
font-size:
|
|
172
|
-
transition:
|
|
255
|
+
font-size: 17px;
|
|
256
|
+
transition: color 0.12s ease;
|
|
173
257
|
}
|
|
174
258
|
|
|
175
|
-
.
|
|
176
|
-
|
|
259
|
+
/* The glyph carries the state, not a filled box behind it. */
|
|
260
|
+
.ide-activity-bar .ide-activity-btn:hover {
|
|
261
|
+
background: transparent;
|
|
177
262
|
color: var(--ide-text);
|
|
178
263
|
}
|
|
179
264
|
|
|
180
|
-
.ide-activity-btn.active {
|
|
265
|
+
.ide-activity-bar .ide-activity-btn.active {
|
|
181
266
|
color: var(--ide-accent-fg);
|
|
182
|
-
border-left:
|
|
267
|
+
border-left-color: var(--ide-accent-fg);
|
|
183
268
|
}
|
|
184
269
|
|
|
185
270
|
.sidebar-panel-title {
|
|
@@ -300,25 +385,25 @@ html, body, #mbeditor-root {
|
|
|
300
385
|
border: 1px solid var(--ide-accent);
|
|
301
386
|
border-radius: 3px;
|
|
302
387
|
color: var(--ide-text);
|
|
303
|
-
font-size:
|
|
388
|
+
font-size: 14px;
|
|
304
389
|
font-family: inherit;
|
|
305
390
|
padding: 1px 4px;
|
|
306
391
|
outline: none;
|
|
307
|
-
height:
|
|
308
|
-
line-height:
|
|
392
|
+
height: 21px;
|
|
393
|
+
line-height: 21px;
|
|
309
394
|
}
|
|
310
395
|
|
|
311
396
|
.tree-item-icon {
|
|
312
|
-
width:
|
|
313
|
-
margin-right:
|
|
314
|
-
font-size:
|
|
397
|
+
width: 20px;
|
|
398
|
+
margin-right: 6px;
|
|
399
|
+
font-size: 14px;
|
|
315
400
|
flex-shrink: 0;
|
|
316
401
|
text-align: center;
|
|
317
402
|
}
|
|
318
403
|
|
|
319
404
|
.tree-folder-icon { color: #dcb67a; }
|
|
320
405
|
.tree-file-icon { color: #78b4e0; }
|
|
321
|
-
.tree-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; font-size:
|
|
406
|
+
.tree-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; font-size: 14px; }
|
|
322
407
|
|
|
323
408
|
/* ── Custom File Icons ───────────────────────────────────── */
|
|
324
409
|
.ruby-icon { color: #f26262 !important; }
|
|
@@ -791,23 +876,33 @@ html, body, #mbeditor-root {
|
|
|
791
876
|
}
|
|
792
877
|
|
|
793
878
|
/* ── Status Bar ──────────────────────────────────────────── */
|
|
879
|
+
/* line-height: 1 is what keeps an icon and the number beside it on the same
|
|
880
|
+
* centre line. Pico's inherited 1.5 gave every text span a 16.5px line box
|
|
881
|
+
* inside a 22px bar while the icons' box was 11px, so the two were centred on
|
|
882
|
+
* different half-leadings; with 1 both boxes are the font's own content box
|
|
883
|
+
* and flex centres them together. */
|
|
794
884
|
.ide-statusbar {
|
|
795
885
|
display: flex;
|
|
796
886
|
align-items: center;
|
|
797
887
|
background: var(--ide-accent);
|
|
798
888
|
height: 22px;
|
|
799
|
-
padding: 0
|
|
800
|
-
gap:
|
|
889
|
+
padding: 0;
|
|
890
|
+
gap: 0;
|
|
801
891
|
flex-shrink: 0;
|
|
802
892
|
font-size: 11px;
|
|
893
|
+
line-height: 1;
|
|
803
894
|
color: var(--ide-accent-text);
|
|
804
895
|
}
|
|
805
896
|
|
|
897
|
+
/* One cell rhythm for every item, button or not. The branch, the message and
|
|
898
|
+
* the chips each carried their own padding on top of the bar's, so the gaps
|
|
899
|
+
* between them were all different widths. */
|
|
900
|
+
.ide-statusbar > * { padding: 0 8px; }
|
|
901
|
+
|
|
806
902
|
.statusbar-branch {
|
|
807
903
|
display: flex;
|
|
808
904
|
align-items: center;
|
|
809
|
-
gap:
|
|
810
|
-
font-size: 13px;
|
|
905
|
+
gap: 4px;
|
|
811
906
|
font-weight: 600;
|
|
812
907
|
color: var(--ide-accent-text);
|
|
813
908
|
}
|
|
@@ -841,7 +936,6 @@ html, body, #mbeditor-root {
|
|
|
841
936
|
font-size: 12px;
|
|
842
937
|
font-weight: 600;
|
|
843
938
|
color: var(--ide-danger);
|
|
844
|
-
padding: 0 10px;
|
|
845
939
|
animation: statusbar-pulse 2s ease-in-out infinite;
|
|
846
940
|
}
|
|
847
941
|
|
|
@@ -941,7 +1035,6 @@ html, body, #mbeditor-root {
|
|
|
941
1035
|
color: color-mix(in srgb, var(--ide-accent-text) 45%, transparent);
|
|
942
1036
|
font-size: 10px;
|
|
943
1037
|
white-space: nowrap;
|
|
944
|
-
padding-left: 8px;
|
|
945
1038
|
cursor: pointer;
|
|
946
1039
|
}
|
|
947
1040
|
.statusbar-version:hover {
|
|
@@ -954,7 +1047,6 @@ html, body, #mbeditor-root {
|
|
|
954
1047
|
font-weight: 600;
|
|
955
1048
|
letter-spacing: 0.04em;
|
|
956
1049
|
opacity: 0.85;
|
|
957
|
-
padding: 0 6px;
|
|
958
1050
|
}
|
|
959
1051
|
|
|
960
1052
|
.statusbar-zen-btn {
|
|
@@ -1140,52 +1232,88 @@ html, body, #mbeditor-root {
|
|
|
1140
1232
|
to { transform: rotate(360deg); }
|
|
1141
1233
|
}
|
|
1142
1234
|
|
|
1235
|
+
/* Tree rows. Both kinds are pinned to the same 22px because MbeditorApp
|
|
1236
|
+
windows them by index * SEARCH_ROW_HEIGHT — change one and change both. */
|
|
1237
|
+
.search-result-file-row,
|
|
1143
1238
|
.search-result-item {
|
|
1144
|
-
height:
|
|
1145
|
-
padding: 4px 6px;
|
|
1239
|
+
height: 22px;
|
|
1146
1240
|
cursor: pointer;
|
|
1147
|
-
border-radius: 3px;
|
|
1148
1241
|
transition: background 0.1s;
|
|
1149
|
-
border-bottom: 1px solid var(--ide-input-bg);
|
|
1150
1242
|
display: flex;
|
|
1151
1243
|
align-items: center;
|
|
1152
|
-
gap:
|
|
1244
|
+
gap: 6px;
|
|
1153
1245
|
overflow: hidden;
|
|
1154
1246
|
box-sizing: border-box;
|
|
1155
1247
|
flex-shrink: 0;
|
|
1156
1248
|
}
|
|
1157
1249
|
|
|
1250
|
+
.search-result-file-row { padding: 0 6px; }
|
|
1251
|
+
/* Indented under its file header, the way the explorer nests children. */
|
|
1252
|
+
.search-result-item { padding: 0 6px 0 24px; }
|
|
1253
|
+
|
|
1254
|
+
.search-result-file-row:hover,
|
|
1158
1255
|
.search-result-item:hover { background: var(--ide-hover-bg); }
|
|
1159
1256
|
|
|
1257
|
+
.search-result-chevron {
|
|
1258
|
+
flex-shrink: 0;
|
|
1259
|
+
width: 12px;
|
|
1260
|
+
font-size: 12px;
|
|
1261
|
+
color: var(--ide-text-muted);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1160
1264
|
.search-result-icon {
|
|
1161
1265
|
flex-shrink: 0;
|
|
1162
1266
|
width: 16px;
|
|
1163
|
-
margin-top: 2px;
|
|
1164
1267
|
text-align: center;
|
|
1165
1268
|
color: #78b4e0;
|
|
1166
1269
|
}
|
|
1167
1270
|
|
|
1168
|
-
.search-result-
|
|
1169
|
-
|
|
1170
|
-
|
|
1271
|
+
.search-result-file-name {
|
|
1272
|
+
font-size: 12px;
|
|
1273
|
+
color: var(--ide-text);
|
|
1274
|
+
white-space: nowrap;
|
|
1275
|
+
flex-shrink: 0;
|
|
1276
|
+
max-width: 60%;
|
|
1277
|
+
overflow: hidden;
|
|
1278
|
+
text-overflow: ellipsis;
|
|
1171
1279
|
}
|
|
1172
1280
|
|
|
1173
|
-
.search-result-file {
|
|
1174
|
-
font-size:
|
|
1175
|
-
color: var(--ide-
|
|
1176
|
-
font-weight: 500;
|
|
1281
|
+
.search-result-file-dir {
|
|
1282
|
+
font-size: 10px;
|
|
1283
|
+
color: var(--ide-text-muted);
|
|
1177
1284
|
white-space: nowrap;
|
|
1178
1285
|
overflow: hidden;
|
|
1179
1286
|
text-overflow: ellipsis;
|
|
1287
|
+
flex: 1;
|
|
1288
|
+
min-width: 0;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
/* Match count, VS Code's little pill on the right of the file row. */
|
|
1292
|
+
.search-result-count {
|
|
1293
|
+
flex-shrink: 0;
|
|
1294
|
+
margin-left: auto;
|
|
1295
|
+
min-width: 16px;
|
|
1296
|
+
padding: 0 5px;
|
|
1297
|
+
border-radius: 9px;
|
|
1298
|
+
background: var(--ide-input-bg);
|
|
1299
|
+
color: var(--ide-text-muted);
|
|
1300
|
+
font-size: 10px;
|
|
1301
|
+
line-height: 15px;
|
|
1302
|
+
text-align: center;
|
|
1180
1303
|
}
|
|
1181
1304
|
|
|
1182
1305
|
.search-result-line-num {
|
|
1306
|
+
flex-shrink: 0;
|
|
1183
1307
|
font-size: 10px;
|
|
1184
1308
|
color: var(--ide-text-muted);
|
|
1185
|
-
|
|
1309
|
+
font-family: monospace;
|
|
1310
|
+
min-width: 28px;
|
|
1311
|
+
text-align: right;
|
|
1186
1312
|
}
|
|
1187
1313
|
|
|
1188
1314
|
.search-result-text {
|
|
1315
|
+
flex: 1;
|
|
1316
|
+
min-width: 0;
|
|
1189
1317
|
font-size: 11px;
|
|
1190
1318
|
color: var(--ide-text-muted);
|
|
1191
1319
|
font-family: monospace;
|
|
@@ -1194,6 +1322,47 @@ html, body, #mbeditor-root {
|
|
|
1194
1322
|
text-overflow: ellipsis;
|
|
1195
1323
|
}
|
|
1196
1324
|
|
|
1325
|
+
/* The match has to stay on screen at any panel width, so a hit line is three
|
|
1326
|
+
boxes rather than one ellipsised string. Shrink order is what does the work:
|
|
1327
|
+
the text BEFORE the match gives way first, then the text after it, and the
|
|
1328
|
+
match itself only as a last resort — so it can never be the part that scrolls
|
|
1329
|
+
out of view. `direction: rtl` is what moves the leading ellipsis to the start
|
|
1330
|
+
of .search-result-pre; searchMatchParts() prefixes a U+200E so an all-symbol
|
|
1331
|
+
segment can't be reordered by it. */
|
|
1332
|
+
.search-result-text-split {
|
|
1333
|
+
display: flex;
|
|
1334
|
+
align-items: center;
|
|
1335
|
+
text-overflow: clip;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
.search-result-pre,
|
|
1339
|
+
.search-result-post,
|
|
1340
|
+
.search-result-match {
|
|
1341
|
+
overflow: hidden;
|
|
1342
|
+
text-overflow: ellipsis;
|
|
1343
|
+
white-space: pre;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
.search-result-pre {
|
|
1347
|
+
flex: 0 100 auto;
|
|
1348
|
+
direction: rtl;
|
|
1349
|
+
text-align: left;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
.search-result-post { flex: 0 10 auto; }
|
|
1353
|
+
|
|
1354
|
+
/* Never shrinks: flex distributes overflow across every shrinkable box in
|
|
1355
|
+
proportion to its size, so even shrink:1 against a long tail cost the match a
|
|
1356
|
+
character or two of ellipsis. max-width is what still bounds a match wider
|
|
1357
|
+
than the panel — it clips instead of overflowing. */
|
|
1358
|
+
.search-result-match {
|
|
1359
|
+
flex: 0 0 auto;
|
|
1360
|
+
max-width: 100%;
|
|
1361
|
+
background: color-mix(in srgb, var(--ide-accent) 40%, transparent);
|
|
1362
|
+
color: var(--ide-text);
|
|
1363
|
+
border-radius: 2px;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1197
1366
|
.search-results-loading-more {
|
|
1198
1367
|
padding: 8px 10px;
|
|
1199
1368
|
font-size: 11px;
|
|
@@ -1412,7 +1581,90 @@ html, body, #mbeditor-root {
|
|
|
1412
1581
|
cursor: pointer;
|
|
1413
1582
|
}
|
|
1414
1583
|
.import-conflict-btn:hover { background: var(--ide-hover-bg, #4a4a4a); }
|
|
1584
|
+
.import-conflict-btn:disabled { opacity: 0.45; cursor: default; }
|
|
1415
1585
|
.import-conflict-btn-danger { border-color: var(--ide-error, #f48771); color: var(--ide-error, #f48771); }
|
|
1586
|
+
.import-conflict-btn-primary {
|
|
1587
|
+
background: var(--ide-accent, #0e639c);
|
|
1588
|
+
border-color: var(--ide-accent, #0e639c);
|
|
1589
|
+
color: #fff;
|
|
1590
|
+
}
|
|
1591
|
+
.import-conflict-btn-primary:hover:not(:disabled) { background: var(--ide-accent-hover, #1177bb); }
|
|
1592
|
+
|
|
1593
|
+
/* Upload dialog — the pointed-at half of drag-and-drop import */
|
|
1594
|
+
.import-dialog { min-width: 460px; max-width: 620px; }
|
|
1595
|
+
.import-dialog .schema-modal-body { padding: 12px 16px; }
|
|
1596
|
+
.import-pick-row { display: flex; gap: 8px; }
|
|
1597
|
+
.import-pick-btn {
|
|
1598
|
+
background: var(--ide-input-bg, #3c3c3c);
|
|
1599
|
+
color: var(--ide-text, #d4d4d4);
|
|
1600
|
+
border: 1px solid var(--ide-border, #3c3c3c);
|
|
1601
|
+
border-radius: 3px;
|
|
1602
|
+
padding: 6px 12px;
|
|
1603
|
+
font-size: 12px;
|
|
1604
|
+
cursor: pointer;
|
|
1605
|
+
}
|
|
1606
|
+
.import-pick-btn:hover { background: var(--ide-hover-bg, #4a4a4a); }
|
|
1607
|
+
.import-pick-btn i { margin-right: 6px; opacity: 0.75; }
|
|
1608
|
+
.import-dialog-empty,
|
|
1609
|
+
.import-dialog-warning {
|
|
1610
|
+
margin-top: 12px;
|
|
1611
|
+
font-size: 12px;
|
|
1612
|
+
color: var(--ide-text-muted, #888);
|
|
1613
|
+
}
|
|
1614
|
+
.import-dialog-warning { color: var(--ide-warning, #cca700); }
|
|
1615
|
+
.import-dialog-section-title {
|
|
1616
|
+
margin: 16px 0 6px;
|
|
1617
|
+
font-size: 10px;
|
|
1618
|
+
font-weight: 600;
|
|
1619
|
+
text-transform: uppercase;
|
|
1620
|
+
letter-spacing: 0.06em;
|
|
1621
|
+
color: var(--ide-text-muted, #888);
|
|
1622
|
+
}
|
|
1623
|
+
.import-dest-options { display: flex; flex-direction: column; gap: 2px; }
|
|
1624
|
+
.import-dest-option {
|
|
1625
|
+
display: flex;
|
|
1626
|
+
align-items: center;
|
|
1627
|
+
gap: 8px;
|
|
1628
|
+
width: 100%;
|
|
1629
|
+
text-align: left;
|
|
1630
|
+
background: none;
|
|
1631
|
+
border: none;
|
|
1632
|
+
border-radius: 3px;
|
|
1633
|
+
padding: 4px 6px;
|
|
1634
|
+
color: var(--ide-text, #d4d4d4);
|
|
1635
|
+
font-size: 12px;
|
|
1636
|
+
cursor: pointer;
|
|
1637
|
+
}
|
|
1638
|
+
.import-dest-option:hover { background: var(--ide-hover, rgba(255,255,255,0.06)); }
|
|
1639
|
+
.import-dest-option.active { background: var(--ide-selection-bg, rgba(14,99,156,0.35)); }
|
|
1640
|
+
.import-dest-radio { opacity: 0.7; font-size: 11px; }
|
|
1641
|
+
.import-dest-label {
|
|
1642
|
+
font-family: var(--ide-mono-font, monospace);
|
|
1643
|
+
overflow: hidden;
|
|
1644
|
+
text-overflow: ellipsis;
|
|
1645
|
+
white-space: nowrap;
|
|
1646
|
+
}
|
|
1647
|
+
.import-dest-hint { color: var(--ide-text-muted, #888); font-size: 11px; margin-left: auto; flex-shrink: 0; }
|
|
1648
|
+
.import-dest-input {
|
|
1649
|
+
width: 100%;
|
|
1650
|
+
margin-top: 8px;
|
|
1651
|
+
box-sizing: border-box;
|
|
1652
|
+
background: var(--ide-input-bg, #3c3c3c);
|
|
1653
|
+
color: var(--ide-text, #d4d4d4);
|
|
1654
|
+
border: 1px solid var(--ide-border, #3c3c3c);
|
|
1655
|
+
border-radius: 3px;
|
|
1656
|
+
padding: 5px 8px;
|
|
1657
|
+
font-family: var(--ide-mono-font, monospace);
|
|
1658
|
+
font-size: 12px;
|
|
1659
|
+
}
|
|
1660
|
+
.import-dest-input:focus { outline: 1px solid var(--ide-accent, #0e639c); }
|
|
1661
|
+
.import-target-replaces {
|
|
1662
|
+
margin-left: 8px;
|
|
1663
|
+
font-size: 10px;
|
|
1664
|
+
text-transform: uppercase;
|
|
1665
|
+
letter-spacing: 0.06em;
|
|
1666
|
+
color: var(--ide-warning, #cca700);
|
|
1667
|
+
}
|
|
1416
1668
|
.schema-table {
|
|
1417
1669
|
width: 100%;
|
|
1418
1670
|
border-collapse: collapse;
|
|
@@ -1969,12 +2221,20 @@ html, body, #mbeditor-root {
|
|
|
1969
2221
|
flex-shrink: 0;
|
|
1970
2222
|
}
|
|
1971
2223
|
|
|
2224
|
+
/* The title yields the header to the action buttons rather than wrapping.
|
|
2225
|
+
*
|
|
2226
|
+
* It used to break-word onto three lines ("SAMPLE_ / WORKSPA / CE") because a
|
|
2227
|
+
* long workspace name plus six buttons genuinely does not fit a 300px sidebar.
|
|
2228
|
+
* flex-shrink against a `flex-shrink: 0` action group means the buttons always
|
|
2229
|
+
* win: full title, then ellipsis, then gone. No JS measuring, and it adapts on
|
|
2230
|
+
* its own to sections with fewer buttons — the Open Editors header keeps its
|
|
2231
|
+
* title at the same width where Explorer has already dropped it. */
|
|
1972
2232
|
.collapsible-title {
|
|
1973
|
-
flex: 1;
|
|
2233
|
+
flex: 1 1 auto;
|
|
1974
2234
|
min-width: 0;
|
|
1975
|
-
|
|
1976
|
-
overflow
|
|
1977
|
-
|
|
2235
|
+
white-space: nowrap;
|
|
2236
|
+
overflow: hidden;
|
|
2237
|
+
text-overflow: ellipsis;
|
|
1978
2238
|
}
|
|
1979
2239
|
|
|
1980
2240
|
.collapsible-actions {
|
|
@@ -1991,6 +2251,45 @@ html, body, #mbeditor-root {
|
|
|
1991
2251
|
gap: 0;
|
|
1992
2252
|
}
|
|
1993
2253
|
|
|
2254
|
+
/* Tooltip for the icon-only sidebar action buttons. See SidebarActionButton
|
|
2255
|
+
* for why this is not a title attribute. Anchored to the button's right edge
|
|
2256
|
+
* because .ide-sidebar-scrollable is overflow-x: hidden — a left-anchored or
|
|
2257
|
+
* centred tooltip on the rightmost button would be clipped by the sidebar. */
|
|
2258
|
+
.sb-tip {
|
|
2259
|
+
position: relative;
|
|
2260
|
+
display: inline-flex;
|
|
2261
|
+
}
|
|
2262
|
+
.sb-tip::after {
|
|
2263
|
+
content: attr(data-tip);
|
|
2264
|
+
position: absolute;
|
|
2265
|
+
top: calc(100% + 4px);
|
|
2266
|
+
right: 0;
|
|
2267
|
+
z-index: 4000;
|
|
2268
|
+
padding: 4px 7px;
|
|
2269
|
+
background: var(--ide-panel-bg, #252526);
|
|
2270
|
+
border: 1px solid var(--ide-border, #3c3c3c);
|
|
2271
|
+
border-radius: 4px;
|
|
2272
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
2273
|
+
color: var(--ide-text, #d4d4d4);
|
|
2274
|
+
/* The section header sets uppercase, 600 weight and letter-spacing; a
|
|
2275
|
+
tooltip inheriting those reads as another heading. */
|
|
2276
|
+
font-size: 11px;
|
|
2277
|
+
font-weight: 400;
|
|
2278
|
+
letter-spacing: 0;
|
|
2279
|
+
text-transform: none;
|
|
2280
|
+
white-space: nowrap;
|
|
2281
|
+
opacity: 0;
|
|
2282
|
+
pointer-events: none;
|
|
2283
|
+
transition: opacity 0.08s ease 0.3s;
|
|
2284
|
+
}
|
|
2285
|
+
.sb-tip:hover::after,
|
|
2286
|
+
.sb-tip:focus-within::after {
|
|
2287
|
+
opacity: 1;
|
|
2288
|
+
}
|
|
2289
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2290
|
+
.sb-tip::after { transition: none; }
|
|
2291
|
+
}
|
|
2292
|
+
|
|
1994
2293
|
/* Open-editors panel: height is controlled by the --open-editors-height CSS variable
|
|
1995
2294
|
set inline from React state (default 140px ≈ 5-6 items), drag-resizable via the
|
|
1996
2295
|
.open-editors-resize-handle strip below. */
|
|
@@ -2319,7 +2618,7 @@ html, body, #mbeditor-root {
|
|
|
2319
2618
|
display: flex;
|
|
2320
2619
|
align-items: flex-start;
|
|
2321
2620
|
justify-content: center;
|
|
2322
|
-
padding-top:
|
|
2621
|
+
padding-top: 12vh;
|
|
2323
2622
|
z-index: 9999;
|
|
2324
2623
|
}
|
|
2325
2624
|
|
|
@@ -2327,8 +2626,9 @@ html, body, #mbeditor-root {
|
|
|
2327
2626
|
background: var(--ide-panel-bg);
|
|
2328
2627
|
border: 1px solid var(--ide-border-input);
|
|
2329
2628
|
border-radius: 8px;
|
|
2330
|
-
|
|
2331
|
-
|
|
2629
|
+
/* vw/vh caps keep the larger dialog inside a phone-sized viewport */
|
|
2630
|
+
width: min(760px, 94vw);
|
|
2631
|
+
max-height: min(620px, 72vh);
|
|
2332
2632
|
display: flex;
|
|
2333
2633
|
flex-direction: column;
|
|
2334
2634
|
box-shadow: 0 16px 48px rgba(0,0,0,0.7);
|
|
@@ -2344,8 +2644,8 @@ html, body, #mbeditor-root {
|
|
|
2344
2644
|
border: none;
|
|
2345
2645
|
border-bottom: 1px solid var(--ide-border);
|
|
2346
2646
|
color: var(--ide-text);
|
|
2347
|
-
padding:
|
|
2348
|
-
font-size:
|
|
2647
|
+
padding: 14px 40px 14px 18px;
|
|
2648
|
+
font-size: 16px;
|
|
2349
2649
|
outline: none;
|
|
2350
2650
|
width: 100%;
|
|
2351
2651
|
box-sizing: border-box;
|
|
@@ -2354,11 +2654,11 @@ html, body, #mbeditor-root {
|
|
|
2354
2654
|
|
|
2355
2655
|
.quick-open-clear-btn {
|
|
2356
2656
|
position: absolute;
|
|
2357
|
-
right:
|
|
2657
|
+
right: 8px;
|
|
2358
2658
|
top: 50%;
|
|
2359
2659
|
transform: translateY(-50%);
|
|
2360
|
-
width:
|
|
2361
|
-
height:
|
|
2660
|
+
width: 26px;
|
|
2661
|
+
height: 26px;
|
|
2362
2662
|
border: none;
|
|
2363
2663
|
border-radius: 4px;
|
|
2364
2664
|
background: transparent;
|
|
@@ -2380,18 +2680,18 @@ html, body, #mbeditor-root {
|
|
|
2380
2680
|
}
|
|
2381
2681
|
|
|
2382
2682
|
.quick-open-result {
|
|
2383
|
-
padding:
|
|
2683
|
+
padding: 8px 18px;
|
|
2384
2684
|
cursor: pointer;
|
|
2385
2685
|
display: flex;
|
|
2386
2686
|
align-items: center;
|
|
2387
|
-
gap:
|
|
2388
|
-
font-size:
|
|
2687
|
+
gap: 10px;
|
|
2688
|
+
font-size: 14px;
|
|
2389
2689
|
transition: background 0.1s;
|
|
2390
2690
|
}
|
|
2391
2691
|
|
|
2392
2692
|
.quick-open-result-icon {
|
|
2393
2693
|
flex-shrink: 0;
|
|
2394
|
-
width:
|
|
2694
|
+
width: 18px;
|
|
2395
2695
|
text-align: center;
|
|
2396
2696
|
color: #78b4e0;
|
|
2397
2697
|
}
|
|
@@ -2405,10 +2705,10 @@ html, body, #mbeditor-root {
|
|
|
2405
2705
|
.quick-open-result.selected { background: var(--ide-active-bg); }
|
|
2406
2706
|
|
|
2407
2707
|
.quick-open-result-name { color: var(--ide-text); }
|
|
2408
|
-
.quick-open-result-path { color: var(--ide-text-muted); font-size:
|
|
2708
|
+
.quick-open-result-path { color: var(--ide-text-muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
2409
2709
|
|
|
2410
2710
|
.quick-open-section { margin-bottom: 4px; }
|
|
2411
|
-
.quick-open-section-header { padding:
|
|
2711
|
+
.quick-open-section-header { padding: 8px 18px 4px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ide-text-muted); font-weight: 600; }
|
|
2412
2712
|
|
|
2413
2713
|
.quick-open-star-btn {
|
|
2414
2714
|
flex-shrink: 0;
|
|
@@ -2417,7 +2717,7 @@ html, body, #mbeditor-root {
|
|
|
2417
2717
|
cursor: pointer;
|
|
2418
2718
|
padding: 2px 6px;
|
|
2419
2719
|
color: var(--ide-text-muted);
|
|
2420
|
-
font-size:
|
|
2720
|
+
font-size: 14px;
|
|
2421
2721
|
line-height: 1;
|
|
2422
2722
|
opacity: 0;
|
|
2423
2723
|
transition: opacity 0.1s, color 0.1s;
|
|
@@ -2431,9 +2731,9 @@ html, body, #mbeditor-root {
|
|
|
2431
2731
|
.quick-open-result-dir .quick-open-result-name { color: #dcb67a; }
|
|
2432
2732
|
|
|
2433
2733
|
.quick-open-empty-hint {
|
|
2434
|
-
padding:
|
|
2734
|
+
padding: 24px 18px;
|
|
2435
2735
|
color: var(--ide-text-muted);
|
|
2436
|
-
font-size:
|
|
2736
|
+
font-size: 13px;
|
|
2437
2737
|
text-align: center;
|
|
2438
2738
|
line-height: 1.6;
|
|
2439
2739
|
}
|
|
@@ -2652,26 +2952,8 @@ button:not(.pico-btn) {
|
|
|
2652
2952
|
font-size: 12px;
|
|
2653
2953
|
}
|
|
2654
2954
|
|
|
2655
|
-
/*
|
|
2656
|
-
*
|
|
2657
|
-
* because Monaco renders them as <a role="button">. Without this reset, Pico
|
|
2658
|
-
* applies its primary-colour background, white text, and large form-element
|
|
2659
|
-
* padding, making those buttons huge and unreadable on certain themes.
|
|
2660
|
-
* Resetting the Pico CSS variables here is lower-impact than fighting
|
|
2661
|
-
* per-property specificity battles with Monaco's --vscode-* rules.
|
|
2662
|
-
*/
|
|
2663
|
-
.monaco-hover [role=button],
|
|
2664
|
-
.action-widget [role=button],
|
|
2665
|
-
.context-view [role=button],
|
|
2666
|
-
.monaco-editor [role=button],
|
|
2667
|
-
.monaco-diff-editor [role=button] {
|
|
2668
|
-
--pico-background-color: transparent;
|
|
2669
|
-
--pico-border-color: transparent;
|
|
2670
|
-
--pico-color: inherit;
|
|
2671
|
-
--pico-box-shadow: none;
|
|
2672
|
-
--pico-form-element-spacing-vertical: 0;
|
|
2673
|
-
--pico-form-element-spacing-horizontal: 0;
|
|
2674
|
-
}
|
|
2955
|
+
/* Pico containment lives at the top of this file — see the block there. It has
|
|
2956
|
+
* to sit above every component rule to stay a floor rather than an override. */
|
|
2675
2957
|
|
|
2676
2958
|
/* Inputs and selects — keep compact but styled */
|
|
2677
2959
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
|
|
@@ -2684,7 +2966,11 @@ textarea {
|
|
|
2684
2966
|
margin-bottom: 0;
|
|
2685
2967
|
}
|
|
2686
2968
|
|
|
2687
|
-
/* Status bar buttons override (22px tall, full-bleed)
|
|
2969
|
+
/* Status bar buttons override (22px tall, full-bleed).
|
|
2970
|
+
* line-height must be set here too, not just on .ide-statusbar: Pico gives
|
|
2971
|
+
* <button> its own line-height, so it does not inherit the bar's, and the
|
|
2972
|
+
* count next to an icon ended up in a 16.5px line box beside the icon's 11px
|
|
2973
|
+
* one. */
|
|
2688
2974
|
.ide-statusbar button,
|
|
2689
2975
|
.statusbar-btn {
|
|
2690
2976
|
--pico-form-element-spacing-vertical: 0;
|
|
@@ -2692,6 +2978,7 @@ textarea {
|
|
|
2692
2978
|
height: 22px;
|
|
2693
2979
|
padding: 0 8px;
|
|
2694
2980
|
font-size: 11px;
|
|
2981
|
+
line-height: 1;
|
|
2695
2982
|
border-radius: 2px;
|
|
2696
2983
|
border: none;
|
|
2697
2984
|
background: transparent;
|
|
@@ -3049,6 +3336,11 @@ button:not(.pico-btn) { margin-bottom: 0; }
|
|
|
3049
3336
|
padding: 2px 6px;
|
|
3050
3337
|
}
|
|
3051
3338
|
.ide-problems-btn:hover { color: var(--ide-fg, #fff); }
|
|
3339
|
+
.ide-problems-btn:disabled { opacity: 0.4; cursor: default; }
|
|
3340
|
+
.ide-problems-btn:disabled:hover { color: var(--ide-fg-muted, #ccc); }
|
|
3341
|
+
.ide-problems-actions { display: flex; gap: 2px; }
|
|
3342
|
+
.ide-problems-actions .ide-problems-btn { white-space: nowrap; }
|
|
3343
|
+
.ide-problems-btn.is-on { color: var(--ide-accent, #0a84ff); }
|
|
3052
3344
|
.ide-problems-body { flex: 1; overflow: auto; padding: 4px 0; font-size: 12px; }
|
|
3053
3345
|
.ide-problems-empty {
|
|
3054
3346
|
padding: 10px 14px;
|
|
@@ -3281,18 +3573,12 @@ button:not(.pico-btn) { margin-bottom: 0; }
|
|
|
3281
3573
|
.ide-problems-frame { padding-left: 28px; }
|
|
3282
3574
|
.ide-problems-frame .ide-problems-code { opacity: 1; }
|
|
3283
3575
|
|
|
3284
|
-
/* Status-bar
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
.statusbar-
|
|
3288
|
-
.statusbar-lsp-ok:hover { opacity: 1; }
|
|
3289
|
-
.statusbar-lsp-degraded,
|
|
3290
|
-
.statusbar-lsp-off { color: var(--ide-warning); }
|
|
3291
|
-
|
|
3292
|
-
/* Status-bar problems indicator: bug count then warning count, VS Code style. */
|
|
3293
|
-
.statusbar-problems { display: inline-flex; align-items: center; gap: 4px; }
|
|
3576
|
+
/* Status-bar problems indicator: bug count then warning count, VS Code style.
|
|
3577
|
+
The gap is the icon-to-its-own-number spacing; the warning icon opens the
|
|
3578
|
+
second pair, so it gets the wider separator. */
|
|
3579
|
+
.statusbar-problems { gap: 4px; }
|
|
3294
3580
|
.statusbar-problems-error-icon { color: var(--ide-danger); }
|
|
3295
|
-
.statusbar-problems-warning-icon { color: var(--ide-warning); }
|
|
3581
|
+
.statusbar-problems-warning-icon { color: var(--ide-warning); margin-left: 8px; }
|
|
3296
3582
|
.statusbar-problems-count { font-variant-numeric: tabular-nums; }
|
|
3297
3583
|
|
|
3298
3584
|
/* Search decorations off across engines — Chrome/Safari draw their own
|