@nextclaw/ui 0.14.1 → 0.14.3
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 +41 -0
- package/dist/assets/{api-DPcvCLfa.js → api-BP_8IaxB.js} +7 -7
- package/dist/assets/channels-list-page-DEh5Jjqx.js +8 -0
- package/dist/assets/chat-page-BRB0N5WW.js +105 -0
- package/dist/assets/config-split-page-CRhlZ_pH.js +1 -0
- package/dist/assets/{confirm-dialog-CWh5FfK2.js → confirm-dialog-DsivFJ4r.js} +2 -2
- package/dist/assets/{desktop-update-config-DsRhBizi.js → desktop-update-config-B0w9p2ep.js} +1 -1
- package/dist/assets/{dist-DPrgcEC0.js → dist-CikkhOlq.js} +1 -1
- package/dist/assets/{dist-DsE4OsSS.js → dist-PVA_xL1D.js} +1 -1
- package/dist/assets/doc-browser-BoNJ7-tE.js +1 -0
- package/dist/assets/doc-browser-CdJ_d4ik.js +1 -0
- package/dist/assets/doc-browser-context-MTw4EvKd.js +1 -0
- package/dist/assets/{ellipsis-B81FStLm.js → ellipsis-y6vDtq4M.js} +1 -1
- package/dist/assets/{external-link-C_dmG-WJ.js → external-link-DVJIQf_G.js} +1 -1
- package/dist/assets/index-BiE-K8-q.css +1 -0
- package/dist/assets/index-D9BAE_L_.js +105 -0
- package/dist/assets/mcp-marketplace-page-B1SZNY5m.js +40 -0
- package/dist/assets/mcp-marketplace-page-Cq_Tw42T.js +1 -0
- package/dist/assets/middleware-CkFT3R4v.js +1 -0
- package/dist/assets/model-config-page-DotaTUHb.js +1 -0
- package/dist/assets/plus-BbZqquJe.js +1 -0
- package/dist/assets/provider-scoped-model-input-DsFRuWJH.js +1 -0
- package/dist/assets/providers-config-page-DW4tQSLN.js +1 -0
- package/dist/assets/{react-sZz5HSCm.js → react-VNqT5Zp7.js} +1 -1
- package/dist/assets/remote-B8TiUfwW.js +1 -0
- package/dist/assets/rotate-cw-DjHDTkCv.js +1 -0
- package/dist/assets/runtime-config-page-S6ErRHR8.js +1 -0
- package/dist/assets/{save-MzjoiHri.js → save-BOJ477H-.js} +1 -1
- package/dist/assets/{search-B29dE4GN.js → search-BEti5beA.js} +1 -1
- package/dist/assets/{search-config-page-Dl5sZzob.js → search-config-page-DGj5am03.js} +1 -1
- package/dist/assets/{secrets-config-page-C_l-IFCK.js → secrets-config-page--IzrIOid.js} +2 -2
- package/dist/assets/{select-BKmh05hd.js → select-hoj8dK4K.js} +2 -2
- package/dist/assets/{tag-chip-BS_7Ueom.js → tag-chip-T8-h-die.js} +1 -1
- package/dist/assets/use-config-CjRV2hwL.js +1 -0
- package/dist/assets/x-D9PXs_xP.js +1 -0
- package/dist/index.html +70 -19
- package/index.html +55 -5
- 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/header.tsx +3 -3
- package/src/app/components/layout/page-layout.tsx +2 -2
- package/src/app/components/layout/runtime-status-entry.tsx +7 -7
- 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/app/styles/design-system.css +388 -26
- package/src/app/test/vitest-setup.ts +31 -0
- 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/chat-sidebar-list-mode-switch.tsx +3 -3
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +4 -2
- 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 +15 -16
- package/src/features/chat/components/conversation/chat-conversation-header.tsx +7 -6
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +19 -19
- package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +13 -13
- 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 +18 -16
- package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +93 -20
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +93 -36
- package/src/features/chat/components/layout/chat-sidebar.tsx +60 -93
- package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +225 -0
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +199 -0
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +308 -0
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +439 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +194 -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} +51 -20
- 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/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-inline-panel-app-card.tsx +7 -7
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +99 -18
- 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 +7 -7
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +6 -6
- package/src/features/chat/features/session/components/session-context-icon.tsx +2 -2
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +2 -2
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
- package/src/features/chat/features/session/components/session-run-badge.tsx +1 -1
- 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-session-type-menu.test.tsx +2 -2
- package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +2 -0
- package/src/features/chat/features/session-type/components/chat-session-type-menu.tsx +2 -2
- package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +2 -2
- package/src/features/chat/features/session-type/hooks/use-chat-session-type-state.ts +10 -2
- 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 -9
- package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
- package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +3 -3
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +4 -4
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +14 -19
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +5 -5
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +6 -6
- package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +6 -8
- package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +1 -16
- 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/panel-apps/components/panel-app-list-item.tsx +8 -8
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +4 -4
- package/src/features/panel-apps/components/panel-apps-list.tsx +20 -20
- package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +70 -6
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +10 -5
- package/src/features/service-apps/components/service-action-authorization-dialog.tsx +8 -8
- package/src/features/service-apps/components/service-apps-panel.tsx +24 -24
- package/src/features/settings/components/config/provider-advanced-settings-section.tsx +5 -5
- package/src/features/settings/components/config/provider-auth-section.tsx +7 -7
- package/src/features/settings/components/config/provider-form.tsx +10 -10
- package/src/features/settings/components/config/provider-models-section.tsx +16 -16
- package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
- package/src/features/settings/pages/providers-config-page.tsx +17 -17
- 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/config-split-page.tsx +11 -11
- package/src/shared/components/doc-browser/doc-browser-home-page.tsx +2 -2
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +4 -4
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +4 -4
- package/src/shared/components/doc-browser/doc-browser.tsx +3 -3
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +1 -1
- package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
- package/src/shared/components/ui/button.tsx +4 -4
- package/src/shared/components/ui/card.tsx +4 -4
- package/src/shared/components/ui/dialog.tsx +5 -5
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/label.tsx +1 -1
- package/src/shared/components/ui/popover.tsx +1 -1
- package/src/shared/components/ui/select.tsx +3 -3
- package/src/shared/components/ui/switch.tsx +3 -3
- 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/components/ui/tabs.tsx +4 -4
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
- package/src/shared/lib/i18n/locales/en-US/core.json +9 -2
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
- package/src/shared/lib/i18n/locales/zh-CN/core.json +9 -2
- package/src/shared/lib/theme/index.ts +94 -52
- 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-D6jtziu4.js +0 -8
- package/dist/assets/chat-page-BBnNJoKG.js +0 -105
- package/dist/assets/config-split-page-BCJhqdK9.js +0 -1
- package/dist/assets/doc-browser-C8xOF_9F.js +0 -1
- package/dist/assets/doc-browser-DgQedeAn.js +0 -1
- package/dist/assets/doc-browser-context-B46tQGmO.js +0 -1
- package/dist/assets/index-7o1WdUbU.js +0 -103
- package/dist/assets/index-DQWmEWzk.css +0 -1
- package/dist/assets/mcp-marketplace-page-CWZN7ohK.js +0 -1
- package/dist/assets/mcp-marketplace-page-Dzull_4-.js +0 -40
- package/dist/assets/model-config-page-Cv0O3BIj.js +0 -1
- package/dist/assets/plus-Bnt56oqG.js +0 -1
- package/dist/assets/provider-scoped-model-input-Duuh7i3h.js +0 -1
- package/dist/assets/providers-config-page-CPDz0Lxc.js +0 -1
- package/dist/assets/remote-B0LMs8u7.js +0 -1
- package/dist/assets/rotate-cw-BfyG_KEF.js +0 -1
- package/dist/assets/runtime-config-page-q0fvv8ME.js +0 -1
- package/dist/assets/use-config-DZkBWIdL.js +0 -1
- package/dist/assets/x-CW2KO-Hz.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
|
@@ -133,11 +133,11 @@ export function ProvidersConfigPage() {
|
|
|
133
133
|
</Button>
|
|
134
134
|
</PopoverTrigger>
|
|
135
135
|
<PopoverContent className="w-[42rem] max-w-[calc(100vw-2rem)] p-3" align="start">
|
|
136
|
-
<div className="mb-2 px-1 text-xs font-semibold text-
|
|
136
|
+
<div className="mb-2 px-1 text-xs font-semibold text-muted-foreground">{t('providerTemplatePickerTitle')}</div>
|
|
137
137
|
<div className="grid max-h-[24rem] grid-cols-2 gap-2 overflow-y-auto sm:grid-cols-3">
|
|
138
138
|
<button
|
|
139
139
|
type="button"
|
|
140
|
-
className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-dashed border-
|
|
140
|
+
className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-dashed border-border bg-card px-3 py-2 text-left transition-colors hover:border-primary/40 hover:bg-accent/70"
|
|
141
141
|
onClick={async () => {
|
|
142
142
|
try {
|
|
143
143
|
const result = await createProvider.mutateAsync({ data: { providerType: null } });
|
|
@@ -150,8 +150,8 @@ export function ProvidersConfigPage() {
|
|
|
150
150
|
}
|
|
151
151
|
}}
|
|
152
152
|
>
|
|
153
|
-
<LogoBadge name="custom" className="h-8 w-8 rounded-lg border border-
|
|
154
|
-
<span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-
|
|
153
|
+
<LogoBadge name="custom" className="h-8 w-8 rounded-lg border border-border bg-background" />
|
|
154
|
+
<span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-foreground">
|
|
155
155
|
{t('providerAddCustom')}
|
|
156
156
|
</span>
|
|
157
157
|
</button>
|
|
@@ -159,7 +159,7 @@ export function ProvidersConfigPage() {
|
|
|
159
159
|
<button
|
|
160
160
|
key={template.providerType}
|
|
161
161
|
type="button"
|
|
162
|
-
className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-
|
|
162
|
+
className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-border bg-card px-3 py-2 text-left transition-colors hover:border-primary/40 hover:bg-accent/70"
|
|
163
163
|
onClick={async () => {
|
|
164
164
|
try {
|
|
165
165
|
const result = await createProvider.mutateAsync({ data: { providerType: template.providerType } });
|
|
@@ -175,10 +175,10 @@ export function ProvidersConfigPage() {
|
|
|
175
175
|
<LogoBadge
|
|
176
176
|
name={template.providerType}
|
|
177
177
|
src={template.logo ? `/logos/${template.logo}` : null}
|
|
178
|
-
className="h-8 w-8 rounded-lg border border-
|
|
178
|
+
className="h-8 w-8 rounded-lg border border-border bg-background"
|
|
179
179
|
imgClassName="h-4 w-4 object-contain"
|
|
180
180
|
/>
|
|
181
|
-
<span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-
|
|
181
|
+
<span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-foreground">
|
|
182
182
|
{template.displayName || template.providerType}
|
|
183
183
|
</span>
|
|
184
184
|
</button>
|
|
@@ -188,9 +188,9 @@ export function ProvidersConfigPage() {
|
|
|
188
188
|
</Popover>
|
|
189
189
|
</ConfigSplitPaneHeader>
|
|
190
190
|
|
|
191
|
-
<div className="border-b border-
|
|
191
|
+
<div className="border-b border-border/70 px-4 py-3">
|
|
192
192
|
<div className="relative">
|
|
193
|
-
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-
|
|
193
|
+
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground/70" />
|
|
194
194
|
<Input
|
|
195
195
|
value={query}
|
|
196
196
|
onChange={(event) => setQuery(event.target.value)}
|
|
@@ -223,8 +223,8 @@ export function ProvidersConfigPage() {
|
|
|
223
223
|
className={cn(
|
|
224
224
|
'w-full rounded-xl border p-2.5 text-left transition-all',
|
|
225
225
|
resolvedSelectedProvider === provider.providerId
|
|
226
|
-
? 'border-primary/
|
|
227
|
-
: 'border-
|
|
226
|
+
? 'border-primary/35 bg-primary-50/45 text-foreground shadow-sm'
|
|
227
|
+
: 'border-border bg-card text-muted-foreground hover:border-primary/35 hover:bg-accent/70 hover:text-accent-foreground',
|
|
228
228
|
)}
|
|
229
229
|
>
|
|
230
230
|
<div className="relative min-h-10">
|
|
@@ -234,15 +234,15 @@ export function ProvidersConfigPage() {
|
|
|
234
234
|
src={template?.logo ? `/logos/${template.logo}` : null}
|
|
235
235
|
className={cn(
|
|
236
236
|
'h-10 w-10 rounded-lg border',
|
|
237
|
-
isReady ? 'border-primary/
|
|
237
|
+
isReady ? 'border-primary/35 bg-background' : 'border-border bg-background',
|
|
238
238
|
)}
|
|
239
239
|
imgClassName="h-5 w-5 object-contain"
|
|
240
|
-
fallback={<span className="text-sm font-semibold uppercase text-
|
|
240
|
+
fallback={<span className="text-sm font-semibold uppercase text-muted-foreground">{provider.providerId[0]}</span>}
|
|
241
241
|
/>
|
|
242
242
|
<div className="min-w-0">
|
|
243
|
-
<p className="truncate text-sm font-semibold text-
|
|
244
|
-
<p className="truncate font-mono text-[10px] text-
|
|
245
|
-
<p className="line-clamp-1 text-[11px] text-
|
|
243
|
+
<p className="truncate text-sm font-semibold text-foreground">{providerLabel}</p>
|
|
244
|
+
<p className="truncate font-mono text-[10px] text-muted-foreground/65">{provider.providerId}</p>
|
|
245
|
+
<p className="line-clamp-1 text-[11px] text-muted-foreground">
|
|
246
246
|
{description} · {provider.models?.length ?? 0}
|
|
247
247
|
</p>
|
|
248
248
|
</div>
|
|
@@ -268,7 +268,7 @@ export function ProvidersConfigPage() {
|
|
|
268
268
|
<PopoverTrigger asChild>
|
|
269
269
|
<button
|
|
270
270
|
type="button"
|
|
271
|
-
className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-
|
|
271
|
+
className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-muted-foreground/70 hover:bg-accent hover:text-accent-foreground"
|
|
272
272
|
onClick={(event) => event.stopPropagation()}
|
|
273
273
|
title={t('more')}
|
|
274
274
|
>
|
|
@@ -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;
|
|
@@ -3,7 +3,7 @@ import { ArrowLeft, type LucideIcon } from "lucide-react";
|
|
|
3
3
|
import { t } from "@/shared/lib/i18n";
|
|
4
4
|
import { cn } from "@/shared/lib/utils";
|
|
5
5
|
|
|
6
|
-
const CARD_CLASS = "min-w-0 overflow-hidden rounded-2xl border border-
|
|
6
|
+
const CARD_CLASS = "min-w-0 overflow-hidden rounded-2xl border border-border bg-card text-card-foreground shadow-card xl:h-[calc(100vh-180px)] xl:max-h-[860px]";
|
|
7
7
|
type DivProps = HTMLAttributes<HTMLDivElement>; type SectionProps = HTMLAttributes<HTMLElement>;
|
|
8
8
|
|
|
9
9
|
function ConfigSplitPane({ className, ...props }: SectionProps) {
|
|
@@ -37,7 +37,7 @@ export function ConfigSplitPage({
|
|
|
37
37
|
<button
|
|
38
38
|
type="button"
|
|
39
39
|
onClick={onMobileBack}
|
|
40
|
-
className="inline-flex items-center gap-2 rounded-full border border-
|
|
40
|
+
className="inline-flex items-center gap-2 rounded-full border border-border bg-card px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
|
|
41
41
|
>
|
|
42
42
|
<ArrowLeft className="h-4 w-4" />
|
|
43
43
|
<span>{mobileListLabel ?? t("backToMain")}</span>
|
|
@@ -81,7 +81,7 @@ export function ConfigSplitEmptyPane({ className, ...props }: SectionProps) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export function ConfigSplitPaneHeader({ className, ...props }: DivProps) {
|
|
84
|
-
return <div className={cn("shrink-0 border-b border-
|
|
84
|
+
return <div className={cn("shrink-0 border-b border-border/70", className)} {...props} />;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
export function ConfigSplitPaneBody({
|
|
@@ -102,7 +102,7 @@ export function ConfigSplitPaneBody({
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
export function ConfigSplitPaneFooter({ className, ...props }: DivProps) {
|
|
105
|
-
return <div className={cn("shrink-0 border-t border-
|
|
105
|
+
return <div className={cn("shrink-0 border-t border-border/70", className)} {...props} />;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export function ConfigSelectionCard({
|
|
@@ -117,8 +117,8 @@ export function ConfigSelectionCard({
|
|
|
117
117
|
className={cn(
|
|
118
118
|
"w-full rounded-xl border p-2.5 text-left transition-all",
|
|
119
119
|
active
|
|
120
|
-
? "border-primary/
|
|
121
|
-
: "border-
|
|
120
|
+
? "border-primary/35 bg-primary-50/45 text-foreground shadow-sm"
|
|
121
|
+
: "border-border bg-card text-muted-foreground hover:border-primary/35 hover:bg-accent/70 hover:text-accent-foreground",
|
|
122
122
|
className,
|
|
123
123
|
)}
|
|
124
124
|
{...props}
|
|
@@ -140,16 +140,16 @@ export function ConfigSplitEmptyState({
|
|
|
140
140
|
return (
|
|
141
141
|
<div
|
|
142
142
|
className={cn(
|
|
143
|
-
"flex min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-
|
|
143
|
+
"flex min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-border bg-muted/60 px-4 py-10 text-center",
|
|
144
144
|
className,
|
|
145
145
|
)}
|
|
146
146
|
{...props}
|
|
147
147
|
>
|
|
148
|
-
<div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-
|
|
149
|
-
<Icon className="h-5 w-5 text-
|
|
148
|
+
<div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-card">
|
|
149
|
+
<Icon className="h-5 w-5 text-muted-foreground/45" />
|
|
150
150
|
</div>
|
|
151
|
-
<p className="text-sm font-medium text-
|
|
152
|
-
{description ? <p className="mt-2 text-xs text-
|
|
151
|
+
<p className="text-sm font-medium text-foreground">{title}</p>
|
|
152
|
+
{description ? <p className="mt-2 text-xs text-muted-foreground">{description}</p> : null}
|
|
153
153
|
</div>
|
|
154
154
|
);
|
|
155
155
|
}
|
|
@@ -5,10 +5,10 @@ export function DocBrowserHomePage() {
|
|
|
5
5
|
return (
|
|
6
6
|
<div className="flex h-full items-center justify-center bg-background px-5 py-6">
|
|
7
7
|
<div className="flex max-w-[260px] flex-col items-center gap-3 text-center">
|
|
8
|
-
<span className="flex h-12 w-12 items-center justify-center rounded-lg border border-
|
|
8
|
+
<span className="flex h-12 w-12 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground shadow-[0_1px_2px_rgba(30,20,10,0.04)]">
|
|
9
9
|
<Boxes className="h-5 w-5" />
|
|
10
10
|
</span>
|
|
11
|
-
<span className="text-sm font-medium text-
|
|
11
|
+
<span className="text-sm font-medium text-foreground">{t('docBrowserHomeTitle')}</span>
|
|
12
12
|
</div>
|
|
13
13
|
</div>
|
|
14
14
|
);
|
|
@@ -38,15 +38,15 @@ export function DocBrowserDocsToolbar({
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
<div className="flex items-center gap-2
|
|
41
|
+
<div className="flex items-center gap-2 border-b border-border/70 bg-card px-3.5 py-2 shrink-0">
|
|
42
42
|
<form onSubmit={onSubmit} className="flex-1 relative">
|
|
43
|
-
<Search className="
|
|
43
|
+
<Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/70" />
|
|
44
44
|
<input
|
|
45
45
|
type="text"
|
|
46
46
|
value={urlInput}
|
|
47
47
|
onChange={(e) => onUrlInputChange(e.target.value)}
|
|
48
48
|
placeholder={t('docBrowserSearchPlaceholder')}
|
|
49
|
-
className="w-full
|
|
49
|
+
className="h-8 w-full rounded-lg border border-border bg-background pl-8 pr-3 text-xs text-foreground transition-colors placeholder:text-muted-foreground/55 focus:border-primary/40 focus:outline-none focus:ring-1 focus:ring-primary/30"
|
|
50
50
|
/>
|
|
51
51
|
</form>
|
|
52
52
|
</div>
|
|
@@ -91,7 +91,7 @@ export function DocBrowserExternalLink({ currentUrl, isDocsTab }: { currentUrl:
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
return (
|
|
94
|
-
<div className="flex items-center justify-between
|
|
94
|
+
<div className="flex items-center justify-between border-t border-border/70 bg-muted/55 px-4 py-2 shrink-0">
|
|
95
95
|
<a
|
|
96
96
|
href={currentUrl}
|
|
97
97
|
target="_blank"
|
|
@@ -111,16 +111,16 @@ export function DocBrowserTabStrip({
|
|
|
111
111
|
tabs={compactTabs}
|
|
112
112
|
actions={actions}
|
|
113
113
|
className={cn(
|
|
114
|
-
"h-11 gap-2
|
|
114
|
+
"h-11 gap-2 border-border/70 bg-card px-2.5 shrink-0 select-none",
|
|
115
115
|
isFullscreen && "h-[calc(env(safe-area-inset-top,0px)+2.75rem)] pt-[env(safe-area-inset-top,0px)]",
|
|
116
116
|
)}
|
|
117
117
|
scrollClassName="doc-browser-tab-scrollbar flex h-full items-center gap-1.5"
|
|
118
118
|
tabsClassName="items-center gap-1.5"
|
|
119
119
|
actionsClassName="h-full items-center gap-1"
|
|
120
|
-
actionButtonClassName="rounded-md p-1.5 hover:text-
|
|
120
|
+
actionButtonClassName="rounded-md p-1.5 hover:text-foreground disabled:opacity-60"
|
|
121
121
|
tabBaseClassName="group inline-flex min-w-0 items-center gap-1 h-7 px-1.5 rounded-lg text-xs border max-w-[220px] shrink-0 transition-colors"
|
|
122
|
-
activeTabClassName="bg-
|
|
123
|
-
inactiveTabClassName="
|
|
122
|
+
activeTabClassName="border-primary/30 bg-primary-50/70 text-foreground shadow-[0_1px_2px_rgba(30,20,10,0.04)]"
|
|
123
|
+
inactiveTabClassName="border-border bg-muted/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
124
124
|
labelClassName="px-1 text-xs font-normal"
|
|
125
125
|
onPointerDown={!isDocked && !isFullscreen ? onDragStart : undefined}
|
|
126
126
|
onScrollPointerDown={(event) => event.stopPropagation()}
|
|
@@ -359,10 +359,10 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
|
|
|
359
359
|
<div
|
|
360
360
|
data-testid="doc-browser-panel"
|
|
361
361
|
className={cn(
|
|
362
|
-
'flex flex-col bg-
|
|
362
|
+
'relative flex flex-col overflow-hidden bg-card text-card-foreground',
|
|
363
363
|
isFullscreen
|
|
364
364
|
? 'fixed inset-0 z-[9999] h-[100dvh] w-screen rounded-none border-0 shadow-2xl'
|
|
365
|
-
: 'rounded-2xl
|
|
365
|
+
: 'rounded-2xl border border-border shadow-2xl',
|
|
366
366
|
)}
|
|
367
367
|
style={
|
|
368
368
|
isFullscreen
|
|
@@ -398,7 +398,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
|
|
|
398
398
|
onPointerDown={startFloatResize('bottom')}
|
|
399
399
|
/>
|
|
400
400
|
<div
|
|
401
|
-
className="absolute bottom-0 right-0
|
|
401
|
+
className="absolute bottom-0 right-0 z-30 flex h-4 w-4 cursor-se-resize items-center justify-center text-muted-foreground/45 transition-colors hover:text-muted-foreground"
|
|
402
402
|
data-testid="doc-browser-resize-bottom-right"
|
|
403
403
|
onPointerDown={startFloatResize('bottom-right')}
|
|
404
404
|
>
|
|
@@ -36,7 +36,7 @@ export function ResizableRightPanel({ children, className, style, defaultWidth =
|
|
|
36
36
|
return (
|
|
37
37
|
<aside
|
|
38
38
|
{...props}
|
|
39
|
-
className={cn("relative flex h-full min-h-0 shrink-0 overflow-hidden bg-
|
|
39
|
+
className={cn("relative flex h-full min-h-0 shrink-0 overflow-hidden bg-card text-card-foreground", overlay ? "fixed inset-0 z-40" : "border-l border-border", className)}
|
|
40
40
|
style={overlay ? style : { ...style, width }}
|
|
41
41
|
>
|
|
42
42
|
{!overlay ? (
|
|
@@ -27,7 +27,7 @@ const IconActionButton = React.forwardRef<HTMLButtonElement, IconActionButtonPro
|
|
|
27
27
|
aria-label={label}
|
|
28
28
|
className={cn(
|
|
29
29
|
'inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 disabled:cursor-not-allowed',
|
|
30
|
-
'text-
|
|
30
|
+
'text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
|
|
31
31
|
className
|
|
32
32
|
)}
|
|
33
33
|
>
|
|
@@ -9,12 +9,12 @@ const buttonVariants = cva(
|
|
|
9
9
|
variant: {
|
|
10
10
|
default: 'bg-primary text-primary-foreground hover:bg-primary-600 active:bg-primary-700 shadow-sm',
|
|
11
11
|
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
12
|
-
outline: 'border border-
|
|
13
|
-
secondary: 'bg-
|
|
14
|
-
ghost: 'hover:bg-
|
|
12
|
+
outline: 'border border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
|
13
|
+
secondary: 'bg-muted text-foreground hover:bg-accent hover:text-accent-foreground',
|
|
14
|
+
ghost: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
|
15
15
|
link: 'text-primary underline-offset-4 hover:underline',
|
|
16
16
|
primary: 'bg-primary text-primary-foreground hover:bg-primary-600 active:bg-primary-700 shadow-sm',
|
|
17
|
-
subtle: 'bg-
|
|
17
|
+
subtle: 'bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
|
18
18
|
'primary-outline': 'border border-primary/30 text-primary hover:bg-primary hover:text-primary-foreground'
|
|
19
19
|
},
|
|
20
20
|
size: {
|
|
@@ -8,8 +8,8 @@ const Card = React.forwardRef<
|
|
|
8
8
|
<div
|
|
9
9
|
ref={ref}
|
|
10
10
|
className={cn(
|
|
11
|
-
'rounded-2xl border border-
|
|
12
|
-
hover && 'hover:
|
|
11
|
+
'rounded-2xl border border-border bg-card text-card-foreground shadow-card transition-all duration-base',
|
|
12
|
+
hover && 'hover:border-primary/25 hover:shadow-card-hover',
|
|
13
13
|
className
|
|
14
14
|
)}
|
|
15
15
|
{...props}
|
|
@@ -36,7 +36,7 @@ const CardTitle = React.forwardRef<
|
|
|
36
36
|
<h3
|
|
37
37
|
ref={ref}
|
|
38
38
|
className={cn(
|
|
39
|
-
'text-[15px] font-semibold leading-tight tracking-tight text-
|
|
39
|
+
'text-[15px] font-semibold leading-tight tracking-tight text-foreground',
|
|
40
40
|
className
|
|
41
41
|
)}
|
|
42
42
|
{...props}
|
|
@@ -50,7 +50,7 @@ const CardDescription = React.forwardRef<
|
|
|
50
50
|
>(({ className, ...props }, ref) => (
|
|
51
51
|
<p
|
|
52
52
|
ref={ref}
|
|
53
|
-
className={cn('text-[13px] text-
|
|
53
|
+
className={cn('text-[13px] text-muted-foreground leading-relaxed', className)}
|
|
54
54
|
{...props}
|
|
55
55
|
/>
|
|
56
56
|
));
|