mbeditor 0.1.0

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.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +127 -0
  3. data/app/assets/javascripts/mbeditor/application.js +19 -0
  4. data/app/assets/javascripts/mbeditor/components/CodeReviewPanel.js +202 -0
  5. data/app/assets/javascripts/mbeditor/components/CollapsibleSection.js +71 -0
  6. data/app/assets/javascripts/mbeditor/components/CombinedDiffViewer.js +139 -0
  7. data/app/assets/javascripts/mbeditor/components/CommitGraph.js +65 -0
  8. data/app/assets/javascripts/mbeditor/components/DiffViewer.js +142 -0
  9. data/app/assets/javascripts/mbeditor/components/EditorPanel.js +363 -0
  10. data/app/assets/javascripts/mbeditor/components/FileHistoryPanel.js +112 -0
  11. data/app/assets/javascripts/mbeditor/components/FileTree.js +304 -0
  12. data/app/assets/javascripts/mbeditor/components/GitPanel.js +416 -0
  13. data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +2335 -0
  14. data/app/assets/javascripts/mbeditor/components/QuickOpenDialog.js +118 -0
  15. data/app/assets/javascripts/mbeditor/components/ShortcutHelp.js +186 -0
  16. data/app/assets/javascripts/mbeditor/components/TabBar.js +123 -0
  17. data/app/assets/javascripts/mbeditor/editor_plugins.js +282 -0
  18. data/app/assets/javascripts/mbeditor/editor_store.js +53 -0
  19. data/app/assets/javascripts/mbeditor/file_service.js +77 -0
  20. data/app/assets/javascripts/mbeditor/git_service.js +104 -0
  21. data/app/assets/javascripts/mbeditor/search_service.js +53 -0
  22. data/app/assets/javascripts/mbeditor/tab_manager.js +461 -0
  23. data/app/assets/stylesheets/mbeditor/application.css +705 -0
  24. data/app/assets/stylesheets/mbeditor/editor.css +1264 -0
  25. data/app/controllers/mbeditor/application_controller.rb +10 -0
  26. data/app/controllers/mbeditor/editors_controller.rb +695 -0
  27. data/app/controllers/mbeditor/git_controller.rb +188 -0
  28. data/app/services/mbeditor/git_blame_service.rb +98 -0
  29. data/app/services/mbeditor/git_commit_graph_service.rb +60 -0
  30. data/app/services/mbeditor/git_diff_service.rb +71 -0
  31. data/app/services/mbeditor/git_file_history_service.rb +42 -0
  32. data/app/services/mbeditor/git_service.rb +82 -0
  33. data/app/services/mbeditor/redmine_service.rb +86 -0
  34. data/app/views/layouts/mbeditor/application.html.erb +71 -0
  35. data/app/views/mbeditor/editors/index.html.erb +1 -0
  36. data/config/environments/development.rb +53 -0
  37. data/config/initializers/assets.rb +9 -0
  38. data/config/routes.rb +37 -0
  39. data/lib/mbeditor/configuration.rb +16 -0
  40. data/lib/mbeditor/engine.rb +28 -0
  41. data/lib/mbeditor/version.rb +3 -0
  42. data/lib/mbeditor.rb +19 -0
  43. data/mbeditor.gemspec +30 -0
  44. data/public/min-maps/vs/base/worker/workerMain.js.map +1 -0
  45. data/public/monaco-editor/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  46. data/public/monaco-editor/vs/base/worker/workerMain.js +31 -0
  47. data/public/monaco-editor/vs/basic-languages/cameligo/cameligo.js +10 -0
  48. data/public/monaco-editor/vs/basic-languages/css/css.js +12 -0
  49. data/public/monaco-editor/vs/basic-languages/dart/dart.js +10 -0
  50. data/public/monaco-editor/vs/basic-languages/flow9/flow9.js +10 -0
  51. data/public/monaco-editor/vs/basic-languages/go/go.js +10 -0
  52. data/public/monaco-editor/vs/basic-languages/handlebars/handlebars.js +440 -0
  53. data/public/monaco-editor/vs/basic-languages/javascript/javascript.js +10 -0
  54. data/public/monaco-editor/vs/basic-languages/markdown/markdown.js +10 -0
  55. data/public/monaco-editor/vs/basic-languages/msdax/msdax.js +10 -0
  56. data/public/monaco-editor/vs/basic-languages/postiats/postiats.js +10 -0
  57. data/public/monaco-editor/vs/basic-languages/pug/pug.js +412 -0
  58. data/public/monaco-editor/vs/basic-languages/restructuredtext/restructuredtext.js +10 -0
  59. data/public/monaco-editor/vs/basic-languages/ruby/ruby.js +10 -0
  60. data/public/monaco-editor/vs/basic-languages/sb/sb.js +10 -0
  61. data/public/monaco-editor/vs/basic-languages/typespec/typespec.js +10 -0
  62. data/public/monaco-editor/vs/basic-languages/yaml/yaml.js +10 -0
  63. data/public/monaco-editor/vs/editor/editor.main.css +8 -0
  64. data/public/monaco-editor/vs/editor/editor.main.js +797 -0
  65. data/public/monaco-editor/vs/language/typescript/tsMode.js +20 -0
  66. data/public/monaco-editor/vs/language/typescript/tsWorker.js +51328 -0
  67. data/public/monaco-editor/vs/loader.js +10 -0
  68. data/public/monaco-editor/vs/nls.messages.de.js +20 -0
  69. data/public/monaco-editor/vs/nls.messages.es.js +20 -0
  70. data/public/monaco-editor/vs/nls.messages.fr.js +18 -0
  71. data/public/monaco-editor/vs/nls.messages.it.js +18 -0
  72. data/public/monaco-editor/vs/nls.messages.ja.js +20 -0
  73. data/public/monaco-editor/vs/nls.messages.ko.js +18 -0
  74. data/public/monaco-editor/vs/nls.messages.ru.js +20 -0
  75. data/public/monaco-editor/vs/nls.messages.zh-cn.js +20 -0
  76. data/public/monaco-editor/vs/nls.messages.zh-tw.js +18 -0
  77. data/public/monaco_worker.js +5 -0
  78. data/vendor/assets/javascripts/axios.min.js +2 -0
  79. data/vendor/assets/javascripts/lodash.min.js +140 -0
  80. data/vendor/assets/javascripts/marked.min.js +6 -0
  81. data/vendor/assets/javascripts/minisearch.min.js +2044 -0
  82. data/vendor/assets/javascripts/prettier-plugin-babel.js +16 -0
  83. data/vendor/assets/javascripts/prettier-plugin-estree.js +35 -0
  84. data/vendor/assets/javascripts/prettier-plugin-html.js +19 -0
  85. data/vendor/assets/javascripts/prettier-plugin-markdown.js +59 -0
  86. data/vendor/assets/javascripts/prettier-plugin-postcss.js +52 -0
  87. data/vendor/assets/javascripts/prettier-standalone.js +37 -0
  88. data/vendor/assets/javascripts/react-dom.min.js +267 -0
  89. data/vendor/assets/javascripts/react.min.js +31 -0
  90. data/vendor/assets/stylesheets/fontawesome.min.css +9 -0
  91. data/vendor/assets/webfonts/fa-brands-400.woff2 +0 -0
  92. data/vendor/assets/webfonts/fa-regular-400.woff2 +0 -0
  93. data/vendor/assets/webfonts/fa-solid-900.woff2 +0 -0
  94. metadata +173 -0
