@nextclaw/ui 0.14.1 → 0.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/assets/{api-DPcvCLfa.js → api-BP_8IaxB.js} +7 -7
  3. package/dist/assets/channels-list-page-DEh5Jjqx.js +8 -0
  4. package/dist/assets/chat-page-BRB0N5WW.js +105 -0
  5. package/dist/assets/config-split-page-CRhlZ_pH.js +1 -0
  6. package/dist/assets/{confirm-dialog-CWh5FfK2.js → confirm-dialog-DsivFJ4r.js} +2 -2
  7. package/dist/assets/{desktop-update-config-DsRhBizi.js → desktop-update-config-B0w9p2ep.js} +1 -1
  8. package/dist/assets/{dist-DPrgcEC0.js → dist-CikkhOlq.js} +1 -1
  9. package/dist/assets/{dist-DsE4OsSS.js → dist-PVA_xL1D.js} +1 -1
  10. package/dist/assets/doc-browser-BoNJ7-tE.js +1 -0
  11. package/dist/assets/doc-browser-CdJ_d4ik.js +1 -0
  12. package/dist/assets/doc-browser-context-MTw4EvKd.js +1 -0
  13. package/dist/assets/{ellipsis-B81FStLm.js → ellipsis-y6vDtq4M.js} +1 -1
  14. package/dist/assets/{external-link-C_dmG-WJ.js → external-link-DVJIQf_G.js} +1 -1
  15. package/dist/assets/index-BiE-K8-q.css +1 -0
  16. package/dist/assets/index-D9BAE_L_.js +105 -0
  17. package/dist/assets/mcp-marketplace-page-B1SZNY5m.js +40 -0
  18. package/dist/assets/mcp-marketplace-page-Cq_Tw42T.js +1 -0
  19. package/dist/assets/middleware-CkFT3R4v.js +1 -0
  20. package/dist/assets/model-config-page-DotaTUHb.js +1 -0
  21. package/dist/assets/plus-BbZqquJe.js +1 -0
  22. package/dist/assets/provider-scoped-model-input-DsFRuWJH.js +1 -0
  23. package/dist/assets/providers-config-page-DW4tQSLN.js +1 -0
  24. package/dist/assets/{react-sZz5HSCm.js → react-VNqT5Zp7.js} +1 -1
  25. package/dist/assets/remote-B8TiUfwW.js +1 -0
  26. package/dist/assets/rotate-cw-DjHDTkCv.js +1 -0
  27. package/dist/assets/runtime-config-page-S6ErRHR8.js +1 -0
  28. package/dist/assets/{save-MzjoiHri.js → save-BOJ477H-.js} +1 -1
  29. package/dist/assets/{search-B29dE4GN.js → search-BEti5beA.js} +1 -1
  30. package/dist/assets/{search-config-page-Dl5sZzob.js → search-config-page-DGj5am03.js} +1 -1
  31. package/dist/assets/{secrets-config-page-C_l-IFCK.js → secrets-config-page--IzrIOid.js} +2 -2
  32. package/dist/assets/{select-BKmh05hd.js → select-hoj8dK4K.js} +2 -2
  33. package/dist/assets/{tag-chip-BS_7Ueom.js → tag-chip-T8-h-die.js} +1 -1
  34. package/dist/assets/use-config-CjRV2hwL.js +1 -0
  35. package/dist/assets/x-D9PXs_xP.js +1 -0
  36. package/dist/index.html +70 -19
  37. package/index.html +55 -5
  38. package/package.json +9 -9
  39. package/src/app/components/app-presenter-provider.tsx +11 -2
  40. package/src/app/components/layout/__tests__/app-layout.test.tsx +11 -2
  41. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +110 -79
  42. package/src/app/components/layout/app-layout.tsx +18 -4
  43. package/src/app/components/layout/header.tsx +3 -3
  44. package/src/app/components/layout/page-layout.tsx +2 -2
  45. package/src/app/components/layout/runtime-status-entry.tsx +7 -7
  46. package/src/app/components/layout/sidebar-items.tsx +194 -71
  47. package/src/app/components/layout/sidebar-rail.styles.ts +15 -0
  48. package/src/app/components/layout/sidebar.tsx +340 -83
  49. package/src/app/managers/viewport-layout.manager.ts +10 -0
  50. package/src/app/stores/viewport-layout.store.ts +39 -3
  51. package/src/app/styles/design-system.css +388 -26
  52. package/src/app/test/vitest-setup.ts +31 -0
  53. package/src/features/agents/components/__tests__/agents-page.test.tsx +62 -39
  54. package/src/features/agents/components/agents-page.tsx +10 -6
  55. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +3 -3
  56. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
  57. package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +4 -2
  58. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +69 -762
  59. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +132 -0
  60. package/src/features/chat/components/conversation/chat-conversation-content.tsx +22 -15
  61. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +15 -16
  62. package/src/features/chat/components/conversation/chat-conversation-header.tsx +7 -6
  63. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +19 -19
  64. package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +13 -13
  65. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +10 -4
  66. package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +52 -11
  67. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +18 -16
  68. package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
  69. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
  70. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +93 -20
  71. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +93 -36
  72. package/src/features/chat/components/layout/chat-sidebar.tsx +60 -93
  73. package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
  74. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +225 -0
  75. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +199 -0
  76. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +308 -0
  77. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +439 -0
  78. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +194 -0
  79. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +66 -0
  80. package/src/features/chat/features/{input/hooks/use-chat-input-bar-query-state.ts → conversation/hooks/use-session-conversation-input-query.ts} +51 -20
  81. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +281 -0
  82. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +158 -0
  83. package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +56 -0
  84. package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +117 -0
  85. package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +77 -0
  86. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +108 -0
  87. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +10 -0
  88. package/src/features/chat/features/input/input-surface-plugins/input-surface-search.utils.ts +108 -0
  89. package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +108 -0
  90. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +161 -0
  91. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
  92. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +26 -13
  93. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +7 -28
  94. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +6 -0
  95. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +26 -51
  96. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +2 -0
  97. package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +5 -6
  98. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +47 -12
  99. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +7 -7
  100. package/src/features/chat/features/message/components/chat-message-list.container.tsx +99 -18
  101. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +31 -12
  102. package/src/features/chat/features/message/utils/chat-message-markdown-part.utils.ts +38 -0
  103. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +1 -1
  104. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +7 -7
  105. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +6 -6
  106. package/src/features/chat/features/session/components/session-context-icon.tsx +2 -2
  107. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +2 -2
  108. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +1 -1
  109. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
  110. package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
  111. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
  112. package/src/features/chat/features/session/components/session-run-badge.tsx +1 -1
  113. package/src/features/chat/features/session/hooks/__tests__/use-chat-session-project.test.tsx +3 -30
  114. package/src/features/chat/features/session/hooks/use-chat-session-project.ts +0 -5
  115. package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +8 -0
  116. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-menu.test.tsx +2 -2
  117. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +2 -0
  118. package/src/features/chat/features/session-type/components/chat-session-type-menu.tsx +2 -2
  119. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +2 -2
  120. package/src/features/chat/features/session-type/hooks/use-chat-session-type-state.ts +10 -2
  121. package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +49 -31
  122. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +2 -9
  123. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
  124. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +3 -3
  125. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +4 -4
  126. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +14 -19
  127. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +5 -5
  128. package/src/features/chat/features/welcome/components/chat-welcome.tsx +6 -6
  129. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +6 -8
  130. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +1 -16
  131. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +54 -0
  132. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +44 -76
  133. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
  134. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +7 -1
  135. package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +40 -31
  136. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +59 -1
  137. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +109 -0
  138. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +44 -4
  139. package/src/features/chat/index.ts +0 -1
  140. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +51 -99
  141. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +135 -21
  142. package/src/features/chat/managers/chat-session-list.manager.ts +12 -43
  143. package/src/features/chat/managers/chat-thread.manager.ts +108 -34
  144. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +48 -1
  145. package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +72 -0
  146. package/src/features/chat/pages/ncp-chat-page.tsx +0 -122
  147. package/src/features/chat/presenters/chat.presenter.ts +2 -19
  148. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +31 -0
  149. package/src/features/chat/stores/chat-thread.store.ts +42 -26
  150. package/src/features/panel-apps/components/panel-app-list-item.tsx +8 -8
  151. package/src/features/panel-apps/components/panel-app-toolbar.tsx +4 -4
  152. package/src/features/panel-apps/components/panel-apps-list.tsx +20 -20
  153. package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
  154. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +70 -6
  155. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +10 -5
  156. package/src/features/service-apps/components/service-action-authorization-dialog.tsx +8 -8
  157. package/src/features/service-apps/components/service-apps-panel.tsx +24 -24
  158. package/src/features/settings/components/config/provider-advanced-settings-section.tsx +5 -5
  159. package/src/features/settings/components/config/provider-auth-section.tsx +7 -7
  160. package/src/features/settings/components/config/provider-form.tsx +10 -10
  161. package/src/features/settings/components/config/provider-models-section.tsx +16 -16
  162. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  163. package/src/features/settings/pages/providers-config-page.tsx +17 -17
  164. package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +50 -10
  165. package/src/platforms/desktop/components/desktop-app-shell.tsx +34 -10
  166. package/src/platforms/desktop/components/desktop-window-chrome.tsx +41 -16
  167. package/src/shared/components/config-split-page.tsx +11 -11
  168. package/src/shared/components/doc-browser/doc-browser-home-page.tsx +2 -2
  169. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +4 -4
  170. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +4 -4
  171. package/src/shared/components/doc-browser/doc-browser.tsx +3 -3
  172. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +1 -1
  173. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  174. package/src/shared/components/ui/button.tsx +4 -4
  175. package/src/shared/components/ui/card.tsx +4 -4
  176. package/src/shared/components/ui/dialog.tsx +5 -5
  177. package/src/shared/components/ui/input.tsx +1 -1
  178. package/src/shared/components/ui/label.tsx +1 -1
  179. package/src/shared/components/ui/popover.tsx +1 -1
  180. package/src/shared/components/ui/select.tsx +3 -3
  181. package/src/shared/components/ui/switch.tsx +3 -3
  182. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +24 -1
  183. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -4
  184. package/src/shared/components/ui/tabs.tsx +4 -4
  185. package/src/shared/components/ui/textarea.tsx +1 -1
  186. package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
  187. package/src/shared/lib/i18n/locales/en-US/core.json +9 -2
  188. package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
  189. package/src/shared/lib/i18n/locales/zh-CN/core.json +9 -2
  190. package/src/shared/lib/theme/index.ts +94 -52
  191. package/src/shared/lib/ui-document-title/__tests__/ui-document-title.test.ts +49 -0
  192. package/src/shared/lib/ui-document-title/index.ts +50 -21
  193. package/dist/assets/channels-list-page-D6jtziu4.js +0 -8
  194. package/dist/assets/chat-page-BBnNJoKG.js +0 -105
  195. package/dist/assets/config-split-page-BCJhqdK9.js +0 -1
  196. package/dist/assets/doc-browser-C8xOF_9F.js +0 -1
  197. package/dist/assets/doc-browser-DgQedeAn.js +0 -1
  198. package/dist/assets/doc-browser-context-B46tQGmO.js +0 -1
  199. package/dist/assets/index-7o1WdUbU.js +0 -103
  200. package/dist/assets/index-DQWmEWzk.css +0 -1
  201. package/dist/assets/mcp-marketplace-page-CWZN7ohK.js +0 -1
  202. package/dist/assets/mcp-marketplace-page-Dzull_4-.js +0 -40
  203. package/dist/assets/model-config-page-Cv0O3BIj.js +0 -1
  204. package/dist/assets/plus-Bnt56oqG.js +0 -1
  205. package/dist/assets/provider-scoped-model-input-Duuh7i3h.js +0 -1
  206. package/dist/assets/providers-config-page-CPDz0Lxc.js +0 -1
  207. package/dist/assets/remote-B0LMs8u7.js +0 -1
  208. package/dist/assets/rotate-cw-BfyG_KEF.js +0 -1
  209. package/dist/assets/runtime-config-page-q0fvv8ME.js +0 -1
  210. package/dist/assets/use-config-DZkBWIdL.js +0 -1
  211. package/dist/assets/x-CW2KO-Hz.js +0 -1
  212. package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +0 -37
  213. package/src/features/chat/features/input/components/__tests__/chat-attachment-upload-limit.test.ts +0 -38
  214. package/src/features/chat/features/input/components/chat-input-bar.container.tsx +0 -496
  215. package/src/features/chat/features/message/utils/chat-message-inline-content.utils.ts +0 -95
  216. package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +0 -448
  217. package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +0 -129
  218. package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +0 -236
  219. package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +0 -219
  220. package/src/features/chat/managers/chat-input.manager.ts +0 -430
  221. package/src/features/chat/managers/chat-run.manager.ts +0 -110
  222. package/src/features/chat/managers/chat-session-preference-sync.manager.ts +0 -142
  223. package/src/features/chat/stores/chat-input.store.ts +0 -104
  224. /package/dist/assets/{config-hints-CTqBnCDp.js → config-hints-BkYBc7z0.js} +0 -0
