@nextclaw/ui 0.14.1-beta.1 → 0.14.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/CHANGELOG.md +61 -0
- package/dist/assets/{api-dQ6uQSZG.js → api-a14tR_z1.js} +7 -7
- package/dist/assets/channels-list-page-CFGkm4DT.js +8 -0
- package/dist/assets/chat-page-CEdavJXc.js +105 -0
- package/dist/assets/{config-split-page-CeFfbaqc.js → config-split-page-B5b9B0uE.js} +1 -1
- package/dist/assets/{confirm-dialog-C95Y4QPC.js → confirm-dialog-ClH_Ec7n.js} +1 -1
- package/dist/assets/{desktop-update-config-CcK6jiEb.js → desktop-update-config-DPNDnVpk.js} +1 -1
- package/dist/assets/{dist-DTGzeil6.js → dist-BtCS2Ucq.js} +1 -1
- package/dist/assets/{dist-fGogBmPA.js → dist-CLGGLm8b.js} +1 -1
- package/dist/assets/doc-browser-5nMWYKBD.js +1 -0
- package/dist/assets/doc-browser-BJRLhztv.js +1 -0
- package/dist/assets/doc-browser-context-D4JwMMxK.js +1 -0
- package/dist/assets/{ellipsis-D2F4KMiU.js → ellipsis-CtJXjIol.js} +1 -1
- package/dist/assets/{external-link-CcgtBK26.js → external-link-CdJiG13p.js} +1 -1
- package/dist/assets/index-BDN1zzMQ.js +105 -0
- package/dist/assets/index-g3uSZXoc.css +1 -0
- package/dist/assets/mcp-marketplace-page-BU0kIjhR.js +40 -0
- package/dist/assets/mcp-marketplace-page-sMNFSq_T.js +1 -0
- package/dist/assets/middleware-CkFT3R4v.js +1 -0
- package/dist/assets/model-config-page-D6hYXROd.js +1 -0
- package/dist/assets/plus-DPjb0piO.js +1 -0
- package/dist/assets/provider-scoped-model-input-DAX2HgmR.js +1 -0
- package/dist/assets/providers-config-page-BzAeaACA.js +1 -0
- package/dist/assets/{react-CTqdhFMk.js → react-C6cZgP44.js} +1 -1
- package/dist/assets/remote-B0G80uPr.js +1 -0
- package/dist/assets/rotate-cw-DnEB1Rju.js +1 -0
- package/dist/assets/runtime-config-page-C5xKaV3i.js +1 -0
- package/dist/assets/{save-C9fKWfVB.js → save-DKA0x4zk.js} +1 -1
- package/dist/assets/{search-D5FQ5q0X.js → search-BNlcoj5c.js} +1 -1
- package/dist/assets/{search-config-page-AMEJJNIS.js → search-config-page-Cq9uJ-N8.js} +1 -1
- package/dist/assets/{secrets-config-page-CcgJnvBO.js → secrets-config-page-CxSbZLBo.js} +2 -2
- package/dist/assets/{select-Cu5n0E-3.js → select-CvTlDZTQ.js} +1 -1
- package/dist/assets/{tag-chip-C5aOtjxu.js → tag-chip-8ffF2y2C.js} +1 -1
- package/dist/assets/use-config-DmT0o1gv.js +1 -0
- package/dist/assets/x-BiSSpgqB.js +1 -0
- package/dist/index.html +15 -14
- package/package.json +9 -9
- package/src/app/components/app-presenter-provider.tsx +11 -2
- package/src/app/components/layout/__tests__/app-layout.test.tsx +11 -2
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +110 -79
- package/src/app/components/layout/app-layout.tsx +18 -4
- package/src/app/components/layout/sidebar-items.tsx +194 -71
- package/src/app/components/layout/sidebar-rail.styles.ts +15 -0
- package/src/app/components/layout/sidebar.tsx +340 -83
- package/src/app/managers/viewport-layout.manager.ts +10 -0
- package/src/app/stores/viewport-layout.store.ts +39 -3
- package/src/features/agents/components/__tests__/agents-page.test.tsx +62 -39
- package/src/features/agents/components/agents-page.tsx +10 -6
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +69 -762
- package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +132 -0
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +22 -15
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +14 -15
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +18 -18
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +10 -4
- package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +52 -11
- package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +77 -12
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +182 -21
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +82 -25
- package/src/features/chat/components/layout/chat-sidebar.tsx +79 -93
- package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +289 -0
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +427 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +204 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +66 -0
- package/src/features/chat/features/{input/hooks/use-chat-input-bar-query-state.ts → conversation/hooks/use-session-conversation-input-query.ts} +32 -17
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +281 -0
- package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +158 -0
- package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +56 -0
- package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +117 -0
- package/src/features/chat/features/input/hooks/use-chat-model-favorites.ts +2 -1
- package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +77 -0
- package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +10 -0
- package/src/features/chat/features/input/input-surface-plugins/input-surface-search.utils.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +161 -0
- package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
- package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +26 -13
- package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +7 -28
- package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +6 -0
- package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +26 -51
- package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +2 -0
- package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +5 -6
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +47 -12
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +93 -12
- package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +31 -12
- package/src/features/chat/features/message/utils/chat-message-markdown-part.utils.ts +38 -0
- package/src/features/chat/features/message/utils/chat-message-part.utils.ts +1 -1
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +2 -2
- package/src/features/chat/features/session/hooks/__tests__/use-chat-session-project.test.tsx +3 -30
- package/src/features/chat/features/session/hooks/use-chat-session-project.ts +0 -5
- package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +8 -0
- package/src/features/chat/features/session-type/components/__tests__/{chat-sidebar-create-menu.test.tsx → chat-session-type-menu.test.tsx} +5 -5
- package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +29 -1
- package/src/features/chat/features/session-type/components/{chat-sidebar-create-menu.tsx → chat-session-type-menu.tsx} +13 -9
- package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +17 -5
- package/src/features/chat/features/session-type/hooks/__tests__/use-chat-new-session-type-preference.test.tsx +152 -0
- package/src/features/chat/features/session-type/hooks/use-chat-new-session-type-preference.ts +159 -0
- package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +49 -31
- package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +2 -2
- package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +2 -2
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +2 -2
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +54 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +44 -76
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +7 -1
- package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +40 -31
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +59 -1
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +109 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +44 -4
- package/src/features/chat/index.ts +0 -1
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +51 -99
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +135 -21
- package/src/features/chat/managers/chat-session-list.manager.ts +12 -43
- package/src/features/chat/managers/chat-thread.manager.ts +108 -34
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +48 -1
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +72 -0
- package/src/features/chat/pages/ncp-chat-page.tsx +0 -122
- package/src/features/chat/presenters/chat.presenter.ts +2 -19
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +31 -0
- package/src/features/chat/stores/chat-thread.store.ts +42 -26
- package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +24 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +8 -3
- package/src/features/marketplace/components/marketplace-item-list-view.tsx +2 -2
- package/src/features/marketplace/components/marketplace-list-card.tsx +124 -98
- package/src/features/marketplace/components/marketplace-page-parts.tsx +11 -6
- package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
- package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +50 -10
- package/src/platforms/desktop/components/desktop-app-shell.tsx +34 -10
- package/src/platforms/desktop/components/desktop-window-chrome.tsx +41 -16
- package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -1
- package/src/shared/components/common/agent-avatar.tsx +5 -2
- package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +24 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -4
- package/src/shared/lib/api/index.ts +1 -0
- package/src/shared/lib/api/preferences/preference-keys.config.ts +9 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
- package/src/shared/lib/i18n/locales/en-US/core.json +2 -0
- package/src/shared/lib/i18n/locales/en-US/marketplace.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
- package/src/shared/lib/i18n/locales/zh-CN/core.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +2 -0
- package/src/shared/lib/ui-document-title/__tests__/ui-document-title.test.ts +49 -0
- package/src/shared/lib/ui-document-title/index.ts +50 -21
- package/dist/assets/channels-list-page-DfpjB8XB.js +0 -8
- package/dist/assets/chat-page-D3QaEqjs.js +0 -105
- package/dist/assets/doc-browser-CuBTcBEZ.js +0 -1
- package/dist/assets/doc-browser-DVHhEb96.js +0 -1
- package/dist/assets/doc-browser-context-BfMXwnrz.js +0 -1
- package/dist/assets/index-ByJCbQqr.css +0 -1
- package/dist/assets/index-DjXqiloY.js +0 -103
- package/dist/assets/mcp-marketplace-page-98-V__3u.js +0 -1
- package/dist/assets/mcp-marketplace-page-BNq_PNmO.js +0 -40
- package/dist/assets/model-config-page-aAUkZkSX.js +0 -1
- package/dist/assets/plus-1Rxl5FlV.js +0 -1
- package/dist/assets/provider-scoped-model-input-we4_Z4gP.js +0 -1
- package/dist/assets/providers-config-page-CtMkPSyu.js +0 -1
- package/dist/assets/remote-fQ7N_r8u.js +0 -1
- package/dist/assets/rotate-cw-CzfIeAJj.js +0 -1
- package/dist/assets/runtime-config-page-TD1UrTbG.js +0 -1
- package/dist/assets/use-config-D8TESeo6.js +0 -1
- package/dist/assets/x-1qETdQ70.js +0 -1
- package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +0 -37
- package/src/features/chat/features/input/components/__tests__/chat-attachment-upload-limit.test.ts +0 -38
- package/src/features/chat/features/input/components/chat-input-bar.container.tsx +0 -496
- package/src/features/chat/features/message/utils/chat-message-inline-content.utils.ts +0 -95
- package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +0 -448
- package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +0 -129
- package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +0 -236
- package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +0 -219
- package/src/features/chat/managers/chat-input.manager.ts +0 -430
- package/src/features/chat/managers/chat-run.manager.ts +0 -110
- package/src/features/chat/managers/chat-session-preference-sync.manager.ts +0 -142
- package/src/features/chat/stores/chat-input.store.ts +0 -104
- /package/dist/assets/{config-hints-CTqBnCDp.js → config-hints-BkYBc7z0.js} +0 -0
|
@@ -37,7 +37,6 @@ type MarketplaceListCardActionProps = {
|
|
|
37
37
|
record?: MarketplaceInstalledRecord;
|
|
38
38
|
state: {
|
|
39
39
|
isInstalling: boolean;
|
|
40
|
-
isDisabled: boolean;
|
|
41
40
|
canUpdate: boolean;
|
|
42
41
|
canUninstall: boolean;
|
|
43
42
|
busyAction?: MarketplaceManageAction;
|
|
@@ -52,17 +51,15 @@ type MarketplaceListCardActionProps = {
|
|
|
52
51
|
function MarketplaceListCardMeta({
|
|
53
52
|
title,
|
|
54
53
|
spec,
|
|
55
|
-
summary,
|
|
56
54
|
}: {
|
|
57
55
|
title: string;
|
|
58
56
|
spec: string;
|
|
59
|
-
summary: string;
|
|
60
57
|
}) {
|
|
61
58
|
return (
|
|
62
59
|
<TooltipProvider delayDuration={400}>
|
|
63
60
|
<Tooltip>
|
|
64
61
|
<TooltipTrigger asChild>
|
|
65
|
-
<div className="truncate text-[14px] font-semibold leading-tight text-gray-
|
|
62
|
+
<div className="truncate text-[14px] font-semibold leading-tight text-gray-950">
|
|
66
63
|
{title}
|
|
67
64
|
</div>
|
|
68
65
|
</TooltipTrigger>
|
|
@@ -71,11 +68,11 @@ function MarketplaceListCardMeta({
|
|
|
71
68
|
</TooltipContent>
|
|
72
69
|
</Tooltip>
|
|
73
70
|
|
|
74
|
-
<div className="mb-
|
|
71
|
+
<div className="mb-2 mt-1 flex min-w-0 items-center gap-1.5">
|
|
75
72
|
{spec ? (
|
|
76
73
|
<Tooltip>
|
|
77
74
|
<TooltipTrigger asChild>
|
|
78
|
-
<span className="max-w-full truncate text-[11px] font-mono text-gray-400">
|
|
75
|
+
<span className="max-w-full truncate text-[11px] font-mono leading-tight text-gray-400">
|
|
79
76
|
{spec}
|
|
80
77
|
</span>
|
|
81
78
|
</TooltipTrigger>
|
|
@@ -85,15 +82,11 @@ function MarketplaceListCardMeta({
|
|
|
85
82
|
</Tooltip>
|
|
86
83
|
) : null}
|
|
87
84
|
</div>
|
|
88
|
-
|
|
89
|
-
<p className="line-clamp-2 text-left text-[12px] leading-relaxed text-gray-500/90">
|
|
90
|
-
{summary}
|
|
91
|
-
</p>
|
|
92
85
|
</TooltipProvider>
|
|
93
86
|
);
|
|
94
87
|
}
|
|
95
88
|
|
|
96
|
-
function
|
|
89
|
+
function MarketplaceListCardActionButtons(props: MarketplaceListCardActionProps) {
|
|
97
90
|
const {
|
|
98
91
|
item,
|
|
99
92
|
record,
|
|
@@ -103,96 +96,94 @@ function MarketplaceListCardActions(props: MarketplaceListCardActionProps) {
|
|
|
103
96
|
} = props;
|
|
104
97
|
const {
|
|
105
98
|
isInstalling,
|
|
106
|
-
isDisabled,
|
|
107
99
|
canUpdate,
|
|
108
100
|
canUninstall,
|
|
109
101
|
busyAction,
|
|
110
102
|
} = state;
|
|
111
103
|
const busyForRecord = Boolean(busyAction);
|
|
112
104
|
const hasActions = Boolean((item && !record) || (record && (canUpdate || canUninstall)));
|
|
105
|
+
if (!hasActions) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
113
108
|
|
|
114
109
|
return (
|
|
115
110
|
<div
|
|
116
111
|
className={cn(
|
|
117
|
-
"
|
|
118
|
-
|
|
112
|
+
"flex shrink-0 items-center justify-end gap-1.5 opacity-100 transition-opacity duration-150",
|
|
113
|
+
"md:pointer-events-none md:opacity-0",
|
|
114
|
+
"md:group-hover:pointer-events-auto md:group-hover:opacity-100",
|
|
115
|
+
"md:group-focus-within:pointer-events-auto md:group-focus-within:opacity-100",
|
|
119
116
|
)}
|
|
120
117
|
>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
118
|
+
{item && !record && (
|
|
119
|
+
<button
|
|
120
|
+
onClick={(event) => {
|
|
121
|
+
event.stopPropagation();
|
|
122
|
+
onInstall(item);
|
|
123
|
+
}}
|
|
124
|
+
disabled={isInstalling}
|
|
125
|
+
className="inline-flex h-6 items-center gap-1 whitespace-nowrap rounded-md bg-primary px-2 text-[11px] font-medium text-white transition-colors hover:bg-primary-600 disabled:opacity-50"
|
|
126
|
+
>
|
|
127
|
+
<Download className="h-3 w-3" />
|
|
128
|
+
{isInstalling ? t("marketplaceInstalling") : t("marketplaceInstall")}
|
|
129
|
+
</button>
|
|
130
|
+
)}
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
className="inline-flex h-8 items-center gap-1.5 whitespace-nowrap rounded-xl bg-primary px-3 text-xs font-medium text-white transition-colors hover:bg-primary-600 disabled:opacity-50"
|
|
148
|
-
>
|
|
149
|
-
<Download className="h-3.5 w-3.5" />
|
|
150
|
-
{isInstalling ? t("marketplaceInstalling") : t("marketplaceInstall")}
|
|
151
|
-
</button>
|
|
152
|
-
)}
|
|
132
|
+
{record && canUpdate && (
|
|
133
|
+
<button
|
|
134
|
+
disabled={busyForRecord}
|
|
135
|
+
onClick={(event) => {
|
|
136
|
+
event.stopPropagation();
|
|
137
|
+
onManage("update", record);
|
|
138
|
+
}}
|
|
139
|
+
className="inline-flex h-6 items-center gap-1 whitespace-nowrap rounded-md border border-blue-200/80 bg-white px-2 text-[11px] font-medium text-blue-600 transition-colors hover:border-blue-300 hover:bg-blue-50 disabled:opacity-50"
|
|
140
|
+
>
|
|
141
|
+
<RefreshCw className="h-3 w-3" />
|
|
142
|
+
{busyAction === "update"
|
|
143
|
+
? t("marketplaceUpdating")
|
|
144
|
+
: t("marketplaceUpdate")}
|
|
145
|
+
</button>
|
|
146
|
+
)}
|
|
153
147
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
148
|
+
{record && canUninstall && (
|
|
149
|
+
<button
|
|
150
|
+
disabled={busyForRecord}
|
|
151
|
+
onClick={(event) => {
|
|
152
|
+
event.stopPropagation();
|
|
153
|
+
onManage("uninstall", record);
|
|
154
|
+
}}
|
|
155
|
+
className="inline-flex h-6 items-center gap-1 whitespace-nowrap rounded-md border border-gray-200/80 bg-white px-2 text-[11px] font-medium text-gray-500 transition-colors hover:border-rose-200 hover:bg-rose-50 hover:text-rose-600 disabled:opacity-50"
|
|
156
|
+
>
|
|
157
|
+
<Trash2 className="h-3 w-3" />
|
|
158
|
+
{busyAction === "uninstall"
|
|
159
|
+
? t("marketplaceRemoving")
|
|
160
|
+
: t("marketplaceUninstall")}
|
|
161
|
+
</button>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
169
166
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
? t("marketplaceRemoving")
|
|
182
|
-
: t("marketplaceUninstall")}
|
|
183
|
-
</button>
|
|
184
|
-
)}
|
|
185
|
-
</div>
|
|
167
|
+
function MarketplaceListCardStatus(props: {
|
|
168
|
+
record?: MarketplaceInstalledRecord;
|
|
169
|
+
disabled: boolean;
|
|
170
|
+
}) {
|
|
171
|
+
const { record, disabled } = props;
|
|
172
|
+
if (!record) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return (
|
|
176
|
+
<div className="flex h-5 w-5 shrink-0 items-center justify-end">
|
|
177
|
+
<MarketplaceInstalledStatusIcon disabled={disabled} />
|
|
186
178
|
</div>
|
|
187
179
|
);
|
|
188
180
|
}
|
|
189
181
|
|
|
190
182
|
function MarketplaceInstalledStatusIcon(props: { disabled: boolean }) {
|
|
191
183
|
const { disabled } = props;
|
|
192
|
-
const { language } = useI18n();
|
|
193
184
|
const label = disabled
|
|
194
|
-
?
|
|
195
|
-
:
|
|
185
|
+
? t("marketplaceDisabledStatus")
|
|
186
|
+
: t("marketplaceInstalledStatus");
|
|
196
187
|
|
|
197
188
|
return (
|
|
198
189
|
<TooltipProvider delayDuration={300}>
|
|
@@ -251,6 +242,7 @@ export function MarketplaceListCard(props: {
|
|
|
251
242
|
pickLocalizedText(item?.summaryI18n, item?.summary, localeFallbacks) ||
|
|
252
243
|
(record ? t("marketplaceInstalledLocalSummary") : "");
|
|
253
244
|
const spec = item?.install.spec ?? record?.spec ?? "";
|
|
245
|
+
const tags = item?.tags ?? [];
|
|
254
246
|
const targetId = record?.id || record?.spec;
|
|
255
247
|
const busyAction = targetId
|
|
256
248
|
? manageState.actionsByTarget.get(targetId)
|
|
@@ -268,35 +260,69 @@ export function MarketplaceListCard(props: {
|
|
|
268
260
|
return (
|
|
269
261
|
<article
|
|
270
262
|
onClick={onOpen}
|
|
271
|
-
className="group flex
|
|
263
|
+
className="group flex h-full min-h-[156px] cursor-pointer flex-col rounded-xl border border-gray-200/60 bg-white p-3.5 shadow-sm transition-colors hover:border-gray-300 hover:bg-gray-50/60"
|
|
272
264
|
>
|
|
273
|
-
<div className="flex min-w-0
|
|
265
|
+
<div className="flex min-w-0 items-start gap-2.5">
|
|
274
266
|
<MarketplaceItemIcon
|
|
275
267
|
name={title}
|
|
276
268
|
fallback={spec || t("marketplaceTypeSkill")}
|
|
269
|
+
className="h-9 w-9 rounded-lg text-xs"
|
|
277
270
|
/>
|
|
278
|
-
<div className="flex min-w-0 flex-1 flex-col
|
|
279
|
-
<MarketplaceListCardMeta title={title} spec={spec}
|
|
271
|
+
<div className="flex min-w-0 flex-1 flex-col">
|
|
272
|
+
<MarketplaceListCardMeta title={title} spec={spec} />
|
|
280
273
|
</div>
|
|
274
|
+
|
|
275
|
+
<MarketplaceListCardStatus record={record} disabled={isDisabled} />
|
|
281
276
|
</div>
|
|
282
277
|
|
|
283
|
-
<
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
278
|
+
<div className="mt-2 flex min-w-0 flex-1 flex-col">
|
|
279
|
+
<p className="line-clamp-2 text-left text-[12px] leading-relaxed text-gray-500">
|
|
280
|
+
{summary}
|
|
281
|
+
</p>
|
|
282
|
+
|
|
283
|
+
<div className="mt-auto flex min-w-0 items-end justify-between gap-2 pt-2">
|
|
284
|
+
<div className="min-w-0 flex-1">
|
|
285
|
+
<MarketplaceListCardTags tags={tags} />
|
|
286
|
+
</div>
|
|
287
|
+
<MarketplaceListCardActionButtons
|
|
288
|
+
item={item}
|
|
289
|
+
record={record}
|
|
290
|
+
state={{
|
|
291
|
+
isInstalling,
|
|
292
|
+
canUpdate,
|
|
293
|
+
canUninstall,
|
|
294
|
+
busyAction,
|
|
295
|
+
}}
|
|
296
|
+
onInstall={onInstall}
|
|
297
|
+
onManage={onManage}
|
|
298
|
+
/>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
296
301
|
</article>
|
|
297
302
|
);
|
|
298
303
|
}
|
|
299
304
|
|
|
300
|
-
function
|
|
301
|
-
|
|
305
|
+
function MarketplaceListCardTags({ tags }: { tags: string[] }) {
|
|
306
|
+
const visibleTags = tags.filter(isVisibleMarketplaceTag).slice(0, 3);
|
|
307
|
+
if (visibleTags.length === 0) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<div className="flex min-w-0 flex-wrap gap-1.5 overflow-hidden">
|
|
313
|
+
{visibleTags.map((tag) => (
|
|
314
|
+
<span
|
|
315
|
+
key={tag}
|
|
316
|
+
className="max-w-[104px] truncate rounded-md bg-gray-100 px-2 py-0.5 text-[11px] font-medium leading-5 text-gray-500"
|
|
317
|
+
>
|
|
318
|
+
{tag}
|
|
319
|
+
</span>
|
|
320
|
+
))}
|
|
321
|
+
</div>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function isVisibleMarketplaceTag(tag: string) {
|
|
326
|
+
const normalized = tag.trim().toLowerCase();
|
|
327
|
+
return normalized.length > 0 && normalized !== "skill";
|
|
302
328
|
}
|
|
@@ -78,21 +78,26 @@ export function MarketplaceListSkeleton({ count }: {
|
|
|
78
78
|
{Array.from({ length: count }, (_, index) => (
|
|
79
79
|
<article
|
|
80
80
|
key={`marketplace-skeleton-${index}`}
|
|
81
|
-
className="h-full rounded-
|
|
81
|
+
className="h-full rounded-xl border border-gray-200/60 bg-white p-3.5 shadow-sm"
|
|
82
82
|
>
|
|
83
|
-
<div className="flex items-start justify-between gap-
|
|
84
|
-
<div className="flex min-w-0 flex-1 gap-
|
|
85
|
-
<Skeleton className="h-
|
|
86
|
-
<div className="min-w-0 flex-1 space-y-2
|
|
83
|
+
<div className="flex items-start justify-between gap-2.5">
|
|
84
|
+
<div className="flex min-w-0 flex-1 gap-2.5">
|
|
85
|
+
<Skeleton className="h-9 w-9 shrink-0 rounded-lg" />
|
|
86
|
+
<div className="min-w-0 flex-1 space-y-2">
|
|
87
87
|
<Skeleton className="h-4 w-32 max-w-[70%]" />
|
|
88
88
|
<div className="flex items-center gap-2">
|
|
89
89
|
<Skeleton className="h-3 w-12" />
|
|
90
90
|
<Skeleton className="h-3 w-24" />
|
|
91
91
|
</div>
|
|
92
92
|
<Skeleton className="h-3 w-full" />
|
|
93
|
+
<div className="flex gap-1.5 pt-0.5">
|
|
94
|
+
<Skeleton className="h-5 w-14 rounded-md" />
|
|
95
|
+
<Skeleton className="h-5 w-16 rounded-md" />
|
|
96
|
+
<Skeleton className="h-5 w-12 rounded-md" />
|
|
97
|
+
</div>
|
|
93
98
|
</div>
|
|
94
99
|
</div>
|
|
95
|
-
<Skeleton className="h-
|
|
100
|
+
<Skeleton className="h-7 w-16 shrink-0 rounded-md" />
|
|
96
101
|
</div>
|
|
97
102
|
</article>
|
|
98
103
|
))}
|
|
@@ -4,10 +4,11 @@ import type { PanelAppPreferencesUpdateView } from '@/shared/lib/api';
|
|
|
4
4
|
|
|
5
5
|
const PANEL_APPS_QUERY_KEY = ['panel-apps'] as const;
|
|
6
6
|
|
|
7
|
-
export function usePanelApps() {
|
|
7
|
+
export function usePanelApps(options: { enabled?: boolean } = {}) {
|
|
8
8
|
return useQuery({
|
|
9
9
|
queryKey: PANEL_APPS_QUERY_KEY,
|
|
10
10
|
queryFn: () => nextclawClient.panelApps.listPanelApps(),
|
|
11
|
+
enabled: options.enabled ?? true,
|
|
11
12
|
staleTime: 0,
|
|
12
13
|
});
|
|
13
14
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { act, render, screen } from "@testing-library/react";
|
|
2
2
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3
3
|
import { MemoryRouter } from "react-router-dom";
|
|
4
|
-
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
5
|
import { DesktopAppShell } from "@/platforms/desktop/components/desktop-app-shell";
|
|
6
|
+
import { viewportLayoutManager } from "@/app/managers/viewport-layout.manager";
|
|
6
7
|
|
|
7
8
|
vi.mock("@/app/components/layout/sidebar", () => ({
|
|
8
9
|
Sidebar: () => <aside data-testid="settings-sidebar">Settings Sidebar</aside>,
|
|
@@ -16,7 +17,10 @@ type WindowStateListener = (snapshot: { isMaximized: boolean }) => void;
|
|
|
16
17
|
|
|
17
18
|
let windowStateListener: WindowStateListener | null = null;
|
|
18
19
|
|
|
19
|
-
function setDesktopPlatform(
|
|
20
|
+
function setDesktopPlatform(
|
|
21
|
+
platform: string | null,
|
|
22
|
+
isMaximized = false,
|
|
23
|
+
): void {
|
|
20
24
|
windowStateListener = null;
|
|
21
25
|
window.nextclawDesktop = platform
|
|
22
26
|
? ({
|
|
@@ -59,6 +63,11 @@ function renderDesktopShell(platform: string | null, isMobileLayout = false) {
|
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
describe("DesktopAppShell", () => {
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
window.localStorage.clear();
|
|
68
|
+
viewportLayoutManager.resetForTests();
|
|
69
|
+
});
|
|
70
|
+
|
|
62
71
|
afterEach(() => {
|
|
63
72
|
setDesktopPlatform(null);
|
|
64
73
|
});
|
|
@@ -68,29 +77,58 @@ describe("DesktopAppShell", () => {
|
|
|
68
77
|
|
|
69
78
|
const chrome = screen.getByTestId("desktop-window-chrome");
|
|
70
79
|
const sidebarChrome = screen.getByTestId("desktop-window-chrome-sidebar");
|
|
71
|
-
const resizeStrip = screen.getByTestId(
|
|
80
|
+
const resizeStrip = screen.getByTestId(
|
|
81
|
+
"desktop-window-chrome-resize-strip",
|
|
82
|
+
);
|
|
72
83
|
const controls = screen.getByTestId("desktop-window-controls");
|
|
73
84
|
|
|
74
85
|
expect(chrome).toBeTruthy();
|
|
75
|
-
expect(
|
|
86
|
+
expect(
|
|
87
|
+
chrome.parentElement?.style.getPropertyValue("--desktop-titlebar-height"),
|
|
88
|
+
).toBe("40px");
|
|
76
89
|
expect(chrome.className).toContain("bg-secondary");
|
|
77
90
|
expect(chrome.className).not.toContain(" shrink-0 border-b ");
|
|
78
|
-
expect(chrome.className).toContain(
|
|
91
|
+
expect(chrome.className).toContain(
|
|
92
|
+
"after:left-[var(--desktop-sidebar-width)]",
|
|
93
|
+
);
|
|
79
94
|
expect(chrome.className).toContain("after:border-b");
|
|
80
95
|
expect(chrome.className).toContain("desktop-window-drag");
|
|
81
|
-
expect(sidebarChrome.className).toContain(
|
|
96
|
+
expect(sidebarChrome.className).toContain(
|
|
97
|
+
"w-[var(--desktop-sidebar-width)]",
|
|
98
|
+
);
|
|
82
99
|
expect(sidebarChrome.className).not.toContain("border-b");
|
|
83
100
|
expect(sidebarChrome.className).toContain("desktop-window-drag");
|
|
84
101
|
expect(resizeStrip.className).toContain("desktop-window-no-drag");
|
|
85
102
|
expect(resizeStrip.className).toContain("top-0");
|
|
86
103
|
expect(resizeStrip.className).toContain("h-1");
|
|
87
104
|
expect(controls.className).toContain("desktop-window-no-drag");
|
|
88
|
-
expect(screen.getByLabelText("Minimize").className).toContain(
|
|
89
|
-
|
|
90
|
-
|
|
105
|
+
expect(screen.getByLabelText("Minimize").className).toContain(
|
|
106
|
+
"desktop-window-no-drag",
|
|
107
|
+
);
|
|
108
|
+
expect(screen.getByLabelText("Maximize").className).toContain(
|
|
109
|
+
"desktop-window-no-drag",
|
|
110
|
+
);
|
|
111
|
+
expect(screen.getByLabelText("Close").className).toContain(
|
|
112
|
+
"desktop-window-no-drag",
|
|
113
|
+
);
|
|
91
114
|
expect(screen.getByTestId("app-content")).toBeTruthy();
|
|
92
115
|
});
|
|
93
116
|
|
|
117
|
+
it("uses the collapsed sidebar width in Windows chrome from the shared layout store", () => {
|
|
118
|
+
viewportLayoutManager.setSidebarCollapsed(true);
|
|
119
|
+
|
|
120
|
+
renderDesktopShell("win32");
|
|
121
|
+
|
|
122
|
+
const chromeRoot = screen.getByTestId(
|
|
123
|
+
"desktop-window-chrome",
|
|
124
|
+
).parentElement;
|
|
125
|
+
|
|
126
|
+
expect(chromeRoot?.style.getPropertyValue("--desktop-sidebar-width")).toBe(
|
|
127
|
+
"56px",
|
|
128
|
+
);
|
|
129
|
+
expect(screen.getByAltText("NextClaw")).toBeTruthy();
|
|
130
|
+
});
|
|
131
|
+
|
|
94
132
|
it("switches the Windows maximize button to restore while maximized", async () => {
|
|
95
133
|
renderDesktopShell("win32");
|
|
96
134
|
|
|
@@ -100,7 +138,9 @@ describe("DesktopAppShell", () => {
|
|
|
100
138
|
windowStateListener?.({ isMaximized: true });
|
|
101
139
|
});
|
|
102
140
|
|
|
103
|
-
expect(screen.getByLabelText("Restore").className).toContain(
|
|
141
|
+
expect(screen.getByLabelText("Restore").className).toContain(
|
|
142
|
+
"desktop-window-no-drag",
|
|
143
|
+
);
|
|
104
144
|
expect(screen.queryByLabelText("Maximize")).toBeNull();
|
|
105
145
|
});
|
|
106
146
|
|
|
@@ -11,9 +11,12 @@ import { MobileBottomNav } from "@/platforms/mobile";
|
|
|
11
11
|
import type { DocBrowserCustomTabRenderers } from "@/shared/components/doc-browser/doc-browser-renderer.types";
|
|
12
12
|
import type { DocBrowserDockControls } from "@/shared/components/doc-browser/doc-browser-context";
|
|
13
13
|
import { cn } from "@/shared/lib/utils";
|
|
14
|
+
import { useViewportLayoutStore } from "@/app/stores/viewport-layout.store";
|
|
15
|
+
import { SIDEBAR_RAIL_WIDTH_PX } from "@/app/components/layout/sidebar-rail.styles";
|
|
14
16
|
|
|
15
17
|
const DocBrowser = lazy(async () => ({
|
|
16
|
-
default: (await import("@/shared/components/doc-browser/doc-browser"))
|
|
18
|
+
default: (await import("@/shared/components/doc-browser/doc-browser"))
|
|
19
|
+
.DocBrowser,
|
|
17
20
|
}));
|
|
18
21
|
|
|
19
22
|
type DesktopAppShellProps = {
|
|
@@ -38,8 +41,17 @@ export function DesktopAppShell({
|
|
|
38
41
|
children,
|
|
39
42
|
}: DesktopAppShellProps) {
|
|
40
43
|
const isMainRoute = isMainWorkspaceRoute(pathname);
|
|
41
|
-
const
|
|
44
|
+
const isSidebarCollapsed = useViewportLayoutStore(
|
|
45
|
+
(state) => state.isSidebarCollapsed,
|
|
46
|
+
);
|
|
47
|
+
const showMobileBottomNav =
|
|
48
|
+
isMobileLayout && !isChatSessionDetailRoute(pathname);
|
|
42
49
|
const shouldUseWindowsChrome = isWindowsDesktopHost();
|
|
50
|
+
const desktopSidebarWidth = isSidebarCollapsed
|
|
51
|
+
? `${SIDEBAR_RAIL_WIDTH_PX}px`
|
|
52
|
+
: isMainRoute
|
|
53
|
+
? "280px"
|
|
54
|
+
: "240px";
|
|
43
55
|
|
|
44
56
|
return (
|
|
45
57
|
<div
|
|
@@ -47,13 +59,19 @@ export function DesktopAppShell({
|
|
|
47
59
|
"h-screen flex flex-col overflow-hidden bg-background font-sans text-foreground",
|
|
48
60
|
shouldUseWindowsChrome ? "rounded-[10px]" : null,
|
|
49
61
|
)}
|
|
50
|
-
style={
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
style={
|
|
63
|
+
shouldUseWindowsChrome
|
|
64
|
+
? ({
|
|
65
|
+
"--desktop-titlebar-height": "40px",
|
|
66
|
+
"--desktop-caption-safe-right": "140px",
|
|
67
|
+
"--desktop-sidebar-width": desktopSidebarWidth,
|
|
68
|
+
} as CSSProperties)
|
|
69
|
+
: undefined
|
|
70
|
+
}
|
|
55
71
|
>
|
|
56
|
-
{shouldUseWindowsChrome ?
|
|
72
|
+
{shouldUseWindowsChrome ? (
|
|
73
|
+
<DesktopWindowChrome sidebarCollapsed={isSidebarCollapsed} />
|
|
74
|
+
) : null}
|
|
57
75
|
<div className="flex min-h-0 flex-1 overflow-hidden">
|
|
58
76
|
{!isMainRoute && <Sidebar mode="settings" />}
|
|
59
77
|
<div className="flex-1 flex min-w-0 overflow-hidden relative">
|
|
@@ -70,7 +88,10 @@ export function DesktopAppShell({
|
|
|
70
88
|
</div>
|
|
71
89
|
{isDocBrowserOpen && docBrowserMode === "docked" ? (
|
|
72
90
|
<Suspense fallback={null}>
|
|
73
|
-
<DocBrowser
|
|
91
|
+
<DocBrowser
|
|
92
|
+
customTabRenderers={docBrowserRenderers}
|
|
93
|
+
dockControls={docBrowserDockControls}
|
|
94
|
+
/>
|
|
74
95
|
</Suspense>
|
|
75
96
|
) : null}
|
|
76
97
|
{sideDock}
|
|
@@ -79,7 +100,10 @@ export function DesktopAppShell({
|
|
|
79
100
|
{showMobileBottomNav ? <MobileBottomNav /> : null}
|
|
80
101
|
{isDocBrowserOpen && docBrowserMode === "floating" ? (
|
|
81
102
|
<Suspense fallback={null}>
|
|
82
|
-
<DocBrowser
|
|
103
|
+
<DocBrowser
|
|
104
|
+
customTabRenderers={docBrowserRenderers}
|
|
105
|
+
dockControls={docBrowserDockControls}
|
|
106
|
+
/>
|
|
83
107
|
</Suspense>
|
|
84
108
|
) : null}
|
|
85
109
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import { Copy, Minus, Square, X } from "lucide-react";
|
|
3
3
|
import { BrandHeader } from "@/shared/components/common/brand-header";
|
|
4
|
+
import { cn } from "@/shared/lib/utils";
|
|
4
5
|
import type { DesktopWindowStateSnapshot } from "@/platforms/desktop/types/desktop-update.types";
|
|
5
6
|
|
|
6
7
|
type DesktopWindowControlAction = "minimize" | "toggle-maximize" | "close";
|
|
@@ -17,7 +18,11 @@ const windowControls: WindowControlDefinition[] = [
|
|
|
17
18
|
{ action: "close", label: "Close", icon: X, variant: "danger" },
|
|
18
19
|
];
|
|
19
20
|
|
|
20
|
-
export function DesktopWindowChrome(
|
|
21
|
+
export function DesktopWindowChrome({
|
|
22
|
+
sidebarCollapsed = false,
|
|
23
|
+
}: {
|
|
24
|
+
sidebarCollapsed?: boolean;
|
|
25
|
+
}) {
|
|
21
26
|
const isMaximized = useDesktopWindowMaximizedState();
|
|
22
27
|
const maximizeControl: WindowControlDefinition = isMaximized
|
|
23
28
|
? { action: "toggle-maximize", label: "Restore", icon: Copy }
|
|
@@ -33,21 +38,37 @@ export function DesktopWindowChrome() {
|
|
|
33
38
|
data-testid="desktop-window-chrome-resize-strip"
|
|
34
39
|
/>
|
|
35
40
|
<div
|
|
36
|
-
className=
|
|
41
|
+
className={cn(
|
|
42
|
+
"desktop-window-drag relative z-10 flex h-full w-[var(--desktop-sidebar-width)] shrink-0 items-center bg-secondary text-secondary-foreground",
|
|
43
|
+
sidebarCollapsed ? "justify-center px-0" : "pl-4 pr-3",
|
|
44
|
+
)}
|
|
37
45
|
data-testid="desktop-window-chrome-sidebar"
|
|
38
46
|
>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
{sidebarCollapsed ? (
|
|
48
|
+
<img
|
|
49
|
+
src="/logo.svg"
|
|
50
|
+
alt="NextClaw"
|
|
51
|
+
className="h-6 w-6 shrink-0 object-contain"
|
|
52
|
+
/>
|
|
53
|
+
) : (
|
|
54
|
+
<BrandHeader
|
|
55
|
+
className="flex min-w-0 shrink-0 items-center gap-2.5"
|
|
56
|
+
density="chrome"
|
|
57
|
+
/>
|
|
58
|
+
)}
|
|
43
59
|
</div>
|
|
44
60
|
<div
|
|
45
61
|
className="desktop-window-no-drag absolute right-0 top-0 z-20 flex h-full w-[var(--desktop-caption-safe-right)] items-start justify-end"
|
|
46
62
|
data-testid="desktop-window-controls"
|
|
47
63
|
>
|
|
48
|
-
{[windowControls[0], maximizeControl, windowControls[1]].map(
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
{[windowControls[0], maximizeControl, windowControls[1]].map(
|
|
65
|
+
(control) => (
|
|
66
|
+
<DesktopWindowControlButton
|
|
67
|
+
key={control.action}
|
|
68
|
+
control={control}
|
|
69
|
+
/>
|
|
70
|
+
),
|
|
71
|
+
)}
|
|
51
72
|
</div>
|
|
52
73
|
</header>
|
|
53
74
|
);
|
|
@@ -86,14 +107,18 @@ function useDesktopWindowMaximizedState(): boolean {
|
|
|
86
107
|
let isSubscribed = true;
|
|
87
108
|
const desktopApi = window.nextclawDesktop;
|
|
88
109
|
|
|
89
|
-
void desktopApi
|
|
90
|
-
|
|
110
|
+
void desktopApi
|
|
111
|
+
?.getWindowState?.()
|
|
112
|
+
.then((snapshot: DesktopWindowStateSnapshot) => {
|
|
113
|
+
if (isSubscribed) {
|
|
114
|
+
setIsMaximized(snapshot.isMaximized);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const unsubscribe = desktopApi?.onWindowStateChanged?.(
|
|
118
|
+
(snapshot: DesktopWindowStateSnapshot) => {
|
|
91
119
|
setIsMaximized(snapshot.isMaximized);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const unsubscribe = desktopApi?.onWindowStateChanged?.((snapshot: DesktopWindowStateSnapshot) => {
|
|
95
|
-
setIsMaximized(snapshot.isMaximized);
|
|
96
|
-
});
|
|
120
|
+
},
|
|
121
|
+
);
|
|
97
122
|
|
|
98
123
|
return () => {
|
|
99
124
|
isSubscribed = false;
|