@nextclaw/ui 0.15.1 → 0.15.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 +51 -0
- package/dist/assets/{api-b1R9VdeH.js → api-iNBpppzj.js} +3 -3
- package/dist/assets/{appearance-settings-page-D2O9pch9.js → appearance-settings-page-DMffQFR3.js} +1 -1
- package/dist/assets/{book-open-B77lQ2Tg.js → book-open-C3mJGwiy.js} +1 -1
- package/dist/assets/channels-list-page-CCtp0BRS.js +8 -0
- package/dist/assets/chat-page-H5a0dWvO.js +1 -0
- package/dist/assets/config-split-page-CrOJgB-Y.js +1 -0
- package/dist/assets/{confirm-dialog-C-NXSioX.js → confirm-dialog-Chv50USy.js} +2 -2
- package/dist/assets/{desktop-update-config-usHpXugP.js → desktop-update-config-KzTuXRf_.js} +1 -1
- package/dist/assets/{dist-jdGmbb6w.js → dist-BunzmC4B.js} +1 -1
- package/dist/assets/{dist-YtoqU-AT.js → dist-ChmGwvtK.js} +1 -1
- package/dist/assets/doc-browser-DNRL4Zvd.js +1 -0
- package/dist/assets/doc-browser-Dg0pmkOg.js +1 -0
- package/dist/assets/doc-browser-context-BHY-0FSD.js +1 -0
- package/dist/assets/{es2015-bNpL2LKy.js → es2015-DQZ5JWwK.js} +1 -1
- package/dist/assets/{external-link-BM6fk8q-.js → external-link-CU0kzzIP.js} +1 -1
- package/dist/assets/form-actions-BvCp_0lS.js +1 -0
- package/dist/assets/{i18n-provider-CntWolRA.js → i18n-provider-Cu8XyZb_.js} +1 -1
- package/dist/assets/index-CzfBdvK1.css +1 -0
- package/dist/assets/index-DGqHne1Q.js +104 -0
- package/dist/assets/loader-circle-CDSFuzmk.js +1 -0
- package/dist/assets/mcp-marketplace-page-BeEQK0DL.js +9 -0
- package/dist/assets/mcp-marketplace-page-D6idOTLp.js +1 -0
- package/dist/assets/model-config-page-bNNo-XyG.js +1 -0
- package/dist/assets/plus-D4DsdLN-.js +1 -0
- package/dist/assets/{provider-scoped-model-input-Cm_a4GHf.js → provider-scoped-model-input-IlgQCsoT.js} +1 -1
- package/dist/assets/providers-config-page-wLo6CAJw.js +1 -0
- package/dist/assets/{react-BN8uzPnp.js → react-BPIsQIlO.js} +1 -1
- package/dist/assets/{refresh-cw-BpVcFPmJ.js → refresh-cw-CILd1vAP.js} +1 -1
- package/dist/assets/remote-uKEYp7AR.js +1 -0
- package/dist/assets/rotate-cw-wPFPg1kH.js +1 -0
- package/dist/assets/runtime-config-page-DDn1sP4G.js +1 -0
- package/dist/assets/{save-BpFW5fpk.js → save-ByJqcPTP.js} +1 -1
- package/dist/assets/{search-D0uO7enf.js → search-DVIV6pfD.js} +1 -1
- package/dist/assets/search-config-page-B-Cf4iiB.js +1 -0
- package/dist/assets/secrets-config-page-DPKsY8Iw.js +3 -0
- package/dist/assets/security-config-e9SSBlKr.js +1 -0
- package/dist/assets/{select-Bh-CrA4p.js → select-BdgczSNw.js} +1 -1
- package/dist/assets/{setting-row-BJfCHRcb.js → setting-row-BkTVUTKx.js} +1 -1
- package/dist/assets/{settings-2-Blzi1vr6.js → settings-2-CH5shGg_.js} +1 -1
- package/dist/assets/{side-dock-ZdaSrQVB.js → side-dock-BsBvcJ9i.js} +2 -2
- package/dist/assets/{skeleton-BLlEzebZ.js → skeleton-DeX1FKw7.js} +1 -1
- package/dist/assets/switch-Cv8Ekb3x.js +1 -0
- package/dist/assets/{tag-chip-CzGihiQx.js → tag-chip-RB9uKcoC.js} +1 -1
- package/dist/assets/{tooltip-CdcrBjrC.js → tooltip-oQlEN-l6.js} +1 -1
- package/dist/assets/{use-config-CVPgsBmU.js → use-config-l3W7y8Qz.js} +1 -1
- package/dist/assets/{use-confirm-dialog-CSeBk9SF.js → use-confirm-dialog-BAxaVOJI.js} +1 -1
- package/dist/assets/x-BBMffEN0.js +1 -0
- package/dist/index.html +38 -30
- package/index.html +12 -4
- package/package.json +9 -9
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +29 -1
- package/src/app/components/layout/sidebar-items.tsx +46 -7
- package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
- package/src/app/components/layout/sidebar.tsx +84 -62
- package/src/app/configs/app-navigation.config.ts +49 -0
- package/src/app/styles/design-system.css +99 -4
- package/src/features/channels/components/config/channel-form.tsx +14 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +40 -0
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -1
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
- package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +48 -0
- package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +55 -0
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -3
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +3 -4
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +30 -31
- package/src/features/chat/components/layout/chat-sidebar.tsx +21 -7
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +2 -1
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
- package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +22 -1
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
- package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +10 -5
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +47 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
- package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +0 -11
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +116 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +108 -46
- package/src/features/chat/features/session/components/chat-sidebar-session-entry.tsx +6 -0
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +48 -24
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +0 -3
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +0 -4
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +2 -2
- package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +25 -3
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +9 -4
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +0 -5
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +226 -56
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +144 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +99 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +4 -2
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +232 -21
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +3 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +44 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +45 -3
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +4 -0
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +33 -2
- package/src/features/chat/managers/chat-session-list.manager.ts +32 -0
- package/src/features/chat/managers/chat-thread.manager.ts +2 -0
- package/src/features/chat/stores/chat-session-list.store.ts +28 -5
- package/src/features/chat/stores/chat-thread.store.ts +3 -0
- package/src/features/cron/components/cron-config.tsx +63 -80
- package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
- package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +5 -12
- package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
- package/src/features/panel-apps/components/panel-app-list-item.tsx +6 -6
- package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
- package/src/features/panel-apps/index.ts +1 -0
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +2 -10
- package/src/features/panel-apps/utils/panel-app-iframe.utils.ts +6 -0
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +11 -3
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +3 -1
- package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
- package/src/features/service-apps/components/service-apps-panel.tsx +145 -35
- package/src/features/settings/components/config/provider-auth-section.tsx +1 -1
- package/src/features/settings/components/config/provider-form.tsx +11 -8
- package/src/features/settings/components/config/provider-models-section.tsx +7 -7
- package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
- package/src/features/settings/components/config/secrets-config-form.tsx +5 -4
- package/src/features/settings/pages/model-config-page.tsx +26 -25
- package/src/features/settings/pages/providers-config-page.tsx +10 -13
- package/src/features/settings/pages/search-config-page.tsx +8 -5
- package/src/features/side-dock/components/side-dock.tsx +3 -3
- package/src/features/system-status/components/config/runtime-config-editor.tsx +5 -4
- package/src/index.css +257 -13
- package/src/shared/components/actions/action-link.tsx +1 -1
- package/src/shared/components/config-split-page.tsx +6 -6
- package/src/shared/components/doc-browser/__tests__/doc-browser-url.utils.test.ts +73 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +48 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +4 -0
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -2
- package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +2 -1
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +10 -10
- package/src/shared/components/doc-browser/doc-browser.tsx +6 -4
- package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +62 -4
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +18 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +28 -3
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +36 -0
- package/src/shared/components/ui/actions/form-actions.tsx +25 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +25 -2
- package/src/shared/components/ui/button.tsx +1 -1
- package/src/shared/components/ui/card.tsx +12 -4
- package/src/shared/components/ui/dialog.tsx +1 -1
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/select.tsx +1 -1
- package/src/shared/components/ui/switch.tsx +1 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -1
- package/src/shared/components/ui/tabs.tsx +1 -1
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/hooks/use-server-path-browse.ts +26 -4
- package/src/shared/hooks/use-server-path-read.ts +11 -1
- package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +3 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +5 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +5 -0
- package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +9 -5
- package/src/shared/lib/theme/index.test.ts +21 -0
- package/src/shared/lib/theme/index.ts +6 -4
- package/src/vite-env.d.ts +2 -0
- package/dist/assets/channels-list-page-DcsIQc6A.js +0 -8
- package/dist/assets/chat-page-CZ7WxPir.js +0 -1
- package/dist/assets/config-split-page-BWQ6_Raq.js +0 -1
- package/dist/assets/doc-browser-B_Tf9n70.js +0 -1
- package/dist/assets/doc-browser-BdZPFOVa.js +0 -1
- package/dist/assets/doc-browser-context-DwokemUn.js +0 -1
- package/dist/assets/index-BIcEw90u.js +0 -104
- package/dist/assets/index-BiNSTKTU.css +0 -1
- package/dist/assets/loader-circle-MBgNSVIH.js +0 -1
- package/dist/assets/mcp-marketplace-page-CLmUstLN.js +0 -9
- package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +0 -1
- package/dist/assets/model-config-page-Di0ySJD2.js +0 -1
- package/dist/assets/plus-vDqW5Kxp.js +0 -1
- package/dist/assets/providers-config-page-BAf2W0MV.js +0 -1
- package/dist/assets/remote-CLQ0IBM8.js +0 -1
- package/dist/assets/rotate-cw-CvNBv7_w.js +0 -1
- package/dist/assets/runtime-config-page-CflvvoDc.js +0 -1
- package/dist/assets/search-config-page-D0klFUXd.js +0 -1
- package/dist/assets/secrets-config-page-dVZ631Wp.js +0 -3
- package/dist/assets/security-config-C5gnlkuj.js +0 -1
- package/dist/assets/switch-CFLJFNSd.js +0 -1
- package/dist/assets/x-BF2KQ--V.js +0 -1
- /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-C_iP1zl_.js} +0 -0
package/src/index.css
CHANGED
|
@@ -546,9 +546,9 @@
|
|
|
546
546
|
FOCUS STATES
|
|
547
547
|
======================================== */
|
|
548
548
|
.focus-ring {
|
|
549
|
-
@apply focus:outline-none focus-visible:ring-
|
|
550
|
-
--tw-ring-color: hsl(var(--
|
|
551
|
-
--tw-ring-offset-color:
|
|
549
|
+
@apply focus:outline-none focus-visible:ring-1 focus-visible:ring-offset-0;
|
|
550
|
+
--tw-ring-color: hsl(var(--border));
|
|
551
|
+
--tw-ring-offset-color: transparent;
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
554
|
|
|
@@ -675,6 +675,24 @@
|
|
|
675
675
|
--md-table-head-bg: rgba(191, 219, 254, 0.16);
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
+
:root[data-theme="work"] .chat-markdown-assistant {
|
|
679
|
+
--md-link: #1f73c9;
|
|
680
|
+
--md-border: rgba(0, 0, 0, 0.11);
|
|
681
|
+
--md-table-head-bg: rgba(0, 0, 0, 0.045);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
:root[data-theme="work"] .chat-markdown-user {
|
|
685
|
+
--md-text: #212121;
|
|
686
|
+
--md-muted: #737373;
|
|
687
|
+
--md-border: rgba(0, 0, 0, 0.12);
|
|
688
|
+
--md-link: #1f73c9;
|
|
689
|
+
--md-inline-code-bg: rgba(0, 0, 0, 0.06);
|
|
690
|
+
--md-inline-code-color: #212121;
|
|
691
|
+
--md-blockquote-border: rgba(0, 0, 0, 0.2);
|
|
692
|
+
--md-blockquote-bg: rgba(0, 0, 0, 0.04);
|
|
693
|
+
--md-table-head-bg: rgba(0, 0, 0, 0.045);
|
|
694
|
+
}
|
|
695
|
+
|
|
678
696
|
:root[data-theme-appearance="dark"] .chat-markdown-assistant {
|
|
679
697
|
--md-text: hsl(var(--foreground));
|
|
680
698
|
--md-muted: hsl(var(--foreground-tertiary));
|
|
@@ -954,101 +972,327 @@
|
|
|
954
972
|
|
|
955
973
|
.chat-codeblock .hljs-keyword,
|
|
956
974
|
.chat-file-code-syntax .hljs-keyword,
|
|
975
|
+
.chat-terminal-pane .hljs-keyword,
|
|
957
976
|
.chat-codeblock .hljs-built_in,
|
|
958
977
|
.chat-file-code-syntax .hljs-built_in,
|
|
978
|
+
.chat-terminal-pane .hljs-built_in,
|
|
959
979
|
.chat-codeblock .hljs-type,
|
|
960
980
|
.chat-file-code-syntax .hljs-type,
|
|
981
|
+
.chat-terminal-pane .hljs-type,
|
|
961
982
|
.chat-codeblock .hljs-literal,
|
|
962
983
|
.chat-file-code-syntax .hljs-literal,
|
|
984
|
+
.chat-terminal-pane .hljs-literal,
|
|
963
985
|
.chat-codeblock .hljs-selector-tag,
|
|
964
|
-
.chat-file-code-syntax .hljs-selector-tag
|
|
986
|
+
.chat-file-code-syntax .hljs-selector-tag,
|
|
987
|
+
.chat-terminal-pane .hljs-selector-tag {
|
|
965
988
|
color: var(--md-code-keyword);
|
|
966
989
|
}
|
|
967
990
|
|
|
968
991
|
.chat-codeblock .hljs-title,
|
|
969
992
|
.chat-file-code-syntax .hljs-title,
|
|
993
|
+
.chat-terminal-pane .hljs-title,
|
|
970
994
|
.chat-codeblock .hljs-title.function_,
|
|
971
995
|
.chat-file-code-syntax .hljs-title.function_,
|
|
996
|
+
.chat-terminal-pane .hljs-title.function_,
|
|
972
997
|
.chat-codeblock .hljs-title.class_,
|
|
973
998
|
.chat-file-code-syntax .hljs-title.class_,
|
|
999
|
+
.chat-terminal-pane .hljs-title.class_,
|
|
974
1000
|
.chat-codeblock .hljs-section,
|
|
975
1001
|
.chat-file-code-syntax .hljs-section,
|
|
1002
|
+
.chat-terminal-pane .hljs-section,
|
|
976
1003
|
.chat-codeblock .hljs-selector-id,
|
|
977
|
-
.chat-file-code-syntax .hljs-selector-id
|
|
1004
|
+
.chat-file-code-syntax .hljs-selector-id,
|
|
1005
|
+
.chat-terminal-pane .hljs-selector-id {
|
|
978
1006
|
color: var(--md-code-title);
|
|
979
1007
|
}
|
|
980
1008
|
|
|
981
1009
|
.chat-codeblock .hljs-string,
|
|
982
1010
|
.chat-file-code-syntax .hljs-string,
|
|
1011
|
+
.chat-terminal-pane .hljs-string,
|
|
983
1012
|
.chat-codeblock .hljs-regexp,
|
|
984
1013
|
.chat-file-code-syntax .hljs-regexp,
|
|
1014
|
+
.chat-terminal-pane .hljs-regexp,
|
|
985
1015
|
.chat-codeblock .hljs-symbol,
|
|
986
1016
|
.chat-file-code-syntax .hljs-symbol,
|
|
1017
|
+
.chat-terminal-pane .hljs-symbol,
|
|
987
1018
|
.chat-codeblock .hljs-bullet,
|
|
988
|
-
.chat-file-code-syntax .hljs-bullet
|
|
1019
|
+
.chat-file-code-syntax .hljs-bullet,
|
|
1020
|
+
.chat-terminal-pane .hljs-bullet {
|
|
989
1021
|
color: var(--md-code-string);
|
|
990
1022
|
}
|
|
991
1023
|
|
|
992
1024
|
.chat-codeblock .hljs-number,
|
|
993
1025
|
.chat-file-code-syntax .hljs-number,
|
|
1026
|
+
.chat-terminal-pane .hljs-number,
|
|
994
1027
|
.chat-codeblock .hljs-variable,
|
|
995
1028
|
.chat-file-code-syntax .hljs-variable,
|
|
1029
|
+
.chat-terminal-pane .hljs-variable,
|
|
996
1030
|
.chat-codeblock .hljs-template-variable,
|
|
997
1031
|
.chat-file-code-syntax .hljs-template-variable,
|
|
1032
|
+
.chat-terminal-pane .hljs-template-variable,
|
|
998
1033
|
.chat-codeblock .hljs-params,
|
|
999
|
-
.chat-file-code-syntax .hljs-params
|
|
1034
|
+
.chat-file-code-syntax .hljs-params,
|
|
1035
|
+
.chat-terminal-pane .hljs-params {
|
|
1000
1036
|
color: var(--md-code-number);
|
|
1001
1037
|
}
|
|
1002
1038
|
|
|
1003
1039
|
.chat-codeblock .hljs-comment,
|
|
1004
1040
|
.chat-file-code-syntax .hljs-comment,
|
|
1041
|
+
.chat-terminal-pane .hljs-comment,
|
|
1005
1042
|
.chat-codeblock .hljs-quote,
|
|
1006
|
-
.chat-file-code-syntax .hljs-quote
|
|
1043
|
+
.chat-file-code-syntax .hljs-quote,
|
|
1044
|
+
.chat-terminal-pane .hljs-quote {
|
|
1007
1045
|
color: var(--md-code-comment);
|
|
1008
1046
|
font-style: italic;
|
|
1009
1047
|
}
|
|
1010
1048
|
|
|
1011
1049
|
.chat-codeblock .hljs-attr,
|
|
1012
1050
|
.chat-file-code-syntax .hljs-attr,
|
|
1051
|
+
.chat-terminal-pane .hljs-attr,
|
|
1013
1052
|
.chat-codeblock .hljs-attribute,
|
|
1014
1053
|
.chat-file-code-syntax .hljs-attribute,
|
|
1054
|
+
.chat-terminal-pane .hljs-attribute,
|
|
1015
1055
|
.chat-codeblock .hljs-property,
|
|
1016
1056
|
.chat-file-code-syntax .hljs-property,
|
|
1057
|
+
.chat-terminal-pane .hljs-property,
|
|
1017
1058
|
.chat-codeblock .hljs-name,
|
|
1018
1059
|
.chat-file-code-syntax .hljs-name,
|
|
1060
|
+
.chat-terminal-pane .hljs-name,
|
|
1019
1061
|
.chat-codeblock .hljs-selector-class,
|
|
1020
|
-
.chat-file-code-syntax .hljs-selector-class
|
|
1062
|
+
.chat-file-code-syntax .hljs-selector-class,
|
|
1063
|
+
.chat-terminal-pane .hljs-selector-class {
|
|
1021
1064
|
color: var(--md-code-attr);
|
|
1022
1065
|
}
|
|
1023
1066
|
|
|
1024
1067
|
.chat-codeblock .hljs-meta,
|
|
1025
1068
|
.chat-file-code-syntax .hljs-meta,
|
|
1069
|
+
.chat-terminal-pane .hljs-meta,
|
|
1026
1070
|
.chat-codeblock .hljs-doctag,
|
|
1027
1071
|
.chat-file-code-syntax .hljs-doctag,
|
|
1072
|
+
.chat-terminal-pane .hljs-doctag,
|
|
1028
1073
|
.chat-codeblock .hljs-tag,
|
|
1029
|
-
.chat-file-code-syntax .hljs-tag
|
|
1074
|
+
.chat-file-code-syntax .hljs-tag,
|
|
1075
|
+
.chat-terminal-pane .hljs-tag {
|
|
1030
1076
|
color: var(--md-code-meta);
|
|
1031
1077
|
}
|
|
1032
1078
|
|
|
1033
1079
|
.chat-codeblock .hljs-subst,
|
|
1034
1080
|
.chat-file-code-syntax .hljs-subst,
|
|
1081
|
+
.chat-terminal-pane .hljs-subst,
|
|
1035
1082
|
.chat-codeblock .hljs-punctuation,
|
|
1036
1083
|
.chat-file-code-syntax .hljs-punctuation,
|
|
1084
|
+
.chat-terminal-pane .hljs-punctuation,
|
|
1037
1085
|
.chat-codeblock .hljs-operator,
|
|
1038
|
-
.chat-file-code-syntax .hljs-operator
|
|
1086
|
+
.chat-file-code-syntax .hljs-operator,
|
|
1087
|
+
.chat-terminal-pane .hljs-operator {
|
|
1039
1088
|
color: var(--md-code-muted);
|
|
1040
1089
|
}
|
|
1041
1090
|
|
|
1042
1091
|
.chat-codeblock .hljs-deletion,
|
|
1043
|
-
.chat-file-code-syntax .hljs-deletion
|
|
1092
|
+
.chat-file-code-syntax .hljs-deletion,
|
|
1093
|
+
.chat-terminal-pane .hljs-deletion {
|
|
1044
1094
|
color: var(--md-code-deletion);
|
|
1045
1095
|
}
|
|
1046
1096
|
|
|
1047
1097
|
.chat-codeblock .hljs-addition,
|
|
1048
|
-
.chat-file-code-syntax .hljs-addition
|
|
1098
|
+
.chat-file-code-syntax .hljs-addition,
|
|
1099
|
+
.chat-terminal-pane .hljs-addition {
|
|
1049
1100
|
color: var(--md-code-addition);
|
|
1050
1101
|
}
|
|
1051
1102
|
|
|
1103
|
+
/* Terminal tool surface: terminal style without decorative chrome */
|
|
1104
|
+
.chat-terminal-surface {
|
|
1105
|
+
--terminal-surface: #0b1220;
|
|
1106
|
+
--terminal-border: rgba(148, 163, 184, 0.28);
|
|
1107
|
+
--terminal-text: #e5e7eb;
|
|
1108
|
+
--terminal-muted: #94a3b8;
|
|
1109
|
+
--terminal-prompt: #34d399;
|
|
1110
|
+
--terminal-caret: rgba(52, 211, 153, 0.92);
|
|
1111
|
+
--terminal-error-border: rgba(251, 113, 133, 0.42);
|
|
1112
|
+
--terminal-error-bg: rgba(127, 29, 29, 0.16);
|
|
1113
|
+
--terminal-error-text: #fecdd3;
|
|
1114
|
+
--md-code-text: #e5e7eb;
|
|
1115
|
+
--md-code-muted: #94a3b8;
|
|
1116
|
+
--md-code-keyword: #c084fc;
|
|
1117
|
+
--md-code-title: #93c5fd;
|
|
1118
|
+
--md-code-string: #86efac;
|
|
1119
|
+
--md-code-number: #fbbf24;
|
|
1120
|
+
--md-code-comment: #94a3b8;
|
|
1121
|
+
--md-code-attr: #67e8f9;
|
|
1122
|
+
--md-code-meta: #f0abfc;
|
|
1123
|
+
--md-code-deletion: #fca5a5;
|
|
1124
|
+
--md-code-addition: #86efac;
|
|
1125
|
+
|
|
1126
|
+
overflow: hidden;
|
|
1127
|
+
border: 1px solid var(--terminal-border);
|
|
1128
|
+
border-radius: 0.55rem;
|
|
1129
|
+
background: var(--terminal-surface);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.chat-terminal-surface-error {
|
|
1133
|
+
border-color: var(--terminal-error-border);
|
|
1134
|
+
background:
|
|
1135
|
+
linear-gradient(180deg, var(--terminal-error-bg), transparent 48%),
|
|
1136
|
+
var(--terminal-surface);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
.chat-terminal-body {
|
|
1140
|
+
max-height: 22rem;
|
|
1141
|
+
overflow: auto;
|
|
1142
|
+
padding: 0.7rem 0.75rem 0.78rem;
|
|
1143
|
+
scrollbar-width: thin;
|
|
1144
|
+
scrollbar-color: rgba(148, 163, 184, 0.45) transparent;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.chat-terminal-line {
|
|
1148
|
+
display: grid;
|
|
1149
|
+
grid-template-columns: 1rem minmax(0, 1fr);
|
|
1150
|
+
column-gap: 0.55rem;
|
|
1151
|
+
align-items: start;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
.chat-terminal-gutter {
|
|
1155
|
+
width: 1rem;
|
|
1156
|
+
color: var(--terminal-prompt);
|
|
1157
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
1158
|
+
font-size: 0.8rem;
|
|
1159
|
+
font-weight: 700;
|
|
1160
|
+
line-height: 1.58;
|
|
1161
|
+
text-align: right;
|
|
1162
|
+
user-select: none;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.chat-terminal-line-content {
|
|
1166
|
+
min-width: 0;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.chat-terminal-output-block {
|
|
1170
|
+
margin-top: 0.55rem;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
.chat-terminal-pre {
|
|
1174
|
+
margin: 0;
|
|
1175
|
+
background: transparent;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
.chat-terminal-pre code,
|
|
1179
|
+
.chat-terminal-code {
|
|
1180
|
+
display: block;
|
|
1181
|
+
white-space: pre-wrap;
|
|
1182
|
+
overflow-wrap: anywhere;
|
|
1183
|
+
word-break: break-word;
|
|
1184
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
1185
|
+
font-size: 0.8rem;
|
|
1186
|
+
line-height: 1.58;
|
|
1187
|
+
color: var(--terminal-text);
|
|
1188
|
+
font-variant-ligatures: none;
|
|
1189
|
+
tab-size: 2;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
.chat-terminal-pre-error,
|
|
1193
|
+
.chat-terminal-code-error {
|
|
1194
|
+
color: var(--terminal-error-text);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
.chat-terminal-empty {
|
|
1198
|
+
color: var(--terminal-muted);
|
|
1199
|
+
font-size: 0.78rem;
|
|
1200
|
+
font-style: italic;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
.chat-terminal-caret {
|
|
1204
|
+
display: inline-block;
|
|
1205
|
+
width: 0.42rem;
|
|
1206
|
+
height: 0.95em;
|
|
1207
|
+
margin-left: 0.12rem;
|
|
1208
|
+
vertical-align: text-bottom;
|
|
1209
|
+
background: var(--terminal-caret);
|
|
1210
|
+
animation: chat-terminal-caret-blink 1s steps(1, end) infinite;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
.chat-terminal-skeleton {
|
|
1214
|
+
height: 0.78rem;
|
|
1215
|
+
width: 9rem;
|
|
1216
|
+
border-radius: 999px;
|
|
1217
|
+
background: rgba(148, 163, 184, 0.28);
|
|
1218
|
+
animation: chat-terminal-skeleton-pulse 1.2s ease-in-out infinite;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.chat-terminal-surface .ansi-bold { font-weight: 700; }
|
|
1222
|
+
.chat-terminal-surface .ansi-dim { opacity: 0.72; }
|
|
1223
|
+
.chat-terminal-surface .ansi-italic { font-style: italic; }
|
|
1224
|
+
.chat-terminal-surface .ansi-underline { text-decoration: underline; }
|
|
1225
|
+
.chat-terminal-surface .ansi-inverse {
|
|
1226
|
+
color: var(--terminal-surface);
|
|
1227
|
+
background: var(--terminal-text);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.chat-terminal-surface .ansi-fg-black { color: #0f172a; }
|
|
1231
|
+
.chat-terminal-surface .ansi-fg-red { color: #f87171; }
|
|
1232
|
+
.chat-terminal-surface .ansi-fg-green { color: #4ade80; }
|
|
1233
|
+
.chat-terminal-surface .ansi-fg-yellow { color: #fbbf24; }
|
|
1234
|
+
.chat-terminal-surface .ansi-fg-blue { color: #60a5fa; }
|
|
1235
|
+
.chat-terminal-surface .ansi-fg-magenta { color: #e879f9; }
|
|
1236
|
+
.chat-terminal-surface .ansi-fg-cyan { color: #22d3ee; }
|
|
1237
|
+
.chat-terminal-surface .ansi-fg-white { color: #e5e7eb; }
|
|
1238
|
+
.chat-terminal-surface .ansi-fg-bright-black { color: #94a3b8; }
|
|
1239
|
+
.chat-terminal-surface .ansi-fg-bright-red { color: #fca5a5; }
|
|
1240
|
+
.chat-terminal-surface .ansi-fg-bright-green { color: #86efac; }
|
|
1241
|
+
.chat-terminal-surface .ansi-fg-bright-yellow { color: #fde68a; }
|
|
1242
|
+
.chat-terminal-surface .ansi-fg-bright-blue { color: #93c5fd; }
|
|
1243
|
+
.chat-terminal-surface .ansi-fg-bright-magenta { color: #f0abfc; }
|
|
1244
|
+
.chat-terminal-surface .ansi-fg-bright-cyan { color: #67e8f9; }
|
|
1245
|
+
.chat-terminal-surface .ansi-fg-bright-white { color: #f8fafc; }
|
|
1246
|
+
|
|
1247
|
+
.chat-terminal-surface .ansi-bg-black { background: #0f172a; }
|
|
1248
|
+
.chat-terminal-surface .ansi-bg-red { background: rgba(248, 113, 113, 0.28); }
|
|
1249
|
+
.chat-terminal-surface .ansi-bg-green { background: rgba(74, 222, 128, 0.22); }
|
|
1250
|
+
.chat-terminal-surface .ansi-bg-yellow { background: rgba(251, 191, 36, 0.22); }
|
|
1251
|
+
.chat-terminal-surface .ansi-bg-blue { background: rgba(96, 165, 250, 0.22); }
|
|
1252
|
+
.chat-terminal-surface .ansi-bg-magenta { background: rgba(232, 121, 249, 0.22); }
|
|
1253
|
+
.chat-terminal-surface .ansi-bg-cyan { background: rgba(34, 211, 238, 0.2); }
|
|
1254
|
+
.chat-terminal-surface .ansi-bg-white { background: rgba(229, 231, 235, 0.18); }
|
|
1255
|
+
|
|
1256
|
+
@keyframes chat-terminal-caret-blink {
|
|
1257
|
+
0%, 49% { opacity: 1; }
|
|
1258
|
+
50%, 100% { opacity: 0; }
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
@keyframes chat-terminal-skeleton-pulse {
|
|
1262
|
+
0%, 100% { opacity: 0.55; }
|
|
1263
|
+
50% { opacity: 1; }
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1267
|
+
.chat-terminal-caret,
|
|
1268
|
+
.chat-terminal-skeleton {
|
|
1269
|
+
animation: none;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
:root[data-theme="work"] .chat-terminal-surface {
|
|
1274
|
+
--terminal-surface: #111827;
|
|
1275
|
+
--terminal-border: rgba(148, 163, 184, 0.24);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
:root[data-theme-appearance="dark"] .chat-terminal-surface {
|
|
1279
|
+
--terminal-surface: #070b14;
|
|
1280
|
+
--terminal-border: rgba(148, 163, 184, 0.22);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/* Prevent browser default "详情/Details" fallback on chat process summaries. */
|
|
1284
|
+
.nextclaw-chat-message-user details > summary,
|
|
1285
|
+
.border-border.bg-card details > summary,
|
|
1286
|
+
.chat-markdown details > summary {
|
|
1287
|
+
list-style: none;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.nextclaw-chat-message-user details > summary::-webkit-details-marker,
|
|
1291
|
+
.border-border.bg-card details > summary::-webkit-details-marker,
|
|
1292
|
+
.chat-markdown details > summary::-webkit-details-marker {
|
|
1293
|
+
display: none;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1052
1296
|
.chat-table-wrap {
|
|
1053
1297
|
margin: 0.15rem 0;
|
|
1054
1298
|
border: 1px solid var(--md-border);
|
|
@@ -37,7 +37,7 @@ export function ExternalActionLink({ label, className, onClick }: ExternalAction
|
|
|
37
37
|
<button
|
|
38
38
|
type="button"
|
|
39
39
|
className={cn(
|
|
40
|
-
'inline-flex h-7 shrink-0 items-center gap-1.5 rounded-md px-1.5 text-[13px] font-medium text-primary transition-colors hover:text-primary-hover focus-visible:outline-none focus-visible:ring-
|
|
40
|
+
'inline-flex h-7 shrink-0 items-center gap-1.5 rounded-md px-1.5 text-[13px] font-medium text-primary transition-colors hover:text-primary-hover focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
|
|
41
41
|
className
|
|
42
42
|
)}
|
|
43
43
|
onClick={onClick}
|
|
@@ -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-border bg-card text-card-foreground
|
|
6
|
+
const CARD_CLASS = "min-w-0 overflow-hidden rounded-2xl border border-border/75 bg-card text-card-foreground 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) {
|
|
@@ -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-border/70", className)} {...props} />;
|
|
105
|
+
return <div className={cn("shrink-0 border-t border-border/70 px-4 py-2.5", className)} {...props} />;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export function ConfigSelectionCard({
|
|
@@ -115,10 +115,10 @@ export function ConfigSelectionCard({
|
|
|
115
115
|
<button
|
|
116
116
|
type={type}
|
|
117
117
|
className={cn(
|
|
118
|
-
"w-full rounded-xl border p-2.5 text-left transition-
|
|
118
|
+
"w-full rounded-xl border p-2.5 text-left transition-colors",
|
|
119
119
|
active
|
|
120
|
-
? "border-
|
|
121
|
-
: "border-
|
|
120
|
+
? "border-border/70 bg-muted/65 text-foreground"
|
|
121
|
+
: "border-transparent bg-transparent text-muted-foreground hover:border-border/50 hover:bg-muted/40 hover:text-foreground",
|
|
122
122
|
className,
|
|
123
123
|
)}
|
|
124
124
|
{...props}
|
|
@@ -140,7 +140,7 @@ 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-border bg-muted/
|
|
143
|
+
"flex min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-border/70 bg-muted/35 px-4 py-10 text-center",
|
|
144
144
|
className,
|
|
145
145
|
)}
|
|
146
146
|
{...props}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
async function importDocsUrlUtils(language: 'en' | 'zh' = 'en') {
|
|
4
|
+
const i18n = await import('@/shared/lib/i18n');
|
|
5
|
+
i18n.setLanguage(language);
|
|
6
|
+
return await import('@/shared/components/doc-browser/utils/doc-browser-url.utils');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function stubTimeZone(timeZone: string) {
|
|
10
|
+
vi.spyOn(Intl, 'DateTimeFormat').mockReturnValue({
|
|
11
|
+
resolvedOptions: () => ({ timeZone }),
|
|
12
|
+
} as Intl.DateTimeFormat);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('doc browser docs URL utilities', () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
vi.resetModules();
|
|
18
|
+
stubTimeZone('America/Los_Angeles');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.unstubAllEnvs();
|
|
23
|
+
vi.unstubAllGlobals();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('uses the official docs origin for English users outside mainland by default', async () => {
|
|
27
|
+
const { getDefaultDocsUrl } = await importDocsUrlUtils('en');
|
|
28
|
+
|
|
29
|
+
expect(getDefaultDocsUrl()).toBe('https://docs.nextclaw.io/en/guide/getting-started');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('uses the mainland mirror for users in the mainland timezone', async () => {
|
|
33
|
+
stubTimeZone('Asia/Shanghai');
|
|
34
|
+
|
|
35
|
+
const { getDefaultDocsUrl } = await importDocsUrlUtils('en');
|
|
36
|
+
|
|
37
|
+
expect(getDefaultDocsUrl()).toBe('https://docs.nextclaw.net/en/guide/getting-started');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('uses the mainland mirror for Chinese users by default', async () => {
|
|
41
|
+
const { getDefaultDocsUrl } = await importDocsUrlUtils('zh');
|
|
42
|
+
|
|
43
|
+
expect(getDefaultDocsUrl()).toBe('https://docs.nextclaw.net/zh/guide/getting-started');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('lets an explicit docs base override the automatic origin', async () => {
|
|
47
|
+
vi.stubEnv('VITE_NEXTCLAW_DOCS_BASE_URL', 'https://docs.example.com/');
|
|
48
|
+
|
|
49
|
+
const { getDocsUrl } = await importDocsUrlUtils('zh');
|
|
50
|
+
|
|
51
|
+
expect(getDocsUrl('/guide/model-selection')).toBe('https://docs.example.com/zh/guide/model-selection');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('does not rewrite non-docs absolute URLs', async () => {
|
|
55
|
+
const { getDocsUrl } = await importDocsUrlUtils('zh');
|
|
56
|
+
|
|
57
|
+
expect(getDocsUrl('https://example.com/help')).toBe('https://example.com/help');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('rewrites official docs URLs to the selected docs origin', async () => {
|
|
61
|
+
const { getDocsUrl } = await importDocsUrlUtils('zh');
|
|
62
|
+
|
|
63
|
+
expect(getDocsUrl('https://docs.nextclaw.io/en/guide/commands?tab=cli#start')).toBe(
|
|
64
|
+
'https://docs.nextclaw.net/en/guide/commands?tab=cli#start',
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('recognizes the mainland mirror as a docs URL', async () => {
|
|
69
|
+
const { isDocsUrl } = await importDocsUrlUtils('en');
|
|
70
|
+
|
|
71
|
+
expect(isDocsUrl('https://docs.nextclaw.net/zh/guide/getting-started')).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -397,6 +397,54 @@ describe("DocBrowser", () => {
|
|
|
397
397
|
expect(screen.getByText("Help Docs")).toBeTruthy();
|
|
398
398
|
});
|
|
399
399
|
|
|
400
|
+
it("focuses panel app iframes on pointer entry without applying the behavior to generic content iframes", () => {
|
|
401
|
+
const panelAppTab: DocBrowserTab = {
|
|
402
|
+
id: "piano",
|
|
403
|
+
kind: "panel-app" as const,
|
|
404
|
+
title: "Piano",
|
|
405
|
+
currentUrl: "/api/panel-apps/piano/content",
|
|
406
|
+
history: ["/api/panel-apps/piano/content"],
|
|
407
|
+
historyIndex: 0,
|
|
408
|
+
navVersion: 0,
|
|
409
|
+
};
|
|
410
|
+
docBrowserState.tabs = [panelAppTab];
|
|
411
|
+
docBrowserState.activeTabId = panelAppTab.id;
|
|
412
|
+
docBrowserState.currentTab = panelAppTab;
|
|
413
|
+
|
|
414
|
+
const { container, unmount } = render(
|
|
415
|
+
<DocBrowser customTabRenderers={PANEL_APPS_DOC_BROWSER_RENDERERS} />,
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
const panelAppIframe = container.querySelector('iframe[title="Piano"]') as HTMLIFrameElement;
|
|
419
|
+
const panelAppIframeFocus = vi.spyOn(panelAppIframe, "focus");
|
|
420
|
+
const panelAppContentFocus = vi.spyOn(panelAppIframe.contentWindow!, "focus").mockImplementation(() => undefined);
|
|
421
|
+
|
|
422
|
+
fireEvent.pointerOver(panelAppIframe);
|
|
423
|
+
|
|
424
|
+
expect(panelAppIframe.getAttribute("tabindex")).toBe("0");
|
|
425
|
+
expect(panelAppIframeFocus).toHaveBeenCalledWith({ preventScroll: true });
|
|
426
|
+
expect(panelAppContentFocus).toHaveBeenCalled();
|
|
427
|
+
|
|
428
|
+
unmount();
|
|
429
|
+
resetDocBrowserTestState();
|
|
430
|
+
const contentTab: DocBrowserTab = {
|
|
431
|
+
id: "local-app",
|
|
432
|
+
kind: "content",
|
|
433
|
+
title: "Local App",
|
|
434
|
+
currentUrl: "http://127.0.0.1:5173/dashboard",
|
|
435
|
+
history: ["http://127.0.0.1:5173/dashboard"],
|
|
436
|
+
historyIndex: 0,
|
|
437
|
+
navVersion: 0,
|
|
438
|
+
};
|
|
439
|
+
docBrowserState.tabs = [contentTab];
|
|
440
|
+
docBrowserState.activeTabId = contentTab.id;
|
|
441
|
+
docBrowserState.currentTab = contentTab;
|
|
442
|
+
|
|
443
|
+
render(<DocBrowser />);
|
|
444
|
+
|
|
445
|
+
expect(screen.getByTitle("Local App").getAttribute("tabindex")).toBeNull();
|
|
446
|
+
});
|
|
447
|
+
|
|
400
448
|
});
|
|
401
449
|
|
|
402
450
|
describe("DocBrowser floating interactions", () => {
|
|
@@ -22,6 +22,10 @@ export {
|
|
|
22
22
|
DOC_BROWSER_HOME_TAB_KIND,
|
|
23
23
|
DOC_BROWSER_HOME_URL,
|
|
24
24
|
DOCS_DEFAULT_BASE_URL,
|
|
25
|
+
DOCS_MAINLAND_BASE_URL,
|
|
26
|
+
getDocsBaseUrl,
|
|
27
|
+
getDocsUrl,
|
|
28
|
+
getDefaultDocsUrl,
|
|
25
29
|
isDocsUrl,
|
|
26
30
|
} from '@/shared/components/doc-browser/utils/doc-browser-url.utils';
|
|
27
31
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode, Ref } from 'react';
|
|
1
|
+
import type { PointerEventHandler, ReactNode, Ref } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
ExternalLink,
|
|
4
4
|
RefreshCw,
|
|
@@ -29,6 +29,7 @@ type DocBrowserFrameContentProps = {
|
|
|
29
29
|
iframeSandbox?: string;
|
|
30
30
|
isDragging: boolean;
|
|
31
31
|
isResizing: boolean;
|
|
32
|
+
onIframePointerOver?: PointerEventHandler<HTMLIFrameElement>;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
export function DocBrowserAddressToolbar({
|
|
@@ -53,7 +54,7 @@ export function DocBrowserAddressToolbar({
|
|
|
53
54
|
onChange={(e) => onUrlInputChange(e.target.value)}
|
|
54
55
|
aria-label={t('docBrowserAddressLabel')}
|
|
55
56
|
placeholder={placeholder}
|
|
56
|
-
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-
|
|
57
|
+
className="h-8 w-full rounded-lg border border-border/75 bg-background pl-8 pr-3 text-xs text-foreground transition-colors placeholder:text-muted-foreground/55 focus:border-border focus:outline-none focus:ring-0"
|
|
57
58
|
/>
|
|
58
59
|
</form>
|
|
59
60
|
<IconActionButton
|
|
@@ -74,6 +75,7 @@ export function DocBrowserFrameContent({
|
|
|
74
75
|
iframeSandbox,
|
|
75
76
|
isDragging,
|
|
76
77
|
isResizing,
|
|
78
|
+
onIframePointerOver,
|
|
77
79
|
}: DocBrowserFrameContentProps) {
|
|
78
80
|
return (
|
|
79
81
|
<div className="flex-1 relative overflow-hidden">
|
|
@@ -87,6 +89,8 @@ export function DocBrowserFrameContent({
|
|
|
87
89
|
className="absolute inset-0 w-full h-full border-0"
|
|
88
90
|
title={currentTab?.title || 'NextClaw Docs'}
|
|
89
91
|
sandbox={iframeSandbox}
|
|
92
|
+
tabIndex={onIframePointerOver ? 0 : undefined}
|
|
93
|
+
onPointerOver={onIframePointerOver}
|
|
90
94
|
allow="clipboard-read; clipboard-write"
|
|
91
95
|
allowFullScreen
|
|
92
96
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { PointerEvent, ReactNode } from 'react';
|
|
2
2
|
import type { DocBrowserContextValue, DocBrowserTab } from './doc-browser-context';
|
|
3
3
|
|
|
4
4
|
export type DocBrowserCustomTabRenderParams = {
|
|
@@ -20,6 +20,7 @@ export type DocBrowserCustomTabRenderer = {
|
|
|
20
20
|
getIframeSandbox?: (tab: DocBrowserTab) => string | undefined;
|
|
21
21
|
getTitle?: (tab: DocBrowserTab) => string;
|
|
22
22
|
onIframeMessage?: (params: DocBrowserIframeMessageParams) => void;
|
|
23
|
+
onIframePointerOver?: (event: PointerEvent<HTMLIFrameElement>) => void;
|
|
23
24
|
renderContent?: (params: DocBrowserCustomTabRenderParams) => ReactNode;
|
|
24
25
|
renderIcon?: (tab: DocBrowserTab) => ReactNode;
|
|
25
26
|
renderToolbar?: (params: DocBrowserCustomTabRenderParams) => ReactNode;
|
|
@@ -117,20 +117,20 @@ export function DocBrowserTabStrip({
|
|
|
117
117
|
tabs={compactTabs}
|
|
118
118
|
actions={actions}
|
|
119
119
|
className={cn(
|
|
120
|
-
"h-
|
|
121
|
-
isFullscreen && "h-[calc(env(safe-area-inset-top,0px)+2.
|
|
120
|
+
"h-10 gap-1.5 border-border/50 bg-card/80 px-2 shrink-0 select-none",
|
|
121
|
+
isFullscreen && "h-[calc(env(safe-area-inset-top,0px)+2.5rem)] pt-[env(safe-area-inset-top,0px)]",
|
|
122
122
|
)}
|
|
123
123
|
scrollClassName={cn(
|
|
124
|
-
"doc-browser-tab-scrollbar flex h-full items-center gap-
|
|
124
|
+
"doc-browser-tab-scrollbar flex h-full items-center gap-0.5",
|
|
125
125
|
!isDocked && !isFullscreen && "cursor-grab active:cursor-grabbing",
|
|
126
126
|
)}
|
|
127
|
-
tabsClassName="items-center gap-
|
|
128
|
-
actionsClassName="h-full items-center gap-
|
|
129
|
-
actionButtonClassName="rounded-md p-1.5 hover:text-foreground disabled:opacity-
|
|
130
|
-
tabBaseClassName="group inline-flex min-w-0 cursor-pointer items-center gap-
|
|
131
|
-
activeTabClassName="
|
|
132
|
-
inactiveTabClassName="
|
|
133
|
-
labelClassName="px-
|
|
127
|
+
tabsClassName="items-center gap-0.5"
|
|
128
|
+
actionsClassName="h-full items-center gap-0.5"
|
|
129
|
+
actionButtonClassName="rounded-md p-1.5 text-muted-foreground hover:bg-muted/60 hover:text-foreground disabled:opacity-50"
|
|
130
|
+
tabBaseClassName="group inline-flex min-w-0 cursor-pointer items-center gap-0.5 h-7 px-2 rounded-md text-xs max-w-[220px] shrink-0 transition-colors"
|
|
131
|
+
activeTabClassName="bg-muted/80 text-foreground"
|
|
132
|
+
inactiveTabClassName="text-muted-foreground hover:bg-muted/45 hover:text-foreground"
|
|
133
|
+
labelClassName="px-0.5 text-xs font-normal"
|
|
134
134
|
onPointerDown={!isDocked && !isFullscreen ? onDragStart : undefined}
|
|
135
135
|
onScrollPointerDown={(event) => {
|
|
136
136
|
if (shouldBlockHeaderDrag(event.target)) {
|