dsh-tauri-panel 0.0.0
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/LICENSE.md +21 -0
- package/cordis.patch.yml +3 -0
- package/dist/client.js +46 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +10 -0
- package/package.json +53 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-PRESENT Hairyf <https://github.com/hairyf>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/cordis.patch.yml
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import{SlotOutlet as e}from"@deepseek-ai/dsh-client-ui-renderer";import{createSnapshotStore as t}from"@deepseek-ai/dsh-client-runtime/client";import{useEffect as n,useRef as r,useState as i,useSyncExternalStore as a}from"react";import{jsx as o,jsxs as s}from"react/jsx-runtime";const c=`panel`,l={"session.new":`新会话`,"session.new.label":`新建会话`,"toggle.open":`打开侧边栏`,"toggle.collapse":`收起侧边栏`},u={"session.new":`New Session`,"session.new.label":`New session`,"toggle.open":`Open sidebar`,"toggle.collapse":`Collapse sidebar`};function d(e){e.effect(()=>{let t=e.locale.register(c,`zh`,l),n=e.locale.register(c,`en`,u);return()=>{t(),n()}},`dsh-tauri-panel: dictionaries`)}let f,p;const m=t(null);let h;function g({t:e}){let t=p;if(!t)return null;let n=t.render;return o(`div`,{"data-dshp-panel-view":``,className:`dshp-panelView`,children:o(`div`,{className:`dshp-panelViewColumn`,children:o(n,{t:e})})})}function _(e){if(!f)return;let t=e.target;t?.closest(`[data-dshp-panel-sidebar]`)!==null&&(t?.closest(`[data-dshp-panel-view]`)!==null||t?.closest(`[data-dshp-panel-action]`)!==null||y())}function v(e,t){p&&p.id===t.id||(f&&y(),p=t,m.set({id:t.id}),f=e.slots.inject(`conversation`,()=>e.slots.register({name:`conversation`,id:`dsh-tauri-panel-conversation-seat`,priority:-1,locale:t.locale??c},g)),document.addEventListener(`pointerdown`,_,!0))}function y(){f?.(),f=void 0,p=void 0,m.set(null),document.removeEventListener(`pointerdown`,_,!0)}function b(){return a(e=>m.subscribe(e),()=>m.getSnapshot())}function x({id:e,icon:t,onClick:n,children:r}){return s(`button`,{type:`button`,className:b()?.id===e?`dshp-menuItem dshp-menuItemSelected`:`dshp-menuItem`,"data-dshp-panel-action":``,onClick:n,children:[t!==void 0&&o(`span`,{className:`dshp-menuItemIcon`,children:t}),o(`span`,{className:`dshp-menuItemLabel`,children:r})]})}function S(e){h&&(f?y():v(h,e))}function C(e){h=e;let t={ActionItem:x,renderPanelContent:S};e.effect(()=>e.reflect.provide(`panel.protocol`,t),`dsh-tauri-panel: panel.protocol host service`)}function w({size:e=16,className:t}){return o(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:e,height:e,viewBox:`0 0 16 16`,fill:`none`,className:t,"aria-hidden":`true`,children:o(`path`,{d:`M8.00003 0.3237C3.76075 0.3237 0.32373 3.76072 0.32373 8C0.32373 9.17603 0.589121 10.2922 1.0632 11.2901L1.35291 11.8989L2.5705 11.3205L2.28079 10.7117C1.89079 9.89074 1.67301 8.97167 1.67301 8C1.67301 4.50546 4.50549 1.67298 8.00003 1.67298C11.4946 1.67298 14.3271 4.50546 14.3271 8C14.3271 11.4945 11.4946 14.327 8.00003 14.327C7.28473 14.327 6.76077 14.277 6.29621 14.1487C5.83857 14.0224 5.40441 13.8109 4.88514 13.4488C4.12569 12.919 3.03778 12.7316 2.141 13.2978L2.12682 13.307L2.11264 13.3171L1.34886 13.854L1.79659 15.188L2.86122 14.4384C3.19068 14.2305 3.68325 14.2542 4.11326 14.5539C4.72789 14.9826 5.30042 15.2724 5.93762 15.4484C6.56803 15.6224 7.22776 15.6763 8.00003 15.6763C12.2393 15.6763 15.6763 12.2393 15.6763 8C15.6763 3.76072 12.2393 0.3237 8.00003 0.3237ZM7.32033 4.82535V7.32536H4.82538V8.67464H7.32033V11.1747H8.6696V8.67464H11.1747V7.32536H8.6696V4.82535H7.32033Z`,fill:`currentColor`})})}function T({size:e=16,className:t}){return s(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:e,height:e,viewBox:`0 0 16 16`,fill:`none`,className:t,"aria-hidden":`true`,children:[o(`rect`,{x:`2`,y:`3`,width:`12`,height:`10`,rx:`1.5`,stroke:`currentColor`,strokeWidth:`1.2`}),o(`path`,{d:`M6.5 3v10`,stroke:`currentColor`,strokeWidth:`1.2`})]})}function E({size:e=24,className:t}){return s(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:e,height:e,viewBox:`0 0 24 24`,fill:`none`,className:t,"aria-hidden":`true`,children:[o(`path`,{d:`M4 12c3-4.5 9-6 16-6 0 7-13 9-16 6Zm0 0c3 2.5 16 4.5 16-6`,stroke:`currentColor`,strokeWidth:`1.5`,strokeLinecap:`round`,strokeLinejoin:`round`}),o(`circle`,{cx:`15.5`,cy:`9.5`,r:`1`,fill:`currentColor`})]})}function D(...e){return e.filter(Boolean).join(` `)}function O({collapsed:t,width:a,startSession:c,toggleSidebar:l,t:u}){let[d,f]=i(!1);n(()=>{f(!1);let e=window.setTimeout(()=>{f(!0)},150);return()=>{window.clearTimeout(e)}},[t]);let p=!t||!d,m=r(a);t||(m.current=a);let h=r(!t);t||(h.current=!0);let[g,_]=i(!1),v=r(void 0),y=()=>{v.current===void 0&&(v.current=window.setTimeout(()=>{v.current=void 0,_(!1)},2e3))},b=()=>{window.clearTimeout(v.current),v.current=void 0};return s(`div`,{className:D(`dshp-root`,!p&&`dshp-collapsed`,!p&&h.current&&`dshp-railIn`,t&&p&&`dshp-fading`,!g&&`dshp-quietBars`),"data-dshp-panel-sidebar":``,style:p?{width:t?m.current:a}:void 0,onPointerEnter:()=>{b(),_(!0)},onPointerLeave:()=>{y()},children:[s(`div`,{className:`dshp-logoRow`,children:[p&&o(`button`,{type:`button`,className:`dshp-brand`,"aria-label":u(`session.new.label`),onClick:()=>c(),children:s(`span`,{className:`dshp-brandIdentity`,"aria-hidden":`true`,children:[o(`span`,{className:`dshp-brandMark`,children:o(e,{slotKey:`sidebar.brand.mark`,ownerProps:{size:24},opts:{fallback:o(E,{size:24})}})}),o(`span`,{className:`dshp-brandName`,children:o(e,{slotKey:`sidebar.brand.name`,ownerProps:{},opts:{fallback:o(`span`,{className:`dshp-fallbackBrandName`,children:`DSH Local Build`})}})})]})}),s(`button`,{type:`button`,className:`dshp-iconButton dshp-toggle`,"aria-label":u(t?`toggle.open`:`toggle.collapse`),title:u(t?`toggle.open`:`toggle.collapse`),onClick:()=>l(),children:[!p&&o(`span`,{className:`dshp-railMark`,"aria-hidden":`true`,children:o(e,{slotKey:`sidebar.brand.mark`,ownerProps:{size:24},opts:{fallback:o(E,{size:24})}})}),o(T,{size:p?16:18,className:`dshp-panelIcon`})]})]}),s(`div`,{className:`dshp-panelArea`,children:[s(`button`,{type:`button`,className:`dshp-menuItem`,title:u(`session.new.label`),onClick:()=>c(),children:[o(`span`,{className:`dshp-menuItemIcon`,children:o(w,{size:16})}),o(`span`,{className:`dshp-menuItemLabel`,children:u(`session.new`)})]}),o(e,{slotKey:`sidebar.panel.action`,ownerProps:{wide:p}})]}),o(`div`,{className:`dshp-regionArea`,children:o(e,{slotKey:`sidebar.workspaces`,ownerProps:{wide:p,expandSidebar:()=>{t&&l()}}})}),s(`div`,{className:`dshp-footArea`,children:[o(`div`,{className:`dshp-footerActions`,children:o(e,{slotKey:`sidebar.footer.action`,ownerProps:{wide:p}})}),o(`div`,{className:`dshp-settingsArea`,children:o(e,{slotKey:`sidebar.settings`,ownerProps:{wide:p}})})]})]})}function k(e){e.slots.inject(`sidebar`,()=>e.slots.register({name:`sidebar`,id:`dsh-tauri-panel`,priority:-1,locale:c,children:{"sidebar.panel.action":{kind:`list`,scope:`root`}},inject:()=>({startSession:t=>e.workspaces.startSession(t),toggleSidebar:()=>e.layout.toggleSidebar()})},O))}const A=`dsh-tauri-panel-styles`;function j(){if(typeof document>`u`||document.getElementById(A)!==null)return;let e=document.createElement(`style`);e.id=A,e.textContent=`
|
|
2
|
+
.dshp-root{--dshp-padding:12px;height:100%;padding:6px var(--dshp-padding);box-sizing:border-box;background:var(--dsw-specific-sidebar-fill);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex-direction:column;font-size:14px;display:flex}
|
|
3
|
+
.dshp-root.dshp-collapsed{padding:18px 10px 6px}
|
|
4
|
+
.dshp-root.dshp-quietBars{--dsh-scrollbar-thumb:transparent;--dsh-scrollbar-thumb-hover:transparent}
|
|
5
|
+
.dshp-fading>*{opacity:0;transition:opacity .15s var(--ds-ease-in-out)}
|
|
6
|
+
.dshp-railIn .dshp-iconButton,.dshp-railIn .dshp-menuItem,.dshp-railIn .dshp-regionArea{animation:dshp-rail-in .15s var(--ds-ease-in-out) backwards}
|
|
7
|
+
.dshp-railIn .dshp-footArea{animation:dshp-rail-fade-in .15s var(--ds-ease-in-out) backwards}
|
|
8
|
+
@keyframes dshp-rail-in{0%{opacity:0;transform:translate(49px)}}
|
|
9
|
+
@keyframes dshp-rail-fade-in{0%{opacity:0}}
|
|
10
|
+
.dshp-logoRow{box-sizing:border-box;flex:none;justify-content:flex-end;align-items:center;gap:8px;height:32px;margin-bottom:4px;padding:4px 0 4px 4px;display:flex;overflow:hidden}
|
|
11
|
+
.dshp-collapsed .dshp-logoRow{justify-content:flex-start;height:32px;margin-bottom:4px;padding:0}
|
|
12
|
+
.dshp-brand{min-width:0;color:inherit;cursor:pointer;background:transparent;border:none;flex:1;align-items:center;padding:0;display:inline-flex;overflow:hidden}
|
|
13
|
+
.dshp-brandIdentity{align-items:center;gap:8px;min-width:0;height:24px;display:inline-flex}
|
|
14
|
+
.dshp-brandMark{flex:none;justify-content:center;align-items:center;display:inline-flex}
|
|
15
|
+
.dshp-brandName{letter-spacing:.04em;align-items:center;gap:6px;min-width:0;height:24px;font-size:18px;font-weight:600;line-height:24px;display:inline-flex}
|
|
16
|
+
.dshp-fallbackBrandName{letter-spacing:0;white-space:nowrap;font-size:17px}
|
|
17
|
+
.dshp-iconButton{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-secondary);background:transparent;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}
|
|
18
|
+
.dshp-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
19
|
+
.dshp-collapsed .dshp-iconButton{width:36px;height:36px;color:var(--dsw-alias-label-primary)}
|
|
20
|
+
.dshp-railMark{justify-content:center;align-items:center;display:inline-flex}
|
|
21
|
+
.dshp-panelArea{flex:none;flex-direction:column;align-items:stretch;gap:2px;margin:0 0 8px;display:flex}
|
|
22
|
+
.dshp-collapsed .dshp-panelArea{align-items:center;gap:4px}
|
|
23
|
+
.dshp-menuItem{box-sizing:border-box;cursor:pointer;user-select:none;color:var(--dsw-alias-label-primary);background:transparent;border:none;border-radius:8px;align-items:center;gap:0;padding:0 8px;height:32px;min-width:0;display:flex;font-family:inherit;font-size:14px;line-height:22px;text-align:left;overflow:hidden}
|
|
24
|
+
.dshp-menuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
25
|
+
.dshp-menuItemSelected,.dshp-menuItemSelected:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
26
|
+
.dshp-menuItemIcon{flex:none;width:16px;height:20px;color:var(--dsw-alias-label-tertiary);justify-content:center;align-items:center;display:inline-flex}
|
|
27
|
+
.dshp-menuItemLabel{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0 6px 0 4px;min-width:0}
|
|
28
|
+
.dshp-collapsed .dshp-menuItem{justify-content:center;width:36px;height:36px;padding:0}
|
|
29
|
+
.dshp-collapsed .dshp-menuItemLabel{display:none}
|
|
30
|
+
.dshp-regionArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--dshp-padding));flex-direction:column;flex:1;padding-left:4px;display:flex;overflow:hidden}
|
|
31
|
+
.dshp-collapsed .dshp-regionArea{margin-left:0;margin-right:0;padding-left:0}
|
|
32
|
+
.dshp-footArea{flex-direction:column;flex:none;display:flex}
|
|
33
|
+
.dshp-settingsArea,.dshp-footerActions{flex:none;width:100%;min-width:0}
|
|
34
|
+
.dshp-footerActions{display:flex}
|
|
35
|
+
.dshp-collapsed .dshp-footArea{align-items:center}
|
|
36
|
+
.dshp-collapsed .dshp-settingsArea,.dshp-collapsed .dshp-footerActions{justify-content:center;width:auto;display:flex}
|
|
37
|
+
/* 会话区替换座位(宿主决定宽度约束):滚动容器 + 内容列。
|
|
38
|
+
内容列镜像官方会话内容列 .Md3f7G_column(max-width var(--dsh-chat-content-width)、
|
|
39
|
+
width 100%、margin 0 auto、flex column、gap 16px);替换后官方
|
|
40
|
+
ConversationRoot(定义该变量处)不渲染,以 748px(官方默认值)兜底,
|
|
41
|
+
外层若已有定义则继承生效——子插件零宽度关注。 */
|
|
42
|
+
.dshp-panelView{height:100%;box-sizing:border-box;min-width:0;overflow-y:auto}
|
|
43
|
+
.dshp-panelViewColumn{max-width:var(--dsh-chat-content-width,748px);min-height:100%;width:100%;margin:0 auto;flex-direction:column;gap:16px;display:flex}
|
|
44
|
+
@media (prefers-reduced-motion:reduce){.dshp-fading>*,.dshp-railIn .dshp-iconButton,.dshp-railIn .dshp-menuItem,.dshp-railIn .dshp-footArea,.dshp-railIn .dshp-regionArea{transition:none;animation:none}}
|
|
45
|
+
`,document.head.append(e)}const M=`dsh-tauri-panel`,N=[`slots`,`layout`,`workspaces`,`locale`];function P(t){if(j(),d(t),C(t),typeof e!=`function`){console.warn(`[dsh-tauri-panel] <SlotOutlet> unavailable (renderer patch missing) — panel sidebar disabled, official UI stays.`);return}k(t)}export{P as apply,N as inject,M as name};
|
|
46
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["en: Record<keyof typeof zh, string>","conversationSeat: (() => void) | undefined","currentSpec: PanelContentSpec | undefined","rootCtx: Context | undefined"],"sources":["../src/client/locale.ts","../src/client/service.tsx","../src/client/icons.tsx","../src/client/sidebar.tsx","../src/client/styles.ts","../src/client/index.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis'\r\n\r\n/**\r\n * locale.ts — 本插件文案(zh/en 双语)。命名空间 `panel`:\r\n * 克隆 SidebarRoot 的壳控制文案(新会话/折叠开关,与官方 sidebar NS 同值,\r\n * 但独立命名空间,互不干扰)。\r\n */\r\nexport const NS = 'panel'\r\n\r\nconst zh = {\r\n 'session.new': '新会话',\r\n 'session.new.label': '新建会话',\r\n 'toggle.open': '打开侧边栏',\r\n 'toggle.collapse': '收起侧边栏',\r\n}\r\n\r\nconst en: Record<keyof typeof zh, string> = {\r\n 'session.new': 'New Session',\r\n 'session.new.label': 'New session',\r\n 'toggle.open': 'Open sidebar',\r\n 'toggle.collapse': 'Collapse sidebar',\r\n}\r\n\r\n/** 注册面板文案命名空间(effect 生命周期,随插件卸载注销)。 */\r\nexport function installPanelLocale(ctx: Context): void {\r\n ctx.effect(\r\n () => {\r\n const disposeZh = ctx.locale.register(NS, 'zh', zh)\r\n const disposeEn = ctx.locale.register(NS, 'en', en)\r\n return () => {\r\n disposeZh()\r\n disposeEn()\r\n }\r\n },\r\n 'dsh-tauri-panel: dictionaries',\r\n )\r\n}\r\n","import type { Context } from '@deepseek-ai/cordis'\r\nimport type { ComponentType, ReactElement, ReactNode } from 'react'\r\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport { useSyncExternalStore } from 'react'\r\nimport { NS } from './locale'\r\n\r\n/**\r\n * service.tsx — 面板协议宿主服务(协议能力,见 PROTOCOL.md)。\r\n *\r\n * 宿主对外只暴露两个构件,子插件无需处理任何状态/机制:\r\n * - `<ActionItem>`:面板区条目组件(样式、折叠态、active 态全由宿主承担);\r\n * - `renderPanelContent(spec)`:切换会话区替换(conversation 槽条件 shadow),\r\n * 子插件在 ActionItem 的 onClick 里调用。\r\n *\r\n * 机制(全部在宿主,单一权威):\r\n * - 服务经 ctx.reflect.provide('panel.protocol', api) 暴露(cordis\r\n * ReflectService,官方 runtime 同款用法 ctx.reflect.provide(\"sessions\", this));\r\n * - renderPanelContent:conversation 槽(single/session-maybe,layout 声明、\r\n * 官方 ui-conversation priority 0 是唯一注册者)以 priority -1 **动态注册**\r\n * → 整个右侧会话区被替换(CenterColumn 内、零定位层);官方条目被\r\n * shadow 但仍 live(children/locale 有效)。再调(同 id)→ dispose 句柄\r\n * → 官方恢复(toggle 语义)。\r\n * - 替换状态存共享 snapshot store:ActionItem 经 useSyncExternalStore\r\n * 感知「当前替换 id === 自己 id」→ 保持 active(hover)样式。\r\n * - 退出时机:无关闭按钮——document capture 层监听 pointerdown,但**只\r\n * 响应侧栏内点击**([data-dshp-panel-sidebar] 根容器):点侧栏任意处\r\n * (会话/搜索/筛选/新会话/折叠/设置等)即恢复官方会话界面,目标操作\r\n * 继续正常执行;右侧区域(第三方悬浮按钮等)不影响替换,避免误关。\r\n * 替换视图内部与面板条目自身不触发(后者留给条目 onClick)。\r\n *\r\n * 不能常驻注册 + SlotOutlet 透传:SlotOutlet 对 single 槽只渲染 live 条目,\r\n * 自己 live 后渲染官方条目 = 自递归(无公开 API 渲染被 shadow 条目)。\r\n */\r\n\r\n/** 面板协议服务名(第三方经 ctx.reflect.get 取用)。 */\r\nexport const PANEL_PROTOCOL_SERVICE = 'panel.protocol'\r\n\r\n/** 内容区替换规格(renderPanelContent 入参)。 */\r\nexport interface PanelContentSpec {\r\n /** 视图唯一标识(同一时刻只存在一个替换;active 态以它匹配 ActionItem)。 */\r\n id: string\r\n /** 视图组件:宿主渲染时按标准 kit 传入 t(可选,自包含组件可忽略)。 */\r\n render: ComponentType<{ t?: (key: string) => string }>\r\n /** 视图文案命名空间(可选,默认宿主 'panel';视图可声明自己的 NS)。 */\r\n locale?: string\r\n}\r\n\r\n/** ActionItem 合成 props:id + 图标 + 点击行为 + 文字(子插件只填这些)。 */\r\nexport interface PanelActionItemProps {\r\n /** 条目唯一标识(active 态:当前内容区替换 id 与之相等则保持选中样式)。 */\r\n id: string\r\n /** 条目图标(16px 语义,自绘 SVG 组件实例)。 */\r\n icon?: ReactElement\r\n /** 点击行为:自定义动作;打开内容区替换典型写法是调 renderPanelContent。 */\r\n onClick?: () => void\r\n /** 条目文字(wide 态显示;折叠态宿主 CSS 自动隐藏,只留图标钮)。 */\r\n children?: ReactNode\r\n}\r\n\r\n/** 当前 conversation 替换的 inject 句柄(undefined = 官方会话区 live)。 */\r\nlet conversationSeat: (() => void) | undefined\r\n/** 当前替换视图规格。 */\r\nlet currentSpec: PanelContentSpec | undefined\r\n/** 替换状态(ActionItem active 样式订阅源)。 */\r\nconst panelViewStore = createSnapshotStore<{ id: string } | null>(null)\r\n/** 根上下文(renderPanelContent 内部注册用)。 */\r\nlet rootCtx: Context | undefined\r\n\r\n/** 渲染 conversation 槽条目:包标记容器 + 宿主内容列(宽度约束由宿主决定,见 styles.ts)。 */\r\nfunction ConversationSeat({ t }: { t: (key: string) => string }): ReactElement | null {\r\n const spec = currentSpec\r\n if (!spec)\r\n return null\r\n const View = spec.render\r\n return (\r\n <div data-dshp-panel-view=\"\" className=\"dshp-panelView\">\r\n {/* 内容列:对齐官方内容列宽度(max-width var(--dsh-chat-content-width, 748px)),\r\n 子插件零宽度关注,只负责内容自身布局(垂直方向自定)。 */}\r\n <div className=\"dshp-panelViewColumn\">\r\n <View t={t} />\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * capture 层 pointerdown:替换激活时,只响应**侧栏内**([data-dshp-panel-sidebar])\r\n * 的点击——右侧区域(第三方悬浮按钮等)不影响替换,避免误关。侧栏内点击\r\n * 替换视图/面板条目不处理(条目留给 onClick),其余关闭替换——官方会话区\r\n * 恢复,目标操作继续正常执行。\r\n */\r\nfunction onPointerDownCapture(event: PointerEvent): void {\r\n if (!conversationSeat)\r\n return\r\n const target = event.target as HTMLElement | null\r\n if (target?.closest('[data-dshp-panel-sidebar]') === null)\r\n return\r\n if (target?.closest('[data-dshp-panel-view]') !== null || target?.closest('[data-dshp-panel-action]') !== null)\r\n return\r\n closeConversation()\r\n}\r\n\r\n/** 打开会话区替换:动态注册 priority -1 的 conversation 条目。 */\r\nfunction openConversation(ctx: Context, spec: PanelContentSpec): void {\r\n if (currentSpec && currentSpec.id === spec.id)\r\n return\r\n if (conversationSeat)\r\n closeConversation()\r\n currentSpec = spec\r\n panelViewStore.set({ id: spec.id })\r\n conversationSeat = ctx.slots.inject('conversation' as never, () =>\r\n ctx.slots.register(\r\n {\r\n name: 'conversation',\r\n id: 'dsh-tauri-panel-conversation-seat',\r\n priority: -1,\r\n locale: spec.locale ?? NS,\r\n } as never,\r\n ConversationSeat,\r\n ))\r\n document.addEventListener('pointerdown', onPointerDownCapture, true)\r\n}\r\n\r\n/** 关闭会话区替换:dispose inject 句柄 → 注销条目 → 官方 ui-conversation 恢复。 */\r\nfunction closeConversation(): void {\r\n conversationSeat?.()\r\n conversationSeat = undefined\r\n currentSpec = undefined\r\n panelViewStore.set(null)\r\n document.removeEventListener('pointerdown', onPointerDownCapture, true)\r\n}\r\n\r\n/** 订阅当前替换 id(null = 官方会话区)。 */\r\nfunction usePanelViewId(): { id: string } | null {\r\n return useSyncExternalStore(\r\n fn => panelViewStore.subscribe(fn),\r\n () => panelViewStore.getSnapshot(),\r\n )\r\n}\r\n\r\n/** ActionItem:面板区条目(样式/折叠/active 态全宿主,子插件只填内容与行为)。 */\r\nexport function PanelActionItem({ id, icon, onClick, children }: PanelActionItemProps): ReactElement {\r\n const active = usePanelViewId()?.id === id\r\n return (\r\n <button\r\n type=\"button\"\r\n className={active ? 'dshp-menuItem dshp-menuItemSelected' : 'dshp-menuItem'}\r\n data-dshp-panel-action=\"\"\r\n onClick={onClick}\r\n >\r\n {icon !== undefined && <span className=\"dshp-menuItemIcon\">{icon}</span>}\r\n <span className=\"dshp-menuItemLabel\">{children}</span>\r\n </button>\r\n )\r\n}\r\n\r\n/**\r\n * 切换会话区替换:未替换则打开(conversation 槽动态注册 spec.render),\r\n * 已替换则关闭恢复官方会话界面。子插件在 ActionItem 的 onClick 里调用。\r\n * @param spec - 内容区规格。\r\n */\r\nexport function renderPanelContent(spec: PanelContentSpec): void {\r\n if (!rootCtx)\r\n return\r\n if (conversationSeat)\r\n closeConversation()\r\n else\r\n openConversation(rootCtx, spec)\r\n}\r\n\r\n/**\r\n * 安装宿主服务:经 ctx.reflect.provide 暴露 panel.protocol(effect 生命周期,\r\n * 插件卸载即注销)。不依赖 renderer 补丁(conversation 注册只走 slots\r\n * runtime)——旧核心下内容区替换仍可用(仅面板区条目需 renderer)。\r\n * @param ctx - 客户端根上下文。\r\n */\r\nexport function installPanelService(ctx: Context): void {\r\n rootCtx = ctx\r\n const api = {\r\n ActionItem: PanelActionItem,\r\n renderPanelContent,\r\n }\r\n ctx.effect(\r\n () => ctx.reflect.provide(PANEL_PROTOCOL_SERVICE, api),\r\n 'dsh-tauri-panel: panel.protocol host service',\r\n )\r\n}\r\n","import type { ReactElement } from 'react'\r\n\r\n/**\r\n * icons.tsx — 自绘内联 SVG 图标(Gravity 风格描边,currentColor)。\r\n * 不依赖 @deepseek-ai/dsh-client-ui-primitives 的类型/运行时(loader 模块表\r\n * 虽提供该模块,但自绘零外部表面、跨部署更稳)。\r\n */\r\n\r\nexport interface IconProps {\r\n size?: number\r\n className?: string\r\n}\r\n\r\n/**\r\n * 新会话:官方 ChatOutline16 同款(聊天气泡 + 加号,fill 风格)。\r\n * primitives 包为 loader 运行时提供、不打进产物;此处自绘官方同一 path——\r\n * 取自桌面前端 bundle(dsh-web-frontend/dist/assets/index-ClqxG24t.js,导出表\r\n * ChatOutline16:V9),保证与官方「新会话」图标完全一致。\r\n */\r\nexport function ChatOutline({ size = 16, className }: IconProps): ReactElement {\r\n return (\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" className={className} aria-hidden=\"true\">\r\n <path d=\"M8.00003 0.3237C3.76075 0.3237 0.32373 3.76072 0.32373 8C0.32373 9.17603 0.589121 10.2922 1.0632 11.2901L1.35291 11.8989L2.5705 11.3205L2.28079 10.7117C1.89079 9.89074 1.67301 8.97167 1.67301 8C1.67301 4.50546 4.50549 1.67298 8.00003 1.67298C11.4946 1.67298 14.3271 4.50546 14.3271 8C14.3271 11.4945 11.4946 14.327 8.00003 14.327C7.28473 14.327 6.76077 14.277 6.29621 14.1487C5.83857 14.0224 5.40441 13.8109 4.88514 13.4488C4.12569 12.919 3.03778 12.7316 2.141 13.2978L2.12682 13.307L2.11264 13.3171L1.34886 13.854L1.79659 15.188L2.86122 14.4384C3.19068 14.2305 3.68325 14.2542 4.11326 14.5539C4.72789 14.9826 5.30042 15.2724 5.93762 15.4484C6.56803 15.6224 7.22776 15.6763 8.00003 15.6763C12.2393 15.6763 15.6763 12.2393 15.6763 8C15.6763 3.76072 12.2393 0.3237 8.00003 0.3237ZM7.32033 4.82535V7.32536H4.82538V8.67464H7.32033V11.1747H8.6696V8.67464H11.1747V7.32536H8.6696V4.82535H7.32033Z\" fill=\"currentColor\" />\r\n </svg>\r\n )\r\n}\r\n\r\n/** 侧栏折叠开关:左侧面板轮廓(16 基准)。 */\r\nexport function PanelLeftOutline({ size = 16, className }: IconProps): ReactElement {\r\n return (\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" className={className} aria-hidden=\"true\">\r\n <rect x=\"2\" y=\"3\" width=\"12\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\r\n <path d=\"M6.5 3v10\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\r\n </svg>\r\n )\r\n}\r\n\r\n/** 品牌 fallback:简化鱼形(sidebar.brand.mark 槽无 live 条目时的兜底,24 基准)。 */\r\nexport function FishMark({ size = 24, className }: IconProps): ReactElement {\r\n return (\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" className={className} aria-hidden=\"true\">\r\n <path d=\"M4 12c3-4.5 9-6 16-6 0 7-13 9-16 6Zm0 0c3 2.5 16 4.5 16-6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n <circle cx=\"15.5\" cy=\"9.5\" r=\"1\" fill=\"currentColor\" />\r\n </svg>\r\n )\r\n}\r\n","import type { Context } from '@deepseek-ai/cordis'\r\nimport type { WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type { ReactElement } from 'react'\r\nimport { SlotOutlet } from '@deepseek-ai/dsh-client-ui-renderer'\r\nimport { useEffect, useRef, useState } from 'react'\r\nimport { ChatOutline, FishMark, PanelLeftOutline } from './icons'\r\nimport { NS } from './locale'\r\n\r\n/**\r\n * sidebar.tsx — sidebar 槽的整槽替换(priority -1 shadow 官方 ui-sidebar)。\r\n *\r\n * 结构为官方 SidebarRoot(dsh-client-ui-sidebar 0.1.1-rc.2)的克隆,改动点:\r\n * - logoRow 高度 60px → 32px、底部间距 8px → 4px(需求①②);\r\n * - 「新会话」按钮从 logoRow 下方移入**面板区**(需求③),样式改为\r\n * workspace 菜单项行样式(需求④,镜像官方 Rows.module.css .sessionRow);\r\n * - 面板区 = 新会话菜单项 + 第三方功能项(槽 `sidebar.panel.action`,\r\n * list/root,本条目 children 声明,协议⑤,见 PROTOCOL.md)。\r\n *\r\n * 渲染官方子槽(brand.mark/brand.name/workspaces/footer.action/settings)一律\r\n * 走 <SlotOutlet>(无 children 所有权检查):官方条目仍 live(被 shadow),\r\n * 其 children 声明与 locale 注册继续生效;本条目**只**声明新增槽\r\n * sidebar.panel.action(子槽 key 全局唯一,绝不重声明官方子槽)。\r\n *\r\n * 交互行为镜像官方:折叠 settled(COLLAPSE_SETTLE_MS=150)→ wide 判定、\r\n * rail-in/fading 动画类、滚动条 linger(quietBars)。\r\n */\r\n\r\n/** COLLAPSE_SETTLE_MS — 折叠动画 settle 延迟(镜像官方)。 */\r\nconst COLLAPSE_SETTLE_MS = 150\r\n/** SCROLLBAR_LINGER_MS — 指针离开后滚动条淡出延迟(镜像官方)。 */\r\nconst SCROLLBAR_LINGER_MS = 2000\r\n\r\n/** 简易 classnames 拼接。 */\r\nfunction cx(...parts: Array<string | false | undefined>): string {\r\n return parts.filter(Boolean).join(' ')\r\n}\r\n\r\n/** sidebar 槽 owner 传入的合成 props 子集。 */\r\ninterface SidebarRootProps {\r\n /** 侧栏折叠态(layout 的 sidebarCol 状态)。 */\r\n collapsed: boolean\r\n /** 侧栏宽度(wide 态生效)。 */\r\n width: number\r\n /** 开始新会话(inject:ctx.workspaces.startSession)。 */\r\n startSession: (workspaceId?: string) => void\r\n /** 折叠/展开切换(inject:ctx.layout.toggleSidebar)。 */\r\n toggleSidebar: () => void\r\n /** 本条目 locale 翻译函数(panel NS)。 */\r\n t: (key: string) => string\r\n}\r\n\r\n/** 克隆的 SidebarRoot:紧凑 logoRow + 面板区 + 官方子槽透传。 */\r\nfunction SidebarRootClone({ collapsed, width, startSession, toggleSidebar, t }: SidebarRootProps): ReactElement {\r\n const [settled, setSettled] = useState(false)\r\n useEffect(() => {\r\n setSettled(false)\r\n const timer = window.setTimeout(() => {\r\n setSettled(true)\r\n }, COLLAPSE_SETTLE_MS)\r\n return () => {\r\n window.clearTimeout(timer)\r\n }\r\n }, [collapsed])\r\n\r\n const wide = !collapsed || !settled\r\n const lastWideWidth = useRef(width)\r\n if (!collapsed)\r\n lastWideWidth.current = width\r\n const everWide = useRef(!collapsed)\r\n if (!collapsed)\r\n everWide.current = true\r\n\r\n // 滚动条 linger:指针进入取消计时,离开后 2s 把滚动条 thumb 变透明。\r\n const [pointerInside, setPointerInside] = useState(false)\r\n const lingerTimer = useRef<number | undefined>(undefined)\r\n const armLinger = (): void => {\r\n if (lingerTimer.current !== undefined)\r\n return\r\n lingerTimer.current = window.setTimeout(() => {\r\n lingerTimer.current = undefined\r\n setPointerInside(false)\r\n }, SCROLLBAR_LINGER_MS)\r\n }\r\n const cancelLinger = (): void => {\r\n window.clearTimeout(lingerTimer.current)\r\n lingerTimer.current = undefined\r\n }\r\n\r\n return (\r\n <div\r\n className={cx(\r\n 'dshp-root',\r\n !wide && 'dshp-collapsed',\r\n !wide && everWide.current && 'dshp-railIn',\r\n collapsed && wide && 'dshp-fading',\r\n !pointerInside && 'dshp-quietBars',\r\n )}\r\n data-dshp-panel-sidebar=\"\"\r\n style={wide ? { width: collapsed ? lastWideWidth.current : width } : undefined}\r\n onPointerEnter={() => {\r\n cancelLinger()\r\n setPointerInside(true)\r\n }}\r\n onPointerLeave={() => {\r\n armLinger()\r\n }}\r\n >\r\n <div className=\"dshp-logoRow\">\r\n {wide && (\r\n <button\r\n type=\"button\"\r\n className=\"dshp-brand\"\r\n aria-label={t('session.new.label')}\r\n onClick={() => startSession()}\r\n >\r\n <span className=\"dshp-brandIdentity\" aria-hidden=\"true\">\r\n <span className=\"dshp-brandMark\">\r\n <SlotOutlet\r\n slotKey=\"sidebar.brand.mark\"\r\n ownerProps={{ size: 24 }}\r\n opts={{ fallback: <FishMark size={24} /> }}\r\n />\r\n </span>\r\n <span className=\"dshp-brandName\">\r\n <SlotOutlet\r\n slotKey=\"sidebar.brand.name\"\r\n ownerProps={{}}\r\n opts={{ fallback: <span className=\"dshp-fallbackBrandName\">DSH Local Build</span> }}\r\n />\r\n </span>\r\n </span>\r\n </button>\r\n )}\r\n <button\r\n type=\"button\"\r\n className=\"dshp-iconButton dshp-toggle\"\r\n aria-label={collapsed ? t('toggle.open') : t('toggle.collapse')}\r\n title={collapsed ? t('toggle.open') : t('toggle.collapse')}\r\n onClick={() => toggleSidebar()}\r\n >\r\n {!wide && (\r\n <span className=\"dshp-railMark\" aria-hidden=\"true\">\r\n <SlotOutlet\r\n slotKey=\"sidebar.brand.mark\"\r\n ownerProps={{ size: 24 }}\r\n opts={{ fallback: <FishMark size={24} /> }}\r\n />\r\n </span>\r\n )}\r\n <PanelLeftOutline size={wide ? 16 : 18} className=\"dshp-panelIcon\" />\r\n </button>\r\n </div>\r\n\r\n <div className=\"dshp-panelArea\">\r\n <button\r\n type=\"button\"\r\n className=\"dshp-menuItem\"\r\n title={t('session.new.label')}\r\n onClick={() => startSession()}\r\n >\r\n <span className=\"dshp-menuItemIcon\"><ChatOutline size={16} /></span>\r\n <span className=\"dshp-menuItemLabel\">{t('session.new')}</span>\r\n </button>\r\n <SlotOutlet slotKey=\"sidebar.panel.action\" ownerProps={{ wide }} />\r\n </div>\r\n\r\n <div className=\"dshp-regionArea\">\r\n <SlotOutlet\r\n slotKey=\"sidebar.workspaces\"\r\n ownerProps={{\r\n wide,\r\n expandSidebar: () => {\r\n if (collapsed)\r\n toggleSidebar()\r\n },\r\n }}\r\n />\r\n </div>\r\n\r\n <div className=\"dshp-footArea\">\r\n <div className=\"dshp-footerActions\">\r\n <SlotOutlet slotKey=\"sidebar.footer.action\" ownerProps={{ wide }} />\r\n </div>\r\n <div className=\"dshp-settingsArea\">\r\n <SlotOutlet slotKey=\"sidebar.settings\" ownerProps={{ wide }} />\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * 注册:等待 sidebar 槽声明(layout 的 AppFrame renderSlot(\"sidebar\"))后,\r\n * 以 priority -1 shadow 官方 ui-sidebar 条目;children 仅声明新增的\r\n * sidebar.panel.action 协议槽。\r\n * @param ctx - 客户端根上下文。\r\n */\r\nexport function installSidebarRoot(ctx: Context): void {\r\n ctx.slots.inject('sidebar' as never, () =>\r\n ctx.slots.register(\r\n {\r\n name: 'sidebar',\r\n id: 'dsh-tauri-panel',\r\n priority: -1,\r\n locale: NS,\r\n children: {\r\n 'sidebar.panel.action': { kind: 'list', scope: 'root' },\r\n },\r\n inject: () => ({\r\n startSession: (workspaceId?: WorkspaceId) => ctx.workspaces.startSession(workspaceId),\r\n toggleSidebar: () => ctx.layout.toggleSidebar(),\r\n }),\r\n } as never,\r\n SidebarRootClone,\r\n ))\r\n}\r\n","/**\r\n * styles.ts — 克隆 SidebarRoot 的样式注入。\r\n *\r\n * 整槽替换的收益:外壳 DOM 与样式完全自控,不依赖官方 CSS module 的 hash\r\n * 类名(hHd-Xa_* 随构建版本漂移)。类名统一 `dshp-` 前缀;数值镜像官方\r\n * SidebarRoot.module.css(0.1.1-rc.2),并按需求改造:\r\n * - logoRow 高度 60px → 32px、底部间距 8px → 4px(①②);\r\n * - 新会话按钮移入面板区、改为 workspace 菜单项行样式(③④,\r\n * 镜像官方 Rows.module.css 的 .sessionRow:32px / radius 8px / padding 0 8px /\r\n * hover var(--dsw-alias-interactive-bg-hover))。\r\n * 动画(rail-in 150ms 49px、fade、wide-in)与滚动条 linger(quietBars)保留官方行为。\r\n * 注入幂等:同 id 的 <style> 只插一次;插件卸载由宿主卸载 bundle,样式留存可接受。\r\n */\r\nconst STYLE_ID = 'dsh-tauri-panel-styles'\r\n\r\nconst CSS = `\r\n.dshp-root{--dshp-padding:12px;height:100%;padding:6px var(--dshp-padding);box-sizing:border-box;background:var(--dsw-specific-sidebar-fill);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex-direction:column;font-size:14px;display:flex}\r\n.dshp-root.dshp-collapsed{padding:18px 10px 6px}\r\n.dshp-root.dshp-quietBars{--dsh-scrollbar-thumb:transparent;--dsh-scrollbar-thumb-hover:transparent}\r\n.dshp-fading>*{opacity:0;transition:opacity .15s var(--ds-ease-in-out)}\r\n.dshp-railIn .dshp-iconButton,.dshp-railIn .dshp-menuItem,.dshp-railIn .dshp-regionArea{animation:dshp-rail-in .15s var(--ds-ease-in-out) backwards}\r\n.dshp-railIn .dshp-footArea{animation:dshp-rail-fade-in .15s var(--ds-ease-in-out) backwards}\r\n@keyframes dshp-rail-in{0%{opacity:0;transform:translate(49px)}}\r\n@keyframes dshp-rail-fade-in{0%{opacity:0}}\r\n.dshp-logoRow{box-sizing:border-box;flex:none;justify-content:flex-end;align-items:center;gap:8px;height:32px;margin-bottom:4px;padding:4px 0 4px 4px;display:flex;overflow:hidden}\r\n.dshp-collapsed .dshp-logoRow{justify-content:flex-start;height:32px;margin-bottom:4px;padding:0}\r\n.dshp-brand{min-width:0;color:inherit;cursor:pointer;background:transparent;border:none;flex:1;align-items:center;padding:0;display:inline-flex;overflow:hidden}\r\n.dshp-brandIdentity{align-items:center;gap:8px;min-width:0;height:24px;display:inline-flex}\r\n.dshp-brandMark{flex:none;justify-content:center;align-items:center;display:inline-flex}\r\n.dshp-brandName{letter-spacing:.04em;align-items:center;gap:6px;min-width:0;height:24px;font-size:18px;font-weight:600;line-height:24px;display:inline-flex}\r\n.dshp-fallbackBrandName{letter-spacing:0;white-space:nowrap;font-size:17px}\r\n.dshp-iconButton{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-secondary);background:transparent;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}\r\n.dshp-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}\r\n.dshp-collapsed .dshp-iconButton{width:36px;height:36px;color:var(--dsw-alias-label-primary)}\r\n.dshp-railMark{justify-content:center;align-items:center;display:inline-flex}\r\n.dshp-panelArea{flex:none;flex-direction:column;align-items:stretch;gap:2px;margin:0 0 8px;display:flex}\r\n.dshp-collapsed .dshp-panelArea{align-items:center;gap:4px}\r\n.dshp-menuItem{box-sizing:border-box;cursor:pointer;user-select:none;color:var(--dsw-alias-label-primary);background:transparent;border:none;border-radius:8px;align-items:center;gap:0;padding:0 8px;height:32px;min-width:0;display:flex;font-family:inherit;font-size:14px;line-height:22px;text-align:left;overflow:hidden}\r\n.dshp-menuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}\r\n.dshp-menuItemSelected,.dshp-menuItemSelected:hover{background:var(--dsw-alias-interactive-bg-hover)}\r\n.dshp-menuItemIcon{flex:none;width:16px;height:20px;color:var(--dsw-alias-label-tertiary);justify-content:center;align-items:center;display:inline-flex}\r\n.dshp-menuItemLabel{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0 6px 0 4px;min-width:0}\r\n.dshp-collapsed .dshp-menuItem{justify-content:center;width:36px;height:36px;padding:0}\r\n.dshp-collapsed .dshp-menuItemLabel{display:none}\r\n.dshp-regionArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--dshp-padding));flex-direction:column;flex:1;padding-left:4px;display:flex;overflow:hidden}\r\n.dshp-collapsed .dshp-regionArea{margin-left:0;margin-right:0;padding-left:0}\r\n.dshp-footArea{flex-direction:column;flex:none;display:flex}\r\n.dshp-settingsArea,.dshp-footerActions{flex:none;width:100%;min-width:0}\r\n.dshp-footerActions{display:flex}\r\n.dshp-collapsed .dshp-footArea{align-items:center}\r\n.dshp-collapsed .dshp-settingsArea,.dshp-collapsed .dshp-footerActions{justify-content:center;width:auto;display:flex}\r\n/* 会话区替换座位(宿主决定宽度约束):滚动容器 + 内容列。\r\n 内容列镜像官方会话内容列 .Md3f7G_column(max-width var(--dsh-chat-content-width)、\r\n width 100%、margin 0 auto、flex column、gap 16px);替换后官方\r\n ConversationRoot(定义该变量处)不渲染,以 748px(官方默认值)兜底,\r\n 外层若已有定义则继承生效——子插件零宽度关注。 */\r\n.dshp-panelView{height:100%;box-sizing:border-box;min-width:0;overflow-y:auto}\r\n.dshp-panelViewColumn{max-width:var(--dsh-chat-content-width,748px);min-height:100%;width:100%;margin:0 auto;flex-direction:column;gap:16px;display:flex}\r\n@media (prefers-reduced-motion:reduce){.dshp-fading>*,.dshp-railIn .dshp-iconButton,.dshp-railIn .dshp-menuItem,.dshp-railIn .dshp-footArea,.dshp-railIn .dshp-regionArea{transition:none;animation:none}}\r\n`\r\n\r\n/** 注入面板样式(幂等:同 id 只插一次)。 */\r\nexport function installPanelStyles(): void {\r\n if (typeof document === 'undefined')\r\n return\r\n if (document.getElementById(STYLE_ID) !== null)\r\n return\r\n const style = document.createElement('style')\r\n style.id = STYLE_ID\r\n style.textContent = CSS\r\n document.head.append(style)\r\n}\r\n","/**\r\n * dsh-tauri-panel 客户端插件体(browser half):工作区上方面板 UI。\r\n *\r\n * 能力(全部 slot-shadow,零结构补丁,零新增依赖):\r\n * 整槽替换 sidebar(priority -1 shadow 官方 ui-sidebar):克隆\r\n * SidebarRoot —— 紧凑 logoRow(32px、底距 4px)、面板区(新会话菜单项\r\n * + 协议槽 sidebar.panel.action 的第三方功能项)、官方子槽(workspaces/\r\n * settings/footer/brand)经 <SlotOutlet> 透传。\r\n *\r\n * 协议:第三方插件向面板区添加功能项 = 注册 `sidebar.panel.action`\r\n * (list/root,本插件声明),详见 PROTOCOL.md。\r\n *\r\n * 依赖:renderer 补丁导出的 <SlotOutlet>(任意槽渲染入口)。核心未带补丁时\r\n * (旧安装)SlotOutlet 为 undefined —— 此时整体不注册(官方侧栏原样工作),\r\n * 绝不白屏。\r\n */\r\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\r\nimport { SlotOutlet } from '@deepseek-ai/dsh-client-ui-renderer'\r\nimport { installPanelLocale } from './locale'\r\nimport { installPanelService } from './service'\r\nimport { installSidebarRoot } from './sidebar'\r\nimport { installPanelStyles } from './styles'\r\n\r\n/** 插件显示名(诊断元数据)。 */\r\nexport const name = 'dsh-tauri-panel'\r\n\r\n/** 需要的客户端服务:slots(注册点位)、layout(折叠/宽度)、workspaces(新会话)、locale(双语文案)。 */\r\nexport const inject = ['slots', 'layout', 'workspaces', 'locale']\r\n\r\n/**\r\n * 插件体:注册面板侧栏(整槽替换)。\r\n * @param ctx - 客户端根上下文。\r\n */\r\nexport function apply(ctx: ClientContext): void {\r\n installPanelStyles()\r\n installPanelLocale(ctx)\r\n // 面板协议宿主服务(panel.protocol:ActionItem + renderPanelContent):\r\n // 只走 slots runtime,不依赖 renderer 补丁——无补丁时内容区替换仍可用。\r\n installPanelService(ctx)\r\n\r\n // 侧栏面板依赖 renderer 补丁导出的 <SlotOutlet>;无补丁时不注册任何条目,\r\n // 官方侧栏原样工作。\r\n if (typeof SlotOutlet !== 'function') {\r\n console.warn(\r\n '[dsh-tauri-panel] <SlotOutlet> unavailable (renderer patch missing) — panel sidebar disabled, official UI stays.',\r\n )\r\n return\r\n }\r\n\r\n installSidebarRoot(ctx)\r\n}\r\n"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-tauri-panel",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"author": "Hairyf <wwu710632@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/hairyf/dsh-tauri-plugins#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/hairyf/dsh-tauri-plugins.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/hairyf/dsh-tauri-plugins/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"dsh",
|
|
15
|
+
"plugin",
|
|
16
|
+
"dsh-plugin",
|
|
17
|
+
"tauri",
|
|
18
|
+
"deepseek-harness"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./dist/index.js",
|
|
23
|
+
"./client": "./dist/client.js",
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"files": [
|
|
30
|
+
"README.md",
|
|
31
|
+
"cordis.patch.yml",
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"dsh": {
|
|
35
|
+
"client": {
|
|
36
|
+
"inject": [
|
|
37
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
38
|
+
"@deepseek-ai/dsh-client-ui-layout"
|
|
39
|
+
],
|
|
40
|
+
"platform": "web"
|
|
41
|
+
},
|
|
42
|
+
"bundle": {
|
|
43
|
+
"patch": "./cordis.patch.yml"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsdown",
|
|
48
|
+
"dev": "tsdown --watch",
|
|
49
|
+
"start": "tsx src/index.ts",
|
|
50
|
+
"test": "vitest",
|
|
51
|
+
"typecheck": "tsc"
|
|
52
|
+
}
|
|
53
|
+
}
|