ninja-terminals 2.0.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.
@@ -0,0 +1,678 @@
1
+ * { margin: 0; padding: 0; box-sizing: border-box; }
2
+
3
+ :root {
4
+ /* ── Retro Command Cards palette ── */
5
+ --bg: #0C0C0C;
6
+ --surface: #161616;
7
+ --border: #252525;
8
+ --border-active: #3a3a3a;
9
+ --text: #C8C0B4;
10
+ --text-dim: #5A5650;
11
+ --text-bright: #E8E0D4;
12
+
13
+ /* Cream accent for labels/badges */
14
+ --cream: #F0E8D8;
15
+ --cream-dark: #666054;
16
+
17
+ /* 4 terminal identity colors (warm-shifted retro) */
18
+ --feed-t1: #1B8A9E; /* deep teal */
19
+ --feed-t2: #D94B2B; /* deep coral */
20
+ --feed-t3: #E8A917; /* golden amber */
21
+ --feed-t4: #7B4FBF; /* rich purple */
22
+
23
+ /* 7-state color system */
24
+ --state-idle: #6B7280;
25
+ --state-working: #3B82F6;
26
+ --state-done: #22C55E;
27
+ --state-blocked: #F59E0B;
28
+ --state-error: #EF4444;
29
+ --state-compacting: #8B5CF6;
30
+ --state-waiting-approval: #F97316;
31
+
32
+ --sidebar-width: 260px;
33
+ --status-bar-height: 32px;
34
+ --pane-header-height: 44px;
35
+ --progress-height: 3px;
36
+ }
37
+
38
+ body {
39
+ background: var(--bg);
40
+ color: var(--text);
41
+ font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
42
+ height: 100vh;
43
+ overflow: hidden;
44
+ }
45
+
46
+ /* ── App Layout ─────────────────────────────── */
47
+
48
+ #app {
49
+ display: flex;
50
+ height: calc(100vh - var(--status-bar-height) - 4px); /* 4px for bottom stripe */
51
+ }
52
+
53
+ /* ── Sidebar ────────────────────────────────── */
54
+
55
+ #sidebar {
56
+ width: var(--sidebar-width);
57
+ min-width: var(--sidebar-width);
58
+ background: var(--surface);
59
+ border-right: 1px solid var(--border);
60
+ display: flex;
61
+ flex-direction: column;
62
+ overflow: hidden;
63
+ transition: margin-left 0.2s ease, min-width 0.2s ease, width 0.2s ease;
64
+ }
65
+
66
+ #sidebar.collapsed {
67
+ margin-left: calc(-1 * var(--sidebar-width));
68
+ min-width: 0;
69
+ width: 0;
70
+ }
71
+
72
+ .sidebar-header {
73
+ display: flex;
74
+ flex-direction: column;
75
+ border-bottom: 1px solid var(--border);
76
+ flex-shrink: 0;
77
+ position: relative;
78
+ }
79
+
80
+ /* ── Logo Card (cream retro label) ── */
81
+
82
+ .logo-card {
83
+ background: var(--cream);
84
+ padding: 14px 16px 10px;
85
+ display: flex;
86
+ flex-direction: column;
87
+ }
88
+
89
+ .logo {
90
+ font-family: 'Bebas Neue', sans-serif;
91
+ font-size: 24px;
92
+ letter-spacing: 5px;
93
+ color: var(--bg);
94
+ line-height: 1;
95
+ }
96
+
97
+ .logo-sub {
98
+ font-family: 'Space Grotesk', sans-serif;
99
+ font-size: 9px;
100
+ letter-spacing: 3px;
101
+ color: var(--cream-dark);
102
+ text-transform: uppercase;
103
+ margin-top: 2px;
104
+ }
105
+
106
+ /* 4-color stripe band below logo */
107
+ .logo-stripes {
108
+ display: flex;
109
+ height: 6px;
110
+ flex-shrink: 0;
111
+ }
112
+ .logo-stripes .stripe { flex: 1; }
113
+ .logo-stripes .s1 { background: var(--feed-t1); }
114
+ .logo-stripes .s2 { background: var(--feed-t2); }
115
+ .logo-stripes .s3 { background: var(--feed-t3); }
116
+ .logo-stripes .s4 { background: var(--feed-t4); }
117
+
118
+ .sidebar-toggle {
119
+ position: absolute;
120
+ top: 10px;
121
+ right: 10px;
122
+ background: none;
123
+ border: none;
124
+ color: var(--cream-dark);
125
+ font-size: 14px;
126
+ cursor: pointer;
127
+ padding: 4px;
128
+ line-height: 1;
129
+ transition: color 0.15s;
130
+ z-index: 2;
131
+ }
132
+ .sidebar-toggle:hover { color: var(--bg); }
133
+
134
+ .sidebar-section {
135
+ flex: 1;
136
+ display: flex;
137
+ flex-direction: column;
138
+ overflow: hidden;
139
+ min-height: 0;
140
+ }
141
+
142
+ .sidebar-title {
143
+ font-family: 'Bebas Neue', sans-serif;
144
+ font-size: 14px;
145
+ letter-spacing: 4px;
146
+ color: var(--text-dim);
147
+ padding: 12px 16px 6px;
148
+ flex-shrink: 0;
149
+ }
150
+
151
+ #sidebar hr {
152
+ border: none;
153
+ border-top: 1px solid var(--border);
154
+ margin: 0;
155
+ flex-shrink: 0;
156
+ }
157
+
158
+ /* Activity Feed */
159
+
160
+ #activity-feed {
161
+ flex: 1;
162
+ overflow-y: auto;
163
+ padding: 4px 0;
164
+ display: flex;
165
+ flex-direction: column;
166
+ }
167
+
168
+ .feed-entry {
169
+ padding: 3px 16px;
170
+ font-size: 11px;
171
+ line-height: 1.4;
172
+ display: flex;
173
+ gap: 8px;
174
+ align-items: baseline;
175
+ }
176
+
177
+ .feed-entry:hover {
178
+ background: rgba(255, 255, 255, 0.03);
179
+ }
180
+
181
+ .feed-time {
182
+ font-size: 10px;
183
+ color: var(--text-dim);
184
+ white-space: nowrap;
185
+ font-family: 'Space Grotesk', monospace;
186
+ flex-shrink: 0;
187
+ }
188
+
189
+ .feed-msg {
190
+ color: var(--text);
191
+ word-break: break-word;
192
+ }
193
+
194
+ .feed-entry.feed-t1 .feed-msg { color: var(--feed-t1); }
195
+ .feed-entry.feed-t2 .feed-msg { color: var(--feed-t2); }
196
+ .feed-entry.feed-t3 .feed-msg { color: var(--feed-t3); }
197
+ .feed-entry.feed-t4 .feed-msg { color: var(--feed-t4); }
198
+
199
+ /* Task Queue */
200
+
201
+ #task-queue {
202
+ flex: 1;
203
+ overflow-y: auto;
204
+ padding: 4px 0;
205
+ }
206
+
207
+ .task-item {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 8px;
211
+ padding: 6px 16px;
212
+ font-size: 11px;
213
+ cursor: default;
214
+ }
215
+
216
+ .task-item:hover {
217
+ background: rgba(255, 255, 255, 0.03);
218
+ }
219
+
220
+ .task-dot {
221
+ width: 6px;
222
+ height: 6px;
223
+ border-radius: 2px;
224
+ flex-shrink: 0;
225
+ }
226
+
227
+ .task-dot.pending { background: var(--state-idle); }
228
+ .task-dot.running { background: var(--state-working); animation: pulse 1.5s infinite; }
229
+ .task-dot.completed { background: var(--state-done); }
230
+ .task-dot.failed { background: var(--state-error); }
231
+ .task-dot.blocked { background: var(--state-blocked); }
232
+
233
+ .task-name {
234
+ flex: 1;
235
+ overflow: hidden;
236
+ text-overflow: ellipsis;
237
+ white-space: nowrap;
238
+ color: var(--text);
239
+ }
240
+
241
+ .task-status {
242
+ font-family: 'Bebas Neue', sans-serif;
243
+ font-size: 12px;
244
+ letter-spacing: 1px;
245
+ color: var(--text-dim);
246
+ text-transform: uppercase;
247
+ flex-shrink: 0;
248
+ }
249
+
250
+ .add-task-btn {
251
+ display: block;
252
+ width: calc(100% - 32px);
253
+ margin: 8px 16px;
254
+ padding: 6px 0;
255
+ background: transparent;
256
+ border: 1px dashed var(--border);
257
+ color: var(--text-dim);
258
+ font-family: 'Space Grotesk', sans-serif;
259
+ font-size: 11px;
260
+ font-weight: 600;
261
+ letter-spacing: 0.5px;
262
+ cursor: pointer;
263
+ transition: all 0.15s;
264
+ flex-shrink: 0;
265
+ }
266
+
267
+ .add-task-btn:hover {
268
+ border-color: var(--text-dim);
269
+ color: var(--text);
270
+ background: rgba(255, 255, 255, 0.03);
271
+ }
272
+
273
+ /* ── Main Grid ──────────────────────────────── */
274
+
275
+ main {
276
+ flex: 1;
277
+ overflow: hidden;
278
+ min-width: 0;
279
+ }
280
+
281
+ #grid {
282
+ display: grid;
283
+ grid-template-columns: 1fr 1fr;
284
+ grid-template-rows: 1fr 1fr;
285
+ gap: 1px;
286
+ background: var(--border);
287
+ width: 100%;
288
+ height: 100%;
289
+ }
290
+
291
+ /* ── Terminal Pane ──────────────────────────── */
292
+
293
+ .terminal-pane {
294
+ background: var(--bg);
295
+ display: flex;
296
+ flex-direction: column;
297
+ overflow: hidden;
298
+ position: relative;
299
+ border: 1px solid var(--border);
300
+ transition: border-color 0.2s;
301
+ }
302
+
303
+ .terminal-pane.active {
304
+ border-color: var(--border-active);
305
+ }
306
+
307
+ .terminal-pane.hidden {
308
+ display: none;
309
+ }
310
+
311
+ .terminal-pane.maximized {
312
+ grid-column: 1 / -1;
313
+ grid-row: 1 / -1;
314
+ z-index: 10;
315
+ }
316
+
317
+ /* State-based borders */
318
+ .terminal-pane.state-error {
319
+ animation: pulse-red 2s infinite;
320
+ }
321
+
322
+ .terminal-pane.state-blocked {
323
+ border-color: var(--state-blocked);
324
+ }
325
+
326
+ .terminal-pane.state-done.flash {
327
+ animation: flash-green 0.5s ease-out;
328
+ }
329
+
330
+ /* ── Pane Header ────────────────────────────── */
331
+
332
+ .pane-header {
333
+ display: flex;
334
+ align-items: center;
335
+ padding: 0 10px;
336
+ background: var(--surface);
337
+ height: var(--pane-header-height);
338
+ flex-shrink: 0;
339
+ gap: 10px;
340
+ cursor: default;
341
+ user-select: none;
342
+ position: relative;
343
+ }
344
+
345
+ /* ── Pane Label (retro cream badge) ── */
346
+
347
+ .pane-label {
348
+ font-family: 'Bebas Neue', sans-serif;
349
+ font-size: 16px;
350
+ letter-spacing: 2px;
351
+ color: var(--bg);
352
+ background: var(--cream);
353
+ padding: 2px 10px;
354
+ border-radius: 2px;
355
+ white-space: nowrap;
356
+ overflow: hidden;
357
+ text-overflow: ellipsis;
358
+ max-width: 160px;
359
+ cursor: default;
360
+ position: relative;
361
+ }
362
+
363
+ /* Color band on left edge of badge — set per terminal index via nth-child */
364
+ .terminal-pane:nth-child(4n+1) .pane-label { border-left: 3px solid var(--feed-t1); }
365
+ .terminal-pane:nth-child(4n+2) .pane-label { border-left: 3px solid var(--feed-t2); }
366
+ .terminal-pane:nth-child(4n+3) .pane-label { border-left: 3px solid var(--feed-t3); }
367
+ .terminal-pane:nth-child(4n+4) .pane-label { border-left: 3px solid var(--feed-t4); }
368
+
369
+ .pane-label.editing {
370
+ background: #1a1a1a;
371
+ border: 1px solid var(--border-active);
372
+ border-radius: 3px;
373
+ padding: 1px 4px;
374
+ outline: none;
375
+ cursor: text;
376
+ color: var(--text-bright);
377
+ font-size: 14px;
378
+ font-weight: 600;
379
+ font-family: 'Space Grotesk', sans-serif;
380
+ }
381
+
382
+ .pane-state {
383
+ display: flex;
384
+ align-items: center;
385
+ gap: 5px;
386
+ flex-shrink: 0;
387
+ }
388
+
389
+ .state-icon {
390
+ width: 8px;
391
+ height: 8px;
392
+ border-radius: 50%;
393
+ flex-shrink: 0;
394
+ }
395
+
396
+ .state-icon.idle { background: var(--state-idle); }
397
+ .state-icon.working { background: var(--state-working); animation: pulse 1.5s infinite; }
398
+ .state-icon.done { background: var(--state-done); }
399
+ .state-icon.blocked { background: var(--state-blocked); animation: pulse 1.5s infinite; }
400
+ .state-icon.error { background: var(--state-error); animation: pulse-red 2s infinite; }
401
+ .state-icon.compacting { background: var(--state-compacting); animation: pulse 0.8s infinite; }
402
+ .state-icon.waiting_approval { background: var(--state-waiting-approval); animation: pulse 1s infinite; }
403
+ .state-icon.starting { background: var(--state-idle); animation: pulse 2s infinite; }
404
+ .state-icon.exited { background: var(--state-error); opacity: 0.5; }
405
+
406
+ .state-text {
407
+ font-family: 'Space Grotesk', sans-serif;
408
+ font-size: 10px;
409
+ font-weight: 700;
410
+ text-transform: uppercase;
411
+ letter-spacing: 0.5px;
412
+ }
413
+
414
+ .state-text.idle { color: var(--state-idle); }
415
+ .state-text.working { color: var(--state-working); }
416
+ .state-text.done { color: var(--state-done); }
417
+ .state-text.blocked { color: var(--state-blocked); }
418
+ .state-text.error { color: var(--state-error); }
419
+ .state-text.compacting { color: var(--state-compacting); }
420
+ .state-text.waiting_approval { color: var(--state-waiting-approval); }
421
+ .state-text.starting { color: var(--state-idle); }
422
+ .state-text.exited { color: var(--state-error); opacity: 0.7; }
423
+
424
+ .pane-elapsed {
425
+ font-size: 10px;
426
+ color: var(--text-dim);
427
+ font-family: 'Space Grotesk', monospace;
428
+ white-space: nowrap;
429
+ flex-shrink: 0;
430
+ }
431
+
432
+ .pane-spacer {
433
+ flex: 1;
434
+ }
435
+
436
+ /* Action Buttons */
437
+
438
+ .pane-actions {
439
+ display: flex;
440
+ gap: 4px;
441
+ flex-shrink: 0;
442
+ }
443
+
444
+ .action-btn {
445
+ background: transparent;
446
+ border: 1px solid var(--border);
447
+ color: var(--text-dim);
448
+ font-family: 'Space Grotesk', sans-serif;
449
+ font-size: 10px;
450
+ font-weight: 600;
451
+ padding: 2px 10px;
452
+ border-radius: 2px;
453
+ cursor: pointer;
454
+ white-space: nowrap;
455
+ transition: all 0.12s;
456
+ line-height: 1.4;
457
+ letter-spacing: 0.3px;
458
+ text-transform: uppercase;
459
+ }
460
+
461
+ .action-btn:hover {
462
+ background: rgba(255, 255, 255, 0.08);
463
+ color: var(--text);
464
+ border-color: rgba(255, 255, 255, 0.2);
465
+ }
466
+
467
+ .action-btn.danger:hover {
468
+ background: rgba(239, 68, 68, 0.12);
469
+ color: var(--state-error);
470
+ border-color: rgba(239, 68, 68, 0.3);
471
+ }
472
+
473
+ /* Progress Bar */
474
+
475
+ .progress-bar-track {
476
+ position: absolute;
477
+ bottom: 0;
478
+ left: 0;
479
+ right: 0;
480
+ height: var(--progress-height);
481
+ background: #1a1a1a;
482
+ }
483
+
484
+ .progress-bar-fill {
485
+ height: 100%;
486
+ width: 0%;
487
+ transition: width 0.3s ease, background-color 0.3s;
488
+ border-radius: 0 2px 2px 0;
489
+ }
490
+
491
+ .progress-bar-fill.idle { background: var(--state-idle); }
492
+ .progress-bar-fill.working { background: var(--state-working); }
493
+ .progress-bar-fill.done { background: var(--state-done); }
494
+ .progress-bar-fill.blocked { background: var(--state-blocked); }
495
+ .progress-bar-fill.error { background: var(--state-error); }
496
+ .progress-bar-fill.compacting { background: var(--state-compacting); }
497
+ .progress-bar-fill.waiting_approval { background: var(--state-waiting-approval); }
498
+
499
+ /* Terminal Container */
500
+
501
+ .terminal-container {
502
+ flex: 1;
503
+ overflow: hidden;
504
+ }
505
+
506
+ .terminal-container .xterm {
507
+ padding: 4px;
508
+ }
509
+
510
+ /* ── Status Bar ─────────────────────────────── */
511
+
512
+ #status-bar {
513
+ height: var(--status-bar-height);
514
+ background: var(--surface);
515
+ border-top: 1px solid var(--border);
516
+ display: flex;
517
+ align-items: center;
518
+ justify-content: space-between;
519
+ padding: 0 16px;
520
+ flex-shrink: 0;
521
+ font-size: 12px;
522
+ z-index: 100;
523
+ }
524
+
525
+ #status-counts {
526
+ display: flex;
527
+ gap: 16px;
528
+ align-items: center;
529
+ }
530
+
531
+ .status-count {
532
+ display: flex;
533
+ align-items: center;
534
+ gap: 5px;
535
+ color: var(--text-dim);
536
+ }
537
+
538
+ .status-dot {
539
+ width: 7px;
540
+ height: 7px;
541
+ border-radius: 2px;
542
+ flex-shrink: 0;
543
+ }
544
+
545
+ .status-dot.working { background: var(--state-working); }
546
+ .status-dot.done { background: var(--state-done); }
547
+ .status-dot.blocked { background: var(--state-blocked); }
548
+ .status-dot.error { background: var(--state-error); }
549
+ .status-dot.idle { background: var(--state-idle); }
550
+ .status-dot.compacting { background: var(--state-compacting); }
551
+ .status-dot.waiting_approval { background: var(--state-waiting-approval); }
552
+
553
+ #status-progress {
554
+ color: var(--text-dim);
555
+ font-family: 'Space Grotesk', monospace;
556
+ font-size: 11px;
557
+ font-weight: 600;
558
+ letter-spacing: 0.5px;
559
+ }
560
+
561
+ /* ── Bottom Stripe Band ─────────────────────── */
562
+
563
+ .status-stripes {
564
+ display: flex;
565
+ height: 4px;
566
+ flex-shrink: 0;
567
+ }
568
+ .status-stripes .stripe { flex: 1; }
569
+ .status-stripes .s1 { background: var(--feed-t1); }
570
+ .status-stripes .s2 { background: var(--feed-t2); }
571
+ .status-stripes .s3 { background: var(--feed-t3); }
572
+ .status-stripes .s4 { background: var(--feed-t4); }
573
+
574
+ /* ── Animations ─────────────────────────────── */
575
+
576
+ @keyframes pulse {
577
+ 0%, 100% { opacity: 1; }
578
+ 50% { opacity: 0.4; }
579
+ }
580
+
581
+ @keyframes flash-green {
582
+ 0% { border-color: var(--state-done); box-shadow: 0 0 12px rgba(34, 197, 94, 0.4); }
583
+ 100% { border-color: var(--border); box-shadow: none; }
584
+ }
585
+
586
+ @keyframes pulse-red {
587
+ 0%, 100% { border-color: var(--state-error); box-shadow: 0 0 6px rgba(239, 68, 68, 0.2); }
588
+ 50% { border-color: rgba(239, 68, 68, 0.4); box-shadow: none; }
589
+ }
590
+
591
+ /* ── Scrollbar ──────────────────────────────── */
592
+
593
+ #activity-feed::-webkit-scrollbar,
594
+ #task-queue::-webkit-scrollbar {
595
+ width: 4px;
596
+ }
597
+
598
+ #activity-feed::-webkit-scrollbar-track,
599
+ #task-queue::-webkit-scrollbar-track {
600
+ background: transparent;
601
+ }
602
+
603
+ #activity-feed::-webkit-scrollbar-thumb,
604
+ #task-queue::-webkit-scrollbar-thumb {
605
+ background: var(--border);
606
+ border-radius: 2px;
607
+ }
608
+
609
+ #activity-feed::-webkit-scrollbar-thumb:hover,
610
+ #task-queue::-webkit-scrollbar-thumb:hover {
611
+ background: var(--text-dim);
612
+ }
613
+
614
+ /* ── Mobile (<768px) ────────────────────────── */
615
+
616
+ @media (max-width: 768px) {
617
+ #sidebar {
618
+ position: fixed;
619
+ top: 0;
620
+ left: 0;
621
+ bottom: calc(var(--status-bar-height) + 4px);
622
+ z-index: 200;
623
+ box-shadow: 4px 0 20px rgba(0, 0, 0, 0.5);
624
+ margin-left: calc(-1 * var(--sidebar-width));
625
+ transition: margin-left 0.2s ease;
626
+ }
627
+
628
+ #sidebar.open {
629
+ margin-left: 0;
630
+ }
631
+
632
+ #sidebar.collapsed {
633
+ margin-left: calc(-1 * var(--sidebar-width));
634
+ }
635
+
636
+ .mobile-toggle {
637
+ display: flex !important;
638
+ }
639
+
640
+ #grid {
641
+ grid-template-columns: 1fr;
642
+ grid-template-rows: repeat(4, 1fr);
643
+ }
644
+ }
645
+
646
+ /* Mobile sidebar toggle (shown outside sidebar on mobile) */
647
+ .mobile-toggle {
648
+ display: none;
649
+ position: fixed;
650
+ top: 8px;
651
+ left: 8px;
652
+ z-index: 201;
653
+ background: var(--surface);
654
+ border: 1px solid var(--border);
655
+ color: var(--text-dim);
656
+ width: 32px;
657
+ height: 32px;
658
+ border-radius: 2px;
659
+ font-size: 16px;
660
+ cursor: pointer;
661
+ align-items: center;
662
+ justify-content: center;
663
+ }
664
+
665
+ .mobile-toggle:hover {
666
+ color: var(--text);
667
+ background: #1a1a1a;
668
+ }
669
+
670
+ /* ── Utility ────────────────────────────────── */
671
+
672
+ .no-tasks {
673
+ padding: 12px;
674
+ font-size: 11px;
675
+ color: var(--text-dim);
676
+ text-align: center;
677
+ font-style: italic;
678
+ }