@ssebastien/tcmd 0.1.4 → 0.1.7

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 (105) hide show
  1. package/README.md +169 -58
  2. package/desktop/dist/index.html +13 -0
  3. package/desktop/dist/main.js +20298 -0
  4. package/desktop/dist/style.css +1515 -0
  5. package/desktop/frontend/index.html +13 -0
  6. package/package.json +17 -5
  7. package/public/fonts/OFL.txt +93 -0
  8. package/public/licenses/LUCIDE.txt +43 -0
  9. package/public/main.js +5066 -1888
  10. package/public/style.css +660 -46
  11. package/scripts/build-desktop.js +31 -0
  12. package/src/js/tcmd/components/App.html +56 -6
  13. package/src/js/tcmd/components/App.js +233 -58
  14. package/src/js/tcmd/components/App.xml +27 -22
  15. package/src/js/tcmd/components/BookmarkList.html +4 -5
  16. package/src/js/tcmd/components/BookmarkList.js +14 -40
  17. package/src/js/tcmd/components/BookmarkList.xml +1 -2
  18. package/src/js/tcmd/components/BookmarkRow.html +2 -1
  19. package/src/js/tcmd/components/BookmarkRow.js +14 -9
  20. package/src/js/tcmd/components/BookmarkRow.xml +1 -1
  21. package/src/js/tcmd/components/CommandArgRow.html +18 -7
  22. package/src/js/tcmd/components/CommandArgRow.js +100 -44
  23. package/src/js/tcmd/components/CommandArgRow.xml +39 -15
  24. package/src/js/tcmd/components/CommandBar.html +1 -1
  25. package/src/js/tcmd/components/CommandBar.js +31 -25
  26. package/src/js/tcmd/components/CommandBar.xml +2 -2
  27. package/src/js/tcmd/components/CommandItem.js +24 -25
  28. package/src/js/tcmd/components/CommandItem.xml +2 -2
  29. package/src/js/tcmd/components/CommandPanel.html +13 -13
  30. package/src/js/tcmd/components/CommandPanel.js +57 -33
  31. package/src/js/tcmd/components/CommandPanel.xml +30 -20
  32. package/src/js/tcmd/components/Confirm.html +2 -2
  33. package/src/js/tcmd/components/EntryDetail.js +21 -7
  34. package/src/js/tcmd/components/FilePicker.html +10 -0
  35. package/src/js/tcmd/components/FilePicker.js +43 -0
  36. package/src/js/tcmd/components/FilePicker.xml +13 -0
  37. package/src/js/tcmd/components/FilePickerRow.html +6 -0
  38. package/src/js/tcmd/components/FilePickerRow.js +27 -0
  39. package/src/js/tcmd/components/FilePickerRow.xml +10 -0
  40. package/src/js/tcmd/components/FilePreview.html +1 -2
  41. package/src/js/tcmd/components/FilePreview.js +40 -4
  42. package/src/js/tcmd/components/FilePreview.xml +17 -10
  43. package/src/js/tcmd/components/FileRow.html +1 -0
  44. package/src/js/tcmd/components/FileRow.js +60 -9
  45. package/src/js/tcmd/components/Frame.js +57 -31
  46. package/src/js/tcmd/components/Help.html +12 -4
  47. package/src/js/tcmd/components/Help.js +198 -47
  48. package/src/js/tcmd/components/Help.xml +13 -4
  49. package/src/js/tcmd/components/HelpRow.html +8 -0
  50. package/src/js/tcmd/components/HelpRow.xml +7 -0
  51. package/src/js/tcmd/components/OverlayList.html +8 -0
  52. package/src/js/tcmd/components/OverlayList.js +69 -0
  53. package/src/js/tcmd/components/OverlayList.xml +13 -0
  54. package/src/js/tcmd/components/OverlayRow.html +5 -0
  55. package/src/js/tcmd/components/OverlayRow.js +47 -0
  56. package/src/js/tcmd/components/OverlayRow.xml +9 -0
  57. package/src/js/tcmd/components/format.js +4 -23
  58. package/src/js/tcmd/components/icons.js +137 -0
  59. package/src/js/tcmd/components/index.js +8 -3
  60. package/src/js/tcmd/components/rows.js +149 -25
  61. package/src/js/tcmd/core/base64.js +64 -0
  62. package/src/js/tcmd/core/bookmarks.js +45 -8
  63. package/src/js/tcmd/core/commands.js +612 -136
  64. package/src/js/tcmd/core/concurrency.js +59 -0
  65. package/src/js/tcmd/core/decompress.js +117 -0
  66. package/src/js/tcmd/core/directory.js +81 -5
  67. package/src/js/tcmd/core/format.js +36 -0
  68. package/src/js/tcmd/core/fs.js +410 -53
  69. package/src/js/tcmd/core/journal.js +93 -0
  70. package/src/js/tcmd/core/keymap.js +39 -3
  71. package/src/js/tcmd/core/operations.js +735 -63
  72. package/src/js/tcmd/core/os.js +29 -3
  73. package/src/js/tcmd/core/pane.js +4 -2
  74. package/src/js/tcmd/core/panel.js +179 -93
  75. package/src/js/tcmd/core/path.js +30 -3
  76. package/src/js/tcmd/core/permissions.js +107 -0
  77. package/src/js/tcmd/core/picker.js +156 -0
  78. package/src/js/tcmd/core/preview.js +102 -0
  79. package/src/js/tcmd/core/session.js +286 -116
  80. package/src/js/tcmd/core/watch.js +153 -0
  81. package/src/js/tcmd/desktop/backend/api.js +165 -0
  82. package/src/js/tcmd/desktop/backend/fs.js +626 -0
  83. package/src/js/tcmd/desktop/backend/main.ts +9 -0
  84. package/src/js/tcmd/desktop/bookmarks.js +23 -0
  85. package/src/js/tcmd/desktop/fs.js +91 -0
  86. package/src/js/tcmd/desktop/main.js +194 -0
  87. package/src/js/tcmd/desktop/os.js +33 -0
  88. package/src/js/tcmd/tui/app.js +111 -74
  89. package/src/js/tcmd/tui/catalogue.js +232 -23
  90. package/src/js/tcmd/tui/index.js +18 -4
  91. package/src/js/tcmd/tui/opentui.js +33 -0
  92. package/src/js/tcmd/tui/syntax.js +91 -0
  93. package/src/js/tcmd/tui/theme.js +27 -2
  94. package/src/js/tcmd/vendor/bzip2.js +276 -0
  95. package/src/js/tcmd/web/app.js +114 -56
  96. package/src/js/tcmd/web/catalogue.js +41 -4
  97. package/src/js/tcmd/web/effects.js +94 -14
  98. package/src/js/tcmd/web/header.html +1 -1
  99. package/src/js/tcmd/web/http.js +13 -0
  100. package/src/js/tcmd/web/index.js +2 -2
  101. package/src/js/tcmd/web/opfs.js +297 -30
  102. package/src/js/tcmd/web/seed.js +1 -1
  103. package/src/js/tcmd/web/server.js +118 -17
  104. package/src/js/tcmd/web/theme.js +3 -0
  105. package/tinyjs.json +16 -0