@@ -0,0 +1,1264 @@
1
+ /* ── Mini Browser Editor Global Styles ──────────────────── */
2
+ *, *::before, *::after { box-sizing: border-box; }
3
+
4
+ html, body, #mbeditor-root {
5
+ margin: 0; padding: 0;
6
+ width: 100%; height: 100%;
7
+ overflow: hidden;
8
+ background: #1e1e1e;
9
+ color: #cdd6f4;
10
+ font-family: 'Segoe UI', system-ui, sans-serif;
11
+ font-size: 13px;
12
+ }
13
+
14
+ /* ── IDE Shell Layout ────────────────────────────────────── */
15
+ .ide-shell {
16
+ display: flex;
17
+ flex-direction: column;
18
+ height: 100vh;
19
+ width: 100vw;
20
+ background: #1e1e1e;
21
+ }
22
+
23
+ .ide-titlebar {
24
+ display: flex;
25
+ align-items: center;
26
+ background: #252526;
27
+ border-bottom: 1px solid #3c3c3c;
28
+ height: 32px;
29
+ padding: 0 12px;
30
+ flex-shrink: 0;
31
+ user-select: none;
32
+ }
33
+
34
+ .ide-titlebar-icon {
35
+ color: #4ec9b0;
36
+ margin-right: 8px;
37
+ font-size: 14px;
38
+ }
39
+
40
+ .ide-titlebar-title {
41
+ font-size: 13px;
42
+ color: #cccccc;
43
+ font-weight: 500;
44
+ }
45
+
46
+ .ide-body {
47
+ display: flex;
48
+ flex: 1;
49
+ overflow: hidden;
50
+ }
51
+
52
+ /* ── Sidebar ─────────────────────────────────────────────── */
53
+ .ide-sidebar {
54
+ width: 240px;
55
+ min-width: 240px;
56
+ max-width: 560px;
57
+ background: #252526;
58
+ border-right: 1px solid #3c3c3c;
59
+ display: flex;
60
+ flex-direction: column;
61
+ overflow: hidden;
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ .panel-divider {
66
+ flex-shrink: 0;
67
+ cursor: col-resize;
68
+ transition: background 0.12s ease;
69
+ }
70
+
71
+ .sidebar-divider {
72
+ width: 6px;
73
+ background: #2a2a2a;
74
+ border-right: 1px solid #3c3c3c;
75
+ }
76
+
77
+ .pane-divider {
78
+ width: 4px;
79
+ background: #333;
80
+ z-index: 10;
81
+ }
82
+
83
+ .panel-divider:hover,
84
+ .panel-divider.active {
85
+ background: #007acc;
86
+ }
87
+
88
+ .ide-sidebar-header {
89
+ padding: 6px 12px;
90
+ font-size: 11px;
91
+ font-weight: 600;
92
+ text-transform: uppercase;
93
+ color: #bbbbbb;
94
+ letter-spacing: 0.08em;
95
+ border-bottom: 1px solid #3c3c3c;
96
+ flex-shrink: 0;
97
+ display: flex;
98
+ align-items: center;
99
+ gap: 6px;
100
+ }
101
+
102
+ .ide-sidebar-tabs {
103
+ display: flex;
104
+ border-bottom: 1px solid #3c3c3c;
105
+ flex-shrink: 0;
106
+ }
107
+
108
+ .ide-sidebar-tab {
109
+ flex: 1;
110
+ padding: 5px 0;
111
+ font-size: 11px;
112
+ text-align: center;
113
+ cursor: pointer;
114
+ color: #888;
115
+ border: none;
116
+ background: transparent;
117
+ transition: color 0.15s, background 0.15s;
118
+ }
119
+
120
+ .ide-sidebar-tab:hover { color: #ccc; background: #2d2d2d; }
121
+ .ide-sidebar-tab.active { color: #4ec9b0; border-bottom: 2px solid #4ec9b0; }
122
+
123
+ .ide-sidebar-content {
124
+ flex: 1;
125
+ overflow-y: auto;
126
+ overflow-x: hidden;
127
+ }
128
+
129
+ .ide-sidebar-content::-webkit-scrollbar { width: 6px; }
130
+ .ide-sidebar-content::-webkit-scrollbar-track { background: transparent; }
131
+ .ide-sidebar-content::-webkit-scrollbar-thumb { background: #424242; border-radius: 3px; }
132
+
133
+ /* ── File Tree ────────────────────────────────────────────── */
134
+ .file-tree-root { padding: 4px 0; }
135
+ .file-tree { padding: 0; }
136
+
137
+ .tree-item {
138
+ display: flex;
139
+ align-items: center;
140
+ position: relative;
141
+ padding: 2px 8px;
142
+ cursor: pointer;
143
+ border-radius: 3px;
144
+ margin: 1px 4px;
145
+ transition: background 0.1s;
146
+ white-space: nowrap;
147
+ overflow: hidden;
148
+ text-overflow: ellipsis;
149
+ }
150
+
151
+ .tree-item:hover { background: #2a2d2e; }
152
+ .tree-item.active { background: #094771; }
153
+ .tree-item.selected { box-shadow: inset 0 0 0 1px rgba(120, 180, 224, 0.5); }
154
+ .tree-item.active.selected { box-shadow: inset 0 0 0 1px rgba(140, 210, 255, 0.8); }
155
+ .tree-item.modified { color: #e2c08d; }
156
+
157
+ /* Inline create row (VS Code-style new file/folder input) */
158
+ .tree-item-inline-create {
159
+ background: transparent;
160
+ cursor: default;
161
+ }
162
+ .tree-item-inline-create:hover {
163
+ background: transparent;
164
+ }
165
+ .tree-inline-input {
166
+ flex: 1;
167
+ min-width: 0;
168
+ background: #3c3c3c;
169
+ border: 1px solid #007acc;
170
+ border-radius: 3px;
171
+ color: #d4d4d4;
172
+ font-size: 12px;
173
+ font-family: inherit;
174
+ padding: 1px 4px;
175
+ outline: none;
176
+ height: 18px;
177
+ line-height: 18px;
178
+ }
179
+
180
+ .tree-item-icon {
181
+ width: 16px;
182
+ margin-right: 5px;
183
+ font-size: 12px;
184
+ flex-shrink: 0;
185
+ text-align: center;
186
+ }
187
+
188
+ .tree-folder-icon { color: #dcb67a; }
189
+ .tree-file-icon { color: #78b4e0; }
190
+ .tree-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; font-size: 12px; }
191
+
192
+ /* ── Custom File Icons ───────────────────────────────────── */
193
+ .ruby-icon { color: #f26262 !important; }
194
+ .react-icon { color: #61dafb !important; }
195
+ .js-icon { color: #f7df1e !important; }
196
+ .erb-icon, .html-icon { color: #e34c26 !important; }
197
+ .css-icon { color: #264de4 !important; }
198
+ .image-icon { color: #7cc6ff !important; }
199
+ .json-icon { color: #cbcb41 !important; }
200
+ .md-icon { color: #87b9ff !important; }
201
+ .yml-icon { color: #cb171e !important; }
202
+
203
+ /* ── Main Editor Area ────────────────────────────────────── */
204
+ .ide-main {
205
+ flex: 1;
206
+ display: flex;
207
+ flex-direction: column;
208
+ overflow: hidden;
209
+ background: #1e1e1e;
210
+ }
211
+
212
+ .ide-pane {
213
+ border: 1px solid transparent;
214
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
215
+ }
216
+
217
+ .ide-pane.drop-target {
218
+ border-color: #4ec9b0;
219
+ box-shadow: inset 0 0 0 1px rgba(78, 201, 176, 0.35);
220
+ }
221
+
222
+ /* ── Tab Bar ─────────────────────────────────────────────── */
223
+ .tab-bar {
224
+ display: flex;
225
+ align-items: center;
226
+ background: #252526;
227
+ border-bottom: 1px solid #3c3c3c;
228
+ height: 35px;
229
+ overflow-x: auto;
230
+ overflow-y: hidden;
231
+ flex-shrink: 0;
232
+ }
233
+
234
+ .tab-bar::-webkit-scrollbar { height: 3px; }
235
+ .tab-bar::-webkit-scrollbar-thumb { background: #555; }
236
+
237
+ .tab-item {
238
+ display: flex;
239
+ align-items: center;
240
+ padding: 0 12px;
241
+ height: 35px;
242
+ min-width: 100px;
243
+ max-width: 200px;
244
+ cursor: pointer;
245
+ border-right: 1px solid #3c3c3c;
246
+ background: #2d2d2d;
247
+ color: #888;
248
+ font-size: 12px;
249
+ transition: background 0.1s, color 0.1s;
250
+ white-space: nowrap;
251
+ overflow: hidden;
252
+ position: relative;
253
+ flex-shrink: 0;
254
+ }
255
+
256
+ .tab-item.dragging {
257
+ opacity: 0.55;
258
+ }
259
+
260
+ .tab-item:hover { background: #333; color: #ccc; }
261
+ .tab-item.active { background: #1e1e1e; color: #fff; border-top: 1px solid #4ec9b0; }
262
+ .tab-item.tab-soft .tab-item-name { font-style: italic; }
263
+
264
+ .tab-has-error {
265
+ border-bottom: 2px solid #d32f2f !important;
266
+ }
267
+ .tab-item.active.tab-has-error {
268
+ border-top: 2px solid #d32f2f !important;
269
+ border-bottom: none !important;
270
+ }
271
+
272
+ .tab-has-warning {
273
+ border-bottom: 2px solid #f9a825 !important;
274
+ }
275
+
276
+ .tab-item.active.tab-has-warning {
277
+ border-top: 2px solid #f9a825 !important;
278
+ border-bottom: none !important;
279
+ }
280
+
281
+ .tab-item-icon {
282
+ width: 14px;
283
+ margin-right: 8px;
284
+ font-size: 12px;
285
+ text-align: center;
286
+ flex-shrink: 0;
287
+ }
288
+
289
+ .tab-item-name {
290
+ overflow: hidden;
291
+ text-overflow: ellipsis;
292
+ flex: 1;
293
+ }
294
+
295
+ .tab-dirty-dot {
296
+ color: #e5c07b;
297
+ margin-left: 4px;
298
+ font-size: 10px;
299
+ line-height: 1;
300
+ }
301
+
302
+ .tab-close {
303
+ margin-left: 6px;
304
+ width: 16px;
305
+ height: 16px;
306
+ display: flex;
307
+ align-items: center;
308
+ justify-content: center;
309
+ border-radius: 3px;
310
+ font-size: 11px;
311
+ color: #666;
312
+ flex-shrink: 0;
313
+ transition: background 0.1s, color 0.1s;
314
+ }
315
+
316
+ .tab-close:hover { background: #555; color: #fff; }
317
+
318
+ .tab-welcome {
319
+ flex: 1;
320
+ display: flex;
321
+ align-items: center;
322
+ justify-content: flex-start;
323
+ flex-direction: column;
324
+ color: #555;
325
+ gap: 12px;
326
+ overflow-y: auto;
327
+ padding: 40px 48px;
328
+ }
329
+
330
+ .tab-welcome i { font-size: 48px; color: #333; opacity: 0.18; }
331
+ .tab-welcome h2 { font-size: 18px; font-weight: 400; color: #444; margin: 0; }
332
+ .tab-welcome p { font-size: 13px; color: #444; margin: 0; }
333
+ .tab-welcome kbd {
334
+ background: #2a2d2e;
335
+ border: 1px solid #444;
336
+ border-radius: 4px;
337
+ padding: 2px 6px;
338
+ font-size: 11px;
339
+ font-family: monospace;
340
+ }
341
+
342
+ .welcome-intro { font-size: 13px; color: #666; margin: 0; }
343
+
344
+ .welcome-shortcuts {
345
+ display: flex;
346
+ flex-wrap: wrap;
347
+ gap: 28px;
348
+ margin-top: 8px;
349
+ max-width: 580px;
350
+ width: 100%;
351
+ }
352
+
353
+ .welcome-section { min-width: 220px; }
354
+
355
+ .welcome-section h3 {
356
+ font-size: 11px;
357
+ font-weight: 700;
358
+ text-transform: uppercase;
359
+ letter-spacing: 0.07em;
360
+ color: #bbb;
361
+ margin: 0 0 8px 0;
362
+ border-bottom: 1px solid #3a3a3a;
363
+ padding-bottom: 4px;
364
+ }
365
+
366
+ .shortcut-table { border-collapse: collapse; width: 100%; }
367
+ .shortcut-table td { padding: 3px 8px 3px 0; font-size: 12px; color: #888; vertical-align: middle; }
368
+ .shortcut-table td:first-child { padding-right: 14px; white-space: nowrap; }
369
+
370
+ .welcome-tips {
371
+ list-style: none;
372
+ margin: 0;
373
+ padding: 0;
374
+ display: flex;
375
+ flex-direction: column;
376
+ gap: 7px;
377
+ }
378
+ .welcome-tips li { font-size: 12px; color: #777; }
379
+ .welcome-tips li i { color: #555; width: 14px; text-align: center; }
380
+
381
+ /* ── Search results meta ─────────────────────────────────── */
382
+ .search-results-meta {
383
+ padding: 4px 8px 6px;
384
+ font-size: 11px;
385
+ color: #888;
386
+ border-bottom: 1px solid #2a2a2a;
387
+ margin-bottom: 4px;
388
+ }
389
+ .search-results-capped { color: #f0a040; }
390
+ .search-results-empty { padding: 12px 8px; font-size: 12px; color: #666; }
391
+
392
+ /* ── Shortcut Help Drawer ────────────────────────────────── */
393
+ .shelp-backdrop {
394
+ position: fixed;
395
+ inset: 0;
396
+ background: rgba(0, 0, 0, 0.55);
397
+ z-index: 9000;
398
+ display: flex;
399
+ align-items: center;
400
+ justify-content: center;
401
+ }
402
+
403
+ .shelp-panel {
404
+ background: #252526;
405
+ border: 1px solid #3c3c3c;
406
+ border-radius: 6px;
407
+ width: 660px;
408
+ max-width: calc(100vw - 48px);
409
+ max-height: calc(100vh - 80px);
410
+ display: flex;
411
+ flex-direction: column;
412
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
413
+ overflow: hidden;
414
+ }
415
+
416
+ .shelp-header {
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: space-between;
420
+ padding: 12px 16px;
421
+ border-bottom: 1px solid #3c3c3c;
422
+ flex-shrink: 0;
423
+ }
424
+
425
+ .shelp-title {
426
+ font-size: 13px;
427
+ font-weight: 600;
428
+ color: #cccccc;
429
+ }
430
+
431
+ .shelp-close {
432
+ background: none;
433
+ border: none;
434
+ color: #888;
435
+ cursor: pointer;
436
+ padding: 2px 6px;
437
+ font-size: 14px;
438
+ border-radius: 3px;
439
+ line-height: 1;
440
+ }
441
+ .shelp-close:hover { background: #3c3c3c; color: #ccc; }
442
+
443
+ .shelp-body {
444
+ overflow-y: auto;
445
+ padding: 16px;
446
+ }
447
+
448
+ .shelp-columns {
449
+ display: flex;
450
+ gap: 24px;
451
+ flex-wrap: wrap;
452
+ }
453
+
454
+ .shelp-col {
455
+ flex: 1;
456
+ min-width: 240px;
457
+ display: flex;
458
+ flex-direction: column;
459
+ gap: 20px;
460
+ }
461
+
462
+ .shelp-section { display: flex; flex-direction: column; gap: 8px; }
463
+
464
+ .shelp-section-title {
465
+ font-size: 11px;
466
+ font-weight: 600;
467
+ text-transform: uppercase;
468
+ letter-spacing: 0.07em;
469
+ color: #666;
470
+ margin: 0;
471
+ border-bottom: 1px solid #2a2a2a;
472
+ padding-bottom: 4px;
473
+ }
474
+
475
+ .shelp-table { border-collapse: collapse; width: 100%; }
476
+ .shelp-table td { padding: 3px 8px 3px 0; vertical-align: middle; }
477
+ .shelp-key { white-space: nowrap; }
478
+ .shelp-key kbd {
479
+ background: #2a2d2e;
480
+ border: 1px solid #444;
481
+ border-radius: 4px;
482
+ padding: 2px 7px;
483
+ font-size: 11px;
484
+ font-family: monospace;
485
+ color: #c8c8c8;
486
+ }
487
+ .shelp-desc { font-size: 12px; color: #999; }
488
+
489
+ .shelp-tips {
490
+ list-style: none;
491
+ margin: 0;
492
+ padding: 0;
493
+ display: flex;
494
+ flex-direction: column;
495
+ gap: 6px;
496
+ }
497
+ .shelp-tips li { font-size: 12px; color: #888; line-height: 1.4; }
498
+ .shelp-tips li::before { content: '•'; color: #555; margin-right: 6px; }
499
+
500
+ /* ── Monaco Container ────────────────────────────────────── */
501
+ .monaco-container {
502
+ flex: 1;
503
+ overflow: hidden;
504
+ }
505
+
506
+ .monaco-editor .monaco-hover,
507
+ .monaco-editor .suggest-widget {
508
+ z-index: 2000 !important;
509
+ }
510
+
511
+ .markdown-preview {
512
+ width: 100%;
513
+ height: 100%;
514
+ overflow-y: auto;
515
+ background: #1e1e1e;
516
+ color: #ccc;
517
+ font-family: 'Segoe UI', system-ui, sans-serif;
518
+ padding: 20px;
519
+ }
520
+
521
+ .markdown-preview h1,
522
+ .markdown-preview h2,
523
+ .markdown-preview h3,
524
+ .markdown-preview h4 {
525
+ color: #ffffff;
526
+ }
527
+
528
+ .markdown-preview a {
529
+ color: #4ec9b0;
530
+ }
531
+
532
+ .markdown-preview code {
533
+ background: #2d2d2d;
534
+ padding: 1px 4px;
535
+ border-radius: 4px;
536
+ font-family: 'JetBrains Mono', Consolas, monospace;
537
+ }
538
+
539
+ .markdown-preview pre code {
540
+ display: block;
541
+ padding: 12px;
542
+ overflow-x: auto;
543
+ }
544
+
545
+ /* ── Status Bar ──────────────────────────────────────────── */
546
+ .ide-statusbar {
547
+ display: flex;
548
+ align-items: center;
549
+ background: #007acc;
550
+ height: 22px;
551
+ padding: 0 8px;
552
+ gap: 4px;
553
+ flex-shrink: 0;
554
+ font-size: 11px;
555
+ }
556
+
557
+ .statusbar-branch {
558
+ display: flex;
559
+ align-items: center;
560
+ gap: 6px;
561
+ font-size: 13px;
562
+ font-weight: 600;
563
+ }
564
+
565
+ .statusbar-aheadbehind {
566
+ font-size: 11px;
567
+ font-weight: 600;
568
+ color: #89d185;
569
+ opacity: 0.9;
570
+ }
571
+ .statusbar-aheadbehind.statusbar-behind { color: #f48771; }
572
+
573
+ .statusbar-file-commit {
574
+ display: flex;
575
+ align-items: center;
576
+ gap: 4px;
577
+ font-size: 11px;
578
+ color: #8a9ab0;
579
+ white-space: nowrap;
580
+ overflow: hidden;
581
+ text-overflow: ellipsis;
582
+ max-width: 260px;
583
+ cursor: default;
584
+ }
585
+
586
+ .statusbar-offline {
587
+ display: flex;
588
+ align-items: center;
589
+ gap: 6px;
590
+ font-size: 12px;
591
+ font-weight: 600;
592
+ color: #f48771;
593
+ padding: 0 10px;
594
+ animation: statusbar-pulse 2s ease-in-out infinite;
595
+ }
596
+
597
+ @keyframes statusbar-pulse {
598
+ 0%, 100% { opacity: 1; }
599
+ 50% { opacity: 0.5; }
600
+ }
601
+
602
+ .statusbar-btn {
603
+ display: flex;
604
+ align-items: center;
605
+ gap: 4px;
606
+ padding: 0 8px;
607
+ height: 22px;
608
+ flex-shrink: 0;
609
+ background: transparent;
610
+ border: none;
611
+ color: rgba(255,255,255,0.9);
612
+ cursor: pointer;
613
+ font-size: 11px;
614
+ border-radius: 2px;
615
+ transition: background 0.1s;
616
+ white-space: nowrap;
617
+ }
618
+
619
+ .statusbar-btn:hover { background: rgba(255,255,255,0.15); }
620
+ .statusbar-btn:disabled { opacity: 0.5; cursor: not-allowed; }
621
+
622
+ .titlebar-git-btn {
623
+ min-width: 62px;
624
+ justify-content: center;
625
+ position: relative;
626
+ z-index: 1;
627
+ }
628
+
629
+ .statusbar-sep { width: 1px; height: 14px; background: rgba(255,255,255,0.2); margin: 0 2px; }
630
+
631
+ .statusbar-msg {
632
+ margin-left: auto;
633
+ color: rgba(255,255,255,0.8);
634
+ font-size: 11px;
635
+ overflow: hidden;
636
+ text-overflow: ellipsis;
637
+ white-space: nowrap;
638
+ max-width: 400px;
639
+ }
640
+
641
+ .statusbar-msg.error { color: #f48771; }
642
+ .statusbar-msg.success { color: #89d185; }
643
+
644
+ /* ── Search Panel ─────────────────────────────────────────── */
645
+ .search-panel {
646
+ padding: 8px;
647
+ display: flex;
648
+ flex-direction: column;
649
+ gap: 6px;
650
+ flex: 1;
651
+ min-height: 0;
652
+ }
653
+
654
+ .search-input-wrap {
655
+ display: flex;
656
+ gap: 6px;
657
+ }
658
+
659
+ .search-input {
660
+ flex: 1;
661
+ background: #3c3c3c;
662
+ border: 1px solid #555;
663
+ border-radius: 4px;
664
+ color: #ccc;
665
+ padding: 4px 8px;
666
+ font-size: 12px;
667
+ outline: none;
668
+ }
669
+
670
+ .search-input:focus { border-color: #4ec9b0; }
671
+
672
+ .search-btn {
673
+ background: #094771;
674
+ border: none;
675
+ border-radius: 4px;
676
+ color: #ccc;
677
+ padding: 4px 10px;
678
+ font-size: 12px;
679
+ cursor: pointer;
680
+ transition: background 0.1s;
681
+ }
682
+
683
+ .search-btn:hover { background: #0e639c; }
684
+
685
+ .search-results {
686
+ flex: 1;
687
+ overflow-y: auto;
688
+ }
689
+
690
+ .search-result-item {
691
+ padding: 4px 6px;
692
+ cursor: pointer;
693
+ border-radius: 3px;
694
+ transition: background 0.1s;
695
+ border-bottom: 1px solid #2d2d2d;
696
+ }
697
+
698
+ .search-result-item:hover { background: #2a2d2e; }
699
+
700
+ .search-result-file {
701
+ font-size: 11px;
702
+ color: #4ec9b0;
703
+ font-weight: 500;
704
+ }
705
+
706
+ .search-result-line-num {
707
+ font-size: 10px;
708
+ color: #666;
709
+ margin-left: 4px;
710
+ }
711
+
712
+ .search-result-text {
713
+ font-size: 11px;
714
+ color: #aaa;
715
+ font-family: monospace;
716
+ white-space: pre;
717
+ overflow: hidden;
718
+ text-overflow: ellipsis;
719
+ }
720
+
721
+ /* ── Git Status Panel ─────────────────────────────────────── */
722
+ .git-panel { padding: 8px; }
723
+
724
+ .git-file-item {
725
+ display: flex;
726
+ align-items: center;
727
+ gap: 2px;
728
+ padding: 1px 6px 1px 2px;
729
+ border-radius: 3px;
730
+ transition: background 0.1s;
731
+ font-size: 12px;
732
+ min-width: 0;
733
+ overflow: hidden;
734
+ }
735
+
736
+ .git-file-item:hover { background: #2a2d2e; }
737
+
738
+ .git-hint {
739
+ padding: 6px 12px;
740
+ font-size: 11px;
741
+ color: #7f8b97;
742
+ }
743
+
744
+ .git-M { color: #e2c08d; }
745
+ .git-A { color: #89d185; }
746
+ .git-D { color: #f48771; }
747
+ .git-R { color: #78b4e0; }
748
+ .git-Q { color: #888; }
749
+
750
+ /* ── Right-side Git Panel ───────────────────────────────── */
751
+ .ide-git-right-panel {
752
+ background: #202124;
753
+ border-left: 1px solid #3c3c3c;
754
+ display: flex;
755
+ flex-direction: column;
756
+ overflow: hidden;
757
+ flex-shrink: 0;
758
+ min-width: 260px;
759
+ max-width: 600px;
760
+ }
761
+
762
+ .gitpanel-divider {
763
+ width: 5px;
764
+ background: #2a2a2a;
765
+ border-left: 1px solid #3c3c3c;
766
+ }
767
+
768
+ .ide-git-panel {
769
+ width: 100%;
770
+ height: 100%;
771
+ background: #202124;
772
+ display: flex;
773
+ flex-direction: column;
774
+ overflow: hidden;
775
+ flex: 1;
776
+ }
777
+
778
+ .ide-git-panel-header-info {
779
+ flex: 1;
780
+ min-width: 0;
781
+ }
782
+
783
+ .ide-git-panel-header {
784
+ display: flex;
785
+ justify-content: space-between;
786
+ align-items: flex-start;
787
+ padding: 10px 10px 8px;
788
+ border-bottom: 1px solid #333;
789
+ }
790
+
791
+ .ide-git-panel-title {
792
+ font-size: 12px;
793
+ font-weight: 700;
794
+ text-transform: uppercase;
795
+ letter-spacing: 0.08em;
796
+ color: #8ec7ff;
797
+ }
798
+
799
+ .ide-git-panel-branch {
800
+ margin-top: 4px;
801
+ color: #d6e9ff;
802
+ font-size: 13px;
803
+ font-weight: 600;
804
+ }
805
+
806
+ .ide-git-panel-actions {
807
+ display: flex;
808
+ gap: 4px;
809
+ }
810
+
811
+ .git-header-btn {
812
+ background: none;
813
+ border: none;
814
+ color: #9fabb7;
815
+ cursor: pointer;
816
+ padding: 3px 5px;
817
+ border-radius: 3px;
818
+ font-size: 12px;
819
+ line-height: 1;
820
+ transition: background 0.12s, color 0.12s;
821
+ }
822
+ .git-header-btn:hover { background: rgba(255,255,255,0.08); color: #cdd9e5; }
823
+
824
+ .git-metadata {
825
+ display: grid;
826
+ grid-template-columns: 1fr;
827
+ gap: 4px;
828
+ padding: 8px 12px;
829
+ border-bottom: 1px solid #2d2f31;
830
+ color: #b4bcc4;
831
+ font-size: 12px;
832
+ }
833
+
834
+ .git-section {
835
+ border-bottom: 1px solid #2d2f31;
836
+ min-height: 0;
837
+ flex-shrink: 0; /* don't let sections steal space from the graph section */
838
+ }
839
+
840
+ .git-commit-section {
841
+ flex: 1;
842
+ overflow: hidden;
843
+ }
844
+
845
+ .git-section-title {
846
+ padding: 8px 12px;
847
+ font-size: 11px;
848
+ font-weight: 700;
849
+ text-transform: uppercase;
850
+ letter-spacing: 0.06em;
851
+ color: #9fabb7;
852
+ background: #25282b;
853
+ }
854
+
855
+ .git-list {
856
+ max-height: 200px;
857
+ overflow-y: auto;
858
+ }
859
+
860
+ .git-history-section .git-history-graph-wrap {
861
+ overflow-y: auto;
862
+ max-height: 400px;
863
+ }
864
+
865
+ /* In the right panel, the history section grows to fill remaining space */
866
+ .ide-git-right-panel .ide-git-panel {
867
+ /* Ensure flex column so sections stack and the history one can stretch */
868
+ display: flex;
869
+ flex-direction: column;
870
+ overflow: hidden;
871
+ flex: 1;
872
+ }
873
+
874
+ .ide-git-right-panel .git-history-section {
875
+ overflow: hidden;
876
+ display: flex;
877
+ flex-direction: column;
878
+ flex-shrink: 0;
879
+ }
880
+
881
+ /* Only stretch when the graph section is open */
882
+ .ide-git-right-panel .git-history-section.expanded {
883
+ flex: 1;
884
+ min-height: 80px;
885
+ }
886
+
887
+ .ide-git-right-panel .git-history-graph-wrap {
888
+ flex: 1;
889
+ overflow-y: auto;
890
+ overflow-x: hidden;
891
+ }
892
+
893
+ .git-file-info {
894
+ display: flex;
895
+ flex-direction: column;
896
+ justify-content: center;
897
+ flex: 1;
898
+ min-width: 0;
899
+ overflow: hidden;
900
+ padding: 3px 4px;
901
+ cursor: pointer;
902
+ }
903
+
904
+ .git-file-name {
905
+ font-size: 12px;
906
+ color: #c8d4df;
907
+ overflow: hidden;
908
+ text-overflow: ellipsis;
909
+ white-space: nowrap;
910
+ }
911
+
912
+ .git-file-dir {
913
+ font-size: 10px;
914
+ color: #6e7a85;
915
+ opacity: 0.6;
916
+ overflow: hidden;
917
+ text-overflow: ellipsis;
918
+ white-space: nowrap;
919
+ margin-top: 1px;
920
+ }
921
+
922
+ .git-file-type-icon {
923
+ font-size: 11px;
924
+ flex-shrink: 0;
925
+ width: 16px;
926
+ text-align: center;
927
+ opacity: 0.85;
928
+ }
929
+
930
+ .git-diff-counts {
931
+ display: flex;
932
+ align-items: center;
933
+ font-size: 10px;
934
+ font-family: var(--font-mono, monospace);
935
+ flex-shrink: 0;
936
+ white-space: nowrap;
937
+ margin-right: 4px;
938
+ gap: 1px;
939
+ }
940
+ .git-stat-add { color: #89d185; }
941
+ .git-stat-del { color: #f48771; }
942
+
943
+ .git-status-badge {
944
+ font-size: 10px;
945
+ font-weight: 700;
946
+ min-width: 16px;
947
+ text-align: right;
948
+ flex-shrink: 0;
949
+ letter-spacing: 0;
950
+ padding-right: 2px;
951
+ }
952
+
953
+ .git-section-count {
954
+ font-size: 10px;
955
+ background: rgba(255,255,255,0.1);
956
+ border-radius: 8px;
957
+ padding: 1px 6px;
958
+ color: #9db0bb;
959
+ font-weight: 600;
960
+ }
961
+
962
+ .git-ahead-chip {
963
+ display: inline-block;
964
+ margin-left: 6px;
965
+ font-size: 11px;
966
+ color: #89d185;
967
+ font-weight: 600;
968
+ }
969
+
970
+ .git-behind-chip {
971
+ display: inline-block;
972
+ margin-left: 4px;
973
+ font-size: 11px;
974
+ color: #f48771;
975
+ font-weight: 600;
976
+ }
977
+
978
+ .git-commit-item {
979
+ padding: 8px 10px;
980
+ border-bottom: 1px solid #2a2e31;
981
+ }
982
+
983
+ .git-commit-title {
984
+ color: #d7dfe7;
985
+ font-size: 12px;
986
+ line-height: 1.35;
987
+ }
988
+
989
+ .git-commit-meta {
990
+ margin-top: 4px;
991
+ font-size: 11px;
992
+ color: #7f8b97;
993
+ }
994
+
995
+ .git-empty,
996
+ .git-error {
997
+ padding: 8px 12px;
998
+ font-size: 12px;
999
+ }
1000
+
1001
+ .git-empty {
1002
+ color: #7d8791;
1003
+ }
1004
+
1005
+ .git-error {
1006
+ color: #f48771;
1007
+ }
1008
+
1009
+ /* ── Collapsible Section ──────────────────────────────────────── */
1010
+ .collapsible-section {
1011
+ border-bottom: 1px solid #3c3c3c;
1012
+ margin-bottom: 0;
1013
+ }
1014
+
1015
+ .collapsible-header {
1016
+ display: flex;
1017
+ align-items: center;
1018
+ gap: 6px;
1019
+ padding: 6px 12px;
1020
+ font-size: 11px;
1021
+ font-weight: 600;
1022
+ text-transform: uppercase;
1023
+ color: #bbbbbb;
1024
+ letter-spacing: 0.08em;
1025
+ cursor: pointer;
1026
+ user-select: none;
1027
+ transition: background 0.1s ease;
1028
+ }
1029
+
1030
+ .collapsible-header:hover {
1031
+ background: #2a2d2e;
1032
+ }
1033
+
1034
+ .collapsible-toggle {
1035
+ font-size: 8px;
1036
+ width: 16px;
1037
+ display: inline-flex;
1038
+ align-items: center;
1039
+ justify-content: center;
1040
+ flex-shrink: 0;
1041
+ transition: transform 0.15s ease;
1042
+ }
1043
+
1044
+ .collapsible-icon {
1045
+ font-size: 12px;
1046
+ margin-right: 2px;
1047
+ flex-shrink: 0;
1048
+ }
1049
+
1050
+ .collapsible-title {
1051
+ flex: 1;
1052
+ }
1053
+
1054
+ .collapsible-actions {
1055
+ display: inline-flex;
1056
+ align-items: center;
1057
+ gap: 4px;
1058
+ margin-left: auto;
1059
+ }
1060
+
1061
+ .project-actions {
1062
+ display: inline-flex;
1063
+ align-items: center;
1064
+ gap: 4px;
1065
+ }
1066
+
1067
+ .open-editors-group-header {
1068
+ font-size: 10px;
1069
+ padding-left: 8px;
1070
+ margin-bottom: 4px;
1071
+ }
1072
+
1073
+ .open-editors-group-title {
1074
+ flex: 1;
1075
+ opacity: 0.7;
1076
+ }
1077
+
1078
+ .open-editors-group-actions {
1079
+ opacity: 0;
1080
+ pointer-events: none;
1081
+ transition: opacity 0.12s ease;
1082
+ }
1083
+
1084
+ .open-editors-group:hover .open-editors-group-actions,
1085
+ .open-editors-group:focus-within .open-editors-group-actions {
1086
+ opacity: 1;
1087
+ pointer-events: auto;
1088
+ }
1089
+
1090
+ .project-action-btn {
1091
+ width: 20px;
1092
+ height: 20px;
1093
+ border: 1px solid transparent;
1094
+ background: transparent;
1095
+ color: #97a3ae;
1096
+ border-radius: 4px;
1097
+ display: inline-flex;
1098
+ align-items: center;
1099
+ justify-content: center;
1100
+ cursor: pointer;
1101
+ transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
1102
+ }
1103
+
1104
+ .project-action-btn:hover:not(:disabled) {
1105
+ background: #303234;
1106
+ border-color: #4a4c4f;
1107
+ color: #d7dce1;
1108
+ }
1109
+
1110
+ .project-action-btn:disabled {
1111
+ opacity: 0.45;
1112
+ cursor: not-allowed;
1113
+ }
1114
+
1115
+ .project-action-btn.danger:hover:not(:disabled) {
1116
+ color: #f48771;
1117
+ border-color: rgba(244, 135, 113, 0.45);
1118
+ }
1119
+
1120
+ /* Context menu */
1121
+ .context-menu {
1122
+ position: fixed;
1123
+ z-index: 9999;
1124
+ min-width: 180px;
1125
+ background: #252526;
1126
+ border: 1px solid #454545;
1127
+ border-radius: 4px;
1128
+ box-shadow: 0 4px 16px rgba(0,0,0,0.5);
1129
+ padding: 4px 0;
1130
+ font-size: 12px;
1131
+ color: #cccccc;
1132
+ user-select: none;
1133
+ }
1134
+
1135
+ .context-menu-item {
1136
+ display: flex;
1137
+ align-items: center;
1138
+ gap: 8px;
1139
+ padding: 6px 14px;
1140
+ cursor: pointer;
1141
+ white-space: nowrap;
1142
+ }
1143
+
1144
+ .context-menu-item:hover {
1145
+ background: #094771;
1146
+ color: #ffffff;
1147
+ }
1148
+
1149
+ .context-menu-item-danger:hover {
1150
+ background: rgba(244, 135, 113, 0.15);
1151
+ color: #f48771;
1152
+ }
1153
+
1154
+ .context-menu-icon {
1155
+ width: 14px;
1156
+ text-align: center;
1157
+ flex-shrink: 0;
1158
+ font-size: 11px;
1159
+ opacity: 0.8;
1160
+ }
1161
+
1162
+ .context-menu-divider {
1163
+ height: 1px;
1164
+ background: #3c3c3c;
1165
+ margin: 4px 0;
1166
+ }
1167
+
1168
+ .collapsible-content {
1169
+ animation: collapsible-open 0.15s ease;
1170
+ }
1171
+
1172
+ @keyframes collapsible-open {
1173
+ from {
1174
+ opacity: 0;
1175
+ max-height: 0;
1176
+ }
1177
+ to {
1178
+ opacity: 1;
1179
+ max-height: 1000px;
1180
+ }
1181
+ }
1182
+
1183
+ /* ── Quick Open Dialog ─────────────────────────────────────── */
1184
+ .quick-open-overlay {
1185
+ position: fixed;
1186
+ inset: 0;
1187
+ background: rgba(0,0,0,0.6);
1188
+ display: flex;
1189
+ align-items: flex-start;
1190
+ justify-content: center;
1191
+ padding-top: 15vh;
1192
+ z-index: 9999;
1193
+ }
1194
+
1195
+ .quick-open-box {
1196
+ background: #252526;
1197
+ border: 1px solid #454545;
1198
+ border-radius: 8px;
1199
+ width: 500px;
1200
+ max-height: 400px;
1201
+ display: flex;
1202
+ flex-direction: column;
1203
+ box-shadow: 0 16px 48px rgba(0,0,0,0.7);
1204
+ overflow: hidden;
1205
+ }
1206
+
1207
+ .quick-open-input {
1208
+ background: transparent;
1209
+ border: none;
1210
+ border-bottom: 1px solid #3c3c3c;
1211
+ color: #ccc;
1212
+ padding: 12px 16px;
1213
+ font-size: 14px;
1214
+ outline: none;
1215
+ width: 100%;
1216
+ }
1217
+
1218
+ .quick-open-results {
1219
+ overflow-y: auto;
1220
+ flex: 1;
1221
+ }
1222
+
1223
+ .quick-open-result {
1224
+ padding: 6px 16px;
1225
+ cursor: pointer;
1226
+ display: flex;
1227
+ align-items: center;
1228
+ gap: 8px;
1229
+ font-size: 12px;
1230
+ transition: background 0.1s;
1231
+ }
1232
+
1233
+ .quick-open-result:hover,
1234
+ .quick-open-result.selected { background: #094771; }
1235
+
1236
+ .quick-open-result-name { color: #ccc; flex: 1; }
1237
+ .quick-open-result-path { color: #666; font-size: 11px; }
1238
+
1239
+ /* ── Scrollbars ────────────────────────────────────────────── */
1240
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
1241
+ ::-webkit-scrollbar-track { background: #1e1e1e; }
1242
+ ::-webkit-scrollbar-thumb { background: #424242; border-radius: 4px; }
1243
+ ::-webkit-scrollbar-thumb:hover { background: #555; }
1244
+
1245
+ /* ── Notification toast ─────────────────────────────────────── */
1246
+ .ide-toast {
1247
+ position: fixed;
1248
+ bottom: 32px;
1249
+ right: 16px;
1250
+ background: #333;
1251
+ border: 1px solid #555;
1252
+ border-radius: 6px;
1253
+ padding: 8px 14px;
1254
+ font-size: 12px;
1255
+ color: #ccc;
1256
+ z-index: 10000;
1257
+ box-shadow: 0 4px 16px rgba(0,0,0,0.5);
1258
+ animation: toast-in 0.15s ease;
1259
+ }
1260
+
1261
+ @keyframes toast-in {
1262
+ from { opacity: 0; transform: translateY(8px); }
1263
+ to { opacity: 1; transform: translateY(0); }
1264
+ }