@@ -133,11 +133,11 @@ export function ProvidersConfigPage() {
133
133
  </Button>
134
134
  </PopoverTrigger>
135
135
  <PopoverContent className="w-[42rem] max-w-[calc(100vw-2rem)] p-3" align="start">
136
- <div className="mb-2 px-1 text-xs font-semibold text-gray-500">{t('providerTemplatePickerTitle')}</div>
136
+ <div className="mb-2 px-1 text-xs font-semibold text-muted-foreground">{t('providerTemplatePickerTitle')}</div>
137
137
  <div className="grid max-h-[24rem] grid-cols-2 gap-2 overflow-y-auto sm:grid-cols-3">
138
138
  <button
139
139
  type="button"
140
- className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-dashed border-gray-300 bg-white px-3 py-2 text-left hover:border-primary/40 hover:bg-gray-50"
140
+ className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-dashed border-border bg-card px-3 py-2 text-left transition-colors hover:border-primary/40 hover:bg-accent/70"
141
141
  onClick={async () => {
142
142
  try {
143
143
  const result = await createProvider.mutateAsync({ data: { providerType: null } });
@@ -150,8 +150,8 @@ export function ProvidersConfigPage() {
150
150
  }
151
151
  }}
152
152
  >
153
- <LogoBadge name="custom" className="h-8 w-8 rounded-lg border border-gray-200 bg-white" />
154
- <span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-gray-800">
153
+ <LogoBadge name="custom" className="h-8 w-8 rounded-lg border border-border bg-background" />
154
+ <span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-foreground">
155
155
  {t('providerAddCustom')}
156
156
  </span>
157
157
  </button>
@@ -159,7 +159,7 @@ export function ProvidersConfigPage() {
159
159
  <button
160
160
  key={template.providerType}
161
161
  type="button"
162
- className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-left hover:border-primary/40 hover:bg-gray-50"
162
+ className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-border bg-card px-3 py-2 text-left transition-colors hover:border-primary/40 hover:bg-accent/70"
163
163
  onClick={async () => {
164
164
  try {
165
165
  const result = await createProvider.mutateAsync({ data: { providerType: template.providerType } });
@@ -175,10 +175,10 @@ export function ProvidersConfigPage() {
175
175
  <LogoBadge
176
176
  name={template.providerType}
177
177
  src={template.logo ? `/logos/${template.logo}` : null}
178
- className="h-8 w-8 rounded-lg border border-gray-200 bg-white"
178
+ className="h-8 w-8 rounded-lg border border-border bg-background"
179
179
  imgClassName="h-4 w-4 object-contain"
180
180
  />
181
- <span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-gray-800">
181
+ <span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-foreground">
182
182
  {template.displayName || template.providerType}
183
183
  </span>
184
184
  </button>
@@ -188,9 +188,9 @@ export function ProvidersConfigPage() {
188
188
  </Popover>
189
189
  </ConfigSplitPaneHeader>
190
190
 
191
- <div className="border-b border-gray-100 px-4 py-3">
191
+ <div className="border-b border-border/70 px-4 py-3">
192
192
  <div className="relative">
193
- <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
193
+ <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground/70" />
194
194
  <Input
195
195
  value={query}
196
196
  onChange={(event) => setQuery(event.target.value)}
@@ -223,8 +223,8 @@ export function ProvidersConfigPage() {
223
223
  className={cn(
224
224
  'w-full rounded-xl border p-2.5 text-left transition-all',
225
225
  resolvedSelectedProvider === provider.providerId
226
- ? 'border-primary/30 bg-primary-50/40 shadow-sm'
227
- : 'border-gray-200/70 bg-white hover:border-gray-300 hover:bg-gray-50/70',
226
+ ? 'border-primary/35 bg-primary-50/45 text-foreground shadow-sm'
227
+ : 'border-border bg-card text-muted-foreground hover:border-primary/35 hover:bg-accent/70 hover:text-accent-foreground',
228
228
  )}
229
229
  >
230
230
  <div className="relative min-h-10">
@@ -234,15 +234,15 @@ export function ProvidersConfigPage() {
234
234
  src={template?.logo ? `/logos/${template.logo}` : null}
235
235
  className={cn(
236
236
  'h-10 w-10 rounded-lg border',
237
- isReady ? 'border-primary/30 bg-white' : 'border-gray-200/70 bg-white',
237
+ isReady ? 'border-primary/35 bg-background' : 'border-border bg-background',
238
238
  )}
239
239
  imgClassName="h-5 w-5 object-contain"
240
- fallback={<span className="text-sm font-semibold uppercase text-gray-500">{provider.providerId[0]}</span>}
240
+ fallback={<span className="text-sm font-semibold uppercase text-muted-foreground">{provider.providerId[0]}</span>}
241
241
  />
242
242
  <div className="min-w-0">
243
- <p className="truncate text-sm font-semibold text-gray-900">{providerLabel}</p>
244
- <p className="truncate font-mono text-[10px] text-gray-400">{provider.providerId}</p>
245
- <p className="line-clamp-1 text-[11px] text-gray-500">
243
+ <p className="truncate text-sm font-semibold text-foreground">{providerLabel}</p>
244
+ <p className="truncate font-mono text-[10px] text-muted-foreground/65">{provider.providerId}</p>
245
+ <p className="line-clamp-1 text-[11px] text-muted-foreground">
246
246
  {description} · {provider.models?.length ?? 0}
247
247
  </p>
248
248
  </div>
@@ -268,7 +268,7 @@ export function ProvidersConfigPage() {
268
268
  <PopoverTrigger asChild>
269
269
  <button
270
270
  type="button"
271
- className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-gray-400 hover:bg-gray-100 hover:text-gray-700"
271
+ className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-muted-foreground/70 hover:bg-accent hover:text-accent-foreground"
272
272
  onClick={(event) => event.stopPropagation()}
273
273
  title={t('more')}
274
274
  >
@@ -1,8 +1,9 @@
1
1
  import { act, render, screen } from "@testing-library/react";
2
2
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
3
  import { MemoryRouter } from "react-router-dom";
4
- import { afterEach, describe, expect, it, vi } from "vitest";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { DesktopAppShell } from "@/platforms/desktop/components/desktop-app-shell";
6
+ import { viewportLayoutManager } from "@/app/managers/viewport-layout.manager";
6
7
 
7
8
  vi.mock("@/app/components/layout/sidebar", () => ({
8
9
  Sidebar: () => <aside data-testid="settings-sidebar">Settings Sidebar</aside>,
@@ -16,7 +17,10 @@ type WindowStateListener = (snapshot: { isMaximized: boolean }) => void;
16
17
 
17
18
  let windowStateListener: WindowStateListener | null = null;
18
19
 
19
- function setDesktopPlatform(platform: string | null, isMaximized = false): void {
20
+ function setDesktopPlatform(
21
+ platform: string | null,
22
+ isMaximized = false,
23
+ ): void {
20
24
  windowStateListener = null;
21
25
  window.nextclawDesktop = platform
22
26
  ? ({
@@ -59,6 +63,11 @@ function renderDesktopShell(platform: string | null, isMobileLayout = false) {
59
63
  }
60
64
 
61
65
  describe("DesktopAppShell", () => {
66
+ beforeEach(() => {
67
+ window.localStorage.clear();
68
+ viewportLayoutManager.resetForTests();
69
+ });
70
+
62
71
  afterEach(() => {
63
72
  setDesktopPlatform(null);
64
73
  });
@@ -68,29 +77,58 @@ describe("DesktopAppShell", () => {
68
77
 
69
78
  const chrome = screen.getByTestId("desktop-window-chrome");
70
79
  const sidebarChrome = screen.getByTestId("desktop-window-chrome-sidebar");
71
- const resizeStrip = screen.getByTestId("desktop-window-chrome-resize-strip");
80
+ const resizeStrip = screen.getByTestId(
81
+ "desktop-window-chrome-resize-strip",
82
+ );
72
83
  const controls = screen.getByTestId("desktop-window-controls");
73
84
 
74
85
  expect(chrome).toBeTruthy();
75
- expect(chrome.parentElement?.style.getPropertyValue("--desktop-titlebar-height")).toBe("40px");
86
+ expect(
87
+ chrome.parentElement?.style.getPropertyValue("--desktop-titlebar-height"),
88
+ ).toBe("40px");
76
89
  expect(chrome.className).toContain("bg-secondary");
77
90
  expect(chrome.className).not.toContain(" shrink-0 border-b ");
78
- expect(chrome.className).toContain("after:left-[var(--desktop-sidebar-width)]");
91
+ expect(chrome.className).toContain(
92
+ "after:left-[var(--desktop-sidebar-width)]",
93
+ );
79
94
  expect(chrome.className).toContain("after:border-b");
80
95
  expect(chrome.className).toContain("desktop-window-drag");
81
- expect(sidebarChrome.className).toContain("w-[var(--desktop-sidebar-width)]");
96
+ expect(sidebarChrome.className).toContain(
97
+ "w-[var(--desktop-sidebar-width)]",
98
+ );
82
99
  expect(sidebarChrome.className).not.toContain("border-b");
83
100
  expect(sidebarChrome.className).toContain("desktop-window-drag");
84
101
  expect(resizeStrip.className).toContain("desktop-window-no-drag");
85
102
  expect(resizeStrip.className).toContain("top-0");
86
103
  expect(resizeStrip.className).toContain("h-1");
87
104
  expect(controls.className).toContain("desktop-window-no-drag");
88
- expect(screen.getByLabelText("Minimize").className).toContain("desktop-window-no-drag");
89
- expect(screen.getByLabelText("Maximize").className).toContain("desktop-window-no-drag");
90
- expect(screen.getByLabelText("Close").className).toContain("desktop-window-no-drag");
105
+ expect(screen.getByLabelText("Minimize").className).toContain(
106
+ "desktop-window-no-drag",
107
+ );
108
+ expect(screen.getByLabelText("Maximize").className).toContain(
109
+ "desktop-window-no-drag",
110
+ );
111
+ expect(screen.getByLabelText("Close").className).toContain(
112
+ "desktop-window-no-drag",
113
+ );
91
114
  expect(screen.getByTestId("app-content")).toBeTruthy();
92
115
  });
93
116
 
117
+ it("uses the collapsed sidebar width in Windows chrome from the shared layout store", () => {
118
+ viewportLayoutManager.setSidebarCollapsed(true);
119
+
120
+ renderDesktopShell("win32");
121
+
122
+ const chromeRoot = screen.getByTestId(
123
+ "desktop-window-chrome",
124
+ ).parentElement;
125
+
126
+ expect(chromeRoot?.style.getPropertyValue("--desktop-sidebar-width")).toBe(
127
+ "56px",
128
+ );
129
+ expect(screen.getByAltText("NextClaw")).toBeTruthy();
130
+ });
131
+
94
132
  it("switches the Windows maximize button to restore while maximized", async () => {
95
133
  renderDesktopShell("win32");
96
134
 
@@ -100,7 +138,9 @@ describe("DesktopAppShell", () => {
100
138
  windowStateListener?.({ isMaximized: true });
101
139
  });
102
140
 
103
- expect(screen.getByLabelText("Restore").className).toContain("desktop-window-no-drag");
141
+ expect(screen.getByLabelText("Restore").className).toContain(
142
+ "desktop-window-no-drag",
143
+ );
104
144
  expect(screen.queryByLabelText("Maximize")).toBeNull();
105
145
  });
106
146
 
@@ -11,9 +11,12 @@ import { MobileBottomNav } from "@/platforms/mobile";
11
11
  import type { DocBrowserCustomTabRenderers } from "@/shared/components/doc-browser/doc-browser-renderer.types";
12
12
  import type { DocBrowserDockControls } from "@/shared/components/doc-browser/doc-browser-context";
13
13
  import { cn } from "@/shared/lib/utils";
14
+ import { useViewportLayoutStore } from "@/app/stores/viewport-layout.store";
15
+ import { SIDEBAR_RAIL_WIDTH_PX } from "@/app/components/layout/sidebar-rail.styles";
14
16
 
15
17
  const DocBrowser = lazy(async () => ({
16
- default: (await import("@/shared/components/doc-browser/doc-browser")).DocBrowser,
18
+ default: (await import("@/shared/components/doc-browser/doc-browser"))
19
+ .DocBrowser,
17
20
  }));
18
21
 
19
22
  type DesktopAppShellProps = {
@@ -38,8 +41,17 @@ export function DesktopAppShell({
38
41
  children,
39
42
  }: DesktopAppShellProps) {
40
43
  const isMainRoute = isMainWorkspaceRoute(pathname);
41
- const showMobileBottomNav = isMobileLayout && !isChatSessionDetailRoute(pathname);
44
+ const isSidebarCollapsed = useViewportLayoutStore(
45
+ (state) => state.isSidebarCollapsed,
46
+ );
47
+ const showMobileBottomNav =
48
+ isMobileLayout && !isChatSessionDetailRoute(pathname);
42
49
  const shouldUseWindowsChrome = isWindowsDesktopHost();
50
+ const desktopSidebarWidth = isSidebarCollapsed
51
+ ? `${SIDEBAR_RAIL_WIDTH_PX}px`
52
+ : isMainRoute
53
+ ? "280px"
54
+ : "240px";
43
55
 
44
56
  return (
45
57
  <div
@@ -47,13 +59,19 @@ export function DesktopAppShell({
47
59
  "h-screen flex flex-col overflow-hidden bg-background font-sans text-foreground",
48
60
  shouldUseWindowsChrome ? "rounded-[10px]" : null,
49
61
  )}
50
- style={shouldUseWindowsChrome ? ({
51
- "--desktop-titlebar-height": "40px",
52
- "--desktop-caption-safe-right": "140px",
53
- "--desktop-sidebar-width": isMainRoute ? "280px" : "240px",
54
- } as CSSProperties) : undefined}
62
+ style={
63
+ shouldUseWindowsChrome
64
+ ? ({
65
+ "--desktop-titlebar-height": "40px",
66
+ "--desktop-caption-safe-right": "140px",
67
+ "--desktop-sidebar-width": desktopSidebarWidth,
68
+ } as CSSProperties)
69
+ : undefined
70
+ }
55
71
  >
56
- {shouldUseWindowsChrome ? <DesktopWindowChrome /> : null}
72
+ {shouldUseWindowsChrome ? (
73
+ <DesktopWindowChrome sidebarCollapsed={isSidebarCollapsed} />
74
+ ) : null}
57
75
  <div className="flex min-h-0 flex-1 overflow-hidden">
58
76
  {!isMainRoute && <Sidebar mode="settings" />}
59
77
  <div className="flex-1 flex min-w-0 overflow-hidden relative">
@@ -70,7 +88,10 @@ export function DesktopAppShell({
70
88
  </div>
71
89
  {isDocBrowserOpen && docBrowserMode === "docked" ? (
72
90
  <Suspense fallback={null}>
73
- <DocBrowser customTabRenderers={docBrowserRenderers} dockControls={docBrowserDockControls} />
91
+ <DocBrowser
92
+ customTabRenderers={docBrowserRenderers}
93
+ dockControls={docBrowserDockControls}
94
+ />
74
95
  </Suspense>
75
96
  ) : null}
76
97
  {sideDock}
@@ -79,7 +100,10 @@ export function DesktopAppShell({
79
100
  {showMobileBottomNav ? <MobileBottomNav /> : null}
80
101
  {isDocBrowserOpen && docBrowserMode === "floating" ? (
81
102
  <Suspense fallback={null}>
82
- <DocBrowser customTabRenderers={docBrowserRenderers} dockControls={docBrowserDockControls} />
103
+ <DocBrowser
104
+ customTabRenderers={docBrowserRenderers}
105
+ dockControls={docBrowserDockControls}
106
+ />
83
107
  </Suspense>
84
108
  ) : null}
85
109
  </div>
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useState } from "react";
2
2
  import { Copy, Minus, Square, X } from "lucide-react";
3
3
  import { BrandHeader } from "@/shared/components/common/brand-header";
4
+ import { cn } from "@/shared/lib/utils";
4
5
  import type { DesktopWindowStateSnapshot } from "@/platforms/desktop/types/desktop-update.types";
5
6
 
6
7
  type DesktopWindowControlAction = "minimize" | "toggle-maximize" | "close";
@@ -17,7 +18,11 @@ const windowControls: WindowControlDefinition[] = [
17
18
  { action: "close", label: "Close", icon: X, variant: "danger" },
18
19
  ];
19
20
 
20
- export function DesktopWindowChrome() {
21
+ export function DesktopWindowChrome({
22
+ sidebarCollapsed = false,
23
+ }: {
24
+ sidebarCollapsed?: boolean;
25
+ }) {
21
26
  const isMaximized = useDesktopWindowMaximizedState();
22
27
  const maximizeControl: WindowControlDefinition = isMaximized
23
28
  ? { action: "toggle-maximize", label: "Restore", icon: Copy }
@@ -33,21 +38,37 @@ export function DesktopWindowChrome() {
33
38
  data-testid="desktop-window-chrome-resize-strip"
34
39
  />
35
40
  <div
36
- className="desktop-window-drag relative z-10 flex h-full w-[var(--desktop-sidebar-width)] shrink-0 items-center bg-secondary pl-4 pr-3 text-secondary-foreground"
41
+ className={cn(
42
+ "desktop-window-drag relative z-10 flex h-full w-[var(--desktop-sidebar-width)] shrink-0 items-center bg-secondary text-secondary-foreground",
43
+ sidebarCollapsed ? "justify-center px-0" : "pl-4 pr-3",
44
+ )}
37
45
  data-testid="desktop-window-chrome-sidebar"
38
46
  >
39
- <BrandHeader
40
- className="flex min-w-0 shrink-0 items-center gap-2.5"
41
- density="chrome"
42
- />
47
+ {sidebarCollapsed ? (
48
+ <img
49
+ src="/logo.svg"
50
+ alt="NextClaw"
51
+ className="h-6 w-6 shrink-0 object-contain"
52
+ />
53
+ ) : (
54
+ <BrandHeader
55
+ className="flex min-w-0 shrink-0 items-center gap-2.5"
56
+ density="chrome"
57
+ />
58
+ )}
43
59
  </div>
44
60
  <div
45
61
  className="desktop-window-no-drag absolute right-0 top-0 z-20 flex h-full w-[var(--desktop-caption-safe-right)] items-start justify-end"
46
62
  data-testid="desktop-window-controls"
47
63
  >
48
- {[windowControls[0], maximizeControl, windowControls[1]].map((control) => (
49
- <DesktopWindowControlButton key={control.action} control={control} />
50
- ))}
64
+ {[windowControls[0], maximizeControl, windowControls[1]].map(
65
+ (control) => (
66
+ <DesktopWindowControlButton
67
+ key={control.action}
68
+ control={control}
69
+ />
70
+ ),
71
+ )}
51
72
  </div>
52
73
  </header>
53
74
  );
@@ -86,14 +107,18 @@ function useDesktopWindowMaximizedState(): boolean {
86
107
  let isSubscribed = true;
87
108
  const desktopApi = window.nextclawDesktop;
88
109
 
89
- void desktopApi?.getWindowState?.().then((snapshot: DesktopWindowStateSnapshot) => {
90
- if (isSubscribed) {
110
+ void desktopApi
111
+ ?.getWindowState?.()
112
+ .then((snapshot: DesktopWindowStateSnapshot) => {
113
+ if (isSubscribed) {
114
+ setIsMaximized(snapshot.isMaximized);
115
+ }
116
+ });
117
+ const unsubscribe = desktopApi?.onWindowStateChanged?.(
118
+ (snapshot: DesktopWindowStateSnapshot) => {
91
119
  setIsMaximized(snapshot.isMaximized);
92
- }
93
- });
94
- const unsubscribe = desktopApi?.onWindowStateChanged?.((snapshot: DesktopWindowStateSnapshot) => {
95
- setIsMaximized(snapshot.isMaximized);
96
- });
120
+ },
121
+ );
97
122
 
98
123
  return () => {
99
124
  isSubscribed = false;
@@ -3,7 +3,7 @@ import { ArrowLeft, type LucideIcon } from "lucide-react";
3
3
  import { t } from "@/shared/lib/i18n";
4
4
  import { cn } from "@/shared/lib/utils";
5
5
 
6
- const CARD_CLASS = "min-w-0 overflow-hidden rounded-2xl border border-gray-200/70 bg-white 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 bg-card text-card-foreground shadow-card xl:h-[calc(100vh-180px)] xl:max-h-[860px]";
7
7
  type DivProps = HTMLAttributes<HTMLDivElement>; type SectionProps = HTMLAttributes<HTMLElement>;
8
8
 
9
9
  function ConfigSplitPane({ className, ...props }: SectionProps) {
@@ -37,7 +37,7 @@ export function ConfigSplitPage({
37
37
  <button
38
38
  type="button"
39
39
  onClick={onMobileBack}
40
- className="inline-flex items-center gap-2 rounded-full border border-gray-200 bg-white px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 hover:text-gray-900"
40
+ className="inline-flex items-center gap-2 rounded-full border border-border bg-card px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
41
41
  >
42
42
  <ArrowLeft className="h-4 w-4" />
43
43
  <span>{mobileListLabel ?? t("backToMain")}</span>
@@ -81,7 +81,7 @@ export function ConfigSplitEmptyPane({ className, ...props }: SectionProps) {
81
81
  }
82
82
 
83
83
  export function ConfigSplitPaneHeader({ className, ...props }: DivProps) {
84
- return <div className={cn("shrink-0 border-b border-gray-100", className)} {...props} />;
84
+ return <div className={cn("shrink-0 border-b border-border/70", className)} {...props} />;
85
85
  }
86
86
 
87
87
  export function ConfigSplitPaneBody({
@@ -102,7 +102,7 @@ export function ConfigSplitPaneBody({
102
102
  }
103
103
 
104
104
  export function ConfigSplitPaneFooter({ className, ...props }: DivProps) {
105
- return <div className={cn("shrink-0 border-t border-gray-100", className)} {...props} />;
105
+ return <div className={cn("shrink-0 border-t border-border/70", className)} {...props} />;
106
106
  }
107
107
 
108
108
  export function ConfigSelectionCard({
@@ -117,8 +117,8 @@ export function ConfigSelectionCard({
117
117
  className={cn(
118
118
  "w-full rounded-xl border p-2.5 text-left transition-all",
119
119
  active
120
- ? "border-primary/30 bg-primary-50/40 shadow-sm"
121
- : "border-gray-200/70 bg-white hover:border-gray-300 hover:bg-gray-50/70",
120
+ ? "border-primary/35 bg-primary-50/45 text-foreground shadow-sm"
121
+ : "border-border bg-card text-muted-foreground hover:border-primary/35 hover:bg-accent/70 hover:text-accent-foreground",
122
122
  className,
123
123
  )}
124
124
  {...props}
@@ -140,16 +140,16 @@ export function ConfigSplitEmptyState({
140
140
  return (
141
141
  <div
142
142
  className={cn(
143
- "flex min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-gray-200 bg-gray-50/70 px-4 py-10 text-center",
143
+ "flex min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-border bg-muted/60 px-4 py-10 text-center",
144
144
  className,
145
145
  )}
146
146
  {...props}
147
147
  >
148
- <div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-white">
149
- <Icon className="h-5 w-5 text-gray-300" />
148
+ <div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-card">
149
+ <Icon className="h-5 w-5 text-muted-foreground/45" />
150
150
  </div>
151
- <p className="text-sm font-medium text-gray-700">{title}</p>
152
- {description ? <p className="mt-2 text-xs text-gray-500">{description}</p> : null}
151
+ <p className="text-sm font-medium text-foreground">{title}</p>
152
+ {description ? <p className="mt-2 text-xs text-muted-foreground">{description}</p> : null}
153
153
  </div>
154
154
  );
155
155
  }
@@ -5,10 +5,10 @@ export function DocBrowserHomePage() {
5
5
  return (
6
6
  <div className="flex h-full items-center justify-center bg-background px-5 py-6">
7
7
  <div className="flex max-w-[260px] flex-col items-center gap-3 text-center">
8
- <span className="flex h-12 w-12 items-center justify-center rounded-lg border border-gray-100 bg-gray-50 text-gray-600 shadow-[0_1px_2px_rgba(30,20,10,0.04)]">
8
+ <span className="flex h-12 w-12 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground shadow-[0_1px_2px_rgba(30,20,10,0.04)]">
9
9
  <Boxes className="h-5 w-5" />
10
10
  </span>
11
- <span className="text-sm font-medium text-gray-800">{t('docBrowserHomeTitle')}</span>
11
+ <span className="text-sm font-medium text-foreground">{t('docBrowserHomeTitle')}</span>
12
12
  </div>
13
13
  </div>
14
14
  );
@@ -38,15 +38,15 @@ export function DocBrowserDocsToolbar({
38
38
  }
39
39
 
40
40
  return (
41
- <div className="flex items-center gap-2 px-3.5 py-2 bg-white border-b border-gray-100 shrink-0">
41
+ <div className="flex items-center gap-2 border-b border-border/70 bg-card px-3.5 py-2 shrink-0">
42
42
  <form onSubmit={onSubmit} className="flex-1 relative">
43
- <Search className="w-3.5 h-3.5 absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
43
+ <Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/70" />
44
44
  <input
45
45
  type="text"
46
46
  value={urlInput}
47
47
  onChange={(e) => onUrlInputChange(e.target.value)}
48
48
  placeholder={t('docBrowserSearchPlaceholder')}
49
- className="w-full h-8 pl-8 pr-3 rounded-lg bg-gray-50 border border-gray-200 text-xs text-gray-700 focus:outline-none focus:ring-1 focus:ring-primary/30 focus:border-primary/40 transition-colors placeholder:text-gray-400"
49
+ className="h-8 w-full rounded-lg border border-border bg-background pl-8 pr-3 text-xs text-foreground transition-colors placeholder:text-muted-foreground/55 focus:border-primary/40 focus:outline-none focus:ring-1 focus:ring-primary/30"
50
50
  />
51
51
  </form>
52
52
  </div>
@@ -91,7 +91,7 @@ export function DocBrowserExternalLink({ currentUrl, isDocsTab }: { currentUrl:
91
91
  }
92
92
 
93
93
  return (
94
- <div className="flex items-center justify-between px-4 py-2 bg-gray-50 border-t border-gray-200 shrink-0">
94
+ <div className="flex items-center justify-between border-t border-border/70 bg-muted/55 px-4 py-2 shrink-0">
95
95
  <a
96
96
  href={currentUrl}
97
97
  target="_blank"
@@ -111,16 +111,16 @@ export function DocBrowserTabStrip({
111
111
  tabs={compactTabs}
112
112
  actions={actions}
113
113
  className={cn(
114
- "h-11 gap-2 px-2.5 bg-background border-[#f1e7d4] shrink-0 select-none",
114
+ "h-11 gap-2 border-border/70 bg-card px-2.5 shrink-0 select-none",
115
115
  isFullscreen && "h-[calc(env(safe-area-inset-top,0px)+2.75rem)] pt-[env(safe-area-inset-top,0px)]",
116
116
  )}
117
117
  scrollClassName="doc-browser-tab-scrollbar flex h-full items-center gap-1.5"
118
118
  tabsClassName="items-center gap-1.5"
119
119
  actionsClassName="h-full items-center gap-1"
120
- actionButtonClassName="rounded-md p-1.5 hover:text-gray-700 disabled:opacity-60"
120
+ actionButtonClassName="rounded-md p-1.5 hover:text-foreground disabled:opacity-60"
121
121
  tabBaseClassName="group inline-flex min-w-0 items-center gap-1 h-7 px-1.5 rounded-lg text-xs border max-w-[220px] shrink-0 transition-colors"
122
- activeTabClassName="bg-amber-50/80 border-amber-200 text-amber-900 shadow-[0_1px_2px_rgba(30,20,10,0.04)]"
123
- inactiveTabClassName="bg-[#f9f8f5] border-[#eee3d1] text-[#78644d] hover:bg-[#fff7ea] hover:text-[#2f2212]"
122
+ activeTabClassName="border-primary/30 bg-primary-50/70 text-foreground shadow-[0_1px_2px_rgba(30,20,10,0.04)]"
123
+ inactiveTabClassName="border-border bg-muted/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground"
124
124
  labelClassName="px-1 text-xs font-normal"
125
125
  onPointerDown={!isDocked && !isFullscreen ? onDragStart : undefined}
126
126
  onScrollPointerDown={(event) => event.stopPropagation()}
@@ -359,10 +359,10 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
359
359
  <div
360
360
  data-testid="doc-browser-panel"
361
361
  className={cn(
362
- 'flex flex-col bg-white overflow-hidden relative',
362
+ 'relative flex flex-col overflow-hidden bg-card text-card-foreground',
363
363
  isFullscreen
364
364
  ? 'fixed inset-0 z-[9999] h-[100dvh] w-screen rounded-none border-0 shadow-2xl'
365
- : 'rounded-2xl shadow-2xl border border-gray-200',
365
+ : 'rounded-2xl border border-border shadow-2xl',
366
366
  )}
367
367
  style={
368
368
  isFullscreen
@@ -398,7 +398,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
398
398
  onPointerDown={startFloatResize('bottom')}
399
399
  />
400
400
  <div
401
- className="absolute bottom-0 right-0 w-4 h-4 cursor-se-resize z-30 flex items-center justify-center text-gray-300 hover:text-gray-500 transition-colors"
401
+ className="absolute bottom-0 right-0 z-30 flex h-4 w-4 cursor-se-resize items-center justify-center text-muted-foreground/45 transition-colors hover:text-muted-foreground"
402
402
  data-testid="doc-browser-resize-bottom-right"
403
403
  onPointerDown={startFloatResize('bottom-right')}
404
404
  >
@@ -36,7 +36,7 @@ export function ResizableRightPanel({ children, className, style, defaultWidth =
36
36
  return (
37
37
  <aside
38
38
  {...props}
39
- className={cn("relative flex h-full min-h-0 shrink-0 overflow-hidden bg-white", overlay ? "fixed inset-0 z-40" : "border-l border-gray-200", className)}
39
+ className={cn("relative flex h-full min-h-0 shrink-0 overflow-hidden bg-card text-card-foreground", overlay ? "fixed inset-0 z-40" : "border-l border-border", className)}
40
40
  style={overlay ? style : { ...style, width }}
41
41
  >
42
42
  {!overlay ? (
@@ -27,7 +27,7 @@ const IconActionButton = React.forwardRef<HTMLButtonElement, IconActionButtonPro
27
27
  aria-label={label}
28
28
  className={cn(
29
29
  'inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 disabled:cursor-not-allowed',
30
- 'text-gray-500 hover:bg-gray-100 hover:text-gray-900 disabled:text-gray-300 disabled:hover:bg-transparent disabled:hover:text-gray-300',
30
+ 'text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
31
31
  className
32
32
  )}
33
33
  >
@@ -9,12 +9,12 @@ const buttonVariants = cva(
9
9
  variant: {
10
10
  default: 'bg-primary text-primary-foreground hover:bg-primary-600 active:bg-primary-700 shadow-sm',
11
11
  destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
12
- outline: 'border border-gray-200 bg-white hover:bg-gray-50 hover:text-gray-800 text-gray-600',
13
- secondary: 'bg-gray-100 text-gray-700 hover:bg-gray-200/80',
14
- ghost: 'hover:bg-gray-100/80 hover:text-gray-800',
12
+ outline: 'border border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground',
13
+ secondary: 'bg-muted text-foreground hover:bg-accent hover:text-accent-foreground',
14
+ ghost: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground',
15
15
  link: 'text-primary underline-offset-4 hover:underline',
16
16
  primary: 'bg-primary text-primary-foreground hover:bg-primary-600 active:bg-primary-700 shadow-sm',
17
- subtle: 'bg-gray-100 text-gray-600 hover:bg-gray-200/80',
17
+ subtle: 'bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground',
18
18
  'primary-outline': 'border border-primary/30 text-primary hover:bg-primary hover:text-primary-foreground'
19
19
  },
20
20
  size: {
@@ -8,8 +8,8 @@ const Card = React.forwardRef<
8
8
  <div
9
9
  ref={ref}
10
10
  className={cn(
11
- 'rounded-2xl border border-gray-200/50 bg-white text-card-foreground shadow-card transition-all duration-base',
12
- hover && 'hover:shadow-card-hover hover:border-gray-200',
11
+ 'rounded-2xl border border-border bg-card text-card-foreground shadow-card transition-all duration-base',
12
+ hover && 'hover:border-primary/25 hover:shadow-card-hover',
13
13
  className
14
14
  )}
15
15
  {...props}
@@ -36,7 +36,7 @@ const CardTitle = React.forwardRef<
36
36
  <h3
37
37
  ref={ref}
38
38
  className={cn(
39
- 'text-[15px] font-semibold leading-tight tracking-tight text-gray-900',
39
+ 'text-[15px] font-semibold leading-tight tracking-tight text-foreground',
40
40
  className
41
41
  )}
42
42
  {...props}
@@ -50,7 +50,7 @@ const CardDescription = React.forwardRef<
50
50
  >(({ className, ...props }, ref) => (
51
51
  <p
52
52
  ref={ref}
53
- className={cn('text-[13px] text-gray-400 leading-relaxed', className)}
53
+ className={cn('text-[13px] text-muted-foreground leading-relaxed', className)}
54
54
  {...props}
55
55
  />
56
56
  ));