@nextclaw/ui 0.26.2 → 0.26.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 (218) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/.vite/manifest.json +366 -365
  3. package/dist/assets/{account-panel-ZM2qzKF4.js → account-panel-DVi_jhkG.js} +1 -1
  4. package/dist/assets/{api-Cjq-o1VN.js → api-BZvNpFOS.js} +2 -2
  5. package/dist/assets/app-presenter-provider-BcYL-VNe.js +124 -0
  6. package/dist/assets/{appearance-settings-page-B4zouKzg.js → appearance-settings-page-AZNBzLmT.js} +1 -1
  7. package/dist/assets/{book-open-AteA89HX.js → book-open-CmRdT3N1.js} +1 -1
  8. package/dist/assets/card-CdRBL1E0.js +1 -0
  9. package/dist/assets/{channels-list-page-fj8kMo-T.js → channels-list-page-eZN74FN3.js} +2 -2
  10. package/dist/assets/{circle-dashed-LSYZTzM7.js → circle-dashed-HOgt3gIJ.js} +1 -1
  11. package/dist/assets/{client-DudCRJw4.js → client-DKKbdJ6Q.js} +1 -1
  12. package/dist/assets/config-split-page-BA3V6b3Q.js +1 -0
  13. package/dist/assets/{confirm-dialog-DShT64F6.js → confirm-dialog-8vqYZ0wy.js} +1 -1
  14. package/dist/assets/context-menu-DHVVdHzN.js +1 -0
  15. package/dist/assets/{createLucideIcon-D7hvIHV-.js → createLucideIcon-DE0sB9Nu.js} +1 -1
  16. package/dist/assets/{desktop-capabilities-page-CzqzFZUY.js → desktop-capabilities-page-B9-B9k1A.js} +1 -1
  17. package/dist/assets/{desktop-update-config-CgeQ0Ffo.js → desktop-update-config-Cfr3IRUe.js} +1 -1
  18. package/dist/assets/{dialog-C7glmAQJ.js → dialog-BUfWO8hr.js} +2 -2
  19. package/dist/assets/{doc-browser-context-BlhBAOLH.js → doc-browser-context-ClLgMbxd.js} +1 -1
  20. package/dist/assets/doc-browser-w8q1j0jL.js +1 -0
  21. package/dist/assets/{download-BYgECE0n.js → download-CKqS1Ksj.js} +1 -1
  22. package/dist/assets/{es2015-CsjAAQ6X.js → es2015-BiB05Sav.js} +1 -1
  23. package/dist/assets/{extensions-qYL-NpL3.js → extensions-vPD4dGqt.js} +1 -1
  24. package/dist/assets/{eye-BBuTzJ53.js → eye-bKzylu3p.js} +1 -1
  25. package/dist/assets/{form-actions-CLGWO52v.js → form-actions-CCoxz33Q.js} +1 -1
  26. package/dist/assets/{i18n-qBGEbcW6.js → i18n-OGmF0Ws_.js} +2 -2
  27. package/dist/assets/{keyboard-shortcuts-settings-page-B-wK_6zG.js → keyboard-shortcuts-settings-page-D8rosOVh.js} +1 -1
  28. package/dist/assets/loader-circle-Clq1Gtb1.js +1 -0
  29. package/dist/assets/{login-page-Cd84lpVV.js → login-page-BT3GV3Sb.js} +1 -1
  30. package/dist/assets/login-page-DKId3By8.js +1 -0
  31. package/dist/assets/main-bEWCGDHr.js +2 -0
  32. package/dist/assets/main-i18n-catalog.config-Bpu5GcwF.js +1 -0
  33. package/dist/assets/main-kqMRTwOs.css +1 -0
  34. package/dist/assets/mcp-marketplace-page-CZIP6j3L.js +1 -0
  35. package/dist/assets/{model-config-page-D0DQlSDa.js → model-config-page-D21a-BO0.js} +1 -1
  36. package/dist/assets/{navigation-link-32iM1-e6.js → navigation-link-DC-Pku0Y.js} +1 -1
  37. package/dist/assets/panel-app-BYfQu_TS.js +1 -0
  38. package/dist/assets/panel-app-i18n-catalog.config-D44qmtfk.js +1 -0
  39. package/dist/assets/panelStandalone-BRg7B1EI.css +1 -0
  40. package/dist/assets/{panelStandalone-C9EKaApN.js → panelStandalone-CX8X2hjh.js} +2 -2
  41. package/dist/assets/{privacy-settings-page-Bxxx12OO.js → privacy-settings-page-e0LFHZJm.js} +1 -1
  42. package/dist/assets/projects-Rki7Fmth.js +1 -0
  43. package/dist/assets/provider-models-DFQgF4hS.js +1 -0
  44. package/dist/assets/provider-scoped-model-input-DaONL0j_.js +1 -0
  45. package/dist/assets/providers-config-page-CEOhQlMe.js +1 -0
  46. package/dist/assets/{puzzle-CWHfFyYN.js → puzzle-D_TiFXOv.js} +1 -1
  47. package/dist/assets/{pwa-CiGUjpcd.js → pwa-C9ac_1dg.js} +1 -1
  48. package/dist/assets/{refresh-cw-y3L6PyLt.js → refresh-cw-BG8VfcdA.js} +1 -1
  49. package/dist/assets/remote-DkSx5x4R.js +1 -0
  50. package/dist/assets/{rotate-cw-CNE9qSHi.js → rotate-cw-DPEegUU2.js} +1 -1
  51. package/dist/assets/{runtime-config-page-5o98T-TD.js → runtime-config-page-DDT1dVLt.js} +1 -1
  52. package/dist/assets/{save-B0p5a0ET.js → save-CPlctBjT.js} +1 -1
  53. package/dist/assets/{search-config-page-CpGcnIzi.js → search-config-page-CDwmd6eX.js} +1 -1
  54. package/dist/assets/{secrets-config-page-C4VTiW3r.js → secrets-config-page-1OvgmwPv.js} +1 -1
  55. package/dist/assets/security-config-Pv4CM-kw.js +1 -0
  56. package/dist/assets/{select-CctTN205.js → select-Y9IEbx9x.js} +1 -1
  57. package/dist/assets/service-apps-panel-DPrLeF3N.js +1 -0
  58. package/dist/assets/{settings-2-EPflrNk6.js → settings-2-CrGx9_De.js} +1 -1
  59. package/dist/assets/{status-dot-CensgJZC.js → status-dot-Cb8ewlUr.js} +1 -1
  60. package/dist/assets/{tag-chip-Bjzb4-qW.js → tag-chip-D-6aPuuh.js} +1 -1
  61. package/dist/assets/{theme-provider-hlle7Skk.js → theme-provider-BjF1Eowc.js} +1 -1
  62. package/dist/assets/{trash-2-C5KH5Rw9.js → trash-2-DER2EJKK.js} +1 -1
  63. package/dist/assets/{use-config-CPl_F79t.js → use-config-BM5jC65L.js} +1 -1
  64. package/dist/assets/{use-desktop-capabilities-CEg9-DrQ.js → use-desktop-capabilities-ezKJwKqg.js} +1 -1
  65. package/dist/assets/{use-viewport-layout-CPZUmTPi.js → use-viewport-layout-vmbQUNT6.js} +1 -1
  66. package/dist/assets/x-DSz9cGhy.js +1 -0
  67. package/dist/index.html +34 -34
  68. package/dist/panel-standalone.html +11 -11
  69. package/package.json +3 -3
  70. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +2 -2
  71. package/src/app/components/layout/page-layout.tsx +5 -2
  72. package/src/app/components/layout/sidebar-rail.styles.ts +3 -3
  73. package/src/app/configs/__tests__/app-navigation.config.test.ts +10 -0
  74. package/src/app/configs/app-navigation.config.ts +6 -2
  75. package/src/app/styles/charcoal-theme.css +0 -3
  76. package/src/app/styles/design-system.css +18 -6
  77. package/src/app/styles/island-theme.css +2 -15
  78. package/src/features/agents/components/agent-details-dialog.tsx +1 -1
  79. package/src/features/agents/components/agents-page.tsx +5 -3
  80. package/src/features/app-data/components/app-data-removal-choice.tsx +1 -1
  81. package/src/features/apps/components/app-package-card.tsx +7 -6
  82. package/src/features/channels/pages/channels-list-page.tsx +1 -1
  83. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +1 -1
  84. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +28 -16
  85. package/src/features/chat/components/conversation/chat-conversation-content.tsx +8 -2
  86. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -3
  87. package/src/features/chat/components/conversation/chat-conversation-header.tsx +4 -4
  88. package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +6 -4
  89. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +22 -1
  90. package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
  91. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +10 -14
  92. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +50 -12
  93. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +4 -4
  94. package/src/features/chat/components/layout/chat-sidebar.tsx +2 -2
  95. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
  96. package/src/features/chat/features/message/components/chat-message-list.container.tsx +12 -1
  97. package/src/features/chat/features/message/components/chat-tool-call-stress-harness.tsx +32 -2
  98. package/src/features/chat/features/message/hooks/__tests__/use-chat-message-virtualizer.test.tsx +7 -5
  99. package/src/features/chat/features/message/hooks/use-chat-message-virtualizer.ts +7 -3
  100. package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +1 -1
  101. package/src/features/chat/features/session/components/chat-mobile-session-row.tsx +2 -2
  102. package/src/features/chat/features/session/components/chat-sidebar-context-card.tsx +1 -1
  103. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +1 -1
  104. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +7 -5
  105. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +45 -10
  106. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +1 -1
  107. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +3 -5
  108. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +4 -3
  109. package/src/features/chat/features/session/components/session-header/chat-session-more-actions-menu.tsx +3 -0
  110. package/src/features/chat/features/session/components/session-header/chat-session-switcher-groups.tsx +6 -6
  111. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +6 -5
  112. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +1 -1
  113. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +0 -1
  114. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
  115. package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +1 -1
  116. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
  117. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
  118. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +2 -2
  119. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +1 -1
  120. package/src/features/chat/features/workspace/components/child-sessions/chat-session-child-sessions.tsx +2 -2
  121. package/src/features/chat/features/workspace/components/file-content-preview/workspace-spreadsheet-preview.tsx +2 -2
  122. package/src/features/chat/features/workspace/components/overview/chat-session-continuous-attention.tsx +3 -3
  123. package/src/features/chat/features/workspace/components/overview/chat-session-token-usage.tsx +1 -1
  124. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +4 -3
  125. package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +2 -1
  126. package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +3 -1
  127. package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +3 -3
  128. package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +2 -2
  129. package/src/features/chat/features/workspace/components/workspace-markdown-outline.tsx +1 -1
  130. package/src/features/cron/components/cron-config.tsx +3 -2
  131. package/src/features/cron/components/cron-job-detail-dialog.tsx +1 -1
  132. package/src/features/cron/components/cron-job-row.tsx +7 -7
  133. package/src/features/cron/components/cron-task-discovery.tsx +1 -1
  134. package/src/features/inbox/components/inbox-delivery-content.tsx +1 -1
  135. package/src/features/inbox/pages/inbox-page.tsx +25 -29
  136. package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.tsx +2 -2
  137. package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +2 -2
  138. package/src/features/marketplace/components/marketplace-list-card.tsx +4 -4
  139. package/src/features/marketplace/components/marketplace-page-parts.tsx +4 -3
  140. package/src/features/marketplace/components/marketplace-page.tsx +4 -4
  141. package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +2 -2
  142. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +3 -3
  143. package/src/features/panel-apps/components/panel-app-list-item.tsx +3 -3
  144. package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +3 -1
  145. package/src/features/projects/components/project-overview.tsx +1 -1
  146. package/src/features/projects/pages/project-home-page.tsx +11 -2
  147. package/src/features/projects/pages/projects-page.test.tsx +4 -2
  148. package/src/features/pwa/components/pwa-install-entry.tsx +1 -1
  149. package/src/features/right-panel-resources/components/__tests__/page-resource-sidebar-nav.test.tsx +9 -1
  150. package/src/features/right-panel-resources/components/page-resource-sidebar-nav.tsx +1 -1
  151. package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
  152. package/src/features/service-apps/components/service-action-row.tsx +3 -3
  153. package/src/features/service-apps/components/service-app-list-item.tsx +4 -4
  154. package/src/features/service-apps/components/service-apps-panel.tsx +1 -1
  155. package/src/features/settings/components/config/provider-model-list.tsx +5 -5
  156. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +4 -4
  157. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  158. package/src/features/settings/pages/appearance-settings-page.tsx +2 -2
  159. package/src/features/settings/pages/providers-config-page.tsx +6 -6
  160. package/src/features/side-dock/components/side-dock.tsx +4 -4
  161. package/src/index.css +4 -0
  162. package/src/platforms/desktop/components/desktop-window-chrome.tsx +1 -1
  163. package/src/platforms/mobile/components/mobile-app-shell.tsx +1 -1
  164. package/src/platforms/mobile/components/mobile-bottom-nav.tsx +10 -9
  165. package/src/platforms/mobile/components/mobile-settings-shell.tsx +24 -23
  166. package/src/platforms/mobile/components/mobile-topbar.tsx +10 -11
  167. package/src/shared/components/common/brand-header.tsx +1 -1
  168. package/src/shared/components/common/searchable-model-input.tsx +2 -2
  169. package/src/shared/components/config-split-page.tsx +3 -3
  170. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +34 -2
  171. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +38 -7
  172. package/src/shared/components/doc-browser/doc-browser.tsx +5 -1
  173. package/src/shared/components/path-picker/server-path-picker-locations.tsx +1 -1
  174. package/src/shared/components/settings/settings-page.tsx +1 -1
  175. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +5 -5
  176. package/src/shared/components/ui/actions/action-feedback.ts +8 -0
  177. package/src/shared/components/ui/actions/icon-action-button.tsx +13 -12
  178. package/src/shared/components/ui/button.tsx +3 -3
  179. package/src/shared/components/ui/card.tsx +1 -1
  180. package/src/shared/components/ui/context-menu/context-menu-items.tsx +6 -5
  181. package/src/shared/components/ui/dialog.tsx +4 -3
  182. package/src/shared/components/ui/input.tsx +7 -2
  183. package/src/shared/components/ui/overlays/sheet.tsx +1 -1
  184. package/src/shared/components/ui/popover.tsx +1 -1
  185. package/src/shared/components/ui/select.tsx +3 -2
  186. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -6
  187. package/src/shared/components/ui/tabs.tsx +3 -3
  188. package/src/shared/components/ui/textarea.tsx +1 -0
  189. package/src/shared/components/workbench/workbench-surface-toolbar.tsx +3 -4
  190. package/src/shared/components/workbench/workbench-surface.tsx +2 -2
  191. package/src/shared/lib/i18n/locales/en-US/agents.json +2 -0
  192. package/src/shared/lib/i18n/locales/en-US/core.json +1 -0
  193. package/src/shared/lib/i18n/locales/en-US/desktop-update.json +1 -1
  194. package/src/shared/lib/i18n/locales/zh-CN/agents.json +2 -0
  195. package/src/shared/lib/i18n/locales/zh-CN/core.json +1 -0
  196. package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +1 -1
  197. package/dist/assets/app-presenter-provider-C02YPoMr.js +0 -124
  198. package/dist/assets/card-BLXvBstA.js +0 -1
  199. package/dist/assets/config-split-page-G7Kt2BnV.js +0 -1
  200. package/dist/assets/context-menu-rd7b_kVD.js +0 -1
  201. package/dist/assets/doc-browser-dBiR9Qi0.js +0 -1
  202. package/dist/assets/loader-circle-BA7EMkih.js +0 -1
  203. package/dist/assets/login-page-VdMyNkFf.js +0 -1
  204. package/dist/assets/main-CR0SrTBf.js +0 -2
  205. package/dist/assets/main-DXH6EdXI.css +0 -1
  206. package/dist/assets/main-i18n-catalog.config-Btp_OowF.js +0 -1
  207. package/dist/assets/mcp-marketplace-page-jacRwiI-.js +0 -1
  208. package/dist/assets/panel-app-CC0bVSu4.js +0 -1
  209. package/dist/assets/panel-app-i18n-catalog.config-LUSBp5Ce.js +0 -1
  210. package/dist/assets/panelStandalone-Y91OJkgV.css +0 -1
  211. package/dist/assets/projects-D56yAPNT.js +0 -1
  212. package/dist/assets/provider-models-C3frdXeW.js +0 -1
  213. package/dist/assets/provider-scoped-model-input-CYetrPYZ.js +0 -1
  214. package/dist/assets/providers-config-page-DESB1h8g.js +0 -1
  215. package/dist/assets/remote-DiGFV8nP.js +0 -1
  216. package/dist/assets/security-config-C5-RQVpS.js +0 -1
  217. package/dist/assets/service-apps-panel-CKE5HKNY.js +0 -1
  218. package/dist/assets/x--xxUvHKW.js +0 -1