package/public/style.css CHANGED
@@ -10,7 +10,17 @@
10
10
 
11
11
  /* Palette mirrors tui/theme.js DARK: night-blue surfaces, gold accents,
12
12
  saturated orange marks. */
13
+ @font-face {
14
+ font-family: "M+1Code Nerd Font Mono";
15
+ src: url("./fonts/M+1CodeNerdFontMono-Regular.ttf") format("truetype");
16
+ font-style: normal;
17
+ font-weight: 400;
18
+ font-display: swap;
19
+ }
20
+
13
21
  :root {
22
+ --font-ui: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
23
+ --font-mono: "M+1Code Nerd Font Mono", ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
14
24
  --bg: #0d1526;
15
25
  --bg-panel: #111b31;
16
26
  --bg-raised: #18233d;
@@ -20,13 +30,21 @@
20
30
  /* The command panel's argument value fields. */
21
31
  --bg-field: #1b2a51;
22
32
  --border: #33508f;
33
+ /* The active pane's border/header rule: the explorer's Tiny blue, the
34
+ commander's gold accent (kept in sync with tui/theme.js). */
35
+ --pane-active-explorer: #4088ff;
36
+ --pane-active-commander: #ffc233;
23
37
  --text: #e6ecff;
24
38
  --text-dim: #8fa3d9;
39
+ --scrollbar-track: transparent;
40
+ --scrollbar-thumb: #22345e;
25
41
  --accent: #ffc233;
26
42
  --accent-soft: #2b3f78;
27
43
  --dir: #5c8cff;
28
44
  --link: #4fc3ff;
29
45
  --dev: #b48eff;
46
+ --exec: #5fd67a;
47
+ --readonly: #7d8ab8;
30
48
  --mark: #ff7a1a;
31
49
  --error: #ff4d5e;
32
50
  --warning: #ffb020;
@@ -43,6 +61,32 @@
43
61
  box-sizing: border-box;
44
62
  }
45
63
 
