@michengai/dsh-codex-ui 0.2.74 → 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 +96 -71
  2. package/package.json +7 -7
package/dist/client.js CHANGED
@@ -1151,14 +1151,17 @@ 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;
1162
1165
  }
1163
1166
  /**
1164
1167
  * 置顶标题区与首项目的上半区都表示“插到第一项之前”,因此必须共用同一条指示线。
@@ -1235,7 +1238,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1235
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}
1236
1239
  .dcu-wb-project-head[draggable=true],.dcu-wb-session[draggable=true]{cursor:grab}
1237
1240
  .dcu-wb-project-head[draggable=true]:active,.dcu-wb-session[draggable=true]:active{cursor:grabbing}
1238
- .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}
1239
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}
1240
1243
  .dcu-wb-project-current .dcu-wb-folder{color:var(--dsw-alias-state-business-primary)}
1241
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}
@@ -1300,15 +1303,13 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1300
1303
  const busyRef = (0, react.useRef)();
1301
1304
  const [error, setError] = (0, react.useState)();
1302
1305
  const [workspaceDragId, setWorkspaceDragId] = (0, react.useState)();
1303
- const [workspaceDropId, setWorkspaceDropId] = (0, react.useState)();
1304
- const [workspaceDropAfter, setWorkspaceDropAfter] = (0, react.useState)(false);
1306
+ const [workspaceDropTarget, setWorkspaceDropTarget] = (0, react.useState)();
1305
1307
  const [headerMenu, setHeaderMenu] = (0, react.useState)();
1306
1308
  const headerMenuRef = (0, react.useRef)();
1307
1309
  headerMenuRef.current = headerMenu;
1308
1310
  const headerMenuPointerAt = (0, react.useRef)(0);
1309
- const [pinSlot, setPinSlot] = (0, react.useState)();
1310
1311
  const [sessionDrag, setSessionDrag] = (0, react.useState)();
1311
- const [sessionDropId, setSessionDropId] = (0, react.useState)();
1312
+ const [sessionDropTarget, setSessionDropTarget] = (0, react.useState)();
1312
1313
  (0, react.useEffect)(() => {
1313
1314
  savePinnedWorkspaceIds(storage$1(), pinnedWorkspaceIds);
1314
1315
  }, [pinnedWorkspaceIds]);
@@ -1405,7 +1406,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1405
1406
  const pinnedGroups = orderByIds(groups.items, pinnedWorkspaceIds, (workspace) => String(workspace.workspaceId));
1406
1407
  const regularGroups = groups.items.filter((workspace) => !projectPinned(workspace.workspaceId));
1407
1408
  const pinDragActive = workspaceDragId !== void 0;
1408
- const pinnedHeaderDrop = pinSlot === "header" ? pinnedHeaderDropIndicator(pinnedGroups.map((workspace) => String(workspace.workspaceId))) : 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;
1409
1412
  const assignedIds = workspaces.items.flatMap((workspace) => workspace.sessionIds.map((id) => String(id)));
1410
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));
1411
1414
  const run = async (key, action) => {
@@ -1527,50 +1530,51 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1527
1530
  } : void 0;
1528
1531
  const isCurrentWorkspace = sessions.current !== void 0 && workspace.visibleIds.includes(sessions.current);
1529
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;
1530
1537
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1531
- 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" : ""}`,
1532
1539
  onDragOver: (event) => {
1533
1540
  if (workspaceDragId === void 0) return;
1534
1541
  event.preventDefault();
1535
1542
  event.stopPropagation();
1536
1543
  event.dataTransfer.dropEffect = "move";
1537
- const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
1538
- const id = String(workspace.workspaceId);
1539
- const ids = (zone === "pinned" ? pinnedGroups : regularGroups).map((item) => String(item.workspaceId));
1540
- const last = ids.length > 0 && ids[ids.length - 1] === id;
1541
- if (zone === "pinned" && after && last) {
1542
- setPinSlot("end");
1543
- setWorkspaceDropId(void 0);
1544
- setWorkspaceDropAfter(false);
1545
- } else {
1546
- setPinSlot(zone === "pinned" ? id : void 0);
1547
- setWorkspaceDropId(id);
1548
- setWorkspaceDropAfter(after);
1549
- }
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);
1550
1555
  },
1551
1556
  onDrop: (event) => {
1552
1557
  event.preventDefault();
1553
1558
  event.stopPropagation();
1554
1559
  const dragged = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
1555
- 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;
1556
1562
  setWorkspaceDragId(void 0);
1557
- setWorkspaceDropId(void 0);
1558
- setWorkspaceDropAfter(false);
1559
- setPinSlot(void 0);
1563
+ setWorkspaceDropTarget(void 0);
1560
1564
  if (dragged === void 0) return;
1565
+ const beforeId = reorderDropBeforeId(zoneIds, dragged, workspaceId, after);
1566
+ if (beforeId === null) return;
1561
1567
  if (zone === "pinned") {
1562
- const ids = pinnedGroups.map((item) => String(item.workspaceId));
1563
- pinWorkspaceAt(dragged, dropBeforeId(ids, String(workspace.workspaceId), after));
1568
+ pinWorkspaceAt(dragged, beforeId);
1564
1569
  return;
1565
1570
  }
1566
1571
  setPinnedWorkspaceIds((ids) => ids.filter((id) => id !== dragged));
1567
- const beforeId = dropBeforeId(regularGroups.map((item) => String(item.workspaceId)), String(workspace.workspaceId), after);
1568
1572
  const hostIds = groups.items.map((item) => String(item.workspaceId));
1569
- 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));
1570
1574
  },
1571
1575
  children: [
1572
1576
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1573
- className: `dcu-wb-project-head${menuOpen ? " dcu-wb-menu-open" : ""}${isPinnedHeaderDrop || workspaceDropId === workspace.workspaceId ? workspaceDropAfter && !isPinnedHeaderDrop ? " 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" : ""}`,
1574
1578
  role: "treeitem",
1575
1579
  "aria-expanded": isExpanded,
1576
1580
  tabIndex: 0,
@@ -1578,7 +1582,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1578
1582
  onDragStart: (event) => {
1579
1583
  event.stopPropagation();
1580
1584
  setSessionDrag(void 0);
1581
- writeWorkspaceDrag(event.dataTransfer, String(workspace.workspaceId), workspace.title);
1585
+ setSessionDropTarget(void 0);
1586
+ writeWorkspaceDrag(event.dataTransfer, workspaceId, workspace.title);
1582
1587
  const preview = document.createElement("div");
1583
1588
  preview.className = "dcu-wb-drag-ghost";
1584
1589
  preview.textContent = workspace.title;
@@ -1587,13 +1592,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1587
1592
  window.requestAnimationFrame(() => {
1588
1593
  preview.remove();
1589
1594
  });
1590
- setWorkspaceDragId(workspace.workspaceId);
1595
+ setWorkspaceDragId(workspaceId);
1591
1596
  },
1592
1597
  onDragEnd: () => {
1593
1598
  setWorkspaceDragId(void 0);
1594
- setWorkspaceDropId(void 0);
1595
- setWorkspaceDropAfter(false);
1596
- setPinSlot(void 0);
1599
+ setWorkspaceDropTarget(void 0);
1597
1600
  },
1598
1601
  onClick: () => {
1599
1602
  toggleGroup(expandKey, true);
@@ -1732,14 +1735,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1732
1735
  x: menu.x,
1733
1736
  y: menu.y
1734
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;
1735
1740
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1736
- 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" : ""}`,
1737
1742
  role: "treeitem",
1738
1743
  "aria-selected": selected,
1739
1744
  draggable: true,
1740
1745
  onDragStart: (event) => {
1741
1746
  event.stopPropagation();
1742
1747
  setWorkspaceDragId(void 0);
1748
+ setWorkspaceDropTarget(void 0);
1743
1749
  writeSessionDrag(event.dataTransfer, id, session.displayTitle);
1744
1750
  const preview = document.createElement("div");
1745
1751
  preview.className = "dcu-wb-drag-ghost";
@@ -1751,27 +1757,39 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1751
1757
  });
1752
1758
  setSessionDrag({
1753
1759
  sessionId: id,
1754
- workspaceId: workspace.workspaceId
1760
+ workspaceId
1755
1761
  });
1756
1762
  },
1757
1763
  onDragEnd: () => {
1758
1764
  setSessionDrag(void 0);
1759
- setSessionDropId(void 0);
1765
+ setSessionDropTarget(void 0);
1760
1766
  },
1761
1767
  onDragOver: (event) => {
1762
- if (sessionDrag?.workspaceId !== workspace.workspaceId) return;
1768
+ if (sessionDrag?.workspaceId !== workspaceId) return;
1763
1769
  event.preventDefault();
1764
- 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);
1765
1782
  },
1766
1783
  onDrop: (event) => {
1767
1784
  event.preventDefault();
1785
+ event.stopPropagation();
1768
1786
  const drag = sessionDrag;
1787
+ const rect = event.currentTarget.getBoundingClientRect();
1769
1788
  setSessionDrag(void 0);
1770
- setSessionDropId(void 0);
1771
- if (drag === void 0) return;
1772
- const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
1773
- const beforeId = dropBeforeId(workspace.visibleIds, id, after);
1774
- 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));
1775
1793
  },
1776
1794
  onClick: () => {
1777
1795
  setUnreadSessionIds((ids) => ids.filter((item) => item !== id));
@@ -1943,24 +1961,25 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1943
1961
  event.preventDefault();
1944
1962
  event.dataTransfer.dropEffect = "move";
1945
1963
  if (event.target === event.currentTarget || event.target instanceof Element && event.target.closest(".dcu-wb-section-head") !== null) {
1946
- setPinSlot("header");
1947
- setWorkspaceDropId(void 0);
1948
- setWorkspaceDropAfter(false);
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
+ });
1949
1970
  }
1950
1971
  },
1951
1972
  onDrop: (event) => {
1952
1973
  event.preventDefault();
1953
1974
  const draggedWorkspace = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
1954
- const slot = pinSlot;
1975
+ const target = workspaceDropTarget;
1955
1976
  setWorkspaceDragId(void 0);
1956
- setWorkspaceDropId(void 0);
1957
- setWorkspaceDropAfter(false);
1958
- setPinSlot(void 0);
1959
- 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);
1960
1979
  },
1961
1980
  onDragLeave: (event) => {
1962
1981
  if (event.currentTarget.contains(event.relatedTarget)) return;
1963
- setPinSlot(void 0);
1982
+ setWorkspaceDropTarget(void 0);
1964
1983
  },
1965
1984
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1966
1985
  className: "dcu-wb-section-head",
@@ -1999,26 +2018,31 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
1999
2018
  event.preventDefault();
2000
2019
  event.stopPropagation();
2001
2020
  event.dataTransfer.dropEffect = "move";
2002
- setPinSlot("header");
2003
- setWorkspaceDropId(void 0);
2004
- setWorkspaceDropAfter(false);
2021
+ setWorkspaceDropTarget({
2022
+ zone: "pinned",
2023
+ beforeId: void 0
2024
+ });
2005
2025
  }
2006
2026
  }),
2007
- 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", {
2008
2028
  className: "dcu-wb-empty",
2009
2029
  children: t("workspace.pinnedEmpty")
2010
2030
  }),
2011
2031
  pinnedGroups.map((workspace) => renderGroup(workspace, "pinned")),
2012
- pinDragActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2013
- 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" : ""}`,
2014
2034
  onDragOver: (event) => {
2015
2035
  if (!pinDragActive) return;
2016
2036
  event.preventDefault();
2017
2037
  event.stopPropagation();
2018
2038
  event.dataTransfer.dropEffect = "move";
2019
- setPinSlot("end");
2020
- setWorkspaceDropId(void 0);
2021
- 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
+ });
2022
2046
  }
2023
2047
  })
2024
2048
  ] })
@@ -2131,6 +2155,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2131
2155
  onDragStart: (event) => {
2132
2156
  event.stopPropagation();
2133
2157
  setWorkspaceDragId(void 0);
2158
+ setWorkspaceDropTarget(void 0);
2134
2159
  writeSessionDrag(event.dataTransfer, id, title);
2135
2160
  const preview = document.createElement("div");
2136
2161
  preview.className = "dcu-wb-drag-ghost";
@@ -2147,8 +2172,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2147
2172
  },
2148
2173
  onDragEnd: () => {
2149
2174
  setSessionDrag(void 0);
2150
- setSessionDropId(void 0);
2151
- setPinSlot(void 0);
2175
+ setSessionDropTarget(void 0);
2176
+ setWorkspaceDropTarget(void 0);
2152
2177
  },
2153
2178
  menuPoint: menu?.type === "session" && menu.id === id && menu.x !== void 0 && menu.y !== void 0 ? {
2154
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.74",
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
+ }