package/dist/index.html CHANGED
@@ -258,47 +258,47 @@
258
258
  })();
259
259
  </script>
260
260
  <title>NextClaw</title>
261
- <script type="module" crossorigin src="/assets/main-CR0SrTBf.js"></script>
261
+ <script type="module" crossorigin src="/assets/main-bEWCGDHr.js"></script>
262
262
  <link rel="modulepreload" crossorigin href="/assets/chunk-DF37yw5_.js">
263
263
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-ca-nBW7U.js">
264
- <link rel="modulepreload" crossorigin href="/assets/i18n-qBGEbcW6.js">
265
- <link rel="modulepreload" crossorigin href="/assets/api-Cjq-o1VN.js">
266
- <link rel="modulepreload" crossorigin href="/assets/client-DudCRJw4.js">
267
- <link rel="modulepreload" crossorigin href="/assets/es2015-CsjAAQ6X.js">
268
- <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-D7hvIHV-.js">
269
- <link rel="modulepreload" crossorigin href="/assets/select-CctTN205.js">
270
- <link rel="modulepreload" crossorigin href="/assets/context-menu-rd7b_kVD.js">
271
- <link rel="modulepreload" crossorigin href="/assets/x--xxUvHKW.js">
272
- <link rel="modulepreload" crossorigin href="/assets/dialog-C7glmAQJ.js">
264
+ <link rel="modulepreload" crossorigin href="/assets/i18n-OGmF0Ws_.js">
265
+ <link rel="modulepreload" crossorigin href="/assets/api-BZvNpFOS.js">
266
+ <link rel="modulepreload" crossorigin href="/assets/client-DKKbdJ6Q.js">
267
+ <link rel="modulepreload" crossorigin href="/assets/es2015-BiB05Sav.js">
268
+ <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-DE0sB9Nu.js">
269
+ <link rel="modulepreload" crossorigin href="/assets/select-Y9IEbx9x.js">
270
+ <link rel="modulepreload" crossorigin href="/assets/context-menu-DHVVdHzN.js">
271
+ <link rel="modulepreload" crossorigin href="/assets/x-DSz9cGhy.js">
272
+ <link rel="modulepreload" crossorigin href="/assets/dialog-BUfWO8hr.js">
273
273
  <link rel="modulepreload" crossorigin href="/assets/katex-CsAM73R9.js">
