@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.
Files changed (192) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/assets/{api-b1R9VdeH.js → api-iNBpppzj.js} +3 -3
  3. package/dist/assets/{appearance-settings-page-D2O9pch9.js → appearance-settings-page-DMffQFR3.js} +1 -1
  4. package/dist/assets/{book-open-B77lQ2Tg.js → book-open-C3mJGwiy.js} +1 -1
  5. package/dist/assets/channels-list-page-CCtp0BRS.js +8 -0
  6. package/dist/assets/chat-page-H5a0dWvO.js +1 -0
  7. package/dist/assets/config-split-page-CrOJgB-Y.js +1 -0
  8. package/dist/assets/{confirm-dialog-C-NXSioX.js → confirm-dialog-Chv50USy.js} +2 -2
  9. package/dist/assets/{desktop-update-config-usHpXugP.js → desktop-update-config-KzTuXRf_.js} +1 -1
  10. package/dist/assets/{dist-jdGmbb6w.js → dist-BunzmC4B.js} +1 -1
  11. package/dist/assets/{dist-YtoqU-AT.js → dist-ChmGwvtK.js} +1 -1
  12. package/dist/assets/doc-browser-DNRL4Zvd.js +1 -0
  13. package/dist/assets/doc-browser-Dg0pmkOg.js +1 -0
  14. package/dist/assets/doc-browser-context-BHY-0FSD.js +1 -0
  15. package/dist/assets/{es2015-bNpL2LKy.js → es2015-DQZ5JWwK.js} +1 -1
  16. package/dist/assets/{external-link-BM6fk8q-.js → external-link-CU0kzzIP.js} +1 -1
  17. package/dist/assets/form-actions-BvCp_0lS.js +1 -0
  18. package/dist/assets/{i18n-provider-CntWolRA.js → i18n-provider-Cu8XyZb_.js} +1 -1
  19. package/dist/assets/index-CzfBdvK1.css +1 -0
  20. package/dist/assets/index-DGqHne1Q.js +104 -0
  21. package/dist/assets/loader-circle-CDSFuzmk.js +1 -0
  22. package/dist/assets/mcp-marketplace-page-BeEQK0DL.js +9 -0
  23. package/dist/assets/mcp-marketplace-page-D6idOTLp.js +1 -0
  24. package/dist/assets/model-config-page-bNNo-XyG.js +1 -0
  25. package/dist/assets/plus-D4DsdLN-.js +1 -0
  26. package/dist/assets/{provider-scoped-model-input-Cm_a4GHf.js → provider-scoped-model-input-IlgQCsoT.js} +1 -1
  27. package/dist/assets/providers-config-page-wLo6CAJw.js +1 -0
  28. package/dist/assets/{react-BN8uzPnp.js → react-BPIsQIlO.js} +1 -1
  29. package/dist/assets/{refresh-cw-BpVcFPmJ.js → refresh-cw-CILd1vAP.js} +1 -1
  30. package/dist/assets/remote-uKEYp7AR.js +1 -0
  31. package/dist/assets/rotate-cw-wPFPg1kH.js +1 -0
  32. package/dist/assets/runtime-config-page-DDn1sP4G.js +1 -0
  33. package/dist/assets/{save-BpFW5fpk.js → save-ByJqcPTP.js} +1 -1
  34. package/dist/assets/{search-D0uO7enf.js → search-DVIV6pfD.js} +1 -1
  35. package/dist/assets/search-config-page-B-Cf4iiB.js +1 -0
  36. package/dist/assets/secrets-config-page-DPKsY8Iw.js +3 -0
  37. package/dist/assets/security-config-e9SSBlKr.js +1 -0
  38. package/dist/assets/{select-Bh-CrA4p.js → select-BdgczSNw.js} +1 -1
  39. package/dist/assets/{setting-row-BJfCHRcb.js → setting-row-BkTVUTKx.js} +1 -1
  40. package/dist/assets/{settings-2-Blzi1vr6.js → settings-2-CH5shGg_.js} +1 -1
  41. package/dist/assets/{side-dock-ZdaSrQVB.js → side-dock-BsBvcJ9i.js} +2 -2
  42. package/dist/assets/{skeleton-BLlEzebZ.js → skeleton-DeX1FKw7.js} +1 -1
  43. package/dist/assets/switch-Cv8Ekb3x.js +1 -0
  44. package/dist/assets/{tag-chip-CzGihiQx.js → tag-chip-RB9uKcoC.js} +1 -1
  45. package/dist/assets/{tooltip-CdcrBjrC.js → tooltip-oQlEN-l6.js} +1 -1
  46. package/dist/assets/{use-config-CVPgsBmU.js → use-config-l3W7y8Qz.js} +1 -1
  47. package/dist/assets/{use-confirm-dialog-CSeBk9SF.js → use-confirm-dialog-BAxaVOJI.js} +1 -1
  48. package/dist/assets/x-BBMffEN0.js +1 -0
  49. package/dist/index.html +38 -30
  50. package/index.html +12 -4
  51. package/package.json +9 -9
  52. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +29 -1
  53. package/src/app/components/layout/sidebar-items.tsx +46 -7
  54. package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
  55. package/src/app/components/layout/sidebar.tsx +84 -62
  56. package/src/app/configs/app-navigation.config.ts +49 -0
  57. package/src/app/styles/design-system.css +99 -4
  58. package/src/features/channels/components/config/channel-form.tsx +14 -11
  59. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +40 -0
  60. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -1
  61. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
  62. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +48 -0
  63. package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +55 -0
  64. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -3
  65. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +3 -4
  66. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +30 -31
  67. package/src/features/chat/components/layout/chat-sidebar.tsx +21 -7
  68. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +2 -1
  69. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
  70. package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +22 -1
  71. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
  72. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +10 -5
  73. package/src/features/chat/features/message/components/chat-message-list.container.tsx +47 -1
  74. package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
  75. package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
  76. package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +0 -11
  77. package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
  78. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
  79. package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +116 -0
  80. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +108 -46
  81. package/src/features/chat/features/session/components/chat-sidebar-session-entry.tsx +6 -0
  82. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +48 -24
  83. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +0 -3
  84. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +0 -4
  85. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +2 -2
  86. package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +25 -3
  87. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +9 -4
  88. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
  89. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
  90. package/src/features/chat/features/welcome/components/chat-welcome.tsx +0 -5
  91. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +226 -56
  92. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +1 -0
  93. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +144 -0
  94. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +99 -0
  95. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
  96. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +4 -2
  97. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +232 -21
  98. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +3 -0
  99. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +44 -1
  100. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +45 -3
  101. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +4 -0
  102. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +33 -2
  103. package/src/features/chat/managers/chat-session-list.manager.ts +32 -0
  104. package/src/features/chat/managers/chat-thread.manager.ts +2 -0
  105. package/src/features/chat/stores/chat-session-list.store.ts +28 -5
  106. package/src/features/chat/stores/chat-thread.store.ts +3 -0
  107. package/src/features/cron/components/cron-config.tsx +63 -80
  108. package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
  109. package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
  110. package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
  111. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +5 -12
  112. package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
  113. package/src/features/panel-apps/components/panel-app-list-item.tsx +6 -6
  114. package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
  115. package/src/features/panel-apps/index.ts +1 -0
  116. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +2 -10
  117. package/src/features/panel-apps/utils/panel-app-iframe.utils.ts +6 -0
  118. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +11 -3
  119. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +3 -1
  120. package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
  121. package/src/features/service-apps/components/service-apps-panel.tsx +145 -35
  122. package/src/features/settings/components/config/provider-auth-section.tsx +1 -1
  123. package/src/features/settings/components/config/provider-form.tsx +11 -8
  124. package/src/features/settings/components/config/provider-models-section.tsx +7 -7
  125. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  126. package/src/features/settings/components/config/secrets-config-form.tsx +5 -4
  127. package/src/features/settings/pages/model-config-page.tsx +26 -25
  128. package/src/features/settings/pages/providers-config-page.tsx +10 -13
  129. package/src/features/settings/pages/search-config-page.tsx +8 -5
  130. package/src/features/side-dock/components/side-dock.tsx +3 -3
  131. package/src/features/system-status/components/config/runtime-config-editor.tsx +5 -4
  132. package/src/index.css +257 -13
  133. package/src/shared/components/actions/action-link.tsx +1 -1
  134. package/src/shared/components/config-split-page.tsx +6 -6
  135. package/src/shared/components/doc-browser/__tests__/doc-browser-url.utils.test.ts +73 -0
  136. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +48 -0
  137. package/src/shared/components/doc-browser/doc-browser-context.tsx +4 -0
  138. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -2
  139. package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +2 -1
  140. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +10 -10
  141. package/src/shared/components/doc-browser/doc-browser.tsx +6 -4
  142. package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +62 -4
  143. package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +18 -0
  144. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +28 -3
  145. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +36 -0
  146. package/src/shared/components/ui/actions/form-actions.tsx +25 -0
  147. package/src/shared/components/ui/actions/icon-action-button.tsx +25 -2
  148. package/src/shared/components/ui/button.tsx +1 -1
  149. package/src/shared/components/ui/card.tsx +12 -4
  150. package/src/shared/components/ui/dialog.tsx +1 -1
  151. package/src/shared/components/ui/input.tsx +1 -1
  152. package/src/shared/components/ui/select.tsx +1 -1
  153. package/src/shared/components/ui/switch.tsx +1 -1
  154. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -1
  155. package/src/shared/components/ui/tabs.tsx +1 -1
  156. package/src/shared/components/ui/textarea.tsx +1 -1
  157. package/src/shared/hooks/use-server-path-browse.ts +26 -4
  158. package/src/shared/hooks/use-server-path-read.ts +11 -1
  159. package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
  160. package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
  161. package/src/shared/lib/i18n/locales/en-US/core.json +3 -0
  162. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +5 -0
  163. package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
  164. package/src/shared/lib/i18n/locales/zh-CN/core.json +3 -0
  165. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +5 -0
  166. package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +9 -5
  167. package/src/shared/lib/theme/index.test.ts +21 -0
  168. package/src/shared/lib/theme/index.ts +6 -4
  169. package/src/vite-env.d.ts +2 -0
  170. package/dist/assets/channels-list-page-DcsIQc6A.js +0 -8
  171. package/dist/assets/chat-page-CZ7WxPir.js +0 -1
  172. package/dist/assets/config-split-page-BWQ6_Raq.js +0 -1
  173. package/dist/assets/doc-browser-B_Tf9n70.js +0 -1
  174. package/dist/assets/doc-browser-BdZPFOVa.js +0 -1
  175. package/dist/assets/doc-browser-context-DwokemUn.js +0 -1
  176. package/dist/assets/index-BIcEw90u.js +0 -104
  177. package/dist/assets/index-BiNSTKTU.css +0 -1
  178. package/dist/assets/loader-circle-MBgNSVIH.js +0 -1
  179. package/dist/assets/mcp-marketplace-page-CLmUstLN.js +0 -9
  180. package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +0 -1
  181. package/dist/assets/model-config-page-Di0ySJD2.js +0 -1
  182. package/dist/assets/plus-vDqW5Kxp.js +0 -1
  183. package/dist/assets/providers-config-page-BAf2W0MV.js +0 -1
  184. package/dist/assets/remote-CLQ0IBM8.js +0 -1
  185. package/dist/assets/rotate-cw-CvNBv7_w.js +0 -1
  186. package/dist/assets/runtime-config-page-CflvvoDc.js +0 -1
  187. package/dist/assets/search-config-page-D0klFUXd.js +0 -1
  188. package/dist/assets/secrets-config-page-dVZ631Wp.js +0 -3
  189. package/dist/assets/security-config-C5gnlkuj.js +0 -1
  190. package/dist/assets/switch-CFLJFNSd.js +0 -1
  191. package/dist/assets/x-BF2KQ--V.js +0 -1
  192. /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-2 focus-visible:ring-offset-2;
