@nextclaw/ui 0.15.2 → 0.15.4

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 (212) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/assets/aiden0z-pptx-renderer.es-Bd99vut2.js +94 -0
  3. package/dist/assets/api-BOXOrpcJ.js +13 -0
  4. package/dist/assets/app-presenter-provider-CkHLbvZQ.js +106 -0
  5. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
  6. package/dist/assets/appearance-settings-page-fLIJbx1C.js +1 -0
  7. package/dist/assets/{book-open-Ba2f7YiG.js → book-open-DWUjS6aW.js} +1 -1
  8. package/dist/assets/channels-list-page-CvCTJraa.js +8 -0
  9. package/dist/assets/chat-page-B42UUIFR.js +1 -0
  10. package/dist/assets/chunk-DseTPa7n.js +1 -0
  11. package/dist/assets/config-split-page-DBgt9S8b.js +1 -0
  12. package/dist/assets/confirm-dialog-GSXIvoRU.js +5 -0
  13. package/dist/assets/desktop-update-config-7bmNeWIC.js +1 -0
  14. package/dist/assets/dist-DC7f4TJH.js +41 -0
  15. package/dist/assets/doc-browser-CgdoLUT92.js +1 -0
  16. package/dist/assets/doc-browser-D0monHjG.js +1 -0
  17. package/dist/assets/doc-browser-context-CGwEOhBy.js +1 -0
  18. package/dist/assets/docx-preview-eFH9DRsS.js +20 -0
  19. package/dist/assets/download-DiP9zx-J.js +1 -0
  20. package/dist/assets/{external-link-DxuPaDoK.js → external-link-C6ZeSPef.js} +1 -1
  21. package/dist/assets/eye-suvKmtwn.js +1 -0
  22. package/dist/assets/folder-CMELbQGG.js +1 -0
  23. package/dist/assets/{form-actions-BztL7P_T.js → form-actions-CUAzpNe_.js} +1 -1
  24. package/dist/assets/index-BFeNDQ4R.css +1 -0
  25. package/dist/assets/index-D_6U-M94.js +2 -0
  26. package/dist/assets/jszip.min-Das2IAnb.js +2 -0
  27. package/dist/assets/loader-circle-tYHStefV.js +1 -0
  28. package/dist/assets/logo-badge-Cu5UGH_4.js +1 -0
  29. package/dist/assets/mcp-marketplace-page-BUzHDwW6.js +9 -0
  30. package/dist/assets/mcp-marketplace-page-ohUAdfqJ.js +1 -0
  31. package/dist/assets/model-config-page-CWP6pyBm.js +1 -0
  32. package/dist/assets/plus-tywizkeY.js +1 -0
  33. package/dist/assets/popover-DImguRok.js +1 -0
  34. package/dist/assets/provider-models-C_yOh6DE.js +1 -0
  35. package/dist/assets/provider-scoped-model-input-CE7p4SbJ.js +1 -0
  36. package/dist/assets/providers-config-page-BKPo8SjH.js +1 -0
  37. package/dist/assets/react-5sjAT_6d.js +8 -0
  38. package/dist/assets/{refresh-cw-eT8BF-8B.js → refresh-cw-CHLBzWWj.js} +1 -1
  39. package/dist/assets/remote-DXJryUxB.js +1 -0
  40. package/dist/assets/rotate-cw-BefO5brU.js +1 -0
  41. package/dist/assets/runtime-config-page-1Axv4QGu.js +1 -0
  42. package/dist/assets/{save-Cb2g0BOi.js → save-BABzyrjB.js} +1 -1
  43. package/dist/assets/{search-BcHjwdsb.js → search-BTqxG3ZG.js} +1 -1
  44. package/dist/assets/search-config-page-BkKKmxmS.js +1 -0
  45. package/dist/assets/secrets-config-page-CWJMyu-k.js +3 -0
  46. package/dist/assets/security-config-DeQUIXfi.js +1 -0
  47. package/dist/assets/select-TYZDBNmq.js +1 -0
  48. package/dist/assets/setting-row-DR23Z_5I.js +1 -0
  49. package/dist/assets/{settings-2-2DWauOjY.js → settings-2-D8WWcBnw.js} +1 -1
  50. package/dist/assets/{skeleton-P5oM14E1.js → skeleton-CloHeg0S.js} +1 -1
  51. package/dist/assets/tabs-CX-ckWoo.js +1 -0
  52. package/dist/assets/tag-chip-mCc23Rhb.js +1 -0
  53. package/dist/assets/trash-2-SAW1Z4Po.js +1 -0
  54. package/dist/assets/use-config-BucdaK23.js +1 -0
  55. package/dist/assets/use-confirm-dialog-C95F6sT1.js +1 -0
  56. package/dist/assets/use-viewport-layout-C6m3Nte7.js +1 -0
  57. package/dist/assets/x-DtCPHwCu.js +1 -0
  58. package/dist/assets/xlsx-B6zVt1RK.js +64 -0
  59. package/dist/index.html +34 -28
  60. package/package.json +14 -9
  61. package/src/app/components/layout/sidebar-items.tsx +3 -3
  62. package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
  63. package/src/app/components/layout/sidebar.tsx +1 -1
  64. package/src/app/styles/design-system.css +17 -4
  65. package/src/features/chat/components/__tests__/chat-popover-content.test.tsx +41 -0
  66. package/src/features/chat/components/chat-popover-content.tsx +26 -0
  67. package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +13 -0
  68. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +21 -11
  69. package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +2 -2
  70. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +28 -1
  71. package/src/features/chat/components/conversation/chat-conversation-content.tsx +5 -4
  72. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +9 -18
  73. package/src/features/chat/components/conversation/chat-conversation-track.tsx +35 -0
  74. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +1 -0
  75. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +7 -7
  76. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +4 -15
  77. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +20 -1
  78. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +69 -54
  79. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
  80. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
  81. package/src/features/chat/features/message/components/chat-message-list.container.tsx +63 -2
  82. package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts +30 -0
  83. package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
  84. package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
  85. package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
  86. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
  87. package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +37 -0
  88. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
  89. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +3 -8
  90. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +65 -20
  91. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +26 -28
  92. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
  93. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +5 -5
  94. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +4 -4
  95. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +4 -4
  96. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +463 -99
  97. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +113 -2
  98. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +1 -0
  99. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +197 -44
  100. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +11 -5
  101. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +8 -6
  102. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +99 -67
  103. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +239 -1
  104. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +56 -6
  105. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +29 -7
  106. package/src/features/chat/features/workspace/components/file-content-preview/use-workspace-file-buffer.ts +42 -0
  107. package/src/features/chat/features/workspace/components/file-content-preview/workspace-document-preview-state.tsx +18 -0
  108. package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.css +89 -0
  109. package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.tsx +87 -0
  110. package/src/features/chat/features/workspace/components/file-content-preview/workspace-presentation-preview.tsx +82 -0
  111. package/src/features/chat/features/workspace/components/file-content-preview/workspace-spreadsheet-preview.tsx +180 -0
  112. package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +191 -0
  113. package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +1 -4
  114. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +53 -10
  115. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +68 -2
  116. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +21 -0
  117. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +63 -0
  118. package/src/features/chat/features/workspace/utils/chat-workspace-file-viewer.utils.ts +49 -0
  119. package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -0
  120. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +120 -38
  121. package/src/features/chat/index.ts +1 -0
  122. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +76 -0
  123. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +44 -60
  124. package/src/features/chat/managers/chat-thread.manager.ts +123 -124
  125. package/src/features/chat/pages/ncp-chat-page.tsx +1 -2
  126. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +78 -1
  127. package/src/features/chat/stores/chat-message-layout.store.test.ts +37 -0
  128. package/src/features/chat/stores/chat-message-layout.store.ts +41 -0
  129. package/src/features/chat/stores/chat-thread.store.ts +73 -13
  130. package/src/features/cron/components/cron-config.tsx +63 -80
  131. package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
  132. package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
  133. package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
  134. package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
  135. package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
  136. package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
  137. package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +25 -8
  138. package/src/features/settings/pages/appearance-settings-page.tsx +92 -13
  139. package/src/features/side-dock/components/side-dock.tsx +3 -3
  140. package/src/index.css +275 -15
  141. package/src/shared/components/__tests__/file-type-icon.test.tsx +61 -0
  142. package/src/shared/components/actions/action-link.tsx +1 -1
  143. package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +19 -0
  144. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +16 -0
  145. package/src/shared/components/doc-browser/doc-browser-context.tsx +1 -0
  146. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +1 -1
  147. package/src/shared/components/doc-browser/doc-browser.tsx +11 -3
  148. package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +5 -0
  149. package/src/shared/components/doc-browser/stores/doc-browser.store.ts +6 -1
  150. package/src/shared/components/doc-browser/types/doc-browser.types.ts +2 -0
  151. package/src/shared/components/doc-browser/utils/doc-browser-state.utils.ts +11 -0
  152. package/src/shared/components/file-type-icon.tsx +272 -0
  153. package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +22 -0
  154. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +17 -2
  155. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  156. package/src/shared/components/ui/button.tsx +1 -1
  157. package/src/shared/components/ui/dialog.tsx +1 -1
  158. package/src/shared/components/ui/input.tsx +1 -1
  159. package/src/shared/components/ui/select.tsx +1 -1
  160. package/src/shared/components/ui/switch.tsx +1 -1
  161. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +38 -0
  162. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +82 -2
  163. package/src/shared/components/ui/tabs.tsx +1 -1
  164. package/src/shared/components/ui/textarea.tsx +1 -1
  165. package/src/shared/lib/api/__tests__/server-path.utils.test.ts +28 -0
  166. package/src/shared/lib/api/utils/server-path.utils.ts +19 -20
  167. package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
  168. package/src/shared/lib/i18n/locales/en-US/core.json +6 -0
  169. package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
  170. package/src/shared/lib/i18n/locales/zh-CN/core.json +6 -0
  171. package/dist/assets/api-B7Qigvtm.js +0 -13
  172. package/dist/assets/appearance-settings-page-CuE0Iiqj.js +0 -1
  173. package/dist/assets/channels-list-page-CTsM6TcP.js +0 -8
  174. package/dist/assets/chat-page-C_5dcuE3.js +0 -1
  175. package/dist/assets/config-split-page-Fbb4PtTf.js +0 -1
  176. package/dist/assets/confirm-dialog-D2EG3nqE.js +0 -5
  177. package/dist/assets/desktop-update-config-BGR3HUi1.js +0 -1
  178. package/dist/assets/dist-7JTjycxE.js +0 -1
  179. package/dist/assets/dist-wXLhk4hl.js +0 -1
  180. package/dist/assets/doc-browser-bHyXnxlj.js +0 -1
  181. package/dist/assets/doc-browser-context-CYAGm5d5.js +0 -1
  182. package/dist/assets/doc-browser-gTrQ3jCF.js +0 -1
  183. package/dist/assets/es2015-j1SRCIX5.js +0 -41
  184. package/dist/assets/i18n-provider-B4oMxOFx.js +0 -1
  185. package/dist/assets/index-CvrvblgX.css +0 -1
  186. package/dist/assets/index-Obd4JYU2.js +0 -104
  187. package/dist/assets/loader-circle-CdzgK4eH.js +0 -1
  188. package/dist/assets/mcp-marketplace-page-Bt7CuOoq.js +0 -9
  189. package/dist/assets/mcp-marketplace-page-Ck3t78_n.js +0 -1
  190. package/dist/assets/model-config-page-DeKk9gvE.js +0 -1
  191. package/dist/assets/plus-Bx7wQbhG.js +0 -1
  192. package/dist/assets/provider-scoped-model-input-DsH2LF1q.js +0 -1
  193. package/dist/assets/providers-config-page-BFnGp68F.js +0 -1
  194. package/dist/assets/react-UirzUuST.js +0 -8
  195. package/dist/assets/remote-CDkHZtA8.js +0 -1
  196. package/dist/assets/rotate-cw-1JqxHTuw.js +0 -1
  197. package/dist/assets/runtime-config-page-BelAqiNG.js +0 -1
  198. package/dist/assets/search-config-page-zPm6--Ig.js +0 -1
  199. package/dist/assets/secrets-config-page-Cxyp-KuQ.js +0 -3
  200. package/dist/assets/security-config-B_gCq9fn.js +0 -1
  201. package/dist/assets/select-CdSEOwVM.js +0 -1
  202. package/dist/assets/setting-row-CTAtGexr.js +0 -1
  203. package/dist/assets/side-dock-DPvakJ0a.js +0 -3
  204. package/dist/assets/switch-BU_UEULb.js +0 -1
  205. package/dist/assets/tag-chip-D-WsKoT1.js +0 -1
  206. package/dist/assets/tooltip-CjkOaHW7.js +0 -1
  207. package/dist/assets/use-config--hx5oxQn.js +0 -1
  208. package/dist/assets/use-confirm-dialog-CD9a_SK1.js +0 -1
  209. package/dist/assets/x-DT5x45JU.js +0 -1
  210. /package/dist/assets/{config-hints-C_iP1zl_.js → config-hints-fDrYfl0l.js} +0 -0
  211. /package/dist/assets/{host-capabilities-9bB_998Z.js → host-capabilities-zZvY9U63.js} +0 -0
  212. /package/dist/assets/{middleware-BILWbJE4.js → middleware-BLMHv9YF.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
 
@@ -736,11 +736,16 @@
736
736
  .chat-markdown h5,
737
737
  .chat-markdown h6 {
738
738
  margin: 0.2rem 0 0;
739
+ padding-bottom: 0.5em;
739
740
  font-weight: 700;
740
741
  line-height: 1.35;
741
742
  letter-spacing: -0.01em;
742
743
  }
743
744
 
745
+ .chat-markdown :is(h1, h2, h3, h4, h5, h6) + * {
746
+ margin-top: 0;
747
+ }
748
+
744
749
  .chat-markdown h1 {
745
750
  font-size: 1.22rem;
746
751
  }
@@ -972,101 +977,327 @@
972
977
 
973
978
  .chat-codeblock .hljs-keyword,
974
979
  .chat-file-code-syntax .hljs-keyword,
980
+ .chat-terminal-pane .hljs-keyword,
975
981
  .chat-codeblock .hljs-built_in,
976
982
  .chat-file-code-syntax .hljs-built_in,
983
+ .chat-terminal-pane .hljs-built_in,
977
984
  .chat-codeblock .hljs-type,
978
985
  .chat-file-code-syntax .hljs-type,
986
+ .chat-terminal-pane .hljs-type,
979
987
  .chat-codeblock .hljs-literal,
980
988
  .chat-file-code-syntax .hljs-literal,
989
+ .chat-terminal-pane .hljs-literal,
981
990
  .chat-codeblock .hljs-selector-tag,
982
- .chat-file-code-syntax .hljs-selector-tag {
991
+ .chat-file-code-syntax .hljs-selector-tag,
992
+ .chat-terminal-pane .hljs-selector-tag {
983
993
  color: var(--md-code-keyword);
984
994
  }
985
995
 
986
996
  .chat-codeblock .hljs-title,
987
997
  .chat-file-code-syntax .hljs-title,
998
+ .chat-terminal-pane .hljs-title,
988
999
  .chat-codeblock .hljs-title.function_,
989
1000
  .chat-file-code-syntax .hljs-title.function_,
1001
+ .chat-terminal-pane .hljs-title.function_,
990
1002
  .chat-codeblock .hljs-title.class_,
991
1003
  .chat-file-code-syntax .hljs-title.class_,
1004
+ .chat-terminal-pane .hljs-title.class_,
992
1005
  .chat-codeblock .hljs-section,
993
1006
  .chat-file-code-syntax .hljs-section,
1007
+ .chat-terminal-pane .hljs-section,
994
1008
  .chat-codeblock .hljs-selector-id,
995
- .chat-file-code-syntax .hljs-selector-id {
1009
+ .chat-file-code-syntax .hljs-selector-id,
1010
+ .chat-terminal-pane .hljs-selector-id {
996
1011
  color: var(--md-code-title);
997
1012
  }
998
1013
 
999
1014
  .chat-codeblock .hljs-string,
1000
1015
  .chat-file-code-syntax .hljs-string,
1016
+ .chat-terminal-pane .hljs-string,
1001
1017
  .chat-codeblock .hljs-regexp,
1002
1018
  .chat-file-code-syntax .hljs-regexp,
1019
+ .chat-terminal-pane .hljs-regexp,
1003
1020
  .chat-codeblock .hljs-symbol,
1004
1021
  .chat-file-code-syntax .hljs-symbol,
1022
+ .chat-terminal-pane .hljs-symbol,
1005
1023
  .chat-codeblock .hljs-bullet,
1006
- .chat-file-code-syntax .hljs-bullet {
1024
+ .chat-file-code-syntax .hljs-bullet,
1025
+ .chat-terminal-pane .hljs-bullet {
1007
1026
  color: var(--md-code-string);
1008
1027
  }
1009
1028
 
1010
1029
  .chat-codeblock .hljs-number,
1011
1030
  .chat-file-code-syntax .hljs-number,
1031
+ .chat-terminal-pane .hljs-number,
1012
1032
  .chat-codeblock .hljs-variable,
1013
1033
  .chat-file-code-syntax .hljs-variable,
1034
+ .chat-terminal-pane .hljs-variable,
1014
1035
  .chat-codeblock .hljs-template-variable,
1015
1036
  .chat-file-code-syntax .hljs-template-variable,
1037
+ .chat-terminal-pane .hljs-template-variable,
1016
1038
  .chat-codeblock .hljs-params,
1017
- .chat-file-code-syntax .hljs-params {
1039
+ .chat-file-code-syntax .hljs-params,
1040
+ .chat-terminal-pane .hljs-params {
1018
1041
  color: var(--md-code-number);
1019
1042
  }
1020
1043
 
1021
1044
  .chat-codeblock .hljs-comment,
1022
1045
  .chat-file-code-syntax .hljs-comment,
1046
+ .chat-terminal-pane .hljs-comment,
1023
1047
  .chat-codeblock .hljs-quote,
1024
- .chat-file-code-syntax .hljs-quote {
1048
+ .chat-file-code-syntax .hljs-quote,
1049
+ .chat-terminal-pane .hljs-quote {
1025
1050
  color: var(--md-code-comment);
1026
1051
  font-style: italic;
1027
1052
  }
1028
1053
 
1029
1054
  .chat-codeblock .hljs-attr,
1030
1055
  .chat-file-code-syntax .hljs-attr,
1056
+ .chat-terminal-pane .hljs-attr,
1031
1057
  .chat-codeblock .hljs-attribute,
1032
1058
  .chat-file-code-syntax .hljs-attribute,
1059
+ .chat-terminal-pane .hljs-attribute,
1033
1060
  .chat-codeblock .hljs-property,
1034
1061
  .chat-file-code-syntax .hljs-property,
1062
+ .chat-terminal-pane .hljs-property,
1035
1063
  .chat-codeblock .hljs-name,
1036
1064
  .chat-file-code-syntax .hljs-name,
1065
+ .chat-terminal-pane .hljs-name,
1037
1066
  .chat-codeblock .hljs-selector-class,
1038
- .chat-file-code-syntax .hljs-selector-class {
1067
+ .chat-file-code-syntax .hljs-selector-class,
1068
+ .chat-terminal-pane .hljs-selector-class {
1039
1069
  color: var(--md-code-attr);
1040
1070
  }
1041
1071
 
1042
1072
  .chat-codeblock .hljs-meta,
1043
1073
  .chat-file-code-syntax .hljs-meta,
1074
+ .chat-terminal-pane .hljs-meta,
1044
1075
  .chat-codeblock .hljs-doctag,
1045
1076
  .chat-file-code-syntax .hljs-doctag,
1077
+ .chat-terminal-pane .hljs-doctag,
1046
1078
  .chat-codeblock .hljs-tag,
1047
- .chat-file-code-syntax .hljs-tag {
1079
+ .chat-file-code-syntax .hljs-tag,
1080
+ .chat-terminal-pane .hljs-tag {
1048
1081
  color: var(--md-code-meta);
1049
1082
  }
1050
1083
 
1051
1084
  .chat-codeblock .hljs-subst,
1052
1085
  .chat-file-code-syntax .hljs-subst,
1086
+ .chat-terminal-pane .hljs-subst,
1053
1087
  .chat-codeblock .hljs-punctuation,
1054
1088
  .chat-file-code-syntax .hljs-punctuation,
1089
+ .chat-terminal-pane .hljs-punctuation,
1055
1090
  .chat-codeblock .hljs-operator,
1056
- .chat-file-code-syntax .hljs-operator {
1091
+ .chat-file-code-syntax .hljs-operator,
1092
+ .chat-terminal-pane .hljs-operator {
1057
1093
  color: var(--md-code-muted);
1058
1094
  }
1059
1095
 
1060
1096
  .chat-codeblock .hljs-deletion,
1061
- .chat-file-code-syntax .hljs-deletion {
1097
+ .chat-file-code-syntax .hljs-deletion,
1098
+ .chat-terminal-pane .hljs-deletion {
1062
1099
  color: var(--md-code-deletion);
1063
1100
  }
1064
1101
 
1065
1102
  .chat-codeblock .hljs-addition,
1066
- .chat-file-code-syntax .hljs-addition {
1103
+ .chat-file-code-syntax .hljs-addition,
1104
+ .chat-terminal-pane .hljs-addition {
1067
1105
  color: var(--md-code-addition);
1068
1106
  }
1069
1107
 
1108
+ /* Terminal tool surface: terminal style without decorative chrome */
1109
+ .chat-terminal-surface {
1110
+ --terminal-surface: #0b1220;
1111
+ --terminal-border: rgba(148, 163, 184, 0.28);
1112
+ --terminal-text: #e5e7eb;
1113
+ --terminal-muted: #94a3b8;
1114
+ --terminal-prompt: #34d399;
1115
+ --terminal-caret: rgba(52, 211, 153, 0.92);
1116
+ --terminal-error-border: rgba(251, 113, 133, 0.42);
1117
+ --terminal-error-bg: rgba(127, 29, 29, 0.16);
1118
+ --terminal-error-text: #fecdd3;
1119
+ --md-code-text: #e5e7eb;
1120
+ --md-code-muted: #94a3b8;
1121
+ --md-code-keyword: #c084fc;
1122
+ --md-code-title: #93c5fd;
1123
+ --md-code-string: #86efac;
1124
+ --md-code-number: #fbbf24;
1125
+ --md-code-comment: #94a3b8;
1126
+ --md-code-attr: #67e8f9;
1127
+ --md-code-meta: #f0abfc;
1128
+ --md-code-deletion: #fca5a5;
1129
+ --md-code-addition: #86efac;
1130
+
1131
+ overflow: hidden;
1132
+ border: 1px solid var(--terminal-border);
1133
+ border-radius: 0.55rem;
1134
+ background: var(--terminal-surface);
1135
+ }
1136
+
1137
+ .chat-terminal-surface-error {
1138
+ border-color: var(--terminal-error-border);
1139
+ background:
1140
+ linear-gradient(180deg, var(--terminal-error-bg), transparent 48%),
1141
+ var(--terminal-surface);
1142
+ }
1143
+
1144
+ .chat-terminal-body {
1145
+ max-height: 22rem;
1146
+ overflow: auto;
1147
+ padding: 0.7rem 0.75rem 0.78rem;
1148
+ scrollbar-width: thin;
1149
+ scrollbar-color: rgba(148, 163, 184, 0.45) transparent;
1150
+ }
1151
+
1152
+ .chat-terminal-line {
1153
+ display: grid;
1154
+ grid-template-columns: 1rem minmax(0, 1fr);
1155
+ column-gap: 0.55rem;
1156
+ align-items: start;
1157
+ }
1158
+
1159
+ .chat-terminal-gutter {
1160
+ width: 1rem;
1161
+ color: var(--terminal-prompt);
1162
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1163
+ font-size: 0.8rem;
1164
+ font-weight: 700;
1165
+ line-height: 1.58;
1166
+ text-align: right;
1167
+ user-select: none;
1168
+ }
1169
+
1170
+ .chat-terminal-line-content {
1171
+ min-width: 0;
1172
+ }
1173
+
1174
+ .chat-terminal-output-block {
1175
+ margin-top: 0.55rem;
1176
+ }
1177
+
1178
+ .chat-terminal-pre {
1179
+ margin: 0;
1180
+ background: transparent;
1181
+ }
1182
+
1183
+ .chat-terminal-pre code,
1184
+ .chat-terminal-code {
1185
+ display: block;
1186
+ white-space: pre-wrap;
1187
+ overflow-wrap: anywhere;
1188
+ word-break: break-word;
1189
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1190
+ font-size: 0.8rem;
1191
+ line-height: 1.58;
1192
+ color: var(--terminal-text);
1193
+ font-variant-ligatures: none;
1194
+ tab-size: 2;
1195
+ }
1196
+
1197
+ .chat-terminal-pre-error,
1198
+ .chat-terminal-code-error {
1199
+ color: var(--terminal-error-text);
1200
+ }
1201
+
1202
+ .chat-terminal-empty {
1203
+ color: var(--terminal-muted);
1204
+ font-size: 0.78rem;
1205
+ font-style: italic;
1206
+ }
1207
+
1208
+ .chat-terminal-caret {
1209
+ display: inline-block;
1210
+ width: 0.42rem;
1211
+ height: 0.95em;
1212
+ margin-left: 0.12rem;
1213
+ vertical-align: text-bottom;
1214
+ background: var(--terminal-caret);
1215
+ animation: chat-terminal-caret-blink 1s steps(1, end) infinite;
1216
+ }
1217
+
1218
+ .chat-terminal-skeleton {
1219
+ height: 0.78rem;
1220
+ width: 9rem;
1221
+ border-radius: 999px;
1222
+ background: rgba(148, 163, 184, 0.28);
1223
+ animation: chat-terminal-skeleton-pulse 1.2s ease-in-out infinite;
1224
+ }
1225
+
1226
+ .chat-terminal-surface .ansi-bold { font-weight: 700; }
1227
+ .chat-terminal-surface .ansi-dim { opacity: 0.72; }
1228
+ .chat-terminal-surface .ansi-italic { font-style: italic; }
1229
+ .chat-terminal-surface .ansi-underline { text-decoration: underline; }
1230
+ .chat-terminal-surface .ansi-inverse {
1231
+ color: var(--terminal-surface);
1232
+ background: var(--terminal-text);
1233
+ }
1234
+
1235
+ .chat-terminal-surface .ansi-fg-black { color: #0f172a; }
1236
+ .chat-terminal-surface .ansi-fg-red { color: #f87171; }
1237
+ .chat-terminal-surface .ansi-fg-green { color: #4ade80; }
1238
+ .chat-terminal-surface .ansi-fg-yellow { color: #fbbf24; }
1239
+ .chat-terminal-surface .ansi-fg-blue { color: #60a5fa; }
1240
+ .chat-terminal-surface .ansi-fg-magenta { color: #e879f9; }
1241
+ .chat-terminal-surface .ansi-fg-cyan { color: #22d3ee; }
1242
+ .chat-terminal-surface .ansi-fg-white { color: #e5e7eb; }
1243
+ .chat-terminal-surface .ansi-fg-bright-black { color: #94a3b8; }
1244
+ .chat-terminal-surface .ansi-fg-bright-red { color: #fca5a5; }
1245
+ .chat-terminal-surface .ansi-fg-bright-green { color: #86efac; }
1246
+ .chat-terminal-surface .ansi-fg-bright-yellow { color: #fde68a; }
1247
+ .chat-terminal-surface .ansi-fg-bright-blue { color: #93c5fd; }
1248
+ .chat-terminal-surface .ansi-fg-bright-magenta { color: #f0abfc; }
1249
+ .chat-terminal-surface .ansi-fg-bright-cyan { color: #67e8f9; }
1250
+ .chat-terminal-surface .ansi-fg-bright-white { color: #f8fafc; }
1251
+
1252
+ .chat-terminal-surface .ansi-bg-black { background: #0f172a; }
1253
+ .chat-terminal-surface .ansi-bg-red { background: rgba(248, 113, 113, 0.28); }
1254
+ .chat-terminal-surface .ansi-bg-green { background: rgba(74, 222, 128, 0.22); }
1255
+ .chat-terminal-surface .ansi-bg-yellow { background: rgba(251, 191, 36, 0.22); }
1256
+ .chat-terminal-surface .ansi-bg-blue { background: rgba(96, 165, 250, 0.22); }
1257
+ .chat-terminal-surface .ansi-bg-magenta { background: rgba(232, 121, 249, 0.22); }
1258
+ .chat-terminal-surface .ansi-bg-cyan { background: rgba(34, 211, 238, 0.2); }
1259
+ .chat-terminal-surface .ansi-bg-white { background: rgba(229, 231, 235, 0.18); }
1260
+
1261
+ @keyframes chat-terminal-caret-blink {
1262
+ 0%, 49% { opacity: 1; }
1263
+ 50%, 100% { opacity: 0; }
1264
+ }
1265
+
1266
+ @keyframes chat-terminal-skeleton-pulse {
1267
+ 0%, 100% { opacity: 0.55; }
1268
+ 50% { opacity: 1; }
1269
+ }
1270
+
1271
+ @media (prefers-reduced-motion: reduce) {
1272
+ .chat-terminal-caret,
1273
+ .chat-terminal-skeleton {
1274
+ animation: none;
1275
+ }
1276
+ }
1277
+
1278
+ :root[data-theme="work"] .chat-terminal-surface {
1279
+ --terminal-surface: #111827;
1280
+ --terminal-border: rgba(148, 163, 184, 0.24);
1281
+ }
1282
+
1283
+ :root[data-theme-appearance="dark"] .chat-terminal-surface {
1284
+ --terminal-surface: #070b14;
1285
+ --terminal-border: rgba(148, 163, 184, 0.22);
1286
+ }
1287
+
1288
+ /* Prevent browser default "详情/Details" fallback on chat process summaries. */
1289
+ .nextclaw-chat-message-user details > summary,
1290
+ .border-border.bg-card details > summary,
1291
+ .chat-markdown details > summary {
1292
+ list-style: none;
1293
+ }
1294
+
1295
+ .nextclaw-chat-message-user details > summary::-webkit-details-marker,
1296
+ .border-border.bg-card details > summary::-webkit-details-marker,
1297
+ .chat-markdown details > summary::-webkit-details-marker {
1298
+ display: none;
1299
+ }
1300
+
1070
1301
  .chat-table-wrap {
1071
1302
  margin: 0.15rem 0;
1072
1303
  border: 1px solid var(--md-border);
@@ -1112,9 +1343,38 @@
1112
1343
  }
1113
1344
 
1114
1345
  .chat-markdown img {
1346
+ display: block;
1347
+ width: auto;
1348
+ max-width: min(100%, 32rem);
1349
+ height: auto;
1350
+ }
1351
+
1352
+ .chat-markdown [data-chat-message-image-preview] {
1353
+ margin-block: 0.72rem;
1354
+ }
1355
+
1356
+ .chat-markdown [data-chat-message-image-preview]:first-child,
1357
+ .chat-markdown [data-chat-message-image-preview]
1358
+ + [data-chat-message-image-preview] {
1359
+ margin-top: 0;
1360
+ }
1361
+
1362
+ .chat-markdown [data-chat-message-image-preview]:last-child {
1363
+ margin-bottom: 0;
1364
+ }
1365
+
1366
+ .chat-markdown [data-chat-image-row="three-column"] {
1367
+ display: grid;
1368
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1369
+ align-items: start;
1370
+ gap: 0.72rem;
1371
+ }
1372
+
1373
+ .chat-markdown
1374
+ [data-chat-image-row="three-column"]
1375
+ > [data-chat-message-image-preview] {
1115
1376
  max-width: 100%;
1116
- border-radius: 0.75rem;
1117
- border: 1px solid var(--md-border);
1377
+ margin: 0;
1118
1378
  }
1119
1379
 
1120
1380
  .chat-markdown blockquote {
@@ -0,0 +1,61 @@
1
+ import { render } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+ import { FileTypeIcon } from "@/shared/components/file-type-icon";
4
+
5
+ function readIcon(container: HTMLElement, name: string): SVGElement {
6
+ const icon = container.querySelector<SVGElement>(
7
+ `[data-file-type-icon="${name}"]`,
8
+ );
9
+ expect(icon).not.toBeNull();
10
+ expect(icon?.innerHTML).not.toContain("undefined");
11
+ expect(icon?.childElementCount).toBeGreaterThan(0);
12
+ return icon!;
13
+ }
14
+
15
+ describe("FileTypeIcon", () => {
16
+ it("renders recognizable SVG icons for common file types", () => {
17
+ const { container } = render(
18
+ <>
19
+ <FileTypeIcon fileName="src/app.tsx" />
20
+ <FileTypeIcon fileName="scripts/setup.js" />
21
+ <FileTypeIcon fileName="docs/guide.md" />
22
+ <FileTypeIcon fileName="assets/hero.png" />
23
+ <FileTypeIcon fileName="reports/data.xlsx" />
24
+ </>,
25
+ );
26
+
27
+ expect(readIcon(container, "react-typescript").tagName).toBe("svg");
28
+ expect(readIcon(container, "javascript").tagName).toBe("svg");
29
+ expect(readIcon(container, "markdown").tagName).toBe("svg");
30
+ expect(readIcon(container, "image").tagName).toBe("svg");
31
+ expect(readIcon(container, "excel").tagName).toBe("svg");
32
+ });
33
+
34
+ it("recognizes editor-style special file names", () => {
35
+ const { container } = render(
36
+ <>
37
+ <FileTypeIcon fileName="package.json" />
38
+ <FileTypeIcon fileName="Dockerfile" />
39
+ <FileTypeIcon fileName=".env.local" />
40
+ <FileTypeIcon fileName="vitest.unit.config.ts" />
41
+ <FileTypeIcon fileName="PHOTO.JPEG" />
42
+ </>,
43
+ );
44
+
45
+ expect(readIcon(container, "npm")).toBeTruthy();
46
+ expect(readIcon(container, "docker")).toBeTruthy();
47
+ expect(readIcon(container, "dotenv")).toBeTruthy();
48
+ expect(readIcon(container, "vitest")).toBeTruthy();
49
+ expect(readIcon(container, "image")).toBeTruthy();
50
+ });
51
+
52
+ it("uses the neutral SVG fallback and compact size predictably", () => {
53
+ const { container } = render(
54
+ <FileTypeIcon fileName="artifact.customtype" size="compact" />,
55
+ );
56
+
57
+ const fallback = readIcon(container, "default");
58
+ expect(fallback.classList.contains("h-3.5")).toBe(true);
59
+ expect(fallback.getAttribute("aria-hidden")).toBe("true");
60
+ });
61
+ });
@@ -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}
@@ -80,6 +80,25 @@ describe('DocBrowserManager layout notifications', () => {
80
80
 
81
81
  expect(onRightPanelOpened).toHaveBeenCalledTimes(1);
82
82
  });
83
+
84
+ it('persists the docked global right panel width across rehydration', async () => {
85
+ const { result } = renderHook(() => useDocBrowser(), { wrapper });
86
+
87
+ act(() => {
88
+ result.current.setDockedWidth(610);
89
+ });
90
+
91
+ await waitFor(() => {
92
+ expect(readPersistedDocBrowserSnapshot()).toMatchObject({
93
+ state: { snapshot: { dockedWidth: 610 } },
94
+ });
95
+ });
96
+
97
+ const savedState = window.localStorage.getItem(docBrowserStorageKey);
98
+ await resetMemoryThenRehydrate(savedState);
99
+
100
+ expect(useDocBrowserStore.getState().snapshot.dockedWidth).toBe(610);
101
+ });
83
102
  });
84
103
 
85
104
  describe('DocBrowserProvider dedupe keys', () => {
@@ -24,6 +24,7 @@ const { docBrowserState } = vi.hoisted<{
24
24
  docBrowserState: {
25
25
  isOpen: true,
26
26
  mode: "docked" as "docked" | "floating",
27
+ dockedWidth: 420,
27
28
  tabs: [
28
29
  {
29
30
  id: "docs",
@@ -58,6 +59,7 @@ const { docBrowserState } = vi.hoisted<{
58
59
  openNewTab: vi.fn(),
59
60
  close: vi.fn(),
60
61
  toggleMode: vi.fn(),
62
+ setDockedWidth: vi.fn(),
61
63
  goBack: vi.fn(),
62
64
  goForward: vi.fn(),
63
65
  navigate: vi.fn(),
@@ -156,6 +158,20 @@ describe("DocBrowser", () => {
156
158
  expect(screen.getByTestId("resizable-right-panel-handle")).toBeTruthy();
157
159
  });
158
160
 
161
+ it("commits the resized docked width to the global browser state owner", () => {
162
+ render(<DocBrowser />);
163
+
164
+ firePointerEvent(
165
+ screen.getByTestId("resizable-right-panel-handle"),
166
+ "pointerdown",
167
+ { clientX: 800, pointerId: 1 },
168
+ );
169
+ firePointerEvent(window, "pointermove", { clientX: 620, pointerId: 1 });
170
+ firePointerEvent(window, "pointerup", { clientX: 620, pointerId: 1 });
171
+
172
+ expect(docBrowserState.setDockedWidth).toHaveBeenCalledWith(600);
173
+ });
174
+
159
175
  it("uses a full viewport panel without desktop resize controls in fullscreen mode", () => {
160
176
  render(<DocBrowser displayMode="fullscreen" />);
161
177
 
@@ -57,6 +57,7 @@ export function DocBrowserProvider({
57
57
  openNewTab: manager.openNewTab,
58
58
  close: manager.close,
59
59
  toggleMode: manager.toggleMode,
60
+ setDockedWidth: manager.setDockedWidth,
60
61
  navigate: manager.navigate,
61
62
  syncUrl: manager.syncUrl,
62
63
  goBack: manager.goBack,
@@ -54,7 +54,7 @@ export function DocBrowserAddressToolbar({
54
54
  onChange={(e) => onUrlInputChange(e.target.value)}
55
55
  aria-label={t('docBrowserAddressLabel')}
56
56
  placeholder={placeholder}
57
- 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"
58
58
  />
59
59
  </form>
60
60
  <IconActionButton
@@ -28,6 +28,10 @@ import { ResizableRightPanel } from '@/shared/components/resizable-right-panel/r
28
28
  import { cn } from '@/shared/lib/utils';
29
29
  import { t } from '@/shared/lib/i18n';
30
30
  import { GripVertical } from 'lucide-react';
31
+ import {
32
+ DOC_BROWSER_DOCKED_MAX_WIDTH,
33
+ DOC_BROWSER_DOCKED_MIN_WIDTH,
34
+ } from '@/shared/components/doc-browser/utils/doc-browser-state.utils';
31
35
 
32
36
  type DocBrowserProps = {
33
37
  customTabRenderers?: DocBrowserCustomTabRenderers;
@@ -159,6 +163,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
159
163
  const {
160
164
  isOpen,
161
165
  mode,
166
+ dockedWidth,
162
167
  tabs,
163
168
  activeTabId,
164
169
  activeHistory,
@@ -169,6 +174,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
169
174
  openNewTab,
170
175
  close,
171
176
  toggleMode,
177
+ setDockedWidth,
172
178
  goBack,
173
179
  goForward,
174
180
  navigate,
@@ -386,9 +392,11 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
386
392
  return (
387
393
  <ResizableRightPanel
388
394
  data-testid="doc-browser-panel"
389
- defaultWidth={420}
390
- minWidth={320}
391
- maxWidth={860}
395
+ defaultWidth={dockedWidth}
396
+ width={dockedWidth}
397
+ minWidth={DOC_BROWSER_DOCKED_MIN_WIDTH}
398
+ maxWidth={DOC_BROWSER_DOCKED_MAX_WIDTH}
399
+ onWidthCommit={setDockedWidth}
392
400
  >
393
401
  {panelContent}
394
402
  </ResizableRightPanel>
@@ -11,6 +11,7 @@ import {
11
11
  createDocBrowserActiveHistoryEntry,
12
12
  createDefaultDocBrowserState,
13
13
  createDocBrowserTab,
14
+ normalizeDocBrowserDockedWidth,
14
15
  } from '@/shared/components/doc-browser/utils/doc-browser-state.utils';
15
16
  import {
16
17
  DOC_BROWSER_HOME_TAB_KIND,
@@ -297,6 +298,10 @@ export class DocBrowserManager {
297
298
  this.onRightPanelOpened?.();
298
299
  };
299
300
 
301
+ readonly setDockedWidth = (width: number): void => {
302
+ this.setSnapshot((prev) => ({ ...prev, dockedWidth: normalizeDocBrowserDockedWidth(width) }));
303
+ };
304
+
300
305
  readonly navigate = (url: string): void => {
301
306
  this.setSnapshot((prev) => {
302
307
  if (!prev.tabs.length) {
@@ -8,7 +8,10 @@ import type {
8
8
  DocBrowserStateUpdate,
9
9
  DocBrowserTab,
10
10
  } from '@/shared/components/doc-browser/types/doc-browser.types';
11
- import { createDefaultDocBrowserState } from '@/shared/components/doc-browser/utils/doc-browser-state.utils';
11
+ import {
12
+ createDefaultDocBrowserState,
13
+ normalizeDocBrowserDockedWidth,
14
+ } from '@/shared/components/doc-browser/utils/doc-browser-state.utils';
12
15
 
13
16
  const DOC_BROWSER_STORAGE_KEY = 'nextclaw.doc-browser.state';
14
17
  const DOC_BROWSER_STORAGE_VERSION = 1;
@@ -168,6 +171,7 @@ function normalizePersistedDocBrowserState(value: unknown): DocBrowserState | nu
168
171
  return {
169
172
  isOpen: value.isOpen === true,
170
173
  mode: isDocBrowserMode(value.mode) ? value.mode : 'docked',
174
+ dockedWidth: normalizeDocBrowserDockedWidth(value.dockedWidth),
171
175
  tabs,
172
176
  activeTabId: resolvedActiveTabId,
173
177
  activeHistory: resolvedActiveHistory,
@@ -198,6 +202,7 @@ export const useDocBrowserStore = create<DocBrowserStore>()(
198
202
  snapshot: {
199
203
  isOpen: state.snapshot.isOpen,
200
204
  mode: state.snapshot.mode,
205
+ dockedWidth: state.snapshot.dockedWidth,
201
206
  tabs: state.snapshot.tabs.slice(-DOC_BROWSER_MAX_PERSISTED_TABS),
202
207
  activeTabId: state.snapshot.activeTabId,
203
208
  activeHistory: state.snapshot.activeHistory,
@@ -76,6 +76,7 @@ export type DocBrowserOpenOptions = {
76
76
  export type DocBrowserState = {
77
77
  isOpen: boolean;
78
78
  mode: DocBrowserMode;
79
+ dockedWidth: number;
79
80
  tabs: DocBrowserTab[];
80
81
  activeTabId: string;
81
82
  activeHistory: DocBrowserActiveHistoryEntry[];
@@ -90,6 +91,7 @@ export type DocBrowserActions = {
90
91
  openNewTab: () => void;
91
92
  close: () => void;
92
93
  toggleMode: () => void;
94
+ setDockedWidth: (width: number) => void;
93
95
  navigate: (url: string) => void;
94
96
  syncUrl: (url: string) => void;
95
97
  goBack: () => void;