274
- <link rel="modulepreload" crossorigin href="/assets/puzzle-CWHfFyYN.js">
274
+ <link rel="modulepreload" crossorigin href="/assets/puzzle-D_TiFXOv.js">
275
275
  <link rel="modulepreload" crossorigin href="/assets/middleware-B--6mAUM.js">
276
- <link rel="modulepreload" crossorigin href="/assets/use-viewport-layout-CPZUmTPi.js">
277
- <link rel="modulepreload" crossorigin href="/assets/book-open-AteA89HX.js">
276
+ <link rel="modulepreload" crossorigin href="/assets/use-viewport-layout-vmbQUNT6.js">
277
+ <link rel="modulepreload" crossorigin href="/assets/book-open-CmRdT3N1.js">
278
278
  <link rel="modulepreload" crossorigin href="/assets/navigation-history-CzErJuPG.js">
279
- <link rel="modulepreload" crossorigin href="/assets/theme-provider-hlle7Skk.js">
280
- <link rel="modulepreload" crossorigin href="/assets/confirm-dialog-DShT64F6.js">
281
- <link rel="modulepreload" crossorigin href="/assets/download-BYgECE0n.js">
279
+ <link rel="modulepreload" crossorigin href="/assets/theme-provider-BjF1Eowc.js">
280
+ <link rel="modulepreload" crossorigin href="/assets/confirm-dialog-8vqYZ0wy.js">
281
+ <link rel="modulepreload" crossorigin href="/assets/download-CKqS1Ksj.js">
282
282
  <link rel="modulepreload" crossorigin href="/assets/host-capabilities-DuIFVsvM.js">