550
- --tw-ring-color: hsl(var(--ring));
551
- --tw-ring-offset-color: hsl(var(--ring-offset));
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-2 focus-visible:ring-ring focus-visible:ring-offset-2',
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 shadow-card xl:h-[calc(100vh-180px)] xl:max-h-[860px]";
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-all",
118
+ "w-full rounded-xl border p-2.5 text-left transition-colors",
119
119
  active
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",
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/60 px-4 py-10 text-center",
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-primary/40 focus:outline-none focus:ring-1 focus:ring-primary/30"
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-11 gap-2 border-border/70 bg-card px-2.5 shrink-0 select-none",
121
- isFullscreen && "h-[calc(env(safe-area-inset-top,0px)+2.75rem)] pt-[env(safe-area-inset-top,0px)]",
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-1.5",
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-1.5"
128
- actionsClassName="h-full items-center gap-1"
129
- actionButtonClassName="rounded-md p-1.5 hover:text-foreground disabled:opacity-60"
130
- tabBaseClassName="group inline-flex min-w-0 cursor-pointer items-center gap-1 h-7 px-1.5 rounded-lg text-xs border max-w-[220px] shrink-0 transition-colors"
131
- activeTabClassName="border-primary/30 bg-primary-50/70 text-foreground shadow-[0_1px_2px_rgba(30,20,10,0.04)]"
132
- inactiveTabClassName="border-border bg-muted/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground"
133
- labelClassName="px-1 text-xs font-normal"
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)) {