64
+ /* Every scrollable surface gets a visible, thin bar only while overflowing.
65
+ The WebKit rules keep Chromium/Electron and Safari consistent with Firefox. */
66
+ :is(.desktop-toolbar, .file-list, .preview-text, .preview-card, .panel-ops, .panel-args, .panel-args-scroll, .bookmark-rows, .overlay-rows, .help-columns) {
67
+ scrollbar-width: thin;
68
+ scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
69
+ }
70
+
71
+ :is(.desktop-toolbar, .file-list, .preview-text, .preview-card, .panel-ops, .panel-args, .panel-args-scroll, .bookmark-rows, .overlay-rows, .help-columns)::-webkit-scrollbar {
72
+ width: 0.65rem;
73
+ height: 0.65rem;
74
+ }
75
+
76
+ :is(.desktop-toolbar, .file-list, .preview-text, .preview-card, .panel-ops, .panel-args, .panel-args-scroll, .bookmark-rows, .overlay-rows, .help-columns)::-webkit-scrollbar-track {
77
+ background: var(--scrollbar-track);
78
+ }
79
+
80
+ :is(.desktop-toolbar, .file-list, .preview-text, .preview-card, .panel-ops, .panel-args, .panel-args-scroll, .bookmark-rows, .overlay-rows, .help-columns)::-webkit-scrollbar-thumb {
81
+ background: var(--scrollbar-thumb);
82
+ border: 2px solid var(--scrollbar-track);
83
+ border-radius: 999px;
84
+ }
85
+
86
+ :is(.desktop-toolbar, .file-list, .preview-text, .preview-card, .panel-ops, .panel-args, .panel-args-scroll, .bookmark-rows, .overlay-rows, .help-columns)::-webkit-scrollbar-thumb:hover {
87
+ background: var(--accent);
88
+ }
89
+
46
90
  html,
47
91
  body,
48
92
  #app {
@@ -53,7 +97,22 @@ body,
53
97
  body {
54
98
  background: var(--bg);
55
99
  color: var(--text);
56
- font: 13px/1.45 ui-monospace, "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
100
+ font: 13px/1.45 var(--font-ui);
101
+ }
102
+
103
+ /* File and path content keeps a fixed-width face; the surrounding controls use
104
+ the native system UI font above. */
105
+ .file-row,
106
+ .breadcrumbs,
107
+ .entry-detail,
108
+ .summary,
109
+ .preview-text,
110
+ .panel-picker-path,
111
+ .panel-row[data-type="entry"] .panel-name,
112
+ .panel-row[data-type="parent"] .panel-name,
113
+ .panel-list-box,
114
+ .bookmark-path {
115
+ font-family: var(--font-mono);
57
116
  }
58
117
 
