@deepseek-ai/dsh-client-ui-layout 0.1.6-alpha.2 → 0.1.7-alpha.2
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/README.i18n.yaml +2 -2
- package/README.md +6 -2
- package/README.zh.md +6 -2
- package/lib/client.js +81 -8
- package/lib/types/client/AppFrame.d.ts +1 -1
- package/lib/types/client/index.d.ts +19 -2
- package/lib/types/client/theme-presenter.d.ts +6 -4
- package/package.json +10 -10
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-layout/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: b26b182f5ea2c727411910cc5f85819b9dfbcb2c
|
|
6
|
+
README.zh.md: 58ef066ab05389898dc912500cd6b37f1a07824d
|
package/README.md
CHANGED
|
@@ -29,6 +29,10 @@ The root slot composes the sidebar, main content, and right column. The sidebar
|
|
|
29
29
|
|
|
30
30
|
Global panels occupy the root-scoped `main` keyed slot; `conversation` is the reserved key for the Conversation. `ctx.layout.selectPanel(id)` selects a registered panel, and `null` selects the Conversation without changing the current Session. No global panel is registered by the shipped composition.
|
|
31
31
|
|
|
32
|
+
### Window-chrome seat
|
|
33
|
+
|
|
34
|
+
On macOS desktop (`html[data-platform='darwin']`, set only by the desktop preload) a collapsed sidebar hides its column entirely instead of keeping the rail, and the frame mounts the single root-scoped `shell.leading` seat at its top-left — beside the hiddenInset traffic lights, over every main panel; ui-sidebar occupies it with the reopen and New Session controls. While the seat is mounted the frame publishes `--dsh-frame-leading-clearance`, the inline band the window chrome occupies measured from the frame's left edge; a main panel whose content reaches the top-left corner pads by it so nothing lands under the lights or the controls. The frame also always publishes `--dsh-frame-top-clearance` (48px) on the root element, the constant step below the window's top strip; entry pages in the main panel (plugin manager and similar, not the conversation) pad their top by it, and overlay primitives (portal menus, bottom-anchored overlays, the settings panel) keep it as their top viewport margin — the root-element home lets overlays portalled to `document.body` read it too. The full-width window drag band is 52px; while the Conversation is selected and its header shows the view tab strip, the band deepens to the 76px header block (title row plus tab strip), so blank header space drags while header controls stay clickable.
|
|
35
|
+
|
|
32
36
|
Windows Electron's `data-windows-titlebar` marker reserves the caption height above all columns and removes the collapsed sidebar rail. Only the content area's top-left corner has a 16px radius; the other corners and the internal divider remain square. The frame publishes `--dsh-windows-content-radius` and `--dsh-windows-sidebar-width` for ui-sidebar-right's fullscreen corner and sidebar clearance. Ordinary Web documents do not receive the marker; macOS retains its separate layout.
|
|
33
37
|
|
|
34
38
|
### Theme presentation
|
|
@@ -45,7 +49,7 @@ The presenter consumes resolved theme snapshots and projects them onto the docum
|
|
|
45
49
|
|
|
46
50
|
`selectPanel(id)` checks the live `main` registry before changing selection; an absent key throws and leaves the current panel intact. `beginNavigation()` returns an abort signal for an asynchronous UI navigation. A later call, a valid panel selection (including repeated selection), or layout disposal aborts that signal without cancelling underlying Session creation. Consumers check the signal before committing navigation or moving drafts.
|
|
47
51
|
|
|
48
|
-
One registration declares
|
|
52
|
+
One registration declares five child slots and binds `ctx.layout` methods `selectPanel`, `toggleSidebar`, `openRightbar(track, fullscreen)`, and `closeRightbar`. One root store separates `panelInfo` selection from `layoutInfo` measurements, width preferences, and presentation reports. `usePanelInfo` subscribes to the stable selection object; AppFrame subscribes to the stable layout object. The `rightbar` owner supplies actual `width`, `viewportWidth`, and normal-presentation eligibility `canShow`; insufficient room causes a deterministic close, never automatic reopening on widening. Fullscreen hides the width handle without releasing a track the occupant retains. AppFrame keeps the column containers mounted. The right column's root controller renders `rightbar.session` through `SessionProvider` only while the Conversation is selected; its unmount report releases the track. The independent title component uses the selected Session title only while the Conversation is visible, with the build-configured product title or localized `common.brand.localBuild` as its fallback; locale revisions update that fallback. The theme presenter is a second effect: pure DOM writes from resolved snapshots — initial state through the getter once, then event-driven only, with no React path. It applies palette, font-size, and token variables before measuring the rendered background as the single color authority. Fullscreen presentation suppresses grid and handle transitions; its occupant reports the new columns only after covering the frame. Fullscreen exit keeps transitions suppressed while the frame installs its destination geometry: close removes the right track, and restore retains it. Subsequent normal geometry actions restore ordinary transitions.
|
|
49
53
|
|
|
50
54
|
</details>
|
|
51
55
|
|
|
@@ -82,7 +86,7 @@ These limits define the current layout behavior. They are current package constr
|
|
|
82
86
|
|
|
83
87
|
- **Panel geometry is transient** — reload restores the sidebar default and the right panel hidden; each dragged width is one frame-wide preference, not a per-Session fact.
|
|
84
88
|
- **Extremely narrow windows** — after the right panel closes, the center may still fall below 400px; the left 56px rail remains.
|
|
85
|
-
- **Track and panel travel on one shared curve** — the frame
|
|
89
|
+
- **Track and panel travel on one shared curve only while animating** — during a discrete open/close the frame sets `data-animating` and its track transition and the occupant's slide read the same duration and easing variables; an occupant that used its own would detach the panel's edge from the conversation's while squeezing. Drags and instant presentation switches run transition-free, so the curve does not cover them.
|
|
86
90
|
- **No scroll anchoring during squeeze reflow** — layout changes may move the reader's viewport.
|
|
87
91
|
|
|
88
92
|
<a id="dev-note"></a>
|
package/README.zh.md
CHANGED
|
@@ -29,6 +29,10 @@ kind: "package-reference"
|
|
|
29
29
|
|
|
30
30
|
全局面板占据 root 作用域的 `main` keyed slot;`conversation` 是为会话界面保留的 key。`ctx.layout.selectPanel(id)` 选中已注册面板,`null` 则选中会话界面,但不改变当前会话。默认组合不注册任何全局面板。
|
|
31
31
|
|
|
32
|
+
### 窗口 chrome 座
|
|
33
|
+
|
|
34
|
+
在 macOS 桌面(`html[data-platform='darwin']`,仅由桌面 preload 设置)下,收起的侧边栏整列隐藏而非保留控制栏,框架在左上角挂载 root 作用域的单一 `shell.leading` 座——位于 hiddenInset 红绿灯旁,覆盖所有主面板;ui-sidebar 以重新打开与 New Session 控件占据该座。座挂载期间框架发布 `--dsh-frame-leading-clearance`:窗口 chrome 占据的行内带宽,自框架左边缘起量;内容抵达左上角的主面板以它做内边距,避免落在红绿灯或控件之下。框架还始终在根元素上发布 `--dsh-frame-top-clearance`(48px):窗口顶带之下的固定下沉量;主面板中的入口型页面(插件管理器等类似页面,非对话)以它做顶部内边距,浮层原语(portal 菜单、底部锚定浮层、设置面板)以它做视口顶部安全边距——放在根元素上让 portal 到 document.body 的浮层也能读到。全宽窗口拖拽带为 52px;选中会话界面且其 header 显示视图 tab 条时,加深至 76px 的 header 块(标题行加 tab 条),header 空白处可拖拽,控件保持可点。
|
|
35
|
+
|
|
32
36
|
Windows Electron 的 `data-windows-titlebar` 标记在所有列上方预留顶栏高度,并移除收起后的侧栏轨道。内容区仅左上角保留 16px 圆角,其余角和内部交界处保持直角。框架发布 `--dsh-windows-content-radius` 和 `--dsh-windows-sidebar-width`,供 ui-sidebar-right 的全屏圆角及侧栏避让使用。普通 Web 文档不会获得该标记;macOS 保留其独立布局。
|
|
33
37
|
|
|
34
38
|
### 主题呈现
|
|
@@ -45,7 +49,7 @@ Windows Electron 的 `data-windows-titlebar` 标记在所有列上方预留顶
|
|
|
45
49
|
|
|
46
50
|
`selectPanel(id)` 在改变选中态前检查实时 `main` 注册表;缺失的 key 会抛错并保留当前面板。`beginNavigation()` 为异步 UI 导航返回 abort signal。后续调用、有效面板选择(包括重复选择)或布局释放会中止该 signal,但不取消底层会话创建。消费方在提交导航或搬移草稿前检查 signal。
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
一次注册声明五个子 slot,并绑定 `ctx.layout` 的 `selectPanel`、`toggleSidebar`、`openRightbar(track, fullscreen)` 与 `closeRightbar`。同一个 root 存储把 `panelInfo` 选中态与 `layoutInfo` 测量、宽度偏好、呈现报告分开。`usePanelInfo` 订阅引用稳定的选中态对象,AppFrame 订阅引用稳定的布局对象。`rightbar` owner 提供实际 `width`、`viewportWidth`,以及表示能否以普通模式呈现的 `canShow`;占用方在空间不足时执行确定性的收起,变宽不自行重新展开。全屏隐藏宽度手柄,但不自行释放占用方要求保留的轨道。AppFrame 保持各列容器挂载。右栏的 root 控制器仅在选中会话界面时,经 `SessionProvider` 渲染 `rightbar.session`;内容卸载时的报告释放轨道。独立的标题组件仅在会话界面可见时使用所选会话标题,以构建配置的产品标题或本地化 `common.brand.localBuild` 为回退值;语言变化会更新该回退值。主题呈现器是第二个 effect:从解析后的快照做纯 DOM 写入——初始状态经 getter 读取一次,此后仅事件驱动,不经过 React。它先应用调色板、字号与 token 变量,再把渲染出的背景测量为唯一的颜色依据。全屏呈现禁用网格和手柄过渡;占用方完全覆盖框架后才报告新的列布局。退出全屏时,框架先保持无过渡并安装目标布局:关闭移除右轨道,恢复保留右轨道。后续普通几何操作恢复正常过渡。
|
|
49
53
|
|
|
50
54
|
</details>
|
|
51
55
|
|
|
@@ -82,7 +86,7 @@ Windows Electron 的 `data-windows-titlebar` 标记在所有列上方预留顶
|
|
|
82
86
|
|
|
83
87
|
- **面板几何是瞬时状态**——重新加载会恢复侧栏默认值并隐藏右侧面板;拖动设置的宽度是整个框架共用的一份偏好,而非每个会话各自的属性。
|
|
84
88
|
- **极窄窗口**——右侧面板关闭后,中栏仍可能小于 400px;左侧 56px 控制栏仍会保留。
|
|
85
|
-
-
|
|
89
|
+
- **轨道与面板仅在动画期间沿同一条曲线运动**——离散开合时框架设置 `data-animating`,其轨道过渡和占用方的滑入读取同一组时长与缓动变量;占用方若自用一套,挤压时面板边缘就会与会话界面的边缘脱开。拖拽和即时呈现切换不带过渡,因此该曲线不覆盖它们。
|
|
86
90
|
- **挤压重排期间无滚动锚定**——布局变化可能移动读者的视口。
|
|
87
91
|
|
|
88
92
|
<a id="dev-note"></a>
|
package/lib/client.js
CHANGED
|
@@ -70,7 +70,7 @@ window.__ModuleLoader__.load({
|
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
72
72
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-layout/src/client/AppFrame.module.css.mjs
|
|
73
|
-
const css = ".pI_x6G_frame{background:var(--dsw-alias-bg-base);height:100%;transition:grid-template-columns var(--ds-transition-duration-slow) var(--ds-ease-in-out)
|
|
73
|
+
const css = ".pI_x6G_frame{background:var(--dsw-alias-bg-base);grid-template-rows:100%;height:100%;display:grid;position:relative;overflow:hidden}.pI_x6G_frame[data-animating]{transition:grid-template-columns var(--ds-transition-duration-slow) var(--ds-ease-in-out)}.pI_x6G_frame[data-dragging]{transition:none}[data-windows-titlebar] .pI_x6G_frame{--dsh-windows-content-radius:16px;box-sizing:border-box;padding-top:var(--dsh-windows-titlebar-height);background:var(--dsw-specific-sidebar-fill);grid-template-rows:minmax(0,1fr)}[data-windows-titlebar] .pI_x6G_centerCol{background:var(--dsw-alias-bg-base);border-radius:var(--dsh-windows-content-radius) 0 0 0;corner-shape:round}[data-windows-titlebar] .pI_x6G_frame:before{content:\"\";height:var(--dsh-windows-titlebar-height);background:var(--dsw-specific-sidebar-fill);-webkit-app-region:drag;position:absolute;inset:0 0 auto}[data-windows-titlebar] .pI_x6G_sidebarCol{border-right:none}[data-windows-titlebar] .pI_x6G_handle{top:var(--dsh-windows-titlebar-height)}@media (prefers-reduced-motion:reduce){.pI_x6G_frame[data-animating]{transition:none}}.pI_x6G_sidebarCol{background:var(--dsw-specific-sidebar-fill);border-right:.5px solid var(--dsw-alias-border-l3);min-width:0;overflow:hidden}.pI_x6G_centerCol{flex-direction:column;min-width:0;display:flex;overflow:hidden}[data-platform=darwin] .pI_x6G_frame{background:0 0}html[data-platform=darwin]{--dsh-frame-top-clearance:48px}[data-platform=darwin] .pI_x6G_sidebarCol{background:linear-gradient(to bottom, #7a9bf01a, #7a9bf000 35%, #8f89b800 68%, #8f89b817), color-mix(in srgb, color-mix(in srgb, var(--dsw-specific-sidebar-fill) 97%, #7a9bf0) 40%, transparent);border-right:none}[data-platform=darwin] [data-ds-dark-theme] .pI_x6G_sidebarCol{background:linear-gradient(to bottom, #7a9bf014, #7a9bf000 35%, #8f89b800 68%, #8f89b812), color-mix(in srgb, var(--dsw-specific-sidebar-fill) 50%, transparent)}@media (prefers-reduced-transparency:reduce){[data-platform=darwin] .pI_x6G_sidebarCol,[data-platform=darwin] [data-ds-dark-theme] .pI_x6G_sidebarCol{background:color-mix(in srgb, var(--dsw-specific-sidebar-fill) 90%, transparent)}}[data-platform=darwin] .pI_x6G_centerCol{background:var(--dsw-alias-bg-base);border-left:.5px solid var(--dsw-alias-border-l3)}[data-platform=darwin] .pI_x6G_rightbarCol{background:var(--dsw-alias-bg-base)}[data-platform=darwin] [data-sidebar-collapsed] .pI_x6G_centerCol{border-left:none}[data-platform=darwin] .pI_x6G_frame[data-sidebar-collapsed]{--dsh-frame-leading-clearance:160px}[data-platform=darwin][data-fullscreen] .pI_x6G_frame[data-sidebar-collapsed]{--dsh-frame-leading-clearance:84px}[data-platform=darwin][data-fullscreen] .pI_x6G_leadingSeat{left:12px}.pI_x6G_leadingBand{pointer-events:none;-webkit-app-region:drag;height:52px;position:absolute;top:0;left:0;right:0}.pI_x6G_frame[data-panel-conversation]:has([data-conversation-tabs]) .pI_x6G_leadingBand{height:76px}.pI_x6G_leadingSeat{z-index:15;-webkit-app-region:no-drag;align-items:center;display:flex;position:absolute;top:11px;left:88px}.pI_x6G_handle{cursor:col-resize;z-index:11;touch-action:none;width:8px;margin-left:-4px;position:absolute;top:0;bottom:0}.pI_x6G_frame[data-animating] .pI_x6G_handle{transition:left var(--ds-transition-duration-slow) var(--ds-ease-in-out)}.pI_x6G_frame[data-dragging] .pI_x6G_handle,.pI_x6G_frame[data-rightbar-fullscreen],.pI_x6G_frame[data-rightbar-fullscreen] .pI_x6G_handle,.pI_x6G_frame[data-rightbar-instant],.pI_x6G_frame[data-rightbar-instant] .pI_x6G_handle{transition:none}@media (prefers-reduced-motion:reduce){.pI_x6G_frame[data-animating] .pI_x6G_handle{transition:none}}.pI_x6G_rightbarCol{min-width:0;position:relative;overflow:visible}.pI_x6G_overlayLayer{z-index:20;pointer-events:none;position:absolute;inset:0}.pI_x6G_overlayLayer>*{pointer-events:auto}";
|
|
74
74
|
const tagId = "@deepseek-ai/dsh-client-ui-layout/AppFrame.module.css";
|
|
75
75
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
76
76
|
const tag = document.createElement("style");
|
|
@@ -83,6 +83,8 @@ window.__ModuleLoader__.load({
|
|
|
83
83
|
"centerCol": "pI_x6G_centerCol",
|
|
84
84
|
"frame": "pI_x6G_frame",
|
|
85
85
|
"handle": "pI_x6G_handle",
|
|
86
|
+
"leadingBand": "pI_x6G_leadingBand",
|
|
87
|
+
"leadingSeat": "pI_x6G_leadingSeat",
|
|
86
88
|
"overlayLayer": "pI_x6G_overlayLayer",
|
|
87
89
|
"rightbarCol": "pI_x6G_rightbarCol",
|
|
88
90
|
"sidebarCol": "pI_x6G_sidebarCol"
|
|
@@ -117,6 +119,23 @@ window.__ModuleLoader__.load({
|
|
|
117
119
|
return renderSlot("main", {}, { entryKey: usePanelInfo((info) => info.activePanelId) ?? "conversation" });
|
|
118
120
|
}
|
|
119
121
|
/**
|
|
122
|
+
* Marks the frame while the Conversation is selected — the deepened drag band
|
|
123
|
+
* (AppFrame.module.css) keys off the attribute. A DOM write from a child keeps
|
|
124
|
+
* the frame itself out of the panel subscription: selecting a panel must not
|
|
125
|
+
* re-render the columns.
|
|
126
|
+
*/
|
|
127
|
+
function ConversationMarker({ usePanelInfo, frameRef }) {
|
|
128
|
+
const conversationActive = usePanelInfo((info) => info.activePanelId === null);
|
|
129
|
+
(0, react.useLayoutEffect)(() => {
|
|
130
|
+
const frame = frameRef.current;
|
|
131
|
+
/* v8 ignore next -- the ref is attached by effect time: the marker renders inside the frame div. */
|
|
132
|
+
if (frame === null) return;
|
|
133
|
+
if (conversationActive) frame.setAttribute("data-panel-conversation", "");
|
|
134
|
+
else frame.removeAttribute("data-panel-conversation");
|
|
135
|
+
}, [conversationActive, frameRef]);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
120
139
|
* Right column grid item. Zero-width unless the occupant asked for a track; the
|
|
121
140
|
* occupant's panel is positioned against the column's right edge, which never
|
|
122
141
|
* moves, so it can hang over the centre when there is no track.
|
|
@@ -236,7 +255,8 @@ window.__ModuleLoader__.load({
|
|
|
236
255
|
const sidebarCollapsed = narrow ? !layoutInfo.narrowExpanded : layoutInfo.sidebar === 0;
|
|
237
256
|
const sidebarPreference = sidebarCollapsed ? 0 : layoutInfo.sidebar === 0 ? 280 : layoutInfo.sidebar;
|
|
238
257
|
const rightbarPreference = layoutInfo.rightbar ?? viewport * .45;
|
|
239
|
-
const
|
|
258
|
+
const darwin = document.documentElement.dataset.platform === "darwin";
|
|
259
|
+
const collapsedWidth = darwin || document.documentElement.hasAttribute("data-windows-titlebar") ? 0 : 56;
|
|
240
260
|
const normal = computeColumns(viewport, !layoutInfo.rightbarShown && narrow ? 0 : sidebarPreference, rightbarPreference, collapsedWidth);
|
|
241
261
|
const cols = computeColumns(viewport, sidebarPreference, layoutInfo.rightbarTrack ? rightbarPreference : 0, collapsedWidth);
|
|
242
262
|
const colsRef = (0, react.useRef)(cols);
|
|
@@ -246,6 +266,36 @@ window.__ModuleLoader__.load({
|
|
|
246
266
|
const sidebarBase = (0, react.useRef)(0);
|
|
247
267
|
const rightbarBase = (0, react.useRef)(0);
|
|
248
268
|
const [dragging, setDragging] = (0, react.useState)(false);
|
|
269
|
+
const [animating, setAnimating] = (0, react.useState)(0);
|
|
270
|
+
const trackToggle = `${sidebarCollapsed}:${layoutInfo.rightbarTrack}`;
|
|
271
|
+
const previousToggle = (0, react.useRef)(trackToggle);
|
|
272
|
+
const previousViewport = (0, react.useRef)(viewport);
|
|
273
|
+
(0, react.useLayoutEffect)(() => {
|
|
274
|
+
const viewportChanged = previousViewport.current !== viewport;
|
|
275
|
+
previousViewport.current = viewport;
|
|
276
|
+
if (previousToggle.current === trackToggle) return;
|
|
277
|
+
previousToggle.current = trackToggle;
|
|
278
|
+
if (viewportChanged) return;
|
|
279
|
+
setAnimating((token) => token + 1);
|
|
280
|
+
}, [trackToggle, viewport]);
|
|
281
|
+
(0, react.useEffect)(() => {
|
|
282
|
+
if (animating === 0) return;
|
|
283
|
+
const frame = frameRef.current;
|
|
284
|
+
/* v8 ignore next -- the ref is always attached by effect time: the frame div renders unconditionally. */
|
|
285
|
+
if (frame === null) return;
|
|
286
|
+
const settle = () => {
|
|
287
|
+
setAnimating(0);
|
|
288
|
+
};
|
|
289
|
+
const onTransitionEnd = (event) => {
|
|
290
|
+
if (event.target === frame && event.propertyName === "grid-template-columns") settle();
|
|
291
|
+
};
|
|
292
|
+
frame.addEventListener("transitionend", onTransitionEnd);
|
|
293
|
+
const timer = setTimeout(settle, 600);
|
|
294
|
+
return () => {
|
|
295
|
+
frame.removeEventListener("transitionend", onTransitionEnd);
|
|
296
|
+
clearTimeout(timer);
|
|
297
|
+
};
|
|
298
|
+
}, [animating]);
|
|
249
299
|
const onDragEnd = (0, react.useCallback)(() => {
|
|
250
300
|
setDragging(false);
|
|
251
301
|
}, []);
|
|
@@ -264,6 +314,7 @@ window.__ModuleLoader__.load({
|
|
|
264
314
|
actions.setRightbar(rightbarBase.current - dx);
|
|
265
315
|
}, [actions]);
|
|
266
316
|
const productTitle = "DeepSeek Harness";
|
|
317
|
+
const rightbarMax = cols.rightbar === 0 ? 0 : clampWidth(rightbarPreference, 300, viewport * RIGHTBAR_MAX_RATIO);
|
|
267
318
|
const sidebar = (0, react.useMemo)(() => renderSlot("sidebar", {
|
|
268
319
|
collapsed: sidebarCollapsed,
|
|
269
320
|
width: cols.sidebar
|
|
@@ -277,19 +328,30 @@ window.__ModuleLoader__.load({
|
|
|
277
328
|
renderSlot
|
|
278
329
|
}), [usePanelInfo, renderSlot]);
|
|
279
330
|
const overlays = (0, react.useMemo)(() => renderSlot("shell.overlay", {}), [renderSlot]);
|
|
331
|
+
const leading = (0, react.useMemo)(() => renderSlot("shell.leading", {}), [renderSlot]);
|
|
332
|
+
const leadingMounted = darwin && sidebarCollapsed;
|
|
280
333
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
281
334
|
ref: frameRef,
|
|
282
335
|
className: AppFrame_module_css_default.frame,
|
|
283
336
|
style: {
|
|
284
337
|
...document.documentElement.hasAttribute("data-windows-titlebar") ? { "--dsh-windows-sidebar-width": `${cols.sidebar}px` } : {},
|
|
285
|
-
gridTemplateColumns: `${cols.sidebar}px minmax(0, 1fr) ${
|
|
338
|
+
gridTemplateColumns: `${cols.sidebar}px minmax(${cols.rightbar === 0 ? 0 : 400}px, 1fr) minmax(0px, ${rightbarMax}px)`
|
|
286
339
|
},
|
|
287
340
|
"data-sidebar-collapsed": sidebarCollapsed || void 0,
|
|
288
341
|
"data-rightbar-collapsed": cols.rightbar === 0 || void 0,
|
|
289
342
|
"data-rightbar-fullscreen": layoutInfo.rightbarFullscreen || void 0,
|
|
290
343
|
"data-rightbar-instant": layoutInfo.rightbarInstant || void 0,
|
|
291
344
|
"data-dragging": dragging || void 0,
|
|
345
|
+
"data-animating": animating > 0 || void 0,
|
|
292
346
|
children: [
|
|
347
|
+
darwin && (0, react_jsx_runtime.jsx)("div", {
|
|
348
|
+
className: AppFrame_module_css_default.leadingBand,
|
|
349
|
+
"data-shell-leading-band": true
|
|
350
|
+
}),
|
|
351
|
+
(0, react_jsx_runtime.jsx)(ConversationMarker, {
|
|
352
|
+
usePanelInfo,
|
|
353
|
+
frameRef
|
|
354
|
+
}),
|
|
293
355
|
(0, react_jsx_runtime.jsx)(DocumentTitle, {
|
|
294
356
|
productTitle,
|
|
295
357
|
useSessions,
|
|
@@ -309,6 +371,11 @@ window.__ModuleLoader__.load({
|
|
|
309
371
|
"data-shell-overlay": true,
|
|
310
372
|
children: overlays
|
|
311
373
|
}),
|
|
374
|
+
leadingMounted && (0, react_jsx_runtime.jsx)("div", {
|
|
375
|
+
className: AppFrame_module_css_default.leadingSeat,
|
|
376
|
+
"data-shell-leading": true,
|
|
377
|
+
children: leading
|
|
378
|
+
}),
|
|
312
379
|
!sidebarCollapsed && (0, react_jsx_runtime.jsx)(DragHandle, {
|
|
313
380
|
side: "sidebar",
|
|
314
381
|
left: cols.sidebar,
|
|
@@ -449,10 +516,12 @@ window.__ModuleLoader__.load({
|
|
|
449
516
|
const DARK_ATTRIBUTE = "data-ds-dark-theme";
|
|
450
517
|
/**
|
|
451
518
|
* Root attribute publishing the theme source (`light`, `dark`, or `system`)
|
|
452
|
-
* for host shells that mirror it into native
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
519
|
+
* for host shells that mirror it into the native theme (the Electron preload
|
|
520
|
+
* forwards it to `nativeTheme.themeSource`, so native chrome, renderer
|
|
521
|
+
* `prefers-color-scheme` queries, and Platform login links follow the app
|
|
522
|
+
* palette on every platform). `system` only when the preference is `system`;
|
|
523
|
+
* a fixed preference (including registered theme ids) publishes its resolved
|
|
524
|
+
* scheme.
|
|
456
525
|
*/
|
|
457
526
|
const THEME_SOURCE_ATTRIBUTE = "data-ds-theme-source";
|
|
458
527
|
/** Body variable carrying the user's content font size in px. */
|
|
@@ -519,7 +588,7 @@ window.__ModuleLoader__.load({
|
|
|
519
588
|
];
|
|
520
589
|
/**
|
|
521
590
|
* Client plugin body: provide ctx.layout, then one register() call — AppFrame
|
|
522
|
-
* into 'root' with the
|
|
591
|
+
* into 'root' with the five child-slot declarations, the layout store seat,
|
|
523
592
|
* and the shared root instance supplying commands and the panel-info source.
|
|
524
593
|
* @param ctx - client root context.
|
|
525
594
|
*/
|
|
@@ -559,6 +628,10 @@ window.__ModuleLoader__.load({
|
|
|
559
628
|
"shell.overlay": {
|
|
560
629
|
kind: "list",
|
|
561
630
|
scope: "root"
|
|
631
|
+
},
|
|
632
|
+
"shell.leading": {
|
|
633
|
+
kind: "single",
|
|
634
|
+
scope: "root"
|
|
562
635
|
}
|
|
563
636
|
},
|
|
564
637
|
store
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
2
|
import type { createLayoutStore } from './stores.ts';
|
|
3
3
|
/** Full composed props: runtime share + child-slot render share + store share. */
|
|
4
|
-
export type AppFrameProps = PropsRuntime<'root'> & PropsRenderSlots<'sidebar' | 'main' | 'rightbar' | 'shell.overlay'> & PropsStore<ReturnType<typeof createLayoutStore>> & PropsLocale<'common'>;
|
|
4
|
+
export type AppFrameProps = PropsRuntime<'root'> & PropsRenderSlots<'sidebar' | 'main' | 'rightbar' | 'shell.overlay' | 'shell.leading'> & PropsStore<ReturnType<typeof createLayoutStore>> & PropsLocale<'common'>;
|
|
5
5
|
/** The three-column frame (see module doc). */
|
|
6
6
|
export declare function AppFrame({ useStore, useSessions, usePanelInfo, actions, renderSlot, t, }: AppFrameProps): import("react").JSX.Element;
|
|
7
7
|
//# sourceMappingURL=AppFrame.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Layout plugin, browser half: one register() call contributes AppFrame into
|
|
3
3
|
* the runtime's built-in 'root' slot and, in the same breath, declares the
|
|
4
|
-
*
|
|
4
|
+
* five child slots (declaration = exclusive render authority), seats the
|
|
5
5
|
* layout store (panel geometry), and wires the panel-action service face.
|
|
6
6
|
* ctx.layout selects the main panel and controls column geometry; Session
|
|
7
7
|
* selection belongs to the Session Controller. A second effect seats the theme
|
|
@@ -81,6 +81,23 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
81
81
|
kind: 'list';
|
|
82
82
|
scope: 'root';
|
|
83
83
|
};
|
|
84
|
+
/**
|
|
85
|
+
* Window-chrome seat at the frame's top-left, over every main panel.
|
|
86
|
+
* Mounted only while the sidebar column is fully hidden (macOS desktop
|
|
87
|
+
* collapse; other platforms keep the rail), so the occupant can assume the
|
|
88
|
+
* frame edge is the window edge and the macOS traffic lights sit before it.
|
|
89
|
+
* OCCUPIED by ui-sidebar's reopen/New Session controls.
|
|
90
|
+
*
|
|
91
|
+
* While the seat is mounted the frame publishes
|
|
92
|
+
* `--dsh-frame-leading-clearance` (the inline inset the seat's band
|
|
93
|
+
* occupies, measured from the frame's left edge); a main panel whose
|
|
94
|
+
* content reaches the top-left corner pads by it so nothing lands under
|
|
95
|
+
* the lights or the controls.
|
|
96
|
+
*/
|
|
97
|
+
'shell.leading': {
|
|
98
|
+
kind: 'single';
|
|
99
|
+
scope: 'root';
|
|
100
|
+
};
|
|
84
101
|
}
|
|
85
102
|
}
|
|
86
103
|
/** Sidebar owner share: live column state from the frame's concession solve. */
|
|
@@ -106,7 +123,7 @@ export interface RightbarOwnerProps {
|
|
|
106
123
|
export declare const inject: string[];
|
|
107
124
|
/**
|
|
108
125
|
* Client plugin body: provide ctx.layout, then one register() call — AppFrame
|
|
109
|
-
* into 'root' with the
|
|
126
|
+
* into 'root' with the five child-slot declarations, the layout store seat,
|
|
110
127
|
* and the shared root instance supplying commands and the panel-info source.
|
|
111
128
|
* @param ctx - client root context.
|
|
112
129
|
*/
|
|
@@ -14,10 +14,12 @@ import type { ThemeSnapshot } from '@deepseek-ai/dsh-client-ui-theme/client';
|
|
|
14
14
|
export declare const DARK_ATTRIBUTE = "data-ds-dark-theme";
|
|
15
15
|
/**
|
|
16
16
|
* Root attribute publishing the theme source (`light`, `dark`, or `system`)
|
|
17
|
-
* for host shells that mirror it into native
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* for host shells that mirror it into the native theme (the Electron preload
|
|
18
|
+
* forwards it to `nativeTheme.themeSource`, so native chrome, renderer
|
|
19
|
+
* `prefers-color-scheme` queries, and Platform login links follow the app
|
|
20
|
+
* palette on every platform). `system` only when the preference is `system`;
|
|
21
|
+
* a fixed preference (including registered theme ids) publishes its resolved
|
|
22
|
+
* scheme.
|
|
21
23
|
*/
|
|
22
24
|
export declare const THEME_SOURCE_ATTRIBUTE = "data-ds-theme-source";
|
|
23
25
|
/** Body variable carrying the user's content font size in px. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-layout",
|
|
3
3
|
"description": "Shell plugin: three-column AppFrame with drag handles, ctx.layout viewing-state service (navigation + panels)",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -38,19 +38,19 @@
|
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@deepseek-ai/cordis": "
|
|
41
|
+
"@deepseek-ai/cordis": "~4.0.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "~18.3.1",
|
|
45
45
|
"react": "^18.2.0",
|
|
46
|
-
"@deepseek-ai/dsh-
|
|
47
|
-
"@deepseek-ai/dsh-
|
|
48
|
-
"@deepseek-ai/dsh-client-store": "
|
|
49
|
-
"@deepseek-ai/dsh-client-ui-renderer": "
|
|
50
|
-
"@deepseek-ai/dsh-client-ui-session": "
|
|
51
|
-
"@deepseek-ai/dsh-client-ui-slots": "
|
|
52
|
-
"@deepseek-ai/dsh-client-ui-theme": "
|
|
53
|
-
"@deepseek-ai/cordis": "
|
|
46
|
+
"@deepseek-ai/dsh-client-locale": "0.1.7-alpha.2",
|
|
47
|
+
"@deepseek-ai/dsh-brand": "0.1.7-alpha.2",
|
|
48
|
+
"@deepseek-ai/dsh-client-store": "0.1.7-alpha.2",
|
|
49
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-session": "0.1.7-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-theme": "0.1.7-alpha.2",
|
|
53
|
+
"@deepseek-ai/cordis": "~4.0.4"
|
|
54
54
|
},
|
|
55
55
|
"files": [
|
|
56
56
|
"lib/index.js",
|