@michengai/dsh-codex-ui 0.2.73 → 0.2.75

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 (2) hide show
  1. package/dist/client.js +112 -71
  2. package/package.json +7 -7
package/dist/client.js CHANGED
@@ -1151,14 +1151,28 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1151
1151
  return next;
1152
1152
  }
1153
1153
  /**
1154
- * 按指针落在目标项上/下半区,算出应插入到哪一项之前。
1155
- * 落在最后一项下半区时返回 undefined,表示追加到末尾。
1154
+ * 复刻 Codex 的排序落点:先从当前列表移除被拖项,再把落点表示成“插到谁之前”。
1155
+ * null 表示悬停自身或最终顺序不变,此时不显示蓝线,也不执行排序。
1156
1156
  */
1157
- function dropBeforeId(ids, hoveredId, after) {
1158
- const index = ids.indexOf(hoveredId);
1159
- if (index < 0) return hoveredId;
1160
- if (!after) return hoveredId;
1161
- return index >= ids.length - 1 ? void 0 : ids[index + 1];
1157
+ function reorderDropBeforeId(ids, draggedId, hoveredId, after) {
1158
+ if (draggedId === hoveredId || !ids.includes(hoveredId)) return null;
1159
+ const remaining = ids.filter((id) => id !== draggedId);
1160
+ const hoveredIndex = remaining.indexOf(hoveredId);
1161
+ if (hoveredIndex < 0) return null;
1162
+ const beforeId = after ? remaining[hoveredIndex + 1] : hoveredId;
1163
+ if (!ids.includes(draggedId)) return beforeId;
1164
+ return moveBefore(ids, draggedId, beforeId).every((id, index) => id === ids[index]) ? null : beforeId;
1165
+ }
1166
+ /**
1167
+ * 置顶标题区与首项目的上半区都表示“插到第一项之前”,因此必须共用同一条指示线。
1168
+ * 非空列表把指示线贴到首项目顶部;空列表才使用独立的起始占位线。
1169
+ */
1170
+ function pinnedHeaderDropIndicator(ids) {
1171
+ const workspaceId = ids[0];
1172
+ return workspaceId === void 0 ? { kind: "empty" } : {
1173
+ kind: "workspace",
1174
+ workspaceId
1175
+ };
1162
1176
  }
1163
1177
  /** 按指定 id 顺序取出对应项;未出现在 ids 中的项丢弃。 */
1164
1178
  function orderByIds(items, ids, idOf) {
@@ -1224,7 +1238,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1224
1238
  .dcu-wb-project-head:hover,.dcu-wb-project-head.dcu-wb-menu-open,.dcu-wb-session:hover,.dcu-wb-session.dcu-wb-selected,.dcu-wb-session.dcu-wb-menu-open{background:var(--dcu-sidebar-hover)}.dcu-wb-project-head+.dcu-wb-session,.dcu-wb-project-head+.dcu-wb-nochat{margin-top:0}.dcu-wb-session+.dcu-wb-session{margin-top:2px}
1225
1239
  .dcu-wb-project-head[draggable=true],.dcu-wb-session[draggable=true]{cursor:grab}
1226
1240
  .dcu-wb-project-head[draggable=true]:active,.dcu-wb-session[draggable=true]:active{cursor:grabbing}
1227
- .dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pin-end,.dcu-wb-pin-start{position:relative;height:8px}.dcu-wb-project-head.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before,.dcu-wb-pin-end.dcu-wb-drop::before,.dcu-wb-pin-start.dcu-wb-drop::before{content:"";position:absolute;left:8px;right:8px;top:-4px;height:8px;pointer-events:none;background:radial-gradient(circle at 4px 50%,var(--dsw-alias-state-business-primary) 3.25px,transparent 3.45px),linear-gradient(var(--dsw-alias-state-business-primary),var(--dsw-alias-state-business-primary)) 10px 50%/calc(100% - 10px) 2px no-repeat}.dcu-wb-pin-start.dcu-wb-drop::before,.dcu-wb-project-head.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before{top:0}.dcu-wb-project-head.dcu-wb-drop-after::before,.dcu-wb-session.dcu-wb-drop-after::before{top:auto;bottom:0}.dcu-wb-dragging{opacity:.28}.dcu-wb-drag-ghost{position:fixed;top:-120px;left:-240px;z-index:10040;max-width:220px;height:32px;padding:0 10px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:var(--dcu-sidebar-hover);color:var(--dcu-sidebar-primary);font:13px/32px var(--dcu-font,inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none;opacity:0}
1241
+ .dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pin-end,.dcu-wb-pin-start{position:relative;height:8px}.dcu-wb-project.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before,.dcu-wb-pin-end.dcu-wb-drop::before,.dcu-wb-pin-start.dcu-wb-drop::before{content:"";position:absolute;z-index:2;left:8px;right:8px;top:-4px;height:8px;pointer-events:none;background:radial-gradient(circle at 4px 50%,var(--dsw-alias-state-business-primary) 3.25px,transparent 3.45px),linear-gradient(var(--dsw-alias-state-business-primary),var(--dsw-alias-state-business-primary)) 10px 50%/calc(100% - 10px) 2px no-repeat}.dcu-wb-pin-start.dcu-wb-drop::before,.dcu-wb-project.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before{top:0}.dcu-wb-project.dcu-wb-drop-after::before,.dcu-wb-session.dcu-wb-drop-after::before{top:auto;bottom:0}.dcu-wb-dragging{opacity:.28}.dcu-wb-drag-ghost{position:fixed;top:-120px;left:-240px;z-index:10040;max-width:220px;height:32px;padding:0 10px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:var(--dcu-sidebar-hover);color:var(--dcu-sidebar-primary);font:13px/32px var(--dcu-font,inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none;opacity:0}
1228
1242
  .dcu-wb-folder{display:grid;place-items:center;flex:none;width:16px;height:20px;color:var(--dcu-sidebar-icon)}.dcu-wb-brand{display:block;width:16px;height:16px}
1229
1243
  .dcu-wb-project-current .dcu-wb-folder{color:var(--dsw-alias-state-business-primary)}
1230
1244
  .dcu-wb-project-title,.dcu-wb-session-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}
@@ -1289,15 +1303,13 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1289
1303
  const busyRef = (0, react.useRef)();
1290
1304
  const [error, setError] = (0, react.useState)();
1291
1305
  const [workspaceDragId, setWorkspaceDragId] = (0, react.useState)();
1292
- const [workspaceDropId, setWorkspaceDropId] = (0, react.useState)();
1293
- const [workspaceDropAfter, setWorkspaceDropAfter] = (0, react.useState)(false);
1306
+ const [workspaceDropTarget, setWorkspaceDropTarget] = (0, react.useState)();
1294
1307
  const [headerMenu, setHeaderMenu] = (0, react.useState)();
1295
1308
  const headerMenuRef = (0, react.useRef)();
1296
1309
  headerMenuRef.current = headerMenu;
1297
1310
  const headerMenuPointerAt = (0, react.useRef)(0);
1298
- const [pinSlot, setPinSlot] = (0, react.useState)();
1299
1311
  const [sessionDrag, setSessionDrag] = (0, react.useState)();
1300
- const [sessionDropId, setSessionDropId] = (0, react.useState)();
1312
+ const [sessionDropTarget, setSessionDropTarget] = (0, react.useState)();
1301
1313
  (0, react.useEffect)(() => {
1302
1314
  savePinnedWorkspaceIds(storage$1(), pinnedWorkspaceIds);
1303
1315
  }, [pinnedWorkspaceIds]);
@@ -1394,6 +1406,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1394
1406
  const pinnedGroups = orderByIds(groups.items, pinnedWorkspaceIds, (workspace) => String(workspace.workspaceId));
1395
1407
  const regularGroups = groups.items.filter((workspace) => !projectPinned(workspace.workspaceId));
1396
1408
  const pinDragActive = workspaceDragId !== void 0;
1409
+ const pinnedGroupIds = pinnedGroups.map((workspace) => String(workspace.workspaceId));
1410
+ const regularGroupIds = regularGroups.map((workspace) => String(workspace.workspaceId));
1411
+ const pinnedHeaderDrop = workspaceDropTarget?.zone === "pinned" && workspaceDropTarget.beforeId === pinnedGroupIds[0] ? pinnedHeaderDropIndicator(pinnedGroupIds) : void 0;
1397
1412
  const assignedIds = workspaces.items.flatMap((workspace) => workspace.sessionIds.map((id) => String(id)));
1398
1413
  const recentIds = ungroupedSessionIds(sessions.ids ?? Object.keys(sessions.byId), sessions.byId, assignedIds, workspaces.archivedSessionIds).sort((left, right) => (sessions.byId[right]?.updatedAt ?? 0) - (sessions.byId[left]?.updatedAt ?? 0));
1399
1414
  const run = async (key, action) => {
@@ -1514,50 +1529,52 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1514
1529
  y: menu.y
1515
1530
  } : void 0;
1516
1531
  const isCurrentWorkspace = sessions.current !== void 0 && workspace.visibleIds.includes(sessions.current);
1532
+ const isPinnedHeaderDrop = zone === "pinned" && pinnedHeaderDrop?.kind === "workspace" && pinnedHeaderDrop.workspaceId === String(workspace.workspaceId);
1533
+ const workspaceId = String(workspace.workspaceId);
1534
+ const zoneIds = zone === "pinned" ? pinnedGroupIds : regularGroupIds;
1535
+ const dropsBefore = workspaceDropTarget?.zone === zone && workspaceDropTarget.beforeId === workspaceId;
1536
+ const dropsAfterLast = workspaceDropTarget?.zone === zone && workspaceDropTarget.beforeId === void 0 && zoneIds[zoneIds.length - 1] === workspaceId;
1517
1537
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1518
- className: `dcu-wb-project${isCurrentWorkspace ? " dcu-wb-project-current" : ""}`,
1538
+ className: `dcu-wb-project${isCurrentWorkspace ? " dcu-wb-project-current" : ""}${isPinnedHeaderDrop || dropsBefore ? " dcu-wb-drop" : ""}${dropsAfterLast ? " dcu-wb-drop dcu-wb-drop-after" : ""}`,
1519
1539
  onDragOver: (event) => {
1520
1540
  if (workspaceDragId === void 0) return;
1521
1541
  event.preventDefault();
1522
1542
  event.stopPropagation();
1523
1543
  event.dataTransfer.dropEffect = "move";
1524
- const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
1525
- const id = String(workspace.workspaceId);
1526
- const ids = (zone === "pinned" ? pinnedGroups : regularGroups).map((item) => String(item.workspaceId));
1527
- const last = ids.length > 0 && ids[ids.length - 1] === id;
1528
- if (zone === "pinned" && after && last) {
1529
- setPinSlot("end");
1530
- setWorkspaceDropId(void 0);
1531
- setWorkspaceDropAfter(false);
1532
- } else {
1533
- setPinSlot(zone === "pinned" ? id : void 0);
1534
- setWorkspaceDropId(id);
1535
- setWorkspaceDropAfter(after);
1536
- }
1544
+ const rect = event.currentTarget.getBoundingClientRect();
1545
+ const after = event.clientY > rect.top + rect.height / 2;
1546
+ const beforeId = reorderDropBeforeId(zoneIds, workspaceDragId, workspaceId, after);
1547
+ setWorkspaceDropTarget(beforeId === null ? void 0 : {
1548
+ zone,
1549
+ beforeId
1550
+ });
1551
+ },
1552
+ onDragLeave: (event) => {
1553
+ if (event.currentTarget.contains(event.relatedTarget)) return;
1554
+ setWorkspaceDropTarget(void 0);
1537
1555
  },
1538
1556
  onDrop: (event) => {
1539
1557
  event.preventDefault();
1540
1558
  event.stopPropagation();
1541
1559
  const dragged = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
1542
- const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
1560
+ const rect = event.currentTarget.getBoundingClientRect();
1561
+ const after = event.clientY > rect.top + rect.height / 2;
1543
1562
  setWorkspaceDragId(void 0);
1544
- setWorkspaceDropId(void 0);
1545
- setWorkspaceDropAfter(false);
1546
- setPinSlot(void 0);
1563
+ setWorkspaceDropTarget(void 0);
1547
1564
  if (dragged === void 0) return;
1565
+ const beforeId = reorderDropBeforeId(zoneIds, dragged, workspaceId, after);
1566
+ if (beforeId === null) return;
1548
1567
  if (zone === "pinned") {
1549
- const ids = pinnedGroups.map((item) => String(item.workspaceId));
1550
- pinWorkspaceAt(dragged, dropBeforeId(ids, String(workspace.workspaceId), after));
1568
+ pinWorkspaceAt(dragged, beforeId);
1551
1569
  return;
1552
1570
  }
1553
1571
  setPinnedWorkspaceIds((ids) => ids.filter((id) => id !== dragged));
1554
- const beforeId = dropBeforeId(regularGroups.map((item) => String(item.workspaceId)), String(workspace.workspaceId), after);
1555
1572
  const hostIds = groups.items.map((item) => String(item.workspaceId));
1556
- if (moveBefore(hostIds, dragged, beforeId).join() !== hostIds.join()) run("workspace-order", () => insertWorkspaceBefore(dragged, beforeId));
1573
+ if (moveBefore(hostIds, dragged, beforeId).some((id, index) => id !== hostIds[index])) run("workspace-order", () => insertWorkspaceBefore(dragged, beforeId));
1557
1574
  },
1558
1575
  children: [
1559
1576
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1560
- className: `dcu-wb-project-head${menuOpen ? " dcu-wb-menu-open" : ""}${workspaceDropId === workspace.workspaceId ? workspaceDropAfter ? " dcu-wb-drop dcu-wb-drop-after" : " dcu-wb-drop" : ""}${workspaceDragId === String(workspace.workspaceId) ? " dcu-wb-dragging" : ""}`,
1577
+ className: `dcu-wb-project-head${menuOpen ? " dcu-wb-menu-open" : ""}${workspaceDragId === workspaceId ? " dcu-wb-dragging" : ""}`,
1561
1578
  role: "treeitem",
1562
1579
  "aria-expanded": isExpanded,
1563
1580
  tabIndex: 0,
@@ -1565,7 +1582,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1565
1582
  onDragStart: (event) => {
1566
1583
  event.stopPropagation();
1567
1584
  setSessionDrag(void 0);
1568
- writeWorkspaceDrag(event.dataTransfer, String(workspace.workspaceId), workspace.title);
1585
+ setSessionDropTarget(void 0);
1586
+ writeWorkspaceDrag(event.dataTransfer, workspaceId, workspace.title);
1569
1587
  const preview = document.createElement("div");
1570
1588
  preview.className = "dcu-wb-drag-ghost";
1571
1589
  preview.textContent = workspace.title;
@@ -1574,13 +1592,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1574
1592
  window.requestAnimationFrame(() => {
1575
1593
  preview.remove();
1576
1594
  });
1577
- setWorkspaceDragId(workspace.workspaceId);
1595
+ setWorkspaceDragId(workspaceId);
1578
1596
  },
1579
1597
  onDragEnd: () => {
1580
1598
  setWorkspaceDragId(void 0);
1581
- setWorkspaceDropId(void 0);
1582
- setWorkspaceDropAfter(false);
1583
- setPinSlot(void 0);
1599
+ setWorkspaceDropTarget(void 0);
1584
1600
  },
1585
1601
  onClick: () => {
1586
1602
  toggleGroup(expandKey, true);
@@ -1719,14 +1735,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1719
1735
  x: menu.x,
1720
1736
  y: menu.y
1721
1737
  } : void 0;
1738
+ const dropsBeforeSession = sessionDropTarget?.workspaceId === workspaceId && sessionDropTarget.beforeId === id;
1739
+ const dropsAfterLastSession = sessionDropTarget?.workspaceId === workspaceId && sessionDropTarget.beforeId === void 0 && shownIds[shownIds.length - 1] === id;
1722
1740
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1723
- className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${sessionMenuOpen ? " dcu-wb-menu-open" : ""}${sessionDropId === id ? " dcu-wb-drop" : ""}`,
1741
+ className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${sessionMenuOpen ? " dcu-wb-menu-open" : ""}${dropsBeforeSession ? " dcu-wb-drop" : ""}${dropsAfterLastSession ? " dcu-wb-drop dcu-wb-drop-after" : ""}`,
1724
1742
  role: "treeitem",
1725
1743
  "aria-selected": selected,
1726
1744
  draggable: true,
1727
1745
  onDragStart: (event) => {
1728
1746
  event.stopPropagation();
1729
1747
  setWorkspaceDragId(void 0);
1748
+ setWorkspaceDropTarget(void 0);
1730
1749
  writeSessionDrag(event.dataTransfer, id, session.displayTitle);
1731
1750
  const preview = document.createElement("div");
1732
1751
  preview.className = "dcu-wb-drag-ghost";
@@ -1738,27 +1757,39 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1738
1757
  });
1739
1758
  setSessionDrag({
1740
1759
  sessionId: id,
1741
- workspaceId: workspace.workspaceId
1760
+ workspaceId
1742
1761
  });
1743
1762
  },
1744
1763
  onDragEnd: () => {
1745
1764
  setSessionDrag(void 0);
1746
- setSessionDropId(void 0);
1765
+ setSessionDropTarget(void 0);
1747
1766
  },
1748
1767
  onDragOver: (event) => {
1749
- if (sessionDrag?.workspaceId !== workspace.workspaceId) return;
1768
+ if (sessionDrag?.workspaceId !== workspaceId) return;
1750
1769
  event.preventDefault();
1751
- setSessionDropId(id);
1770
+ event.stopPropagation();
1771
+ event.dataTransfer.dropEffect = "move";
1772
+ const rect = event.currentTarget.getBoundingClientRect();
1773
+ const beforeId = reorderDropBeforeId(shownIds, sessionDrag.sessionId, id, event.clientY > rect.top + rect.height / 2);
1774
+ setSessionDropTarget(beforeId === null ? void 0 : {
1775
+ workspaceId,
1776
+ beforeId
1777
+ });
1778
+ },
1779
+ onDragLeave: (event) => {
1780
+ if (event.currentTarget.contains(event.relatedTarget)) return;
1781
+ setSessionDropTarget(void 0);
1752
1782
  },
1753
1783
  onDrop: (event) => {
1754
1784
  event.preventDefault();
1785
+ event.stopPropagation();
1755
1786
  const drag = sessionDrag;
1787
+ const rect = event.currentTarget.getBoundingClientRect();
1756
1788
  setSessionDrag(void 0);
1757
- setSessionDropId(void 0);
1758
- if (drag === void 0) return;
1759
- const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
1760
- const beforeId = dropBeforeId(workspace.visibleIds, id, after);
1761
- if (moveBefore(workspace.visibleIds, drag.sessionId, beforeId).join() !== workspace.visibleIds.join()) run("session-order", () => insertSessionBefore(workspace.workspaceId, drag.sessionId, beforeId));
1789
+ setSessionDropTarget(void 0);
1790
+ if (drag === void 0 || drag.workspaceId !== workspaceId) return;
1791
+ const beforeId = reorderDropBeforeId(shownIds, drag.sessionId, id, event.clientY > rect.top + rect.height / 2);
1792
+ if (beforeId !== null) run("session-order", () => insertSessionBefore(workspace.workspaceId, drag.sessionId, beforeId));
1762
1793
  },
1763
1794
  onClick: () => {
1764
1795
  setUnreadSessionIds((ids) => ids.filter((item) => item !== id));
@@ -1929,21 +1960,26 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1929
1960
  if (!pinDragActive) return;
1930
1961
  event.preventDefault();
1931
1962
  event.dataTransfer.dropEffect = "move";
1932
- if (event.target === event.currentTarget || event.target instanceof Element && event.target.closest(".dcu-wb-section-head") !== null) setPinSlot("header");
1963
+ if (event.target === event.currentTarget || event.target instanceof Element && event.target.closest(".dcu-wb-section-head") !== null) {
1964
+ const firstId = pinnedGroupIds[0];
1965
+ const beforeId = firstId === void 0 ? void 0 : reorderDropBeforeId(pinnedGroupIds, workspaceDragId, firstId, false);
1966
+ setWorkspaceDropTarget(beforeId === null ? void 0 : {
1967
+ zone: "pinned",
1968
+ beforeId
1969
+ });
1970
+ }
1933
1971
  },
1934
1972
  onDrop: (event) => {
1935
1973
  event.preventDefault();
1936
1974
  const draggedWorkspace = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
1937
- const slot = pinSlot;
1975
+ const target = workspaceDropTarget;
1938
1976
  setWorkspaceDragId(void 0);
1939
- setWorkspaceDropId(void 0);
1940
- setWorkspaceDropAfter(false);
1941
- setPinSlot(void 0);
1942
- if (draggedWorkspace !== void 0) pinWorkspaceAt(draggedWorkspace, slot === "header" ? pinnedGroups[0] === void 0 ? void 0 : String(pinnedGroups[0].workspaceId) : slot === "end" || slot === void 0 ? void 0 : slot);
1977
+ setWorkspaceDropTarget(void 0);
1978
+ if (draggedWorkspace !== void 0 && target?.zone === "pinned") pinWorkspaceAt(draggedWorkspace, target.beforeId);
1943
1979
  },
1944
1980
  onDragLeave: (event) => {
1945
1981
  if (event.currentTarget.contains(event.relatedTarget)) return;
1946
- setPinSlot(void 0);
1982
+ setWorkspaceDropTarget(void 0);
1947
1983
  },
1948
1984
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1949
1985
  className: "dcu-wb-section-head",
@@ -1976,33 +2012,37 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1976
2012
  className: "dcu-wb-section-body",
1977
2013
  "data-open": sectionOpen("pinned"),
1978
2014
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
1979
- (pinDragActive || pinSlot === "header") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1980
- className: `dcu-wb-pin-start${pinSlot === "header" ? " dcu-wb-drop" : ""}`,
2015
+ pinDragActive && pinnedGroups.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2016
+ className: `dcu-wb-pin-start${pinnedHeaderDrop?.kind === "empty" ? " dcu-wb-drop" : ""}`,
1981
2017
  onDragOver: (event) => {
1982
- if (!pinDragActive) return;
1983
2018
  event.preventDefault();
1984
2019
  event.stopPropagation();
1985
2020
  event.dataTransfer.dropEffect = "move";
1986
- setPinSlot("header");
1987
- setWorkspaceDropId(void 0);
1988
- setWorkspaceDropAfter(false);
2021
+ setWorkspaceDropTarget({
2022
+ zone: "pinned",
2023
+ beforeId: void 0
2024
+ });
1989
2025
  }
1990
2026
  }),