283
- <link rel="modulepreload" crossorigin href="/assets/navigation-link-32iM1-e6.js">
284
- <link rel="modulepreload" crossorigin href="/assets/eye-BBuTzJ53.js">
285
- <link rel="modulepreload" crossorigin href="/assets/tag-chip-Bjzb4-qW.js">
286
- <link rel="modulepreload" crossorigin href="/assets/loader-circle-BA7EMkih.js">
287
- <link rel="modulepreload" crossorigin href="/assets/trash-2-C5KH5Rw9.js">
288
- <link rel="modulepreload" crossorigin href="/assets/refresh-cw-y3L6PyLt.js">
289
- <link rel="modulepreload" crossorigin href="/assets/use-desktop-capabilities-CEg9-DrQ.js">
290
- <link rel="modulepreload" crossorigin href="/assets/status-dot-CensgJZC.js">
291
- <link rel="modulepreload" crossorigin href="/assets/doc-browser-context-BlhBAOLH.js">
292
- <link rel="modulepreload" crossorigin href="/assets/card-BLXvBstA.js">
293
- <link rel="modulepreload" crossorigin href="/assets/provider-models-C3frdXeW.js">
294
- <link rel="modulepreload" crossorigin href="/assets/use-config-CPl_F79t.js">
295
- <link rel="modulepreload" crossorigin href="/assets/app-presenter-provider-C02YPoMr.js">
296
- <link rel="modulepreload" crossorigin href="/assets/provider-scoped-model-input-CYetrPYZ.js">
297
- <link rel="modulepreload" crossorigin href="/assets/settings-2-EPflrNk6.js">
298
- <link rel="modulepreload" crossorigin href="/assets/pwa-CiGUjpcd.js">
299
- <link rel="modulepreload" crossorigin href="/assets/login-page-Cd84lpVV.js">
283
+ <link rel="modulepreload" crossorigin href="/assets/navigation-link-DC-Pku0Y.js">
284
+ <link rel="modulepreload" crossorigin href="/assets/eye-bKzylu3p.js">
285
+ <link rel="modulepreload" crossorigin href="/assets/tag-chip-D-6aPuuh.js">
286
+ <link rel="modulepreload" crossorigin href="/assets/loader-circle-Clq1Gtb1.js">
287
+ <link rel="modulepreload" crossorigin href="/assets/trash-2-DER2EJKK.js">
288
+ <link rel="modulepreload" crossorigin href="/assets/refresh-cw-BG8VfcdA.js">
289
+ <link rel="modulepreload" crossorigin href="/assets/use-desktop-capabilities-ezKJwKqg.js">
290
+ <link rel="modulepreload" crossorigin href="/assets/status-dot-Cb8ewlUr.js">
291
+ <link rel="modulepreload" crossorigin href="/assets/doc-browser-context-ClLgMbxd.js">
292
+ <link rel="modulepreload" crossorigin href="/assets/card-CdRBL1E0.js">
293
+ <link rel="modulepreload" crossorigin href="/assets/provider-models-DFQgF4hS.js">
294
+ <link rel="modulepreload" crossorigin href="/assets/use-config-BM5jC65L.js">
295
+ <link rel="modulepreload" crossorigin href="/assets/app-presenter-provider-BcYL-VNe.js">
296
+ <link rel="modulepreload" crossorigin href="/assets/provider-scoped-model-input-DaONL0j_.js">
297
+ <link rel="modulepreload" crossorigin href="/assets/settings-2-CrGx9_De.js">
298
+ <link rel="modulepreload" crossorigin href="/assets/pwa-C9ac_1dg.js">
299
+ <link rel="modulepreload" crossorigin href="/assets/login-page-BT3GV3Sb.js">
300
300
  <link rel="stylesheet" crossorigin href="/assets/app-presenter-provider-jNGlmBLe.css">
301
- <link rel="stylesheet" crossorigin href="/assets/main-DXH6EdXI.css">
301
+ <link rel="stylesheet" crossorigin href="/assets/main-kqMRTwOs.css">
302
302
  </head>
303
303
 
304
304
  <body>
@@ -5,20 +5,20 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="theme-color" content="#ffffff" />
7
7
  <title>Panel App · NextClaw</title>
8
- <script type="module" crossorigin src="/assets/panelStandalone-C9EKaApN.js"></script>
8
+ <script type="module" crossorigin src="/assets/panelStandalone-CX8X2hjh.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-DF37yw5_.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-ca-nBW7U.js">
11
- <link rel="modulepreload" crossorigin href="/assets/i18n-qBGEbcW6.js">
12
- <link rel="modulepreload" crossorigin href="/assets/api-Cjq-o1VN.js">
13
- <link rel="modulepreload" crossorigin href="/assets/client-DudCRJw4.js">
14
- <link rel="modulepreload" crossorigin href="/assets/es2015-CsjAAQ6X.js">
15
- <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-D7hvIHV-.js">
16
- <link rel="modulepreload" crossorigin href="/assets/context-menu-rd7b_kVD.js">
17
- <link rel="modulepreload" crossorigin href="/assets/x--xxUvHKW.js">
18
- <link rel="modulepreload" crossorigin href="/assets/dialog-C7glmAQJ.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/i18n-OGmF0Ws_.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/api-BZvNpFOS.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/client-DKKbdJ6Q.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/es2015-BiB05Sav.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-DE0sB9Nu.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/context-menu-DHVVdHzN.js">
17
+ <link rel="modulepreload" crossorigin href="/assets/x-DSz9cGhy.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/dialog-BUfWO8hr.js">
19
19
  <link rel="modulepreload" crossorigin href="/assets/navigation-history-CzErJuPG.js">
20
- <link rel="modulepreload" crossorigin href="/assets/theme-provider-hlle7Skk.js">
21
- <link rel="stylesheet" crossorigin href="/assets/panelStandalone-Y91OJkgV.css">
20
+ <link rel="modulepreload" crossorigin href="/assets/theme-provider-BjF1Eowc.js">
21
+ <link rel="stylesheet" crossorigin href="/assets/panelStandalone-BRg7B1EI.css">
22
22
  </head>
23
23
  <body>
24
24
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/ui",
3
- "version": "0.26.2",
3
+ "version": "0.26.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -35,9 +35,9 @@
35
35
  "zod": "^3.23.8",
36
36
  "zustand": "^5.0.2",
37
37
  "@nextclaw/agent-chat": "0.3.14",
38
- "@nextclaw/client-sdk": "0.12.8",
39
- "@nextclaw/agent-chat-ui": "0.10.1",
38
+ "@nextclaw/client-sdk": "0.12.9",
40
39
  "@nextclaw/ncp": "0.11.2",