59
118
  .app {
@@ -89,9 +148,19 @@ body {
89
148
  }
90
149
 
91
150
  /* The mode word shimmers like the brand: explorer along the Tiny blues,
92
- commander along the Cmd oranges. */
151
+ commander along the Cmd oranges. Clicking it toggles the view mode. */
93
152
  .app-header-mode {
153
+ display: inline-flex;
154
+ align-items: center;
155
+ gap: 0.25rem;
94
156
  font-weight: 600;
157
+ cursor: pointer;
158
+ }
159
+
160
+ .header-mode-icon {
161
+ width: 0.8rem;
162
+ height: 0.8rem;
163
+ color: var(--accent);
95
164
  }
96
165
 
97
166
  .app-header-mode.mode-explorer {
@@ -101,6 +170,10 @@ body {
101
170
  color: transparent;
102
171
  }
103
172
 
173
+ .app-header-mode.mode-explorer .header-mode-icon {
174
+ color: var(--pane-active-explorer);
175
+ }
176
+
104
177
  .app-header-mode.mode-commander {
105
178
  background: linear-gradient(90deg, var(--brand-cmd-from), var(--brand-cmd-to));
106
179
  -webkit-background-clip: text;
@@ -131,6 +204,98 @@ body {
131
204
  color: transparent;
132
205
  }
133
206
 
207
+ /* Desktop chrome -------------------------------------------------------- */
208
+
209
+ .desktop-toolbar {
210
+ display: flex;
211
+ align-items: center;
212
+ flex: none;
213
+ gap: 0.45rem;
214
+ min-height: 2.55rem;
215
+ padding: 0.3rem 0.55rem;
216
+ border-bottom: 1px solid var(--border);
217
+ background: linear-gradient(180deg, #17243c, var(--bg-panel));
218
+ white-space: nowrap;
219
+ overflow-x: auto;
220
+ }
221
+
222
+ .desktop-toolbar-group {
223
+ display: flex;
224
+ align-items: center;
225
+ gap: 0.35rem;
226
+ flex: none;
227
+ }
228
+
229
+ .desktop-toolbar-spacer {
230
+ flex: 1;
231
+ min-width: 0.5rem;
232
+ }
233
+
234
+ .desktop-toolbar-separator {
235
+ flex: none;
236
+ height: 1.35rem;
237
+ border-left: 1px solid var(--border);
238
+ }
239
+
240
+ .desktop-toolbar-button {
241
+ display: inline-flex;
242
+ align-items: center;
243
+ justify-content: center;
244
+ gap: 0.4rem;
245
+ min-height: 1.9rem;
246
+ padding: 0.2rem 0.55rem;
247
+ border: 1px solid transparent;
248
+ border-radius: 5px;
249
+ background: transparent;
250
+ color: var(--text-dim);
251
+ font: inherit;
252
+ font-size: 12px;
253
+ cursor: pointer;
254
+ }
255
+
256
+ .desktop-toolbar-button:hover {
257
+ border-color: var(--border);
258
+ background: var(--bg-raised);
259
+ color: var(--text);
260
+ }
261
+
262
+ .desktop-toolbar-button.is-primary {
263
+ border-color: var(--accent-soft);
264
+ background: #202f50;
265
+ color: var(--text);
266
+ }
267
+
268
+ .desktop-toolbar-button.is-primary:hover {
269
+ border-color: var(--accent);
270
+ background: #283b62;
271
+ }
272
+
273
+ .ui-icon {
274
+ flex: none;
275
+ fill: none;
276
+ stroke: currentColor;
277
+ stroke-width: 2;
278
+ stroke-linecap: round;
279
+ stroke-linejoin: round;
280
+ }
281
+
282
+ .lucide-defs {
283
+ display: none;
284
+ }
285
+
286
+ .toolbar-icon {
287
+ width: 1rem;
288
+ height: 1rem;
289
+ color: var(--accent);
290
+ }
291
+
292
+ .toolbar-chevron {
293
+ width: 0.75rem;
294
+ height: 0.75rem;
295
+ margin-left: -0.2rem;
296
+ color: var(--text-dim);
297
+ }
298
+
134
299
  /* Panes ---------------------------------------------------------------- */
135
300
 
136
301
  .panes {
@@ -152,7 +317,12 @@ body {
152
317
  }
153
318
 
154
319
  .pane.is-active {
155
- border-color: var(--accent);
320
+ border-color: var(--pane-active-commander);
321
+ }
322
+
323
+ /* Explorer tints the active pane with the Tiny blue instead of the gold. */
324
+ .app.is-explorer .pane.is-active {
325
+ border-color: var(--pane-active-explorer);
156
326
  }
157
327
 
158
328
  /* Explorer mode: the middle (current) column carries the extra width, the
@@ -176,7 +346,11 @@ body {
176
346
  }
177
347
 
178
348
  .pane.is-active .pane-header {
179
- border-bottom-color: var(--accent);
349
+ border-bottom-color: var(--pane-active-commander);
350
+ }
351
+
352
+ .app.is-explorer .pane.is-active .pane-header {
353
+ border-bottom-color: var(--pane-active-explorer);
180
354
  }
181
355
 
182
356
  .pane-header > div {
@@ -247,9 +421,9 @@ body {
247
421
 
248
422
  .file-row {
249
423
  display: grid;
250
- grid-template-columns: 1.1rem minmax(0, 1fr) auto;
424
+ grid-template-columns: 1.1rem 1rem minmax(0, 1fr) auto;
251
425
  gap: 0.4rem;
252
- align-items: baseline;
426
+ align-items: center;
253
427
  padding: 0 0.35rem;
254
428
  white-space: nowrap;
255
429
  cursor: pointer;
@@ -280,6 +454,24 @@ body {
280
454
  color: var(--mark);
281
455
  }
282
456
 
457
+ .file-row-icon {
458
+ width: 1rem;
459
+ height: 1rem;
460
+ color: var(--text-dim);
461
+ }
462
+
463
+ .file-row[data-kind="dir"] .file-row-icon {
464
+ color: var(--dir);
465
+ }
466
+
467
+ .file-row[data-kind="link"] .file-row-icon {
468
+ color: var(--link);
469
+ }
470
+
471
+ .file-row[data-kind="dev"] .file-row-icon {
472
+ color: var(--dev);
473
+ }
474
+
283
475
  .name {
284
476
  overflow: hidden;
285
477
  text-overflow: ellipsis;
@@ -290,6 +482,14 @@ body {
290
482
  font-weight: 600;
291
483
  }
292
484
 
485
+ .name.is-exec {
486
+ color: var(--exec);
487
+ }
488
+
489
+ .name.is-readonly {
490
+ color: var(--readonly);
491
+ }
492
+
293
493
  .file-row[data-kind="link"] .name {
294
494
  color: var(--link);
295
495
  }
@@ -350,6 +550,14 @@ body {
350
550
  color: var(--dev);
351
551
  }
352
552
 
553
+ .entry-detail-type.is-exec {
554
+ color: var(--exec);
555
+ }
556
+
557
+ .entry-detail-type.is-readonly {
558
+ color: var(--readonly);
559
+ }
560
+
353
561
  .entry-detail-mode {
354
562
  color: var(--accent);
355
563
  }
@@ -479,15 +687,6 @@ body {
479
687
  color: var(--text-dim);
480
688
  }
481
689
 
482
- .preview-actions {
483
- flex: none;
484
- /* The rule that separates the shortcuts from the contents above them. */
485
- border-top: 1px solid var(--border);
486
- padding-top: 0.35rem;
487
- color: var(--text-dim);
488
- font-size: 11px;
489
- }
490
-
491
690
  /* Command bar ---------------------------------------------------------- */
492
691
 
493
692
  .command-bar {
@@ -505,8 +704,10 @@ body {
505
704
 
506
705
  .command-bar-keys {
507
706
  display: flex;
508
- flex-wrap: wrap;
707
+ flex-wrap: nowrap;
509
708
  gap: 0.45rem;
709
+ min-width: 0;
710
+ overflow: hidden;
510
711
  }
511
712
 
512
713
  .command-key {
@@ -518,6 +719,7 @@ body {
518
719
  font: inherit;
519
720
  font-size: 11px;
520
721
  padding: 0.05rem 0.4rem;
722
+ white-space: nowrap;
521
723
  }
522
724
 
523
725
  .command-key:hover {
@@ -606,6 +808,7 @@ input:focus-visible {
606
808
  }
607
809
 
608
810
  .command-dialog {
811
+ position: relative;
609
812
  height: 72vh;
610
813
  }
611
814
 
@@ -614,7 +817,7 @@ input:focus-visible {
614
817
  width: min(640px, 95vw);
615
818
  }
616
819
 
617
- .command-dialog > header,
820
+ .panel-title,
618
821
  .help-dialog > header,
619
822
  .bookmark-dialog h2 {
620
823
  color: var(--text);
@@ -623,6 +826,29 @@ input:focus-visible {
623
826
  margin: 0 0 0.4rem;
624
827
  }
625
828
 
829
+ /* The dialog's close action sits in the top border like a close button: the
830
+ panel background masks the border run underneath it. */
831
+ .panel-close {
832
+ position: absolute;
833
+ top: -0.55rem;
834
+ right: 0.9rem;
835
+ z-index: 2;
836
+ padding: 0 0.3rem;
837
+ border: none;
838
+ border-radius: 3px;
839
+ background: var(--bg-panel);
840
+ color: var(--text-dim);
841
+ font: inherit;
842
+ line-height: 1.1;
843
+ cursor: pointer;
844
+ }
845
+
846
+ .panel-close:hover,
847
+ .panel-close:focus-visible {
848
+ color: var(--text);
849
+ background: var(--accent-soft);
850
+ }
851
+
626
852
  .panel-query-line,
627
853
  .panel-value-line,
628
854
  .bookmark-dialog > header {
@@ -656,34 +882,157 @@ input:focus-visible {
656
882
  font-weight: 600;
657
883
  }
658
884
 
659
- /* The resolved command, dim, at the foot of the argument pane. */
660
- .panel-runs {
661
- margin-top: auto;
662
- padding: 0.4rem 0.6rem 0.2rem;
885
+ /* The argument pane's rows: an aligned label + boxed value field for an
886
+ argument, and a bordered list of selected paths under a selection. */
887
+ .panel-row[data-type="arg"] .panel-name {
888
+ white-space: pre;
663
889
  color: var(--text-dim);
664
- overflow: auto;
890
+ }
891
+
892
+ .panel-row[data-type="arg"].is-focused .panel-name {
893
+ color: var(--accent);
894
+ }
895
+
896
+ .panel-row[data-type="group"] {
897
+ padding-top: 0.45rem;
898
+ cursor: default;
899
+ font-size: 0.82em;
900
+ font-weight: 700;
901
+ letter-spacing: 0.06em;
902
+ text-transform: uppercase;
903
+ }
904
+
905
+ .panel-row[data-type="group"][data-group="White"] {
906
+ color: var(--text);
907
+ }
908
+
909
+ .panel-row[data-type="group"][data-group="Amber"] {
910
+ color: var(--warning);
911
+ }
912
+
913
+ .panel-row[data-type="group"][data-group="Red"] {
914
+ color: var(--error);
915
+ }
916
+
917
+ .panel-row[data-type="op"] {
918
+ padding-left: 1.5rem;
919
+ }
920
+
921
+ .panel-row[data-type="run"] {
922
+ justify-content: flex-start;
923
+ margin-top: 0;
924
+ padding-top: 0.25rem;
925
+ padding-bottom: 0.25rem;
926
+ }
927
+
928
+ .panel-preview {
929
+ flex: 0 1 auto;
665
930
  max-height: 20vh;
931
+ margin: 0;
932
+ padding: 0.35rem 0.6rem;
666
933
  border-top: 1px solid var(--border);
934
+ color: var(--text-dim);
935
+ overflow: auto;
936
+ white-space: pre-wrap;
937
+ overflow-wrap: anywhere;
938
+ font: inherit;
939
+ }
940
+
941
+ .panel-run-action {
942
+ flex: none;
943
+ list-style: none;
944
+ margin: 0;
945
+ padding: 0 0.6rem 0.4rem 0;
946
+ }
947
+
948
+ .panel-run-button {
949
+ padding: 0.15rem 0.7rem;
950
+ border: 1px solid var(--text);
951
+ border-radius: 4px;
952
+ background: transparent;
953
+ color: var(--text);
954
+ font: inherit;
955
+ cursor: pointer;
956
+ }
957
+
958
+ .panel-row[data-type="run"].is-focused .panel-run-button {
959
+ background: var(--accent-soft);
960
+ }
961
+
962
+ .panel-row[data-type="run"][data-risk="caution"] .panel-run-button {
963
+ border-color: var(--warning);
964
+ color: var(--warning);
965
+ }
966
+
967
+ .panel-row[data-type="run"][data-risk="destructive"] .panel-run-button {
968
+ border-color: var(--error);
969
+ color: var(--error);
970
+ }
971
+
972
+ .panel-run-error-block {
973
+ margin: 0.25rem 0.6rem 0.35rem 0.5rem;
974
+ padding: 0.25rem 0.5rem;
975
+ border: 1px solid var(--error);
976
+ border-radius: 4px;
977
+ }
978
+
979
+ .panel-run-error-block p {
980
+ margin: 0;
981
+ color: var(--error);
982
+ white-space: pre-wrap;
983
+ overflow-wrap: anywhere;
667
984
  }
668
985
 
669
- .panel-runs pre {
986
+ /* The armed command, printed below `[Confirm]` in the action's risk colour. */
987
+ .panel-confirm-command {
670
988
  margin: 0;
989
+ padding: 0.15rem 0.6rem 0.4rem 0.5rem;
671
990
  white-space: pre-wrap;
672
991
  overflow-wrap: anywhere;
673
- font: inherit;
674
992
  }
675
993
 
676
- /* The argument pane's rows: an aligned label + boxed value field for an
677
- argument, and a bordered list of selected paths under a selection. */
678
- .panel-row[data-type="arg"] .panel-name {
679
- white-space: pre;
994
+ .panel-confirm-command[data-risk="caution"] {
995
+ color: var(--warning);
996
+ }
997
+
998
+ .panel-confirm-command[data-risk="destructive"] {
999
+ color: var(--error);
1000
+ }
1001
+
1002
+ /* A permission class row: a label and three r/w/x cells. */
1003
+ .panel-perm {
1004
+ display: inline-flex;
1005
+ align-items: baseline;
1006
+ gap: 0.6rem;
1007
+ }
1008
+
1009
+ .panel-perm-class {
1010
+ width: 3.5rem;
680
1011
  color: var(--text-dim);
681
1012
  }
682
1013
 
683
- .panel-row[data-type="arg"].is-focused .panel-name {
1014
+ .panel-perm-bit {
1015
+ width: 1.4rem;
1016
+ padding: 0;
1017
+ border: none;
1018
+ border-radius: 3px;
1019
+ background: transparent;
1020
+ color: var(--text-dim);
1021
+ font: inherit;
1022
+ font-weight: 600;
1023
+ text-align: center;
1024
+ cursor: pointer;
1025
+ }
1026
+
1027
+ .panel-perm-bit.is-on {
684
1028
  color: var(--accent);
685
1029
  }
686
1030
 
1031
+ .panel-perm-bit.is-bit-focused {
1032
+ background: var(--accent-soft);
1033
+ color: var(--text);
1034
+ }
1035
+
687
1036
  .panel-field {
688
1037
  display: inline-flex;
689
1038
  align-items: baseline;
@@ -691,9 +1040,28 @@ input:focus-visible {
691
1040
  min-width: 0;
692
1041
  background: var(--bg-field);
693
1042
  border-radius: 3px;
1043
+ border: 1px solid var(--border);
694
1044
  padding: 0 0.25rem;
695
1045
  }
696
1046
 
1047
+ .panel-field[data-editable="false"] {
1048
+ background: transparent;
1049
+ border-color: transparent;
1050
+ padding-left: 0;
1051
+ }
1052
+
1053
+ .panel-field[data-editable="true"] {
1054
+ border-color: var(--accent-soft);
1055
+ }
1056
+
1057
+ .panel-field[data-editable="false"] .panel-field-bracket {
1058
+ display: none;
1059
+ }
1060
+
1061
+ .panel-field[data-editable="false"] .panel-field-value {
1062
+ color: var(--text-dim);
1063
+ }
1064
+
697
1065
  .panel-field-bracket {
698
1066
  color: var(--text-dim);
699
1067
  }
@@ -773,6 +1141,23 @@ input:focus-visible {
773
1141
  min-height: 0;
774
1142
  }
775
1143
 
1144
+ .panel-ops {
1145
+ flex: 1 1 0;
1146
+ }
1147
+
1148
+ /* The argument pane scrolls as a whole so the Run action follows the last
1149
+ field instead of being pinned to the bottom of the column. */
1150
+ .panel-args-scroll {
1151
+ flex: 1 1 0;
1152
+ min-height: 0;
1153
+ overflow: auto;
1154
+ }
1155
+
1156
+ .panel-args {
1157
+ flex: none;
1158
+ overflow: visible;
1159
+ }
1160
+
776
1161
  /* The argument column: an empty state (a TinyCmd action binds no arguments)
777
1162
  above the rows, with the divider on the column rather than the list so both
778
1163
  stay visible. */
@@ -784,14 +1169,29 @@ input:focus-visible {
784
1169
  }
785
1170
 
786
1171
  .panel-args-empty {
787
- margin: 0;
788
- padding: 0.3rem 0.6rem;
1172
+ display: flex;
1173
+ flex-direction: column;
1174
+ gap: 0.1rem;
1175
+ margin: 0.3rem 0;
1176
+ padding: 0 0.6rem;
789
1177
  color: var(--text-dim);
790
- font-style: italic;
791
1178
  }
792
1179
 
793
- /* File picker sub-mode: the browsed path, its filter, then the entry rows
1180
+
1181
+
1182
+ /* File picker sub-mode: a nested pane containing its path, filter and entries
794
1183
  (which reuse `.panel-row` through the shared arg-row map). */
1184
+ .panel-picker-pane {
1185
+ display: flex;
1186
+ flex: 1 1 0;
1187
+ flex-direction: column;
1188
+ min-height: 0;
1189
+ margin: 0.35rem 0.5rem 0.5rem;
1190
+ border: 1px solid var(--border);
1191
+ border-radius: 4px;
1192
+ overflow: hidden;
1193
+ }
1194
+
795
1195
  .panel-picker {
796
1196
  display: flex;
797
1197
  flex-direction: column;
@@ -800,12 +1200,23 @@ input:focus-visible {
800
1200
  border-bottom: 1px solid var(--border);
801
1201
  }
802
1202
 
1203
+ .panel-picker-rows {
1204
+ flex: 1 1 0;
1205
+ }
1206
+
803
1207
  .panel-picker-path {
1208
+ flex: 1;
1209
+ min-width: 0;
804
1210
  margin: 0;
805
- color: var(--text-dim);
806
- overflow: hidden;
807
- text-overflow: ellipsis;
808
- white-space: nowrap;
1211
+ padding: 0;
1212
+ background: transparent;
1213
+ border: none;
1214
+ color: var(--text);
1215
+ font: inherit;
1216
+ }
1217
+
1218
+ .panel-picker-path:focus {
1219
+ outline: none;
809
1220
  }
810
1221
 
811
1222
  .panel-picker-line {
@@ -814,13 +1225,15 @@ input:focus-visible {
814
1225
  gap: 0.5rem;
815
1226
  }
816
1227
 
817
- .panel-picker-query {
818
- flex: 1;
819
- min-width: 0;
820
- background: transparent;
821
- border: none;
822
- color: var(--text);
823
- font: inherit;
1228
+ .panel-picker-icon {
1229
+ width: 1rem;
1230
+ height: 1rem;
1231
+ color: var(--accent);
1232
+ }
1233
+
1234
+ .panel-picker-rows .picker-row {
1235
+ padding-left: 0.6rem;
1236
+ padding-right: 0.6rem;
824
1237
  }
825
1238
 
826
1239
  .panel-row,
@@ -833,6 +1246,44 @@ input:focus-visible {
833
1246
  cursor: pointer;
834
1247
  }
835
1248
 
1249
+ .bookmark-icon {
1250
+ width: 0.9rem;
1251
+ height: 0.9rem;
1252
+ align-self: center;
1253
+ color: var(--text-dim);
1254
+ }
1255
+
1256
+ /* An argument stacks its label over its value: the marker and label on the
1257
+ first line, the value field aligned under the label on the second. */
1258
+ .panel-row[data-type="arg"] {
1259
+ display: grid;
1260
+ grid-template-columns: minmax(0, 1fr);
1261
+ grid-template-rows: auto auto;
1262
+ row-gap: 0.1rem;
1263
+ align-items: baseline;
1264
+ }
1265
+
1266
+ /* Labels and values start one space in from the pane border. */
1267
+ .panel-args .panel-row[data-type="arg"],
1268
+ .panel-args .panel-row[data-type="perm"],
1269
+ .panel-run-action .panel-row {
1270
+ padding-left: 0.5rem;
1271
+ }
1272
+
1273
+ .panel-row[data-type="arg"] > .panel-marker {
1274
+ display: none;
1275
+ }
1276
+
1277
+ .panel-row[data-type="arg"] > .panel-name {
1278
+ grid-area: 1 / 1;
1279
+ min-width: 0;
1280
+ overflow: hidden;
1281
+ }
1282
+
1283
+ .panel-row[data-type="arg"] > .panel-field {
1284
+ grid-area: 2 / 1;
1285
+ }
1286
+
836
1287
  .panel-row.is-focused,
837
1288
  .bookmark-row.is-selected {
838
1289
  background: var(--accent-soft);
@@ -852,6 +1303,18 @@ input:focus-visible {
852
1303
  text-overflow: ellipsis;
853
1304
  }
854
1305
 
1306
+ .panel-op-chevron {
1307
+ width: 0.9rem;
1308
+ height: 0.9rem;
1309
+ flex: none;
1310
+ margin-left: auto;
1311
+ color: var(--text-dim);
1312
+ }
1313
+
1314
+ .panel-row.is-focused .panel-op-chevron {
1315
+ color: var(--accent);
1316
+ }
1317
+
855
1318
  .panel-row.is-focused .panel-name {
856
1319
  color: var(--accent);
857
1320
  }
@@ -871,18 +1334,169 @@ input:focus-visible {
871
1334
  .command-dialog > footer,
872
1335
  .bookmark-dialog > footer,
873
1336
  .help-dialog > footer,
874
- .bookmark-target,
875
1337
  .bookmark-empty {
876
1338
  color: var(--text-dim);
877
1339
  padding-top: 0.3rem;
878
1340
  }
879
1341
 
880
- .help-dialog pre {
1342
+ /* Shared list overlay (history / trash) --------------------------------- */
1343
+
1344
+ .overlay-list {
1345
+ position: fixed;
1346
+ inset: 0;
1347
+ z-index: 18;
1348
+ display: flex;
1349
+ align-items: center;
1350
+ justify-content: center;
1351
+ padding: 1rem;
1352
+ background: rgb(0 0 0 / 45%);
1353
+ }
1354
+
1355
+ .overlay-dialog {
1356
+ display: flex;
1357
+ flex-direction: column;
1358
+ width: min(640px, 95vw);
1359
+ max-height: 85vh;
1360
+ min-height: 0;
1361
+ padding: 0.6rem;
1362
+ border: 1px solid var(--accent);
1363
+ border-radius: 6px;
1364
+ background: var(--bg-panel);
1365
+ }
1366
+
1367
+ .overlay-dialog h2 {
1368
+ color: var(--text);
881
1369
  font: inherit;
1370
+ font-weight: 600;
1371
+ margin: 0 0 0.4rem;
1372
+ }
1373
+
1374
+ .overlay-rows {
1375
+ list-style: none;
1376
+ margin: 0;
1377
+ padding: 0.3rem 0;
882
1378
  overflow: auto;
883
1379
  min-height: 0;
884
1380
  }
885
1381
 
1382
+ .overlay-row {
1383
+ display: flex;
1384
+ align-items: baseline;
1385
+ gap: 0.5rem;
1386
+ padding: 0.15rem 0.3rem;
1387
+ white-space: nowrap;
1388
+ cursor: pointer;
1389
+ }
1390
+
1391
+ .overlay-row[data-current="true"] {
1392
+ background: var(--accent-soft);
1393
+ }
1394
+
1395
+ .overlay-marker {
1396
+ color: var(--accent);
1397
+ white-space: pre;
1398
+ }
1399
+
1400
+ .overlay-text {
1401
+ color: var(--text);
1402
+ min-width: 0;
1403
+ overflow: hidden;
1404
+ text-overflow: ellipsis;
1405
+ }
1406
+
1407
+ .overlay-row[data-dim="true"] .overlay-text {
1408
+ color: var(--text-dim);
1409
+ }
1410
+
1411
+ .overlay-row[data-current="true"] .overlay-text {
1412
+ color: var(--accent);
1413
+ }
1414
+
1415
+ .overlay-meta {
1416
+ margin-left: auto;
1417
+ color: var(--text-dim);
1418
+ min-width: 0;
1419
+ overflow: hidden;
1420
+ text-overflow: ellipsis;
1421
+ }
1422
+
1423
+ .overlay-dialog > footer,
1424
+ .overlay-empty {
1425
+ color: var(--text-dim);
1426
+ padding-top: 0.3rem;
1427
+ }
1428
+
1429
+ .help-columns {
1430
+ display: flex;
1431
+ gap: 1.5rem;
1432
+ flex: 1;
1433
+ min-height: 0;
1434
+ overflow: auto;
1435
+ }
1436
+
1437
+ .help-column {
1438
+ flex: 1;
1439
+ min-width: 0;
1440
+ }
1441
+
1442
+ .help-block {
1443
+ min-height: 1.2em;
1444
+ }
1445
+
1446
+ .help-section {
1447
+ color: var(--text);
1448
+ font-weight: 700;
1449
+ letter-spacing: 0.04em;
1450
+ }
1451
+
1452
+ .help-entry {
1453
+ display: inline-flex;
1454
+ align-items: center;
1455
+ gap: 0.35rem;
1456
+ max-width: 100%;
1457
+ min-height: 1.55rem;
1458
+ padding: 0 0.4rem;
1459
+ border: 1px solid var(--border);
1460
+ border-radius: 4px;
1461
+ background: var(--bg-raised);
1462
+ white-space: nowrap;
1463
+ }
1464
+
1465
+ .help-icon {
1466
+ width: 0.9rem;
1467
+ height: 0.9rem;
1468
+ color: var(--accent);
1469
+ }
1470
+
1471
+ .help-title {
1472
+ color: var(--text);
1473
+ }
1474
+
1475
+ .help-entry .help-title {
1476
+ overflow: hidden;
1477
+ text-overflow: ellipsis;
1478
+ }
1479
+
1480
+ .help-key {
1481
+ color: var(--accent);
1482
+ }
1483
+
1484
+ .help-entry .help-key {
1485
+ flex: none;
1486
+ padding-left: 0.35rem;
1487
+ border-left: 1px solid var(--border);
1488
+ font: 11px/1.5 var(--font-mono);
1489
+ }
1490
+
1491
+ .help-bracket {
1492
+ color: var(--text-dim);
1493
+ }
1494
+
1495
+ .help-footer {
1496
+ border-top: 1px solid var(--accent);
1497
+ padding-top: 0.3rem;
1498
+ }
1499
+
886
1500
  .viewer > .preview {
887
1501
  flex: none;
888
1502
  width: 90%;