@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
@@ -1,5 +1,6 @@
1
- import type { ReactNode } from "react";
2
- import { MessageSquareText } from "lucide-react";
1
+ import { useState, type ReactNode } from "react";
2
+ import { ChatCollapsibleContent } from "@nextclaw/agent-chat-ui";
3
+ import { ChevronRight, MessageSquareText } from "lucide-react";
3
4
  import type { NcpSessionListItemView } from "@/features/chat/features/ncp/hooks/use-ncp-session-list-view";
4
5
  import type {
5
6
  ChatSidebarDateGroup,
@@ -8,6 +9,7 @@ import type {
8
9
  import { ChatSidebarProjectGroups } from "@/features/chat/features/session/components/chat-sidebar-project-groups";
9
10
  import type { ChatSessionTypeOption } from "@/features/chat/features/session-type/utils/chat-session-type.utils";
10
11
  import { t } from "@/shared/lib/i18n";
12
+ import { cn } from "@/shared/lib/utils";
11
13
 
12
14
  type SessionTypeOption = ChatSessionTypeOption;
13
15
 
@@ -32,6 +34,41 @@ function ChatSidebarEmptyState({ label }: { label: string }) {
32
34
  );
33
35
  }
34
36
 
37
+ function ChatSidebarSessionGroup({ group, variant, renderSessionItem }: {
38
+ group: ChatSidebarDateGroup;
39
+ variant: 'desktop' | 'mobile';
40
+ renderSessionItem: ChatSidebarSessionListProps['renderSessionItem'];
41
+ }) {
42
+ const [open, setOpen] = useState(true);
43
+ return (
44
+ <div>
45
+ <button
46
+ type="button"
47
+ aria-expanded={open}
48
+ onClick={() => setOpen((value) => !value)}
49
+ className={cn(
50
+ 'group/session-heading flex w-full cursor-pointer items-center justify-between gap-2 rounded-xl text-left text-xs font-medium text-muted-foreground outline-none transition-colors duration-base hover:bg-[var(--interaction-hover)] hover:text-foreground',
51
+ variant === 'mobile' ? 'min-h-9 px-4' : 'min-h-7 px-2',
52
+ )}
53
+ >
54
+ <span className="truncate">{group.label}</span>
55
+ <ChevronRight
56
+ aria-hidden="true"
57
+ className={cn(
58
+ 'h-3 w-3 shrink-0 opacity-0 transition-[opacity,transform] duration-200 group-hover/session-heading:opacity-100 motion-reduce:transition-none',
59
+ open && 'rotate-90',
60
+ )}
61
+ />
62
+ </button>
63
+ <ChatCollapsibleContent open={open}>{() => (
64
+ <div className={variant === 'mobile' ? undefined : 'space-y-0.5'}>
65
+ {group.items.map(renderSessionItem)}
66
+ </div>
67
+ )}</ChatCollapsibleContent>
68
+ </div>
69
+ );
70
+ }
71
+
35
72
  export function ChatSidebarSessionList({
36
73
  variant = 'desktop',
37
74
  defaultSessionType,
@@ -72,14 +109,12 @@ export function ChatSidebarSessionList({
72
109
  return (
73
110
  <div className={variant === 'mobile' ? undefined : 'space-y-2'}>
74
111
  {groups.map((group) => (
75
- <div key={group.label}>
76
- <div className={variant === 'mobile' ? 'px-4 py-1 text-[11px] text-muted-foreground' : 'px-2 pb-1 pt-0.5 text-[11px] font-medium uppercase tracking-wider text-muted-foreground/65'}>
77
- {group.label}
78
- </div>
79
- <div className={variant === 'mobile' ? undefined : 'space-y-0.5'}>
80
- {group.items.map(renderSessionItem)}
81
- </div>
82
- </div>
112
+ <ChatSidebarSessionGroup
113
+ key={group.label}
114
+ group={group}
115
+ variant={variant}
116
+ renderSessionItem={renderSessionItem}
117
+ />
83
118
  ))}
84
119
  </div>
85
120
  );
@@ -187,7 +187,7 @@ describe('ChatSessionHeaderActions', () => {
187
187
 
188
188
  const actionGroup = screen.getByRole('button', { name: 'More actions' }).parentElement;
189
189
 
190
- expect(actionGroup?.className).toContain('gap-1.5');
190
+ expect(actionGroup?.className).toContain('max-md:gap-0');
191
191
  expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('h-7');
192
192
  expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('w-7');
193
193
  });
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react';
2
2
  import { Braces, FolderOpen, PanelRightClose, PanelRightOpen, Trash2 } from 'lucide-react';
3
- import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
3
+ import { IconActionButton, IconActionGroup } from '@/shared/components/ui/actions/icon-action-button';
4
4
  import { useChatSessionProject } from '@/features/chat/features/session/hooks/use-chat-session-project';
5
5
  import { ChatSessionHeaderMenuItem } from './chat-session-header-menu-item';
6
6
  import { ChatSessionMoreActionsMenu } from './chat-session-more-actions-menu';
@@ -8,8 +8,6 @@ import { ChatSessionMetadataDialog } from './chat-session-metadata-dialog';
8
8
  import { ChatSessionProjectDialog } from './chat-session-project-dialog';
9
9
  import { t } from '@/shared/lib/i18n';
10
10
 
11
- const SESSION_HEADER_ACTION_GROUP_CLASS = 'flex shrink-0 items-center gap-1.5';
12
-
13
11
  type ChatSessionHeaderActionsProps = {
14
12
  sessionKey: string | null;
15
13
  sessionTitle?: string;
@@ -60,7 +58,7 @@ export function ChatSessionHeaderActions({
60
58
  };
61
59
 
62
60
  return (
63
- <div className={SESSION_HEADER_ACTION_GROUP_CLASS}>
61
+ <IconActionGroup>
64
62
  <IconActionButton
65
63
  icon={
66
64
  isWorkspaceOpen ? (
@@ -123,6 +121,6 @@ export function ChatSessionHeaderActions({
123
121
  />
124
122
  </>
125
123
  ) : null}
126
- </div>
124
+ </IconActionGroup>
127
125
  );
128
126
  }
@@ -1,5 +1,6 @@
1
1
  import type { LucideIcon } from 'lucide-react';
2
2
  import { cn } from '@/shared/lib/utils';
3
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
3
4
 
4
5
  type ChatSessionHeaderMenuItemProps = {
5
6
  icon: LucideIcon;
@@ -20,10 +21,10 @@ export function ChatSessionHeaderMenuItem({
20
21
  <button
21
22
  type="button"
22
23
  className={cn(
23
- 'flex h-8 w-full items-center gap-2 rounded-lg px-2.5 text-left text-[13px] font-medium outline-none transition-colors disabled:cursor-not-allowed disabled:opacity-50',
24
+ ACTION_MENU_ITEM_CLASS,
24
25
  destructive
25
- ? 'text-destructive hover:bg-destructive/10 focus-visible:bg-destructive/10'
26
- : 'text-foreground hover:bg-muted focus-visible:bg-muted'
26
+ ? ACTION_FEEDBACK.destructive
27
+ : `text-foreground ${ACTION_FEEDBACK.item}`
27
28
  )}
28
29
  onClick={onClick}
29
30
  disabled={disabled}
@@ -22,6 +22,7 @@ type ChatSessionMoreActionsMenuProps = {
22
22
  disabled?: boolean;
23
23
  triggerSize?: IconActionButtonSize;
24
24
  triggerTone?: IconActionButtonTone;
25
+ triggerTooltipSide?: 'top' | 'bottom';
25
26
  className?: string;
26
27
  };
27
28
 
@@ -39,6 +40,7 @@ export function ChatSessionMoreActionsMenu({
39
40
  disabled = false,
40
41
  triggerSize = 'md',
41
42
  triggerTone = 'default',
43
+ triggerTooltipSide = 'bottom',
42
44
  className,
43
45
  }: ChatSessionMoreActionsMenuProps) {
44
46
  const [isOpen, setIsOpen] = useState(false);
@@ -59,6 +61,7 @@ export function ChatSessionMoreActionsMenu({
59
61
  label={t('chatSessionMoreActions')}
60
62
  size={triggerSize}
61
63
  tone={triggerTone}
64
+ tooltipSide={triggerTooltipSide}
62
65
  className={className}
63
66
  disabled={disabled}
64
67
  onClick={(event) => event.stopPropagation()}
@@ -66,9 +66,9 @@ function ChatSessionSwitchItem({
66
66
  type="button"
67
67
  aria-current={active ? "page" : undefined}
68
68
  className={cn(
69
- "flex w-full min-w-0 items-start gap-2 rounded-lg px-2.5 py-2 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
69
+ "flex w-full min-w-0 items-start gap-2 rounded-lg px-2.5 py-1.5 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
70
70
  active
71
- ? "bg-accent text-accent-foreground"
71
+ ? "bg-accent/60 text-accent-foreground"
72
72
  : "text-foreground hover:bg-[var(--interaction-hover)] hover:text-accent-foreground",
73
73
  )}
74
74
  onClick={() => onSelect(session.key)}
@@ -101,7 +101,7 @@ function ChatSessionSwitchItem({
101
101
  </span>
102
102
  ) : null}
103
103
  </span>
104
- <span className="mt-0.5 flex min-w-0 items-center gap-2 text-[11px] text-muted-foreground">
104
+ <span className="mt-0.5 flex min-w-0 items-center gap-2 text-[11px] text-muted-foreground/75">
105
105
  <span className="min-w-0 truncate">{previewText}</span>
106
106
  <span className="shrink-0">{trailingText}</span>
107
107
  </span>
@@ -177,12 +177,12 @@ function ChatSessionSwitchProjectGroup({
177
177
  aria-controls={contentId}
178
178
  aria-expanded={!isCollapsed}
179
179
  aria-label={actionLabel}
180
- className="group flex h-10 w-full min-w-0 items-center gap-1.5 rounded-lg px-2 text-left text-muted-foreground transition-colors hover:bg-gray-200/60 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
180
+ className="group flex h-8 w-full min-w-0 items-center gap-1.5 rounded-lg px-2 text-left 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"
181
181
  onClick={() => onToggleCollapsed(group.projectRoot)}
182
182
  >
183
183
  <Folder className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
184
184
  <span
185
- className="min-w-0 flex-1 truncate text-[11px] font-medium uppercase tracking-wider"
185
+ className="min-w-0 flex-1 truncate text-[13px] font-medium"
186
186
  title={group.projectRoot}
187
187
  >
188
188
  {group.projectName}
@@ -222,7 +222,7 @@ export function ChatSessionSwitcherGroups({
222
222
  projectGroups: ChatSidebarProjectGroup[];
223
223
  }) {
224
224
  return (
225
- <div className="space-y-3">
225
+ <div className="space-y-0.5">
226
226
  {isProjectFirstView
227
227
  ? projectGroups.map((group) => (
228
228
  <ChatSessionSwitchProjectGroup
@@ -29,7 +29,7 @@ import { cn } from "@/shared/lib/utils";
29
29
  import { useProjects } from "@/shared/hooks/use-projects";
30
30
 
31
31
  const SWITCHER_TRIGGER_CLASS =
32
- "group inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-md px-1.5 py-1 text-sm font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border";
32
+ "group inline-flex min-w-0 max-w-full items-center gap-1.5 max-md:gap-1 rounded-md px-2 py-1 text-sm font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border";
33
33
 
34
34
  function ChatSessionTitle({ title }: { title: string }) {
35
35
  return (
@@ -165,9 +165,9 @@ function ChatSessionTitleSwitcherPopover({
165
165
  </PopoverTrigger>
166
166
  <ChatPopoverContent
167
167
  align="start"
168
- className="w-[22rem] max-w-[calc(100vw-2rem)] p-0"
168
+ className="flex w-[22rem] max-w-[calc(100vw-2rem)] flex-col overflow-hidden p-0"
169
169
  >
170
- <div className="space-y-2 border-b border-border px-3 py-2">
170
+ <div className="shrink-0 space-y-2 border-b border-border/40 px-3 py-2">
171
171
  <div className="flex items-center justify-between gap-3">
172
172
  <div className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground/75">
173
173
  {t("chatSessionSwitcherTitle")}
@@ -180,16 +180,17 @@ function ChatSessionTitleSwitcherPopover({
180
180
  <div className="relative">
181
181
  <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/65" />
182
182
  <Input
183
+ density="compact"
183
184
  value={searchQuery}
184
185
  onChange={(event) => setSearchQuery(event.target.value)}
185
186
  placeholder={t("chatSearchSessionPlaceholder")}
186
187
  aria-label={t("chatSearchSessionPlaceholder")}
187
- className="h-8 rounded-lg bg-background pl-8 pr-2 text-xs"
188
+ className="h-8 rounded-lg border-0 bg-muted/50 pl-8 pr-2"
188
189
  autoFocus
189
190
  />
190
191
  </div>
191
192
  </div>
192
- <div className="max-h-80 overflow-y-auto p-1.5">
193
+ <div className="min-h-0 max-h-80 overflow-y-auto overscroll-contain p-1.5">
193
194
  {isLoading ? (
194
195
  <ChatSessionTitleSwitcherLoadingState />
195
196
  ) : hasVisibleGroups ? (
@@ -27,7 +27,7 @@ export function ChatSessionTypeOptionItem(props: {
27
27
  onClick={onSelect}
28
28
  className={cn(
29
29
  "w-full rounded-2xl px-3 py-2.5 text-left transition-colors",
30
- selected ? "bg-gray-50" : "hover:bg-gray-50",
30
+ selected ? "bg-[var(--interaction-selection)]" : "hover:bg-[var(--interaction-hover)]",
31
31
  disabled ? "cursor-not-allowed opacity-70" : null,
32
32
  )}
33
33
  >
@@ -48,7 +48,6 @@ export function ChatWelcomeAgentPicker({
48
48
  </div>
49
49
  </SelectTrigger>
50
50
  <SelectContent
51
- className="rounded-xl border-border shadow-lg"
52
51
  style={{ maxHeight: AGENT_PICKER_MAX_HEIGHT }}
53
52
  >
54
53
  {agents.map((agent) => (
@@ -55,7 +55,7 @@ export function ChatWelcomeProjectPicker({
55
55
  </PopoverTrigger>
56
56
  <ChatPopoverContent
57
57
  align="start"
58
- className="flex w-[min(20rem,calc(100vw-1rem))] flex-col overflow-hidden rounded-2xl border border-border bg-popover p-0 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
58
+ className="flex w-[min(20rem,calc(100vw-1rem))] flex-col overflow-hidden p-0"
59
59
  style={{ maxHeight: PROJECT_PICKER_MAX_HEIGHT }}
60
60
  >
61
61
  <div className="shrink-0 px-3 pb-2 pt-3 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
@@ -27,7 +27,7 @@ export function ChatWelcomePromptSuggestions({
27
27
  key={suggestion.labelKey}
28
28
  type="button"
29
29
  onClick={() => onSelectPrompt(t(suggestion.promptKey))}
30
- className="rounded-full bg-muted/55 px-3.5 py-2 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
30
+ className="rounded-full bg-muted/55 px-3.5 py-2 text-xs font-medium text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
31
31
  >
32
32
  {t(suggestion.labelKey)}
33
33
  </button>
@@ -61,7 +61,7 @@ export function ChatWelcomeSessionTypePicker({
61
61
  </PopoverTrigger>
62
62
  <ChatPopoverContent
63
63
  align="start"
64
- className="flex w-[min(16rem,calc(100vw-1rem))] flex-col overflow-hidden rounded-2xl border border-border bg-popover p-1.5 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
64
+ className="flex w-[min(16rem,calc(100vw-1rem))] flex-col overflow-hidden p-1.5"
65
65
  style={{ maxHeight: SESSION_TYPE_PICKER_MAX_HEIGHT }}
66
66
  >
67
67
  <div className="min-h-0 flex-1 overflow-y-auto">
@@ -70,7 +70,7 @@ export function WorkspaceBreadcrumbBrowser({
70
70
  <Fragment key={breadcrumb.path}>
71
71
  <button
72
72
  type="button"
73
- className="h-5 rounded-sm px-1 text-left hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
73
+ className="h-5 rounded-sm px-1 text-left hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
74
74
  onClick={() => onBrowsePathChange(breadcrumb.path)}
75
75
  >
76
76
  {breadcrumb.label}
@@ -100,7 +100,7 @@ export function WorkspaceBreadcrumbBrowser({
100
100
  key={entry.path}
101
101
  type="button"
102
102
  className={cn(
103
- "flex h-6 w-full items-center gap-1.5 rounded-sm px-1.5 text-left text-[11px] text-gray-700 transition-colors hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
103
+ "flex h-6 w-full items-center gap-1.5 rounded-sm px-1.5 text-left text-[11px] text-gray-700 transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
104
104
  entry.hidden ? "opacity-65" : null,
105
105
  )}
106
106
  onClick={() => openEntry(entry)}
@@ -43,9 +43,9 @@ function WorkspaceBreadcrumbSegmentButton({
43
43
  type="button"
44
44
  aria-current={segment.isCurrent ? 'page' : undefined}
45
45
  className={cn(
46
- 'inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-sm px-1 text-[11px] leading-none transition-colors hover:bg-gray-200/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
46
+ 'inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-sm px-1 text-[11px] leading-none transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
47
47
  segment.kind === 'workspace'
48
- ? 'bg-primary/8 text-primary hover:bg-primary/12'
48
+ ? 'bg-[var(--interaction-selection)] text-foreground hover:bg-[var(--interaction-selection)]'
49
49
  : segment.isCurrent
50
50
  ? 'bg-gray-200/70 text-gray-900'
51
51
  : 'text-gray-500',
@@ -66,7 +66,7 @@ function WorkspaceOverviewEntry({
66
66
  return (
67
67
  <button
68
68
  type="button"
69
- className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
69
+ className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
70
70
  onClick={onClick}
71
71
  >
72
72
  <span className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-600">
@@ -27,7 +27,7 @@ export function ChatSessionChildSessions({
27
27
  </div>
28
28
  <button
29
29
  type="button"
30
- className="inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-2.5 py-1.5 text-xs font-semibold text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25 disabled:cursor-not-allowed disabled:opacity-50"
30
+ className="inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-2.5 py-1.5 text-xs font-semibold text-primary-foreground transition-colors hover:bg-[hsl(var(--primary-hover))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25 disabled:cursor-not-allowed disabled:opacity-50"
31
31
  disabled={!sessionKey}
32
32
  onClick={() => presenter.chatThreadManager.openSideChatDraft(sessionKey)}
33
33
  >
@@ -42,7 +42,7 @@ export function ChatSessionChildSessions({
42
42
  {childSessionTabs.map((tab) => (
43
43
  <div
44
44
  key={tab.sessionKey}
45
- className="group relative flex w-full items-center rounded-lg border border-gray-200/80 bg-white transition-colors hover:border-gray-300 hover:bg-gray-50"
45
+ className="group relative flex w-full items-center rounded-lg border border-gray-200/80 bg-white transition-colors hover:border-gray-300 hover:bg-[var(--interaction-hover)]"
46
46
  >
47
47
  <button
48
48
  type="button"
@@ -121,8 +121,8 @@ export function WorkspaceSpreadsheetPreview({
121
121
  className={cn(
122
122
  "h-7 shrink-0 rounded-md px-2.5 text-xs transition-colors",
123
123
  sheet.name === activeSheet?.name
124
- ? "bg-accent font-medium text-accent-foreground"
125
- : "text-muted-foreground hover:bg-muted hover:text-foreground",
124
+ ? "bg-[var(--interaction-selection)] font-medium text-foreground"
125
+ : "text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-foreground",
126
126
  )}
127
127
  onClick={() => setSelectedSheetName(sheet.name)}
128
128
  >
@@ -96,7 +96,7 @@ function ObservationRow({
96
96
  type="button"
97
97
  data-testid={`observation-${item.id}-${toggleAction}`}
98
98
  disabled={isPending}
99
- className="inline-flex items-center gap-1.5 rounded-md border border-gray-200 px-2.5 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50"
99
+ className="inline-flex items-center gap-1.5 rounded-md border border-gray-200 px-2.5 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-[var(--interaction-hover)] disabled:cursor-not-allowed disabled:opacity-50"
100
100
  onClick={() => onAction(toggleAction)}
101
101
  >
102
102
  {toggleAction === 'pause' ? <Pause className="h-3.5 w-3.5" /> : <Play className="h-3.5 w-3.5" />}
@@ -107,7 +107,7 @@ function ObservationRow({
107
107
  type="button"
108
108
  data-testid={`observation-${item.id}-remove`}
109
109
  disabled={isPending}
110
- className="inline-flex items-center gap-1.5 rounded-md border border-rose-200 px-2.5 py-1.5 text-xs font-medium text-rose-700 transition-colors hover:bg-rose-50 disabled:cursor-not-allowed disabled:opacity-50"
110
+ className="inline-flex items-center gap-1.5 rounded-md border border-rose-200 px-2.5 py-1.5 text-xs font-medium text-rose-700 transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50"
111
111
  onClick={() => onAction('remove')}
112
112
  >
113
113
  <Trash2 className="h-3.5 w-3.5" />
@@ -179,7 +179,7 @@ export function ChatSessionContinuousAttention({ sessionKey }: { sessionKey: str
179
179
  type="button"
180
180
  role="tab"
181
181
  aria-selected={activeGroup === group}
182
- className={cn('flex-1 rounded-md px-3 py-2 text-xs font-medium transition-colors', activeGroup === group ? 'bg-gray-100 text-gray-900' : 'text-gray-500 hover:text-gray-700')}
182
+ className={cn('flex-1 rounded-md px-3 py-2 text-xs font-medium transition-colors', activeGroup === group ? 'bg-[var(--interaction-selection)] text-foreground' : 'text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-foreground')}
183
183
  onClick={() => setActiveGroup(group)}
184
184
  >
185
185
  {getGroupLabel(group)} <span className="ml-1 tabular-nums text-gray-400">{count}</span>
@@ -90,7 +90,7 @@ export function ChatSessionTokenUsage({ sessionKey }: { sessionKey: string | nul
90
90
  <span>{t('chatWorkspaceTokenUsageLoadFailed')}</span>
91
91
  <button
92
92
  type="button"
93
- className="shrink-0 rounded px-1.5 py-1 font-semibold text-gray-700 hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
93
+ className="shrink-0 rounded px-1.5 py-1 font-semibold text-gray-700 hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
94
94
  onClick={() => void usageQuery.refetch()}
95
95
  >
96
96
  {t('chatWorkspaceTokenUsageRetry')}
@@ -355,8 +355,8 @@ export function WorkspaceDirectoryTreeEntry({
355
355
  ref={rowRef}
356
356
  data-workspace-tree-entry=""
357
357
  className={cn(
358
- 'group flex h-[26px] w-full min-w-0 items-center text-gray-700 transition-colors hover:bg-gray-100 focus-within:bg-gray-100',
359
- selected ? 'bg-primary/10' : null,
358
+ 'group flex h-[26px] w-full min-w-0 items-center text-gray-700 transition-colors hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)]',
359
+ selected ? 'bg-[var(--interaction-selection)] hover:bg-[var(--interaction-selection)] focus-within:bg-[var(--interaction-selection)]' : null,
360
360
  entry.hidden ? 'opacity-65' : null,
361
361
  )}
362
362
  style={{ paddingLeft: `${6 + level * 12}px` }}
@@ -371,9 +371,10 @@ export function WorkspaceDirectoryTreeEntry({
371
371
  }}
372
372
  >
373
373
  <Input
374
+ density="compact"
374
375
  autoFocus
375
376
  aria-label={t('chatWorkspaceRenameName')}
376
- className="h-6 min-w-0 flex-1 px-1.5 text-xs"
377
+ className="h-6 min-w-0 flex-1 px-1.5"
377
378
  value={rename.name}
378
379
  onChange={(event) => rename.updateName(event.target.value)}
379
380
  onKeyDown={(event) => {
@@ -67,9 +67,10 @@ export function WorkspaceNewFolderTreeItem({
67
67
  <Folder className="h-4 w-4 shrink-0 text-amber-500" />
68
68
  )}
69
69
  <Input
70
+ density="compact"
70
71
  ref={inputRef}
71
72
  aria-label={t(kind === 'file' ? 'chatWorkspaceFileName' : 'chatWorkspaceFolderName')}
72
- className="h-7 min-w-0 flex-1 rounded-md px-2 text-xs"
73
+ className="h-7 min-w-0 flex-1 rounded-md px-2"
73
74
  disabled={isCreating}
74
75
  placeholder={t(kind === 'file' ? 'chatWorkspaceFileNamePlaceholder' : 'chatWorkspaceFolderNamePlaceholder')}
75
76
  value={name}
@@ -1,5 +1,5 @@
1
1
  import { ChevronsUp, FilePlus2, FolderPlus, MoreVertical, RefreshCw } from 'lucide-react';
2
- import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
2
+ import { IconActionButton, IconActionGroup } from '@/shared/components/ui/actions/icon-action-button';
3
3
  import { ContextMenuTrigger } from '@/shared/components/ui/context-menu/context-menu';
4
4
  import { t } from '@/shared/lib/i18n';
5
5
 
@@ -26,6 +26,7 @@ export function WorkspaceProjectFilesToolbar({
26
26
  >
27
27
  {rootLabel}
28
28
  </span>
29
+ <IconActionGroup>
29
30
  <IconActionButton
30
31
  icon={<FilePlus2 className="h-4 w-4" />}
31
32
  label={t('chatWorkspaceNewFile')}
@@ -59,6 +60,7 @@ export function WorkspaceProjectFilesToolbar({
59
60
  size="sm"
60
61
  />
61
62
  </ContextMenuTrigger>
63
+ </IconActionGroup>
62
64
  </div>
63
65
  );
64
66
  }
@@ -83,7 +83,7 @@ function SessionCronJobCard({
83
83
  const jobLabel = job.name || job.id;
84
84
 
85
85
  return (
86
- <article className="rounded-2xl border border-border/60 bg-background px-3.5 py-3 shadow-sm transition-colors hover:bg-muted/20 focus-within:bg-muted/20">
86
+ <article className="rounded-2xl border border-border/60 bg-background px-3.5 py-3 shadow-sm transition-colors hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)]">
87
87
  <div className="flex items-start gap-3">
88
88
  <span
89
89
  className={cn(
@@ -189,7 +189,7 @@ function SessionCronJobCard({
189
189
  setMenuOpen(false);
190
190
  void cronActions.runJob(job);
191
191
  }}
192
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50"
192
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-[var(--interaction-hover)] disabled:cursor-not-allowed disabled:opacity-50"
193
193
  >
194
194
  <Play className="h-3.5 w-3.5 text-muted-foreground" />
195
195
  {t("cronRunNow")}
@@ -201,7 +201,7 @@ function SessionCronJobCard({
201
201
  setMenuOpen(false);
202
202
  void cronActions.deleteJob(job);
203
203
  }}
204
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50"
204
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50"
205
205
  >
206
206
  {t("delete")}
207
207
  </button>
@@ -105,7 +105,7 @@ function WorkspaceUnsupportedContent({
105
105
  <a
106
106
  href={contentUrl}
107
107
  download={label}
108
- className="inline-flex h-8 items-center rounded-lg border border-border bg-card px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted"
108
+ className="inline-flex h-8 items-center rounded-lg border border-border bg-card px-3 text-xs font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)]"
109
109
  >
110
110
  {t("chatWorkspacePreviewDownload")}
111
111
  </a>
@@ -113,7 +113,7 @@ function WorkspaceUnsupportedContent({
113
113
  href={contentUrl}
114
114
  target="_blank"
115
115
  rel="noreferrer"
116
- className="inline-flex h-8 items-center rounded-lg bg-primary px-3 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90"
116
+ className="inline-flex h-8 items-center rounded-lg bg-primary px-3 text-xs font-medium text-primary-foreground transition-colors hover:bg-[hsl(var(--primary-hover))]"
117
117
  >
118
118
  {t("chatWorkspacePreviewOpenExternally")}
119
119
  </a>
@@ -137,7 +137,7 @@ export function WorkspaceMarkdownOutline({
137
137
  <li key={item.index}>
138
138
  <button
139
139
  type="button"
140
- className="block w-full truncate rounded-md py-1.5 pr-2 text-left text-xs leading-4 text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-950 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-border active:bg-gray-200"
140
+ className="block w-full truncate rounded-md py-1.5 pr-2 text-left text-xs leading-4 text-gray-600 transition-colors hover:bg-[var(--interaction-hover)] hover:text-gray-950 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-border active:bg-[var(--interaction-hover)]"
141
141
  style={{
142
142
  paddingInlineStart: `${0.5 + item.depth * 0.75}rem`,
143
143
  }}
@@ -220,6 +220,7 @@ export function CronConfig() {
220
220
  return (
221
221
  <PageLayout className="space-y-6">
222
222
  <PageHeader
223
+ mobileTitleInShell
223
224
  headingLevel={1}
224
225
  title={t("cronPageTitle")}
225
226
  description={t("cronPageDescription")}
@@ -307,8 +308,8 @@ export function CronConfig() {
307
308
  handlePageChange(0);
308
309
  }}
309
310
  className={cn(
310
- "rounded-lg px-2.5 py-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
311
- status === value && "bg-muted text-foreground",
311
+ "rounded-lg px-2.5 py-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground",
312
+ status === value && "bg-[var(--interaction-selection)] hover:bg-[var(--interaction-selection)] text-foreground",
312
313
  )}
313
314
  >
314
315
  {t(label)}
@@ -206,7 +206,7 @@ export function CronJobDetailDialog({
206
206
  <SheetFooter className="shrink-0 border-t border-border/60 bg-background px-5 py-4 sm:px-7">
207
207
  <Button
208
208
  variant="ghost"
209
- className="text-red-600 hover:bg-red-50 hover:text-red-700"
209
+ className="text-red-600 hover:bg-destructive/10 hover:text-red-700"
210
210
  onClick={() => onDelete(job)}
211
211
  >
212
212
  <Trash2 className="mr-2 h-4 w-4" />
@@ -105,14 +105,14 @@ export function CronJobRow({
105
105
  return (
106
106
  <div
107
107
  className={cn(
108
- "group relative rounded-xl border-b border-border/55 transition-colors duration-150 last:border-b-0 hover:bg-muted/35 focus-within:bg-muted/35",
108
+ "group relative rounded-xl border-b border-border/55 transition-colors duration-150 last:border-b-0 hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)]",
109
109
  expanded && "bg-muted/35",
110
110
  )}
111
111
  >
112
- <div className="flex items-center gap-3 px-1 py-3.5">
112
+ <div className="flex flex-wrap items-center gap-3 px-1 py-3.5">
113
113
  <button
114
114
  type="button"
115
- className="grid min-w-0 flex-1 grid-cols-[36px_minmax(0,1fr)] items-center gap-3 rounded-lg pr-16 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
115
+ className="grid min-w-0 flex-1 max-md:basis-full grid-cols-[36px_minmax(0,1fr)] items-center gap-3 rounded-lg md:pr-16 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
116
116
  aria-controls={previewId}
117
117
  aria-expanded={expanded}
118
118
  aria-label={`${t(expanded ? "cronCollapseTask" : "cronExpandTask")} ${jobLabel}`}
@@ -159,14 +159,14 @@ export function CronJobRow({
159
159
  </button>
160
160
 
161
161
  <TooltipProvider delayDuration={250}>
162
- <div className="relative flex shrink-0 items-center gap-1">
162
+ <div className="relative flex shrink-0 items-center gap-1 max-md:ml-auto">
163
163
  <Switch
164
164
  checked={job.enabled}
165
165
  onCheckedChange={(checked) => onToggle(job, checked)}
166
166
  aria-label={job.enabled ? t("cronDisable") : t("cronEnable")}
167
167
  />
168
168
 
169
- <div className="flex items-center gap-0.5 opacity-100 transition-opacity duration-150 [@media(hover:hover)]:pointer-events-none [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-focus-within:pointer-events-auto [@media(hover:hover)]:group-focus-within:opacity-100 [@media(hover:hover)]:group-hover:pointer-events-auto [@media(hover:hover)]:group-hover:opacity-100">
169
+ <div className="flex items-center gap-0.5 opacity-100 transition-opacity duration-150 md:[@media(hover:hover)]:pointer-events-none md:[@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-focus-within:pointer-events-auto [@media(hover:hover)]:group-focus-within:opacity-100 [@media(hover:hover)]:group-hover:pointer-events-auto [@media(hover:hover)]:group-hover:opacity-100">
170
170
  <Tooltip>
171
171
  <TooltipTrigger asChild>
172
172
  <Button
@@ -206,7 +206,7 @@ export function CronJobRow({
206
206
  setMenuOpen(false);
207
207
  onRun(job);
208
208
  }}
209
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-muted"
209
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-[var(--interaction-hover)]"
210
210
  >
211
211
  <Play className="h-3.5 w-3.5 text-muted-foreground" />
212
212
  {t("cronRunNow")}
@@ -217,7 +217,7 @@ export function CronJobRow({
217
217
  setMenuOpen(false);
218
218
  onDelete(job);
219
219
  }}
220
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-red-50"
220
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-destructive/10"
221
221
  >
222
222
  <Trash2 className="h-3.5 w-3.5" />
223
223
  {t("delete")}