@michengai/dsh-codex-ui 1.1.10 → 1.1.12
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.
- package/CHANGELOG.md +48 -0
- package/CHANGELOG.zh-CN.md +48 -0
- package/lib/client.js +257 -36
- package/lib/session-title-plugin.mjs +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,54 @@
|
|
|
4
4
|
|
|
5
5
|
This changelog records recent releases of DSH Codex UI and its one-click installer. Earlier changes remain available in the [Git history](https://github.com/MichengAI/dsh-codex-ui/commits/main).
|
|
6
6
|
|
|
7
|
+
## 1.1.12 - 2026-09-17
|
|
8
|
+
|
|
9
|
+
- Session rows show compact relative time on the right (now, minutes, hours, days, weeks, months, years). Hover or the action menu yields to the archive shortcut; a pending label hides the inline time.
|
|
10
|
+
- Truncated session titles scroll on hover or when the menu is open. Reduced motion keeps the ellipsis.
|
|
11
|
+
- Relative times refresh every minute. Inline English uses now; hover cards use Just now.
|
|
12
|
+
|
|
13
|
+
## suite-installer-v1.0.14 - 2026-09-16
|
|
14
|
+
|
|
15
|
+
Install or maintain 11 first-party plugins in one step. Included plugins and versions:
|
|
16
|
+
|
|
17
|
+
- `@michengai/dsh-archive-manager@0.1.43`
|
|
18
|
+
- `@michengai/dsh-codex-ui@1.1.11`
|
|
19
|
+
- `@michengai/dsh-skills-manager@0.1.52`
|
|
20
|
+
- `@michengai/dsh-agency-agents@0.1.43`
|
|
21
|
+
- `@michengai/dsh-im-connect@0.1.50`
|
|
22
|
+
- `@michengai/dsh-automation@0.1.44`
|
|
23
|
+
- `@michengai/dsh-btw@0.1.8`
|
|
24
|
+
- `@michengai/dsh-simplify@0.1.5`
|
|
25
|
+
- `@michengai/dsh-pua@0.3.13`
|
|
26
|
+
- `@michengai/dsh-code-review@0.1.2`
|
|
27
|
+
- `@michengai/dsh-codex-pet@0.1.6`
|
|
28
|
+
|
|
29
|
+
The installer uses these exact versions for reproducible installation.
|
|
30
|
+
|
|
31
|
+
## 1.1.11 - 2026-09-16
|
|
32
|
+
|
|
33
|
+
- Open the settings page (and usage statistics) through a `document.body` portal so a collapsed 56px rail cannot trap the overlay in a transform containing block.
|
|
34
|
+
- Skip the dsh-context `context-overview` footer action by slot id and render the remaining footer actions one by one. Usage statistics stays visible. Footer actions without an id are dropped. The per-session Context tab is unchanged.
|
|
35
|
+
- Pin a dragged project into an empty pinned section even when dragleave clears the insertion target.
|
|
36
|
+
|
|
37
|
+
## suite-installer-v1.0.13 - 2026-09-16
|
|
38
|
+
|
|
39
|
+
Install or maintain 11 first-party plugins in one step. Included plugins and versions:
|
|
40
|
+
|
|
41
|
+
- `@michengai/dsh-archive-manager@0.1.43`
|
|
42
|
+
- `@michengai/dsh-codex-ui@1.1.10`
|
|
43
|
+
- `@michengai/dsh-skills-manager@0.1.52`
|
|
44
|
+
- `@michengai/dsh-agency-agents@0.1.43`
|
|
45
|
+
- `@michengai/dsh-im-connect@0.1.50`
|
|
46
|
+
- `@michengai/dsh-automation@0.1.44`
|
|
47
|
+
- `@michengai/dsh-btw@0.1.8`
|
|
48
|
+
- `@michengai/dsh-simplify@0.1.5`
|
|
49
|
+
- `@michengai/dsh-pua@0.3.13`
|
|
50
|
+
- `@michengai/dsh-code-review@0.1.2`
|
|
51
|
+
- `@michengai/dsh-codex-pet@0.1.6`
|
|
52
|
+
|
|
53
|
+
The installer uses these exact versions for reproducible installation.
|
|
54
|
+
|
|
7
55
|
## 1.1.10 - 2026-09-16
|
|
8
56
|
|
|
9
57
|
- Cold start registers session titles through a dedicated `@michengai/dsh-codex-ui/session-title` plugin after `sessionTitle` and `llm` are ready, and recycles the provider on unload.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,54 @@
|
|
|
4
4
|
|
|
5
5
|
本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
|
|
6
6
|
|
|
7
|
+
## 1.1.12 - 2026-09-17
|
|
8
|
+
|
|
9
|
+
- 会话行右侧显示紧凑相对时间(刚刚、分、小时、天、周、月、年)。悬停或打开菜单时让位给归档快捷图标;待处理标签优先于行内时间。
|
|
10
|
+
- 标题被截断时,悬停或打开菜单会横向滚动全文;系统减动效时保持省略号。
|
|
11
|
+
- 相对时间每分钟对齐刷新。行内英文用 now,悬停卡片用 Just now。
|
|
12
|
+
|
|
13
|
+
## suite-installer-v1.0.14 - 2026-09-16
|
|
14
|
+
|
|
15
|
+
一键维护安装 11 个自研插件。包含以下插件及版本:
|
|
16
|
+
|
|
17
|
+
- `@michengai/dsh-archive-manager@0.1.43`
|
|
18
|
+
- `@michengai/dsh-codex-ui@1.1.11`
|
|
19
|
+
- `@michengai/dsh-skills-manager@0.1.52`
|
|
20
|
+
- `@michengai/dsh-agency-agents@0.1.43`
|
|
21
|
+
- `@michengai/dsh-im-connect@0.1.50`
|
|
22
|
+
- `@michengai/dsh-automation@0.1.44`
|
|
23
|
+
- `@michengai/dsh-btw@0.1.8`
|
|
24
|
+
- `@michengai/dsh-simplify@0.1.5`
|
|
25
|
+
- `@michengai/dsh-pua@0.3.13`
|
|
26
|
+
- `@michengai/dsh-code-review@0.1.2`
|
|
27
|
+
- `@michengai/dsh-codex-pet@0.1.6`
|
|
28
|
+
|
|
29
|
+
安装器使用这些精确版本执行安装,确保可复现。
|
|
30
|
+
|
|
31
|
+
## 1.1.11 - 2026-09-16
|
|
32
|
+
|
|
33
|
+
- 设置页和用量统计改为挂到 `document.body`。侧栏收缩后,宿主或插件若给窄轨加了 transform,全屏页不再被困在 56px 里挤成竖排。
|
|
34
|
+
- 侧栏底部按 slot id 跳过 dsh-context 的 `context-overview`,其余底部动作(含费用统计)仍按 id 单独渲染。没有 id 的底部动作不渲染。会话里的上下文页还在。
|
|
35
|
+
- 置顶为空时,从项目区拖入仍会置顶;松手时即使蓝线落点被清掉也不丢。
|
|
36
|
+
|
|
37
|
+
## suite-installer-v1.0.13 - 2026-09-16
|
|
38
|
+
|
|
39
|
+
一键维护安装 11 个自研插件。包含以下插件及版本:
|
|
40
|
+
|
|
41
|
+
- `@michengai/dsh-archive-manager@0.1.43`
|
|
42
|
+
- `@michengai/dsh-codex-ui@1.1.10`
|
|
43
|
+
- `@michengai/dsh-skills-manager@0.1.52`
|
|
44
|
+
- `@michengai/dsh-agency-agents@0.1.43`
|
|
45
|
+
- `@michengai/dsh-im-connect@0.1.50`
|
|
46
|
+
- `@michengai/dsh-automation@0.1.44`
|
|
47
|
+
- `@michengai/dsh-btw@0.1.8`
|
|
48
|
+
- `@michengai/dsh-simplify@0.1.5`
|
|
49
|
+
- `@michengai/dsh-pua@0.3.13`
|
|
50
|
+
- `@michengai/dsh-code-review@0.1.2`
|
|
51
|
+
- `@michengai/dsh-codex-pet@0.1.6`
|
|
52
|
+
|
|
53
|
+
安装器使用这些精确版本执行安装,确保可复现。
|
|
54
|
+
|
|
7
55
|
## 1.1.10 - 2026-09-16
|
|
8
56
|
|
|
9
57
|
- 冷启动也能自动命名:独立挂上 `@michengai/dsh-codex-ui/session-title`,等 `sessionTitle` 与 `llm` 就绪后再占 first-prompt;卸载时回收提供方。
|
package/lib/client.js
CHANGED
|
@@ -1246,6 +1246,23 @@ window.__ModuleLoader__.load({
|
|
|
1246
1246
|
return parseChannelGroups(payload, fallbackLabel);
|
|
1247
1247
|
}
|
|
1248
1248
|
//#endregion
|
|
1249
|
+
//#region src/client/session-title-scroll.ts
|
|
1250
|
+
/** 会话行只展示标题第一行,避免换行把胶囊撑高。 */
|
|
1251
|
+
function sessionTitleLine(title) {
|
|
1252
|
+
return title.split(/\r?\n/)[0] ?? title;
|
|
1253
|
+
}
|
|
1254
|
+
/** 标题比可视槽多出来的像素;1px 内当作测量误差。 */
|
|
1255
|
+
function titleOverflowPx(scrollWidth, clientWidth) {
|
|
1256
|
+
const extra = Math.ceil(scrollWidth - clientWidth);
|
|
1257
|
+
return extra > 1 ? extra : 0;
|
|
1258
|
+
}
|
|
1259
|
+
const PX_PER_SECOND = 42;
|
|
1260
|
+
/** 按溢出长度估算单程时长,长标题更慢,避免一闪而过。 */
|
|
1261
|
+
function titleScrollDurationMs(overflowPx) {
|
|
1262
|
+
if (overflowPx <= 0) return 0;
|
|
1263
|
+
return Math.min(8e3, Math.max(1600, Math.round(overflowPx / PX_PER_SECOND * 1e3)));
|
|
1264
|
+
}
|
|
1265
|
+
//#endregion
|
|
1249
1266
|
//#region src/client/session-tree.tsx
|
|
1250
1267
|
function PinIcon() {
|
|
1251
1268
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pin, {
|
|
@@ -1416,7 +1433,58 @@ window.__ModuleLoader__.load({
|
|
|
1416
1433
|
});
|
|
1417
1434
|
return null;
|
|
1418
1435
|
}
|
|
1419
|
-
function
|
|
1436
|
+
function SessionTime({ time }) {
|
|
1437
|
+
if (time === void 0 || time === "") return null;
|
|
1438
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1439
|
+
className: "dcu-wb-session-time",
|
|
1440
|
+
children: time
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
function SessionRowTitle({ title }) {
|
|
1444
|
+
const text = sessionTitleLine(title);
|
|
1445
|
+
const wrapRef = (0, react.useRef)(null);
|
|
1446
|
+
const textRef = (0, react.useRef)(null);
|
|
1447
|
+
const [shift, setShift] = (0, react.useState)(0);
|
|
1448
|
+
(0, react.useLayoutEffect)(() => {
|
|
1449
|
+
const wrap = wrapRef.current;
|
|
1450
|
+
const inner = textRef.current;
|
|
1451
|
+
if (wrap === null || inner === null) return;
|
|
1452
|
+
const measure = () => {
|
|
1453
|
+
setShift(titleOverflowPx(inner.scrollWidth, wrap.clientWidth));
|
|
1454
|
+
};
|
|
1455
|
+
measure();
|
|
1456
|
+
let cancelled = false;
|
|
1457
|
+
const fonts = typeof document === "undefined" ? void 0 : document.fonts;
|
|
1458
|
+
if (fonts !== void 0) fonts.ready.then(() => {
|
|
1459
|
+
if (!cancelled) measure();
|
|
1460
|
+
});
|
|
1461
|
+
if (typeof ResizeObserver === "undefined") return () => {
|
|
1462
|
+
cancelled = true;
|
|
1463
|
+
};
|
|
1464
|
+
const observer = new ResizeObserver(measure);
|
|
1465
|
+
observer.observe(wrap);
|
|
1466
|
+
return () => {
|
|
1467
|
+
cancelled = true;
|
|
1468
|
+
observer.disconnect();
|
|
1469
|
+
};
|
|
1470
|
+
}, [text]);
|
|
1471
|
+
const style = shift > 0 ? {
|
|
1472
|
+
"--dcu-title-shift": `${shift}px`,
|
|
1473
|
+
"--dcu-title-duration": `${titleScrollDurationMs(shift)}ms`
|
|
1474
|
+
} : void 0;
|
|
1475
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1476
|
+
ref: wrapRef,
|
|
1477
|
+
className: "dcu-wb-session-title",
|
|
1478
|
+
"data-overflow": shift > 0 || void 0,
|
|
1479
|
+
style,
|
|
1480
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1481
|
+
ref: textRef,
|
|
1482
|
+
className: "dcu-wb-session-title-text",
|
|
1483
|
+
children: text
|
|
1484
|
+
})
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
function SessionRow({ id, title, selected, menuOpen, unread, running, pendingInteraction, t, menuItems, onOpen, onMenuChange, onSelectAction, onArchive, onHover, onLeave, onContextMenu, menuPoint, subtitle, flat, draggable, dropActive, onDragStart, onDragEnd, onDragOver, onDrop, time }) {
|
|
1420
1488
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1421
1489
|
"data-dcu-session": id,
|
|
1422
1490
|
className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${menuOpen ? " dcu-wb-menu-open" : ""}${dropActive === true ? " dcu-wb-drop" : ""}${flat === true ? " dcu-wb-session-flat" : ""}`,
|
|
@@ -1434,23 +1502,18 @@ window.__ModuleLoader__.load({
|
|
|
1434
1502
|
children: [
|
|
1435
1503
|
subtitle !== void 0 && subtitle !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1436
1504
|
className: "dcu-wb-session-copy",
|
|
1437
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1438
|
-
className: "dcu-wb-session-title",
|
|
1439
|
-
children: title.split(/\r?\n/)[0] ?? title
|
|
1440
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1505
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1441
1506
|
className: "dcu-wb-session-sub",
|
|
1442
1507
|
children: subtitle
|
|
1443
1508
|
})]
|
|
1444
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1445
|
-
className: "dcu-wb-session-title",
|
|
1446
|
-
children: title.split(/\r?\n/)[0] ?? title
|
|
1447
|
-
}),
|
|
1509
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title }),
|
|
1448
1510
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
|
|
1449
1511
|
pendingInteraction,
|
|
1450
1512
|
unread,
|
|
1451
1513
|
running,
|
|
1452
1514
|
t
|
|
1453
1515
|
}),
|
|
1516
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time }),
|
|
1454
1517
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1455
1518
|
className: "dcu-wb-quick-actions",
|
|
1456
1519
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -1915,13 +1978,84 @@ window.__ModuleLoader__.load({
|
|
|
1915
1978
|
top: rect.top
|
|
1916
1979
|
};
|
|
1917
1980
|
}
|
|
1918
|
-
|
|
1981
|
+
const HOUR = 3600;
|
|
1982
|
+
const DAY = HOUR * 24;
|
|
1983
|
+
const WEEK = DAY * 7;
|
|
1984
|
+
const MONTH = DAY * 30;
|
|
1985
|
+
const YEAR = DAY * 365;
|
|
1986
|
+
function formatRelativeTime(updatedAt, t, now, justNow) {
|
|
1987
|
+
const seconds = Math.max(0, Math.floor((now - updatedAt) / 1e3));
|
|
1988
|
+
if (seconds < 60) return t(justNow);
|
|
1989
|
+
if (seconds < HOUR) return t("time.minutes", { count: Math.floor(seconds / 60) });
|
|
1990
|
+
if (seconds < DAY) return t("time.hours", { count: Math.floor(seconds / HOUR) });
|
|
1991
|
+
if (seconds < WEEK) return t("time.days", { count: Math.floor(seconds / DAY) });
|
|
1992
|
+
if (seconds < MONTH) return t("time.weeks", { count: Math.floor(seconds / WEEK) });
|
|
1993
|
+
if (seconds < YEAR) return t("time.months", { count: Math.floor(seconds / MONTH) });
|
|
1994
|
+
return t("time.years", { count: Math.floor(seconds / YEAR) });
|
|
1995
|
+
}
|
|
1996
|
+
/** 悬停卡片右上角。分档与 ChatGPT `$wa` 一致;英文刚刚用 Just now。 */
|
|
1919
1997
|
function formatHoverTime(updatedAt, t, now = Date.now()) {
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
return
|
|
1998
|
+
return formatRelativeTime(updatedAt, t, now, "time.justNow");
|
|
1999
|
+
}
|
|
2000
|
+
/** 会话行右侧。分档相同;英文刚刚用 now,避免挤占标题。 */
|
|
2001
|
+
function formatCompactTime(updatedAt, t, now = Date.now()) {
|
|
2002
|
+
return formatRelativeTime(updatedAt, t, now, "time.justNowShort");
|
|
2003
|
+
}
|
|
2004
|
+
//#endregion
|
|
2005
|
+
//#region src/client/shared-now.ts
|
|
2006
|
+
const SHARED_NOW_INTERVAL_MS = 6e4;
|
|
2007
|
+
/** 对齐到下一个整档,避免「刚刚」在整分钟边界之后还多停将近一轮。 */
|
|
2008
|
+
function msUntilNextNowTick(now, intervalMs = SHARED_NOW_INTERVAL_MS) {
|
|
2009
|
+
const remainder = now % intervalMs;
|
|
2010
|
+
return remainder === 0 ? intervalMs : intervalMs - remainder;
|
|
2011
|
+
}
|
|
2012
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2013
|
+
let sharedNow = Date.now();
|
|
2014
|
+
let timeoutId = 0;
|
|
2015
|
+
let intervalId = 0;
|
|
2016
|
+
let cancelled = true;
|
|
2017
|
+
function publish(now) {
|
|
2018
|
+
sharedNow = now;
|
|
2019
|
+
for (const listener of listeners) listener();
|
|
2020
|
+
}
|
|
2021
|
+
function startClock() {
|
|
2022
|
+
cancelled = false;
|
|
2023
|
+
timeoutId = window.setTimeout(() => {
|
|
2024
|
+
if (cancelled) return;
|
|
2025
|
+
publish(Date.now());
|
|
2026
|
+
intervalId = window.setInterval(() => {
|
|
2027
|
+
publish(Date.now());
|
|
2028
|
+
}, SHARED_NOW_INTERVAL_MS);
|
|
2029
|
+
if (cancelled) {
|
|
2030
|
+
window.clearInterval(intervalId);
|
|
2031
|
+
intervalId = 0;
|
|
2032
|
+
}
|
|
2033
|
+
}, msUntilNextNowTick(Date.now()));
|
|
2034
|
+
}
|
|
2035
|
+
function stopClock() {
|
|
2036
|
+
cancelled = true;
|
|
2037
|
+
window.clearTimeout(timeoutId);
|
|
2038
|
+
window.clearInterval(intervalId);
|
|
2039
|
+
timeoutId = 0;
|
|
2040
|
+
intervalId = 0;
|
|
2041
|
+
}
|
|
2042
|
+
function subscribe(listener) {
|
|
2043
|
+
if (listeners.size === 0) {
|
|
2044
|
+
sharedNow = Date.now();
|
|
2045
|
+
startClock();
|
|
2046
|
+
}
|
|
2047
|
+
listeners.add(listener);
|
|
2048
|
+
return () => {
|
|
2049
|
+
listeners.delete(listener);
|
|
2050
|
+
if (listeners.size === 0) stopClock();
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
function getSnapshot() {
|
|
2054
|
+
return sharedNow;
|
|
2055
|
+
}
|
|
2056
|
+
/** 模块级当前时刻。几棵树挂着都只走一套定时器,每分钟刷新一次。 */
|
|
2057
|
+
function useSharedNow() {
|
|
2058
|
+
return (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1925
2059
|
}
|
|
1926
2060
|
//#endregion
|
|
1927
2061
|
//#region src/client/conversation-bubbles.ts
|
|
@@ -2451,6 +2585,18 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2451
2585
|
workspaceId
|
|
2452
2586
|
};
|
|
2453
2587
|
}
|
|
2588
|
+
/**
|
|
2589
|
+
* 空置顶没有项目行可自行计算落点,松手时 dragleave 又常把 relatedTarget 置空并清掉蓝线。
|
|
2590
|
+
* 只要这次 drop 发生在置顶区,空列表也必须把项目置顶。
|
|
2591
|
+
*/
|
|
2592
|
+
function resolvePinnedSectionDrop(draggedWorkspace, target, pinnedEmpty) {
|
|
2593
|
+
if (draggedWorkspace === void 0) return void 0;
|
|
2594
|
+
if (target?.zone === "pinned") return {
|
|
2595
|
+
id: draggedWorkspace,
|
|
2596
|
+
beforeId: target.beforeId
|
|
2597
|
+
};
|
|
2598
|
+
return pinnedEmpty ? { id: draggedWorkspace } : void 0;
|
|
2599
|
+
}
|
|
2454
2600
|
/** 按指定 id 顺序取出对应项;未出现在 ids 中的项丢弃。 */
|
|
2455
2601
|
function orderByIds(items, ids, idOf) {
|
|
2456
2602
|
const byId = new Map(items.map((item) => [idOf(item), item]));
|
|
@@ -2889,7 +3035,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2889
3035
|
}
|
|
2890
3036
|
const previewTitle = document.createElement("span");
|
|
2891
3037
|
previewTitle.className = "dcu-wb-drag-ghost-title";
|
|
2892
|
-
previewTitle.textContent = title
|
|
3038
|
+
previewTitle.textContent = sessionTitleLine(title);
|
|
2893
3039
|
preview.appendChild(previewTitle);
|
|
2894
3040
|
document.body.appendChild(preview);
|
|
2895
3041
|
preview.offsetWidth;
|
|
@@ -3004,11 +3150,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3004
3150
|
.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}
|
|
3005
3151
|
.dcu-wb-project-title{flex:1;font-weight:400;color:var(--dcu-sidebar-primary)}
|
|
3006
3152
|
.dcu-wb-session{position:relative;min-width:0;min-height:30px;gap:0;overflow:hidden;padding-left:30px;padding-right:28px}
|
|
3007
|
-
.dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}.dcu-wb-session-flat:has(.dcu-wb-running),.dcu-wb-session-top:has(.dcu-wb-running){padding-left:30px}
|
|
3153
|
+
.dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-title-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (prefers-reduced-motion:no-preference){.dcu-wb-session:hover .dcu-wb-session-title[data-overflow] .dcu-wb-session-title-text,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-session-title[data-overflow] .dcu-wb-session-title-text{display:inline-block;width:max-content;max-width:none;overflow:visible;text-overflow:clip;animation:dcu-wb-title-scroll var(--dcu-title-duration,2.4s) linear 320ms infinite alternate}}@keyframes dcu-wb-title-scroll{0%,18%{transform:translateX(0)}82%,100%{transform:translateX(calc(-1 * var(--dcu-title-shift,0px)))}}.dcu-wb-session-time{position:absolute;right:8px;top:50%;transform:translateY(-50%);color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:18px;font-weight:400;font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none}.dcu-wb-session:has(.dcu-wb-session-time){padding-right:64px}.dcu-wb-session:has(.dcu-wb-unread) .dcu-wb-session-time{right:22px}.dcu-wb-session:has(.dcu-wb-unread):has(.dcu-wb-session-time){padding-right:78px}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}.dcu-wb-session-flat:has(.dcu-wb-running),.dcu-wb-session-top:has(.dcu-wb-running){padding-left:30px}
|
|
3008
3154
|
.dcu-wb-actions{display:none;align-items:center;gap:8px;flex:none}
|
|
3009
3155
|
.dcu-wb-quick-actions{position:absolute;right:8px;top:50%;display:flex;align-items:center;gap:2px;opacity:0;pointer-events:none;transform:translateY(-50%);background:var(--dcu-sidebar-hover);border-radius:6px}
|
|
3010
3156
|
.dcu-wb-project-head:hover .dcu-wb-actions,.dcu-wb-project-head.dcu-wb-menu-open .dcu-wb-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-actions{display:flex}
|
|
3011
|
-
.dcu-wb-session:hover .dcu-wb-quick-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-quick-actions{opacity:1;pointer-events:auto}.dcu-wb-session:hover .dcu-wb-pending,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-pending,.dcu-wb-session:hover .dcu-wb-unread,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-unread{visibility:hidden}
|
|
3157
|
+
.dcu-wb-session:hover .dcu-wb-quick-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-quick-actions{opacity:1;pointer-events:auto}.dcu-wb-session:hover .dcu-wb-pending,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-pending,.dcu-wb-session:hover .dcu-wb-unread,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-unread,.dcu-wb-session:hover .dcu-wb-session-time,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-session-time{visibility:hidden}.dcu-wb-session:has(.dcu-wb-pending) .dcu-wb-session-time{display:none}
|
|
3012
3158
|
.dcu-wb-more{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:4px;padding:0;background:transparent;color:var(--dcu-sidebar-tertiary);cursor:pointer}
|
|
3013
3159
|
.dcu-wb-more:hover{color:var(--dcu-sidebar-primary)}
|
|
3014
3160
|
.dcu-wb-context-anchor{opacity:0;pointer-events:none}
|
|
@@ -3079,6 +3225,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3079
3225
|
}
|
|
3080
3226
|
function CodexWorkspaceTree({ wide, useSessions, useSessionPendingInteraction, useWorkspaces, t, archiveSession, deleteSession, deleteWorkspace, forkSession, insertSessionBefore, insertWorkspaceBefore, moveSession, openPath, openSession, renameSession, renameWorkspace, startSession, canDeleteSession }) {
|
|
3081
3227
|
const sessions = useSessions((state) => state);
|
|
3228
|
+
const now = useSharedNow();
|
|
3082
3229
|
const pendingInteractions = (useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state);
|
|
3083
3230
|
const workspaces = useWorkspaces((state) => state);
|
|
3084
3231
|
const baselinesReady = workspaceBaselinesReady(workspaces, sessions);
|
|
@@ -3939,23 +4086,21 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3939
4086
|
project: workspace.title,
|
|
3940
4087
|
path,
|
|
3941
4088
|
branch,
|
|
3942
|
-
time: formatHoverTime(session.updatedAt, t),
|
|
4089
|
+
time: formatHoverTime(session.updatedAt, t, now),
|
|
3943
4090
|
left: box.left,
|
|
3944
4091
|
top: box.top
|
|
3945
4092
|
});
|
|
3946
4093
|
},
|
|
3947
4094
|
onMouseLeave: hideTip,
|
|
3948
4095
|
children: [
|
|
3949
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3950
|
-
className: "dcu-wb-session-title",
|
|
3951
|
-
children: session.displayTitle.split(/\r?\n/)[0] ?? session.displayTitle
|
|
3952
|
-
}),
|
|
4096
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title: session.displayTitle }),
|
|
3953
4097
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
|
|
3954
4098
|
pendingInteraction,
|
|
3955
4099
|
unread: unreadSessionIds.includes(id),
|
|
3956
4100
|
running: session.running === true,
|
|
3957
4101
|
t
|
|
3958
4102
|
}),
|
|
4103
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time: formatCompactTime(session.updatedAt, t, now) }),
|
|
3959
4104
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3960
4105
|
className: "dcu-wb-quick-actions",
|
|
3961
4106
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -4492,10 +4637,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4492
4637
|
const target = workspaceDropTargetRef.current;
|
|
4493
4638
|
setWorkspaceDragId(void 0);
|
|
4494
4639
|
setWorkspaceDropTarget(void 0);
|
|
4495
|
-
|
|
4640
|
+
const drop = resolvePinnedSectionDrop(draggedWorkspace, target, pinnedGroups.length === 0);
|
|
4641
|
+
if (drop !== void 0) pinWorkspaceAt(drop.id, drop.beforeId);
|
|
4496
4642
|
},
|
|
4497
4643
|
onDragLeave: (event) => {
|
|
4498
|
-
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
4644
|
+
if (!(event.relatedTarget instanceof Node) || event.currentTarget.contains(event.relatedTarget)) return;
|
|
4499
4645
|
setWorkspaceDropTarget(void 0);
|
|
4500
4646
|
},
|
|
4501
4647
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4541,10 +4687,36 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4541
4687
|
zone: "pinned",
|
|
4542
4688
|
beforeId: void 0
|
|
4543
4689
|
});
|
|
4690
|
+
},
|
|
4691
|
+
onDrop: (event) => {
|
|
4692
|
+
event.preventDefault();
|
|
4693
|
+
event.stopPropagation();
|
|
4694
|
+
const draggedWorkspace = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
|
|
4695
|
+
setWorkspaceDragId(void 0);
|
|
4696
|
+
setWorkspaceDropTarget(void 0);
|
|
4697
|
+
if (draggedWorkspace !== void 0) pinWorkspaceAt(draggedWorkspace);
|
|
4544
4698
|
}
|
|
4545
4699
|
}),
|
|
4546
4700
|
pinnedGroups.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4547
4701
|
className: "dcu-wb-empty",
|
|
4702
|
+
onDragOver: (event) => {
|
|
4703
|
+
if (!pinDragActive) return;
|
|
4704
|
+
event.preventDefault();
|
|
4705
|
+
event.stopPropagation();
|
|
4706
|
+
event.dataTransfer.dropEffect = "move";
|
|
4707
|
+
setWorkspaceDropTarget({
|
|
4708
|
+
zone: "pinned",
|
|
4709
|
+
beforeId: void 0
|
|
4710
|
+
});
|
|
4711
|
+
},
|
|
4712
|
+
onDrop: (event) => {
|
|
4713
|
+
event.preventDefault();
|
|
4714
|
+
event.stopPropagation();
|
|
4715
|
+
const draggedWorkspace = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
|
|
4716
|
+
setWorkspaceDragId(void 0);
|
|
4717
|
+
setWorkspaceDropTarget(void 0);
|
|
4718
|
+
if (draggedWorkspace !== void 0) pinWorkspaceAt(draggedWorkspace);
|
|
4719
|
+
},
|
|
4548
4720
|
children: t("workspace.pinnedEmpty")
|
|
4549
4721
|
}),
|
|
4550
4722
|
pinnedGroups.map((workspace) => renderGroup(workspace, "pinned")),
|
|
@@ -4685,6 +4857,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4685
4857
|
unread,
|
|
4686
4858
|
running: session.running === true,
|
|
4687
4859
|
pendingInteraction,
|
|
4860
|
+
time: formatCompactTime(session.updatedAt, t, now),
|
|
4688
4861
|
t,
|
|
4689
4862
|
menuItems: sessionMenu(id, session.cwd),
|
|
4690
4863
|
draggable: true,
|
|
@@ -4730,7 +4903,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4730
4903
|
kind: "session",
|
|
4731
4904
|
id,
|
|
4732
4905
|
title,
|
|
4733
|
-
time: formatHoverTime(session.updatedAt, t),
|
|
4906
|
+
time: formatHoverTime(session.updatedAt, t, now),
|
|
4734
4907
|
left: box.left,
|
|
4735
4908
|
top: box.top
|
|
4736
4909
|
});
|
|
@@ -5379,6 +5552,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5379
5552
|
}
|
|
5380
5553
|
function ChannelBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, menu, setMenu }) {
|
|
5381
5554
|
const sessions = useSessions((state) => state);
|
|
5555
|
+
const now = useSharedNow();
|
|
5382
5556
|
const workspaces = useWorkspaces?.((state) => state);
|
|
5383
5557
|
const pendingInteractions = (useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state);
|
|
5384
5558
|
const [groups, setGroups] = (0, react.useState)([]);
|
|
@@ -5498,6 +5672,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5498
5672
|
unread,
|
|
5499
5673
|
running,
|
|
5500
5674
|
pendingInteraction,
|
|
5675
|
+
time: updatedAt === void 0 ? void 0 : formatCompactTime(updatedAt, t, now),
|
|
5501
5676
|
t,
|
|
5502
5677
|
menuItems: sessionMenuItems(t, {
|
|
5503
5678
|
unread,
|
|
@@ -5523,7 +5698,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5523
5698
|
showTip({
|
|
5524
5699
|
title,
|
|
5525
5700
|
project: label,
|
|
5526
|
-
time: updatedAt === void 0 ? void 0 : formatHoverTime(updatedAt, t),
|
|
5701
|
+
time: updatedAt === void 0 ? void 0 : formatHoverTime(updatedAt, t, now),
|
|
5527
5702
|
left: box.left,
|
|
5528
5703
|
top: box.top
|
|
5529
5704
|
});
|
|
@@ -5653,6 +5828,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5653
5828
|
}
|
|
5654
5829
|
function ScheduleBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, openTaskSettings, menu, setMenu }) {
|
|
5655
5830
|
const sessions = useSessions((state) => state);
|
|
5831
|
+
const now = useSharedNow();
|
|
5656
5832
|
const pendingInteractions = (useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state);
|
|
5657
5833
|
const workspaces = useWorkspaces((state) => state);
|
|
5658
5834
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(browserStorage(), SCHEDULE_EXPANSION_STORAGE_KEY));
|
|
@@ -5802,6 +5978,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5802
5978
|
unread,
|
|
5803
5979
|
running: session.running,
|
|
5804
5980
|
pendingInteraction,
|
|
5981
|
+
time: session.updatedAt === void 0 ? void 0 : formatCompactTime(session.updatedAt, t, now),
|
|
5805
5982
|
t,
|
|
5806
5983
|
menuItems: sessionMenuItems(t, {
|
|
5807
5984
|
unread,
|
|
@@ -5827,7 +6004,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5827
6004
|
showTip({
|
|
5828
6005
|
title,
|
|
5829
6006
|
project: group.label,
|
|
5830
|
-
time: session.updatedAt === void 0 ? void 0 : formatHoverTime(session.updatedAt, t),
|
|
6007
|
+
time: session.updatedAt === void 0 ? void 0 : formatHoverTime(session.updatedAt, t, now),
|
|
5831
6008
|
left: box.left,
|
|
5832
6009
|
top: box.top
|
|
5833
6010
|
});
|
|
@@ -6449,6 +6626,8 @@ body[data-ds-dark-theme] [data-conversation-scroll] [data-trigger-menu]{backgrou
|
|
|
6449
6626
|
//#region src/client/CodexSidebar.tsx
|
|
6450
6627
|
const subscribeEmptyCompanionTabs = () => () => {};
|
|
6451
6628
|
const getEmptyCompanionTabs = () => EMPTY_COMPANION_TABS;
|
|
6629
|
+
const emptyFooterActions = [];
|
|
6630
|
+
const getEmptyFooterActions = () => emptyFooterActions;
|
|
6452
6631
|
const SIDEBAR_COLLAPSE_SETTLE_MS = 500;
|
|
6453
6632
|
const SIDEBAR_EXPANSION_STORAGE_KEY = "dsh-codex-ui.sidebar-expansion.v1";
|
|
6454
6633
|
const EXTENSIONS_EXPANSION_KEY = "extensions";
|
|
@@ -6833,8 +7012,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6833
7012
|
});
|
|
6834
7013
|
});
|
|
6835
7014
|
/** Codex 风格的 DSH 侧栏,只替换导航外观,项目浏览和设置仍由 DSH 官方组件提供。 */
|
|
6836
|
-
function CodexSidebar({ globalPanels, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, canDeleteSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
|
|
7015
|
+
function CodexSidebar({ globalPanels, footerActions, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, canDeleteSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
|
|
6837
7016
|
const panels = (0, react.useSyncExternalStore)(globalPanels?.subscribe ?? subscribeEmptyCompanionTabs, globalPanels?.getSnapshot ?? getEmptyPanels, globalPanels?.getSnapshot ?? getEmptyPanels);
|
|
7017
|
+
const visibleFooterActions = (0, react.useSyncExternalStore)(footerActions?.subscribe ?? subscribeEmptyCompanionTabs, footerActions?.getSnapshot ?? getEmptyFooterActions, footerActions?.getSnapshot ?? getEmptyFooterActions);
|
|
6838
7018
|
const activePanelId = usePanelInfo((info) => info.activePanelId);
|
|
6839
7019
|
const panelButtons = (wide) => selectPanel === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GlobalPanelButtons, {
|
|
6840
7020
|
panels,
|
|
@@ -7325,7 +7505,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7325
7505
|
className: "dcu-foot",
|
|
7326
7506
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7327
7507
|
className: "dcu-footer-actions",
|
|
7328
|
-
children: renderSlot("sidebar.footer.action", { wide: !visualCompact })
|
|
7508
|
+
children: footerActions === void 0 ? renderSlot("sidebar.footer.action", { wide: !visualCompact }) : visibleFooterActions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlot("sidebar.footer.action", { wide: !visualCompact }, { only: action.id }) }, action.id))
|
|
7329
7509
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7330
7510
|
ref: settingsSeat,
|
|
7331
7511
|
className: "dcu-settings-seat",
|
|
@@ -8242,9 +8422,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8242
8422
|
"turns.untitled": "未命名提问",
|
|
8243
8423
|
"turns.jump": "跳转到第 {index} 轮:{summary}",
|
|
8244
8424
|
"time.justNow": "刚刚",
|
|
8425
|
+
"time.justNowShort": "刚刚",
|
|
8245
8426
|
"time.minutes": "{count}分",
|
|
8246
8427
|
"time.hours": "{count}小时",
|
|
8247
8428
|
"time.days": "{count}天",
|
|
8429
|
+
"time.weeks": "{count}周",
|
|
8430
|
+
"time.months": "{count}个月",
|
|
8431
|
+
"time.years": "{count}年",
|
|
8248
8432
|
"errors.unauthorized": "请先登录 DSH,再重试。",
|
|
8249
8433
|
"errors.forbidden": "请求被安全检查拒绝,请从可信的 DSH 地址重试。",
|
|
8250
8434
|
"errors.serviceUnavailable": "服务暂不可用,请稍后重试。",
|
|
@@ -8526,9 +8710,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8526
8710
|
"turns.untitled": "Untitled prompt",
|
|
8527
8711
|
"turns.jump": "Jump to turn {index}: {summary}",
|
|
8528
8712
|
"time.justNow": "Just now",
|
|
8713
|
+
"time.justNowShort": "now",
|
|
8529
8714
|
"time.minutes": "{count}m",
|
|
8530
8715
|
"time.hours": "{count}h",
|
|
8531
8716
|
"time.days": "{count}d",
|
|
8717
|
+
"time.weeks": "{count}w",
|
|
8718
|
+
"time.months": "{count}mo",
|
|
8719
|
+
"time.years": "{count}y",
|
|
8532
8720
|
"errors.unauthorized": "Sign in to DSH, then try again.",
|
|
8533
8721
|
"errors.forbidden": "The security check rejected this request. Try again from a trusted DSH address.",
|
|
8534
8722
|
"errors.serviceUnavailable": "The service is unavailable. Try again later.",
|
|
@@ -8550,6 +8738,38 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8550
8738
|
"sessionTitle.type.research": "Research",
|
|
8551
8739
|
"meta.locale": "en-US"
|
|
8552
8740
|
};
|
|
8741
|
+
const HIDDEN_FOOTER_ACTION_IDS = /* @__PURE__ */ new Set(["context-overview"]);
|
|
8742
|
+
function visibleFooterActions(slots) {
|
|
8743
|
+
return slots.entriesOfSlot("sidebar.footer.action").flatMap(({ options }) => {
|
|
8744
|
+
const id = options.id;
|
|
8745
|
+
if (id === void 0 || HIDDEN_FOOTER_ACTION_IDS.has(id)) return [];
|
|
8746
|
+
return [{
|
|
8747
|
+
id,
|
|
8748
|
+
order: options.order ?? 0
|
|
8749
|
+
}];
|
|
8750
|
+
}).sort((left, right) => left.order - right.order);
|
|
8751
|
+
}
|
|
8752
|
+
function sameFooterActions(left, right) {
|
|
8753
|
+
return left.length === right.length && left.every((action, index) => {
|
|
8754
|
+
const previous = right[index];
|
|
8755
|
+
return previous !== void 0 && action.id === previous.id && action.order === previous.order;
|
|
8756
|
+
});
|
|
8757
|
+
}
|
|
8758
|
+
/** 给 React useSyncExternalStore 用的底部动作快照;按 slot id 过滤,不靠 DOM class。 */
|
|
8759
|
+
function createFooterActionSource(slots) {
|
|
8760
|
+
let cached = [];
|
|
8761
|
+
return {
|
|
8762
|
+
getSnapshot() {
|
|
8763
|
+
const next = visibleFooterActions(slots);
|
|
8764
|
+
if (sameFooterActions(next, cached)) return cached;
|
|
8765
|
+
cached = next;
|
|
8766
|
+
return cached;
|
|
8767
|
+
},
|
|
8768
|
+
subscribe(listener) {
|
|
8769
|
+
return slots.subscribe("sidebar.footer.action", listener);
|
|
8770
|
+
}
|
|
8771
|
+
};
|
|
8772
|
+
}
|
|
8553
8773
|
//#endregion
|
|
8554
8774
|
//#region src/client/host-open-path.ts
|
|
8555
8775
|
const OPEN_IN_EXPLORER_ENDPOINT = CODEX_UI_API_ENDPOINTS.openInExplorer;
|
|
@@ -8985,10 +9205,10 @@ html[data-dsh-native-backdrop=mica] #root :is([class$="_centerCol"],[class$="_de
|
|
|
8985
9205
|
html[data-dsh-native-backdrop=mica] :is(.dcu-root,.dcu-settings-nav){background:rgba(255,255,255,.18)}
|
|
8986
9206
|
html[data-dsh-native-backdrop=mica] body[data-ds-dark-theme] :is(.dcu-root,.dcu-settings-nav){background:rgba(20,23,22,.18)}
|
|
8987
9207
|
/* 会话折叠容器显式设了 visible,必须同时隐藏隔离分支的后代,避免穿透透明设置页。 */
|
|
8988
|
-
html[data-dsh-native-backdrop=mica]
|
|
9208
|
+
html[data-dsh-native-backdrop=mica] body:has(.dcu-settings-page) .dcu-root :is([inert],[inert] *){visibility:hidden!important}
|
|
8989
9209
|
/* 同步隐藏本设置页隔离的外部 portal,保留引导模态及其他组件自己的 inert 语义。 */
|
|
8990
9210
|
body:has(.dcu-settings-page) :is([data-dcu-settings-isolated],[data-dcu-settings-isolated] *){visibility:hidden!important}
|
|
8991
|
-
html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-backdrop=mica]
|
|
9211
|
+
html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-backdrop=mica] body:has(.dcu-settings-page) .dcu-root{background:transparent}
|
|
8992
9212
|
|
|
8993
9213
|
.dcu-settings-inner:has(.dcu-usage-section){height:100%;display:flex;flex-direction:column;padding-bottom:0}
|
|
8994
9214
|
.dcu-settings-inner:has(.dcu-usage-section)>.dcu-settings-heading{display:none}
|
|
@@ -9233,7 +9453,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9233
9453
|
restartActionLabel: t("settings.reconnect"),
|
|
9234
9454
|
onReconnect: reconnect
|
|
9235
9455
|
}),
|
|
9236
|
-
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9456
|
+
(0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9237
9457
|
ref: page,
|
|
9238
9458
|
className: "dcu-settings-page",
|
|
9239
9459
|
"data-dcu-settings-page": true,
|
|
@@ -9325,8 +9545,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9325
9545
|
}), active !== void 0 && renderSlot("settings.section", { close }, { only: active.id })]
|
|
9326
9546
|
})
|
|
9327
9547
|
})]
|
|
9328
|
-
}),
|
|
9329
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9548
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9330
9549
|
ref: onboardingRoot,
|
|
9331
9550
|
style: { display: "contents" },
|
|
9332
9551
|
children: step !== void 0 && renderSlot("settings.onboarding", {
|
|
@@ -9336,7 +9555,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9336
9555
|
},
|
|
9337
9556
|
openSection
|
|
9338
9557
|
}, { only: step.id })
|
|
9339
|
-
})
|
|
9558
|
+
})] }), document.body)
|
|
9340
9559
|
] });
|
|
9341
9560
|
}
|
|
9342
9561
|
/** 每条偏好仍由原插件渲染和保存,只为公共条目添加可扩展的分组容器。 */
|
|
@@ -10292,6 +10511,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10292
10511
|
});
|
|
10293
10512
|
const companionSlots = createCompanionTabSource(ctx.slots);
|
|
10294
10513
|
const globalPanels = createGlobalPanelSource(ctx.slots, ctx.locale);
|
|
10514
|
+
const footerActions = createFooterActionSource(ctx.slots);
|
|
10295
10515
|
ctx.slots.inject("sidebar", () => ctx.slots.register({
|
|
10296
10516
|
name: "sidebar",
|
|
10297
10517
|
registrant: "michengai-codex-ui",
|
|
@@ -10347,6 +10567,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10347
10567
|
openPath,
|
|
10348
10568
|
companionSlots,
|
|
10349
10569
|
globalPanels,
|
|
10570
|
+
footerActions,
|
|
10350
10571
|
selectPanel: (id) => {
|
|
10351
10572
|
selectGlobalPanel(ctx.layout, id);
|
|
10352
10573
|
}
|
|
@@ -259,9 +259,13 @@ const zh = {
|
|
|
259
259
|
"turns.untitled": "未命名提问",
|
|
260
260
|
"turns.jump": "跳转到第 {index} 轮:{summary}",
|
|
261
261
|
"time.justNow": "刚刚",
|
|
262
|
+
"time.justNowShort": "刚刚",
|
|
262
263
|
"time.minutes": "{count}分",
|
|
263
264
|
"time.hours": "{count}小时",
|
|
264
265
|
"time.days": "{count}天",
|
|
266
|
+
"time.weeks": "{count}周",
|
|
267
|
+
"time.months": "{count}个月",
|
|
268
|
+
"time.years": "{count}年",
|
|
265
269
|
"errors.unauthorized": "请先登录 DSH,再重试。",
|
|
266
270
|
"errors.forbidden": "请求被安全检查拒绝,请从可信的 DSH 地址重试。",
|
|
267
271
|
"errors.serviceUnavailable": "服务暂不可用,请稍后重试。",
|
|
@@ -543,9 +547,13 @@ const en = {
|
|
|
543
547
|
"turns.untitled": "Untitled prompt",
|
|
544
548
|
"turns.jump": "Jump to turn {index}: {summary}",
|
|
545
549
|
"time.justNow": "Just now",
|
|
550
|
+
"time.justNowShort": "now",
|
|
546
551
|
"time.minutes": "{count}m",
|
|
547
552
|
"time.hours": "{count}h",
|
|
548
553
|
"time.days": "{count}d",
|
|
554
|
+
"time.weeks": "{count}w",
|
|
555
|
+
"time.months": "{count}mo",
|
|
556
|
+
"time.years": "{count}y",
|
|
549
557
|
"errors.unauthorized": "Sign in to DSH, then try again.",
|
|
550
558
|
"errors.forbidden": "The security check rejected this request. Try again from a trusted DSH address.",
|
|
551
559
|
"errors.serviceUnavailable": "The service is unavailable. Try again later.",
|