1991
- pinnedGroups.length === 0 && pinSlot !== "header" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2027
+ pinnedGroups.length === 0 && !(workspaceDropTarget?.zone === "pinned" && workspaceDropTarget.beforeId === void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1992
2028
  className: "dcu-wb-empty",
1993
2029
  children: t("workspace.pinnedEmpty")
1994
2030
  }),
1995
2031
  pinnedGroups.map((workspace) => renderGroup(workspace, "pinned")),
1996
- pinDragActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1997
- className: `dcu-wb-pin-end${pinSlot === "end" ? " dcu-wb-drop" : ""}`,
2032
+ pinDragActive && pinnedGroups.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2033
+ className: `dcu-wb-pin-end${workspaceDropTarget?.zone === "pinned" && workspaceDropTarget.beforeId === void 0 ? " dcu-wb-drop" : ""}`,
1998
2034
  onDragOver: (event) => {
1999
2035
  if (!pinDragActive) return;
2000
2036
  event.preventDefault();
2001
2037
  event.stopPropagation();
2002
2038
  event.dataTransfer.dropEffect = "move";
2003
- setPinSlot("end");
2004
- setWorkspaceDropId(void 0);
2005
- setWorkspaceDropAfter(false);
2039
+ const lastId = pinnedGroupIds[pinnedGroupIds.length - 1];
2040
+ if (lastId === void 0 || workspaceDragId === void 0) return;
2041
+ const beforeId = reorderDropBeforeId(pinnedGroupIds, workspaceDragId, lastId, true);
2042
+ setWorkspaceDropTarget(beforeId === null ? void 0 : {
2043
+ zone: "pinned",
2044
+ beforeId
2045
+ });
2006
2046
  }
