@yemi33/minions 0.1.1973 → 0.1.1974
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.
|
@@ -485,17 +485,103 @@ function ccRenderTabBar() {
|
|
|
485
485
|
for (var i = 0; i < _ccTabs.length; i++) {
|
|
486
486
|
var t = _ccTabs[i];
|
|
487
487
|
var isActive = t.id === _ccActiveTabId;
|
|
488
|
-
|
|
488
|
+
// draggable="true" + DnD handlers enable click-and-drag reorder of tabs.
|
|
489
|
+
// The handlers below splice _ccTabs in place (preserving per-tab in-flight
|
|
490
|
+
// state: _sending, _queue, _abortController, _streamedText, _toolsUsed)
|
|
491
|
+
// and persist via ccSaveState. The close X / new-tab + opt out of drag
|
|
492
|
+
// with draggable="false" + ondragstart preventDefault so the affordances
|
|
493
|
+
// don't accidentally start a drag.
|
|
494
|
+
html += '<div class="cc-tab' + (isActive ? ' active' : '') + (t._sending ? ' working' : '') + '" draggable="true"'
|
|
495
|
+
+ ' ondragstart="ccTabDragStart(event, \'' + t.id + '\')"'
|
|
496
|
+
+ ' ondragover="ccTabDragOver(event, \'' + t.id + '\')"'
|
|
497
|
+
+ ' ondragleave="ccTabDragLeave(event)"'
|
|
498
|
+
+ ' ondrop="ccTabDrop(event, \'' + t.id + '\')"'
|
|
499
|
+
+ ' ondragend="ccTabDragEnd(event)"'
|
|
500
|
+
+ ' onclick="ccSwitchTab(\'' + t.id + '\')" title="' + escHtml(t.title) + '">';
|
|
489
501
|
html += '<span class="cc-tab-text">' + escHtml(t.title) + '</span>';
|
|
490
502
|
if (t._unread) html += '<span class="notif-badge done"></span>';
|
|
491
|
-
html += '<span class="cc-tab-close" onclick="event.stopPropagation();ccCloseTab(\'' + t.id + '\')">×</span>';
|
|
503
|
+
html += '<span class="cc-tab-close" draggable="false" ondragstart="event.preventDefault();event.stopPropagation();" onmousedown="event.stopPropagation();" onclick="event.stopPropagation();ccCloseTab(\'' + t.id + '\')">×</span>';
|
|
492
504
|
html += '</div>';
|
|
493
505
|
}
|
|
494
|
-
html += '<div class="cc-tab cc-tab-new" onclick="ccNewTab()" title="New tab">+</div>';
|
|
506
|
+
html += '<div class="cc-tab cc-tab-new" draggable="false" ondragstart="event.preventDefault();event.stopPropagation();" onclick="ccNewTab()" title="New tab">+</div>';
|
|
495
507
|
html += '</div>';
|
|
496
508
|
bar.innerHTML = html;
|
|
497
509
|
}
|
|
498
510
|
|
|
511
|
+
// ── Tab drag-to-reorder ─────────────────────────────────────────────────────
|
|
512
|
+
// Native HTML5 DnD: dragstart records the source tab id, dragover on a peer
|
|
513
|
+
// tab calls preventDefault to allow drop and adds a drop-target indicator,
|
|
514
|
+
// drop splices _ccTabs in place so per-tab references (and their in-flight
|
|
515
|
+
// state) are preserved, and dragend clears any leftover visual state.
|
|
516
|
+
var _ccDragSourceId = null;
|
|
517
|
+
|
|
518
|
+
function ccTabDragStart(ev, id) {
|
|
519
|
+
_ccDragSourceId = id;
|
|
520
|
+
try {
|
|
521
|
+
ev.dataTransfer.effectAllowed = 'move';
|
|
522
|
+
// setData is required for Firefox to actually start the drag.
|
|
523
|
+
ev.dataTransfer.setData('text/plain', id);
|
|
524
|
+
} catch {}
|
|
525
|
+
var el = ev.currentTarget;
|
|
526
|
+
if (el && el.classList) el.classList.add('cc-tab-dragging');
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function ccTabDragOver(ev, id) {
|
|
530
|
+
if (!_ccDragSourceId) return;
|
|
531
|
+
// preventDefault must fire on every dragover (including the source) so the
|
|
532
|
+
// drop event actually fires — required to detect "released on same tab".
|
|
533
|
+
ev.preventDefault();
|
|
534
|
+
try { ev.dataTransfer.dropEffect = 'move'; } catch {}
|
|
535
|
+
if (_ccDragSourceId === id) return;
|
|
536
|
+
var el = ev.currentTarget;
|
|
537
|
+
if (el && el.classList) el.classList.add('cc-tab-drop-target');
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function ccTabDragLeave(ev) {
|
|
541
|
+
var el = ev.currentTarget;
|
|
542
|
+
if (el && el.classList) el.classList.remove('cc-tab-drop-target');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function ccTabDrop(ev, targetId) {
|
|
546
|
+
ev.preventDefault();
|
|
547
|
+
var srcId = _ccDragSourceId;
|
|
548
|
+
// Clear all visual indicators before any early-return.
|
|
549
|
+
var nodes = document.querySelectorAll('.cc-tab-drop-target, .cc-tab-dragging');
|
|
550
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
551
|
+
nodes[i].classList.remove('cc-tab-drop-target');
|
|
552
|
+
nodes[i].classList.remove('cc-tab-dragging');
|
|
553
|
+
}
|
|
554
|
+
// Released on the source tab (or no source): treat as a click — activate
|
|
555
|
+
// the tab and skip any reorder/state churn. ccSwitchTab is a no-op when
|
|
556
|
+
// the target is already active.
|
|
557
|
+
if (!srcId || srcId === targetId) {
|
|
558
|
+
if (targetId) ccSwitchTab(targetId);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
var fromIdx = _ccTabs.findIndex(function(t) { return t.id === srcId; });
|
|
562
|
+
var toIdx = _ccTabs.findIndex(function(t) { return t.id === targetId; });
|
|
563
|
+
if (fromIdx === -1 || toIdx === -1) return;
|
|
564
|
+
// Splice the existing tab reference so per-tab in-flight state survives
|
|
565
|
+
// (_sending, _queue, _abortController, _streamedText, _toolsUsed,
|
|
566
|
+
// _retryRequests, _sendStartedAt, etc.). Do NOT clone/replace the object.
|
|
567
|
+
var moved = _ccTabs.splice(fromIdx, 1)[0];
|
|
568
|
+
_ccTabs.splice(toIdx, 0, moved);
|
|
569
|
+
// _ccActiveTabId is intentionally unchanged: the same tab stays active,
|
|
570
|
+
// just at a new position.
|
|
571
|
+
ccRenderTabBar();
|
|
572
|
+
ccSaveState();
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function ccTabDragEnd(_ev) {
|
|
576
|
+
_ccDragSourceId = null;
|
|
577
|
+
// Defensive cleanup: dragend always fires, even if drop didn't.
|
|
578
|
+
var nodes = document.querySelectorAll('.cc-tab-dragging, .cc-tab-drop-target');
|
|
579
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
580
|
+
nodes[i].classList.remove('cc-tab-dragging');
|
|
581
|
+
nodes[i].classList.remove('cc-tab-drop-target');
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
499
585
|
function ccRestoreMessages() {
|
|
500
586
|
var el = document.getElementById('cc-messages');
|
|
501
587
|
var tab = _ccActiveTab();
|
package/dashboard/styles.css
CHANGED
|
@@ -654,8 +654,11 @@
|
|
|
654
654
|
|
|
655
655
|
/* Command Center tab bar */
|
|
656
656
|
.cc-tab-scroll { display: flex; gap: 4px; align-items: center; overflow-x: auto; overflow-y: hidden; flex: 1 1 auto; min-width: 0; scrollbar-width: thin; }
|
|
657
|
-
.cc-tab { padding: 4px 10px; font-size: 10px; border: 1px solid var(--border); border-bottom: none; border-radius: 6px 6px 0 0; background: var(--surface2); color: var(--muted); cursor:
|
|
658
|
-
.cc-tab
|
|
657
|
+
.cc-tab { padding: 4px 10px; font-size: 10px; border: 1px solid var(--border); border-bottom: none; border-radius: 6px 6px 0 0; background: var(--surface2); color: var(--muted); cursor: grab; white-space: nowrap; max-width: 140px; display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; margin-bottom: -1px; position: relative; }
|
|
658
|
+
.cc-tab:active { cursor: grabbing; }
|
|
659
|
+
.cc-tab.cc-tab-dragging { opacity: 0.5; cursor: grabbing; }
|
|
660
|
+
.cc-tab.cc-tab-drop-target { box-shadow: inset 2px 0 0 0 var(--blue); }
|
|
661
|
+
.cc-tab-new { color: var(--muted); padding: 4px 8px; cursor: pointer; }
|
|
659
662
|
.cc-tab-text { overflow: hidden; text-overflow: ellipsis; flex: 1; min-width: 0; }
|
|
660
663
|
.cc-tab.active { color: var(--text); background: var(--bg); border-color: var(--border); z-index: 1; font-weight: 600; }
|
|
661
664
|
.cc-tab.working { border-color: var(--blue); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1974",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|