40
+ "@nextclaw/agent-chat-ui": "0.11.0",
41
41
  "@nextclaw/ncp-react": "0.5.30",
42
42
  "@nextclaw/ncp-http-agent-client": "0.4.25",
43
43
  "@nextclaw/ncp-toolkit": "0.6.27",
@@ -107,7 +107,7 @@ describe("Sidebar", () => {
107
107
  expect(backLink).toBeTruthy();
108
108
  expect(header.className).not.toContain("bg-white");
109
109
  expect(header.className).not.toContain("rounded-2xl");
110
- expect(backLink.className).toContain("hover:bg-[hsl(var(--gray-200)/0.6)]");
110
+ expect(backLink.className).toContain("hover:bg-[var(--sidebar-interaction-hover)]");
111
111
  });
112
112
 
113
113
  it("keeps the settings navigation in the expected product order", () => {
@@ -207,7 +207,7 @@ describe("Sidebar", () => {
207
207
  expect(screen.queryByRole("combobox", { name: "Language" })).toBeNull();
208
208
  expect(accountEntry.className).toContain("py-2");
209
209
  expect(accountEntry.className).toContain("text-muted-foreground");
210
- expect(accountEntry.className).toContain("hover:bg-[hsl(var(--gray-200)/0.6)]");
210
+ expect(accountEntry.className).toContain("hover:bg-[var(--sidebar-interaction-hover)]");
211
211
  expect(navigationList?.className).toContain("space-y-0.5");
212
212
  expect(footer?.className).toContain("space-y-0.5");
213
213
  expect(footer?.firstElementChild?.textContent).toContain("Help Docs");
@@ -37,6 +37,8 @@ interface PageHeaderProps {
37
37
  description?: string;
38
38
  actions?: React.ReactNode;
39
39
  headingLevel?: 1 | 2;
40
+ /** The mobile shell already provides the page title. */
41
+ mobileTitleInShell?: boolean;
40
42
  className?: string;
41
43
  }
42
44
 
@@ -45,6 +47,7 @@ export function PageHeader({
45
47
  description,
46
48
  actions,
47
49
  headingLevel = 2,
50
+ mobileTitleInShell = false,
48
51
  className
49
52
  }: PageHeaderProps) {
50
53
  const Heading = headingLevel === 1 ? 'h1' : 'h2';
@@ -54,8 +57,8 @@ export function PageHeader({
54
57
  data-theme-surface="header"
55
58
  className={cn('flex shrink-0 flex-col gap-3 sm:flex-row sm:items-start sm:justify-between', className)}
56
59
  >
57
- <div className="min-w-0">
58
- <Heading className="text-xl font-semibold tracking-tight text-foreground">{title}</Heading>
60
+ <div className={cn("min-w-0", mobileTitleInShell && !description && "hidden md:block")}>
61
+ <Heading className={cn("text-xl font-semibold tracking-tight text-foreground", mobileTitleInShell && "hidden md:block")}>{title}</Heading>
59
62
  {description && (
60
63
  <p className="mt-1 max-w-2xl text-sm leading-6 text-muted-foreground">{description}</p>
61
64
  )}
@@ -10,13 +10,13 @@ export const SIDEBAR_RAIL_ITEM_GAP_CLASS = "gap-1";
10
10
  // Use theme neutral tokens directly so legacy gray utility overrides cannot
11
11
  // turn sidebar feedback into a content selection or accent surface.
12
12
  export const SIDEBAR_ITEM_SURFACE_CLASS =
13
- "rounded-xl text-muted-foreground transition-colors duration-base hover:bg-[hsl(var(--gray-200)/0.6)] hover:text-foreground focus-within:bg-[hsl(var(--gray-200)/0.6)] has-[[data-context-menu-open]]:bg-[hsl(var(--gray-200)/0.6)]";
13
+ "rounded-xl text-muted-foreground transition-colors duration-base hover:bg-[var(--sidebar-interaction-hover)] hover:text-foreground focus-within:bg-[var(--sidebar-interaction-hover)] has-[[data-context-menu-open]]:bg-[var(--sidebar-interaction-hover)]";
14
14
 
15
15
  export const SIDEBAR_ITEM_ACTIVE_SURFACE_CLASS =
16
- "bg-[hsl(var(--gray-200)/0.8)] text-foreground hover:bg-[hsl(var(--gray-200)/0.8)] focus-within:bg-[hsl(var(--gray-200)/0.8)] has-[[data-context-menu-open]]:bg-[hsl(var(--gray-200)/0.8)]";
16
+ "bg-[var(--sidebar-interaction-selection)] text-foreground hover:bg-[var(--sidebar-interaction-selection)] focus-within:bg-[var(--sidebar-interaction-selection)] has-[[data-context-menu-open]]:bg-[var(--sidebar-interaction-selection)]";
17
17
 
18
18
  export const SIDEBAR_RAIL_SURFACE_CLASS =
19
- `${SIDEBAR_ITEM_SURFACE_CLASS} active:bg-[hsl(var(--gray-200)/0.8)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border`;
19
+ `${SIDEBAR_ITEM_SURFACE_CLASS} active:bg-[var(--sidebar-interaction-selection)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border`;
20
20
 
21
21
  export const SIDEBAR_RAIL_ACTIVE_SURFACE_CLASS = SIDEBAR_ITEM_ACTIVE_SURFACE_CLASS;
22
22
 
@@ -29,6 +29,16 @@ describe("panel app main navigation", () => {
29
29
  describe("project home navigation", () => {
30
30
  const translate = (key: string) => key;
31
31
 
32
+ it("returns project details to the project picker", () => {
33
+ expect(resolveMobileRouteMeta("/projects/example/overview", translate).backTarget).toBe("/projects");
34
+ });
35
+
36
+ it("labels scheduled tasks and returns to chat", () => {
37
+ expect(resolveMobileRouteMeta("/cron", translate)).toEqual({
38
+ title: "cron", backTarget: "/chat", backLabel: "chat",
39
+ });
40
+ });
41
+
32
42
  it("keeps projects in the main workspace without a parallel global nav item", () => {
33
43
  expect(isMainWorkspaceRoute("/projects")).toBe(true);
34
44
  expect(getMainSidebarNavItems(translate).map((item) => item.target)).not.toContain("/projects");
@@ -259,8 +259,8 @@ export function resolveMobileRouteMeta(
259
259
  if (normalized === "/projects" || normalized.startsWith("/projects/")) {
260
260
  return {
261
261
  title: translate("projectsTitle"),
262
- backTarget: "/chat",
263
- backLabel: translate("chat"),
262
+ backTarget: normalized === "/projects" ? "/chat" : "/projects",
263
+ backLabel: translate(normalized === "/projects" ? "chat" : "projectsTitle"),
264
264
  };
265
265
  }
266
266
 
@@ -280,6 +280,10 @@ export function resolveMobileRouteMeta(
280
280
  };
281
281
  }
282
282
 
283
+ if (normalized === "/cron" || normalized.startsWith("/cron/")) {
284
+ return { title: translate("cron"), backTarget: "/chat", backLabel: translate("chat") };
285
+ }
286
+
283
287
  for (const item of settingsItems) {
284
288
  if (matchesRouteTarget(normalized, item.target)) {
285
289
  return {
@@ -42,9 +42,6 @@
42
42
  --secondary-foreground: var(--gray-800);
43
43
  --accent: 0 0% 19%;
44
44
  --accent-foreground: var(--gray-900);
45
- --interaction-hover: hsl(var(--gray-200));
46
- --interaction-selection: hsl(202 38% 27%);
47
- --interaction-selection-border: hsl(202 48% 40%);
48
45
  --muted: var(--gray-100);
49
46
  --muted-foreground: var(--gray-500);
50
47
  --destructive: 0 72% 60%;
@@ -12,8 +12,15 @@
12
12
  }
13
13
 
14
14
  :root {
15
+ --shadow-popover: 0 12px 36px -8px rgb(0 0 0 / 0.18), 0 3px 10px -2px rgb(0 0 0 / 0.08);
15
16
  color-scheme: light;
16
17
 
18
+ /* Mobile density: hit target, visual feedback, and chrome are separate. */
19
+ --control-touch-size: 2.75rem;
20
+ --icon-control-size: 2.5rem;
21
+ --icon-feedback-size: 2rem;
22
+ --mobile-header-height: 3rem;
23
+
17
24
  /* ========================================
18
25
  BRAND COLORS (Natural Olive)
19
26
  ======================================== */
@@ -80,9 +87,16 @@
80
87
  /* Accent */
81
88
  --accent: var(--brand-50);
82
89
  --accent-foreground: var(--brand-700);
83
- --interaction-hover: hsl(0 0% 96%);
84
- --interaction-selection: hsl(211 100% 92%);
85
- --interaction-selection-border: hsl(211 75% 84%);
90
+ --interaction-hover: hsl(var(--foreground) / 0.04);
91
+ --interaction-selection: hsl(var(--foreground) / 0.07);
92
+ --interaction-selection-border: hsl(var(--foreground) / 0.12);
93
+ /* Desktop sidebar feedback matches the verified VPS v0.54.2 baseline. */
94
+ --sidebar-interaction-hover: hsl(var(--gray-200) / 0.6);
95
+ --sidebar-interaction-selection: hsl(var(--gray-200) / 0.8);
96
+ --sidebar-segment-selection: hsl(var(--gray-200) / 0.7);
97
+ /* Mobile conversation rows retain their separate paper surface. */
98
+ --session-interaction-hover: hsl(var(--background) / 0.65);
99
+ --session-interaction-selection: hsl(var(--background) / 0.9);
86
100
 
87
101
  /* Muted */
88
102
  --muted: var(--gray-100);
@@ -717,9 +731,6 @@
717
731
  --secondary-foreground: var(--gray-800);
718
732
  --accent: 151 32% 18%;
719
733
  --accent-foreground: 148 34% 84%;
720
- --interaction-hover: hsl(var(--gray-200));
721
- --interaction-selection: hsl(211 48% 30%);
722
- --interaction-selection-border: hsl(211 48% 42%);
723
734
  --muted: var(--gray-100);
724
735
  --muted-foreground: var(--gray-500);
725
736
  --destructive: 0 70% 52%;
@@ -828,6 +839,7 @@
828
839
 
829
840
  @layer base {
830
841
  :root[data-theme-appearance="dark"] {
842
+ --shadow-popover: 0 8px 32px -8px rgb(0 0 0 / 0.4), 0 2px 8px -2px rgb(0 0 0 / 0.24);
831
843
  --link-foreground: 213 94% 68%;
832
844
  --link-foreground-hover: 213 97% 79%;
833
845
  }
@@ -44,9 +44,6 @@
44
44
  --secondary-foreground: var(--gray-800);
45
45
  --accent: 151 28% 88%;
46
46
  --accent-foreground: var(--brand-800);
47
- --interaction-hover: hsl(151 25% 86% / 0.72);
48
- --interaction-selection: hsl(153 35% 80% / 0.82);
49
- --interaction-selection-border: hsl(157 37% 58% / 0.88);
50
47
  --muted: var(--gray-100);
51
48
  --muted-foreground: var(--gray-500);
52
49
  --destructive: 5 61% 47%;
@@ -323,8 +320,8 @@
323
320
  -webkit-backdrop-filter: blur(18px) saturate(0.9);
324
321
  backdrop-filter: blur(18px) saturate(0.9);
325
322
  background-color: hsl(var(--popover) / 0.9);
326
- border-color: hsl(var(--border) / 0.7);
327
- box-shadow: 0 18px 42px -24px hsl(158 27% 20% / 0.46);
323
+ border-color: hsl(var(--border) / 0.4);
324
+ box-shadow: var(--shadow-popover);
328
325
  }
329
326
 
330
327
  :root[data-theme="island"] [data-theme-overlay="tooltip"] {
@@ -446,16 +443,6 @@
446
443
  border-radius: 0;
447
444
  }
448
445
 
449
- :root[data-theme="island"]
450
- [data-theme-surface="navigation"]
451
- :is([aria-current="page"], [aria-selected="true"], [data-state="active"]),
452
- :root[data-theme="island"]
453
- [data-theme-surface="utility-rail"]
454
- :is([aria-pressed="true"], [data-state="active"]) {
455
- background-color: hsl(151 27% 84% / 0.68);
456
- color: hsl(var(--brand-800));
457
- }
458
-
459
446
  :root[data-theme="island"]
460
447
  :is(
461
448
  .custom-scrollbar,
@@ -350,7 +350,7 @@ function DetailItem(props: {
350
350
  return (
351
351
  <div
352
352
  className={cn(
353
- "grid min-w-0 grid-cols-[10rem_minmax(0,1fr)] items-baseline gap-x-2",
353
+ "grid min-w-0 grid-cols-1 sm:grid-cols-[10rem_minmax(0,1fr)] items-baseline gap-x-2 gap-y-1",
354
354
  (wide || isStructuredValue) && "sm:col-span-2",
355
355
  )}
356
356
  >
@@ -1,4 +1,5 @@
1
1
  import { PageResourceActionItems } from '@/features/right-panel-resources';
2
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
2
3
  import { pageResourceFromSystemObject } from '@/features/right-panel-resources';
3
4
  import { useMemo, useState } from "react";
4
5
  import {
@@ -97,10 +98,10 @@ function AgentActionMenuItem(props: {
97
98
  <button
98
99
  type="button"
99
100
  className={cn(
100
- "flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50",
101
+ ACTION_MENU_ITEM_CLASS,
101
102
  destructive
102
- ? "text-destructive hover:bg-destructive/10"
103
- : "text-foreground hover:bg-muted",
103
+ ? ACTION_FEEDBACK.destructive
104
+ : `text-foreground ${ACTION_FEEDBACK.item}`,
104
105
  )}
105
106
  onClick={onClick}
106
107
  disabled={disabled}
@@ -342,6 +343,7 @@ export function AgentsPage() {
342
343
  return (
343
344
  <PageLayout className="space-y-6">
344
345
  <PageHeader
346
+ mobileTitleInShell
345
347
  headingLevel={1}
346
348
  title={t("agentsHeroEyebrow")}
347
349
  description={t("agentsHeroDescription")}
@@ -25,7 +25,7 @@ export function AppDataRemovalChoice({
25
25
  onClick={onClick}
26
26
  className={cn(
27
27
  'flex items-start gap-3 rounded-xl border px-3 py-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:cursor-not-allowed disabled:opacity-50',
28
- checked ? 'border-foreground/25 bg-muted/55' : 'border-border/60 hover:bg-muted/35',
28
+ checked ? 'border-[var(--interaction-selection-border)] bg-[var(--interaction-selection)]' : 'border-border/60 hover:bg-[var(--interaction-hover)]',
29
29
  )}
30
30
  >
31
31
  <span className={cn(
@@ -1,4 +1,5 @@
1
1
  import { useRef, useState } from "react";
2
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
2
3
  import type { AppDataEntry, AppPackageOperationView, AppPackageView } from "@nextclaw/client-sdk";
3
4
  import {
4
5
  AlertCircle,
@@ -80,11 +81,11 @@ export function AppPackageCard({
80
81
 
81
82
  return (
82
83
  <Card surface="flat" hover={false} className="overflow-hidden border-border/60 shadow-[0_1px_2px_rgba(0,0,0,0.025)]">
83
- <div className="flex items-start gap-3.5 px-4 pb-3.5 pt-4">
84
+ <div className="flex max-md:grid max-md:grid-cols-[auto_minmax(0,1fr)] items-start gap-3.5 px-4 pb-3.5 pt-4">
84
85
  <AppArtwork icon={appPackage.icon} name={displayName} />
85
86
  <div className="min-w-0 flex-1">
86
87
  <div className="flex min-w-0 items-center gap-2">
87
- <h2 className="truncate text-sm font-semibold text-foreground">{displayName}</h2>
88
+ <h2 className="truncate max-md:whitespace-normal max-md:break-words text-sm font-semibold text-foreground">{displayName}</h2>
88
89
  <span className={cn("shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium", availability.className)}>{availability.label}</span>
89
90
  </div>
90
91
  {availability.message ? (
@@ -125,7 +126,7 @@ export function AppPackageCard({
125
126
  <code className="min-w-0 truncate font-mono text-[10px]">{appPackage.storage.dataDirectory}</code>
126
127
  </div>
127
128
  </div>
128
- <div className="flex shrink-0 items-center gap-1">
129
+ <div className="flex shrink-0 items-center gap-1 max-md:col-start-2 max-md:justify-end">
129
130
  <Button
130
131
  type="button"
131
132
  size="sm"
@@ -148,7 +149,7 @@ export function AppPackageCard({
148
149
  aria-label={t("appPackagesMoreActions")}
149
150
  title={t("appPackagesMoreActions")}
150
151
  disabled={pending}
151
- className="rounded-full p-2 text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:opacity-50"
152
+ className="max-md:min-h-11 max-md:min-w-11 inline-flex items-center justify-center rounded-full p-2 text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:opacity-50"
152
153
  >
153
154
  <MoreVertical className="h-4 w-4" />
154
155
  </button>
@@ -314,8 +315,8 @@ function AppPackageMenuItem({ destructive = false, icon: Icon, label, onClick }:
314
315
  type="button"
315
316
  onClick={onClick}
316
317
  className={cn(
317
- "flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-left text-sm transition-colors",
318
- destructive ? "text-destructive hover:bg-destructive/10" : "text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-accent-foreground",
318
+ ACTION_MENU_ITEM_CLASS,
319
+ destructive ? ACTION_FEEDBACK.destructive : `text-foreground ${ACTION_FEEDBACK.item}`,
319
320
  )}
320
321
  >
321
322
  <Icon className="h-4 w-4 shrink-0" />
@@ -138,7 +138,7 @@ export function ChannelsList() {
138
138
  <a
139
139
  href={tutorialUrl}
140
140
  onClick={(event) => event.stopPropagation()}
141
- className='inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground/45 transition-colors hover:bg-muted hover:text-foreground'
141
+ className='inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground/45 transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground'
142
142
  title={t('channelsGuideTitle')}
143
143
  >
144
144
  <ExternalLink className='h-3.5 w-3.5' />
@@ -14,7 +14,7 @@ export function ChatSidebarListModeSwitch({ isProjectFirstView, onSelectMode }:
14
14
  <span
15
15
  aria-hidden="true"
16
16
  className={cn(
17
- 'pointer-events-none absolute bottom-0.5 left-0.5 top-0.5 w-[calc(50%-2px)] rounded-full bg-gray-200/70 transition-transform duration-200 ease-out motion-reduce:transition-none',
17
+ 'pointer-events-none absolute bottom-0.5 left-0.5 top-0.5 w-[calc(50%-2px)] rounded-full bg-[var(--sidebar-segment-selection)] transition-transform duration-200 ease-out motion-reduce:transition-none',
18
18
  isProjectFirstView && 'translate-x-full',
19
19
  )}
20
20
  />
@@ -8,6 +8,7 @@ import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
8
8
  import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
9
9
  import { useChatThreadStore } from "@/features/chat/stores/chat-thread.store";
10
10
  import { viewportLayoutManager } from "@/app/managers/viewport-layout.manager";
11
+ import { ChatSessionSwitcherGroups } from "@/features/chat/features/session/components/session-header/chat-session-switcher-groups";
11
12
  import type { NcpSessionListItemView } from "@/features/chat/features/ncp/hooks/use-ncp-session-list-view";
12
13
  import type { NcpSessionSummaryView, SessionEntryView } from "@/shared/lib/api";
13
14
 
@@ -312,42 +313,51 @@ describe("ChatConversationHeaderSection", () => {
312
313
  ).toBeTruthy();
313
314
  });
314
315
 
315
- it("switches to collapsible project groups inside the header popover", async () => {
316
+ it("renders compact collapsible project groups inside the header popover", async () => {
316
317
  const user = userEvent.setup();
317
- viewportLayoutManager.setSidebarCollapsed(true);
318
- mocks.sessionItems = [
319
- createSessionListItem({
318
+ const alphaItem = createSessionListItem({
320
319
  key: "parent-session-1",
321
320
  label: "Parent Task",
322
321
  projectName: "Alpha",
323
322
  projectRoot: "/workspace/alpha",
324
- }),
325
- createSessionListItem({
323
+ });
324
+ const betaItem = createSessionListItem({
326
325
  key: "session:ncp-2",
327
326
  label: "Background Task",
328
327
  projectName: "Beta",
329
328
  projectRoot: "/workspace/beta",
330
- }),
331
- ];
329
+ });
332
330
 
333
- renderHeaderSection();
334
- await user.click(screen.getByRole("button", { name: /Switch session/ }));
335
- await user.click(screen.getByRole("button", { name: "Project" }));
331
+ render(
332
+ <ChatSessionSwitcherGroups
333
+ collapsedProjectRoots={[]}
334
+ dateGroups={[]}
335
+ isProjectFirstView
336
+ onSelect={mocks.selectSession}
337
+ onToggleProjectCollapsed={mocks.toggleProjectCollapsed}
338
+ optimisticReadAtBySessionKey={{}}
339
+ projectGroups={[
340
+ { projectRoot: "/workspace/alpha", projectName: "Alpha", items: [alphaItem], latestUpdatedAt: 1, isPinned: false },
341
+ { projectRoot: "/workspace/beta", projectName: "Beta", items: [betaItem], latestUpdatedAt: 1, isPinned: false },
342
+ ]}
343
+ selectedSessionKey="parent-session-1"
344
+ sessionTypeOptions={[]}
345
+ />,
346
+ );
336
347
 
337
- expect(mocks.setListMode).toHaveBeenCalledWith("project-first");
338
- const alphaGroup = screen.getByRole("region", { name: "Alpha" });
348
+ const alphaGroup = await screen.findByRole("region", { name: "Alpha" });
339
349
  const alphaToggle = within(alphaGroup).getByRole("button", {
340
350
  name: "Collapse project · Alpha",
341
351
  });
342
352
  expect(alphaToggle.getAttribute("aria-expanded")).toBe("true");
353
+ expect(alphaToggle.className).toContain("h-8");
343
354
  expect(alphaToggle.className).not.toContain("bg-muted");
355
+ expect(alphaToggle.querySelector('[title="/workspace/alpha"]')?.getAttribute("class")).toContain("text-[13px]");
356
+ expect(alphaGroup.parentElement?.className).toContain("space-y-0.5");
344
357
  expect(within(alphaGroup).getByText("Parent Task")).toBeTruthy();
345
358
 
346
359
  await user.click(alphaToggle);
347
360
  expect(mocks.toggleProjectCollapsed).toHaveBeenCalledWith("/workspace/alpha");
348
- expect(
349
- within(screen.getByRole("region", { name: "Alpha" })).queryByText("Parent Task"),
350
- ).toBeNull();
351
361
  });
352
362
 
353
363
  it("keeps the desktop title plain while the sidebar is expanded", () => {
@@ -447,6 +457,8 @@ describe("ChatConversationHeaderSection", () => {
447
457
  const searchInput = screen.getByRole("textbox", {
448
458
  name: "Search session key / label",
449
459
  });
460
+ expect(searchInput.className).toContain("max-md:text-[13px]");
461
+ expect(searchInput.className).toContain("max-md:min-h-0");
450
462
  await user.type(searchInput, "Background");
451
463
  await user.click(screen.getByRole("button", { name: /Background Task/ }));
452
464
 
@@ -95,6 +95,9 @@ export function ChatConversationContent({
95
95
  }: ChatConversationContentProps) {
96
96
  const threadRef = useRef<HTMLDivElement>(null);
97
97
  const contentRef = useRef<HTMLDivElement>(null);
98
+ const turnAnchorRef = useRef<HTMLDivElement>(null);
99
+ const turnFrameRef = useRef<HTMLDivElement>(null);
100
+ const latestUserMessageId = messages.findLast((message) => message.role === "user")?.id ?? null;
98
101
  const hasConversationContent = messages.length > 0 || isSending;
99
102
  const readingKey = createConversationScrollRestorationKey(sessionKey, showWelcome);
100
103
  const initialReadingPosition = useMemo(() => readingKey ? scrollRestorationManager.read(readingKey) : null, [readingKey]);
@@ -112,6 +115,8 @@ export function ChatConversationContent({
112
115
  isLoading: isHistoryLoading,
113
116
  hasContent: hasConversationContent,
114
117
  contentVersion: messages[messages.length - 1] ?? isSending,
118
+ stickyThresholdPx: 80,
119
+ turnSpace: { key: latestUserMessageId, anchorRef: turnAnchorRef, frameRef: turnFrameRef },
115
120
  });
116
121
  const hasMessages = messages.length > 0;
117
122
  const handleScroll = useCallback(
@@ -148,7 +153,7 @@ export function ChatConversationContent({
148
153
  {showWelcome ? (
149
154
  (welcomeSlot ?? null)
150
155
  ) : (
151
- <div ref={contentRef} className="pb-7">
156
+ <div ref={turnFrameRef}><div ref={contentRef} className="pb-7">
152
157
  {hasConversationContent ? (
153
158
  <ChatConversationTrack className="relative py-4 sm:py-5">
154
159
  <ConversationHistoryStatus historyError={historyError} isLoadingPreviousMessages={isLoadingPreviousMessages} onLoadPreviousMessages={onLoadPreviousMessages} />
@@ -163,6 +168,7 @@ export function ChatConversationContent({
163
168
  onLoadMessageDetails={onLoadMessageDetails}
164
169
  scrollRef={threadRef}
165
170
  sessionKey={sessionKey}
171
+ turnAnchorRef={turnAnchorRef}
166
172
  />
167
173
  {isContextCompacting ? <ChatContextCompactionDivider /> : null}
168
174
  </ChatConversationTrack>
@@ -172,7 +178,7 @@ export function ChatConversationContent({
172
178
  {bottomSlot}
173
179
  </ChatConversationTrack>
174
180
  ) : null}
175
- </div>
181
+ </div></div>
176
182
  )}
177
183
  </div>
178
184
  {hasMessages && !showWelcome && !isAtBottom ? (
@@ -19,7 +19,7 @@ import { useChatSessionListStore } from "@/features/chat/stores/chat-session-lis
19
19
  import { useChatThreadStore } from "@/features/chat/stores/chat-thread.store";
20
20
  import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
21
21
  import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
22
- import { IconActionButton } from "@/shared/components/ui/actions/icon-action-button";
22
+ import { IconActionButton, IconActionGroup } from "@/shared/components/ui/actions/icon-action-button";
23
23
  import {
24
24
  getSessionProjectName,
25
25
  normalizeSessionProjectRootValue,
@@ -150,7 +150,7 @@ export function ChatConversationHeaderSection({
150
150
  ) : null
151
151
  }
152
152
  actions={
153
- <div className="flex shrink-0 items-center gap-1.5">
153
+ <IconActionGroup>
154
154
  {layoutMode === "mobile" && sessionKey ? (
155
155
  <IconActionButton
156
156
  icon={<SquarePen className="h-4 w-4" />}
@@ -180,7 +180,7 @@ export function ChatConversationHeaderSection({
180
180
  onToggleWorkspace={toggleWorkspace}
181
181
  onDeleteSession={presenter.chatThreadManager.deleteSession}
182
182
  />
183
- </div>
183
+ </IconActionGroup>
184
184
  }
185
185
  />
186
186
  );