2007
2047
  })
2008
2048
  ] })
@@ -2115,6 +2155,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2115
2155
  onDragStart: (event) => {
2116
2156
  event.stopPropagation();
2117
2157
  setWorkspaceDragId(void 0);
2158
+ setWorkspaceDropTarget(void 0);
2118
2159
  writeSessionDrag(event.dataTransfer, id, title);
2119
2160
  const preview = document.createElement("div");
2120
2161
  preview.className = "dcu-wb-drag-ghost";
@@ -2131,8 +2172,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2131
2172
  },
2132
2173
  onDragEnd: () => {
2133
2174
  setSessionDrag(void 0);
2134
- setSessionDropId(void 0);
2135
- setPinSlot(void 0);
2175
+ setSessionDropTarget(void 0);
2176
+ setWorkspaceDropTarget(void 0);
2136
2177
  },
2137
2178
  menuPoint: menu?.type === "session" && menu.id === id && menu.x !== void 0 && menu.y !== void 0 ? {
2138
2179
  x: menu.x,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-codex-ui",
3
- "version": "0.2.73",
3
+ "version": "0.2.75",
4
4
  "description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -51,11 +51,6 @@
51
51
  "platform": "web"
52
52
  }
53
53
  },
54
- "scripts": {
55
- "build": "tsc --noEmit && tsdown",
56
- "typecheck": "tsc --noEmit",
57
- "test": "pnpm run typecheck && vitest run tests/client-runtime.integration.spec.ts && tsdown && node tests/run-assertions.mjs"
58
- },
59
54
  "peerDependencies": {
60
55
  "@deepseek-ai/cordis": ">=4.0.1 <5.0.0",
61
56
  "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.0 <0.2.0",
@@ -101,5 +96,10 @@
101
96
  "tsx": "^4.22.4",
102
97
  "typescript": "^6.0.3",
103
98
  "vitest": "^4.1.8"
99
+ },
100
+ "scripts": {
101
+ "build": "tsc --noEmit && tsdown",
102
+ "typecheck": "tsc --noEmit",
103
+ "test": "pnpm run typecheck && vitest run tests/client-runtime.integration.spec.ts && tsdown && node tests/run-assertions.mjs"
104
104
  }
105
- }
105
+ }