@nextclaw/ui 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/assets/{api-b1R9VdeH.js → api-iNBpppzj.js} +3 -3
  3. package/dist/assets/{appearance-settings-page-D2O9pch9.js → appearance-settings-page-DMffQFR3.js} +1 -1
  4. package/dist/assets/{book-open-B77lQ2Tg.js → book-open-C3mJGwiy.js} +1 -1
  5. package/dist/assets/channels-list-page-CCtp0BRS.js +8 -0
  6. package/dist/assets/chat-page-H5a0dWvO.js +1 -0
  7. package/dist/assets/config-split-page-CrOJgB-Y.js +1 -0
  8. package/dist/assets/{confirm-dialog-C-NXSioX.js → confirm-dialog-Chv50USy.js} +2 -2
  9. package/dist/assets/{desktop-update-config-usHpXugP.js → desktop-update-config-KzTuXRf_.js} +1 -1
  10. package/dist/assets/{dist-jdGmbb6w.js → dist-BunzmC4B.js} +1 -1
  11. package/dist/assets/{dist-YtoqU-AT.js → dist-ChmGwvtK.js} +1 -1
  12. package/dist/assets/doc-browser-DNRL4Zvd.js +1 -0
  13. package/dist/assets/doc-browser-Dg0pmkOg.js +1 -0
  14. package/dist/assets/doc-browser-context-BHY-0FSD.js +1 -0
  15. package/dist/assets/{es2015-bNpL2LKy.js → es2015-DQZ5JWwK.js} +1 -1
  16. package/dist/assets/{external-link-BM6fk8q-.js → external-link-CU0kzzIP.js} +1 -1
  17. package/dist/assets/form-actions-BvCp_0lS.js +1 -0
  18. package/dist/assets/{i18n-provider-CntWolRA.js → i18n-provider-Cu8XyZb_.js} +1 -1
  19. package/dist/assets/index-CzfBdvK1.css +1 -0
  20. package/dist/assets/index-DGqHne1Q.js +104 -0
  21. package/dist/assets/loader-circle-CDSFuzmk.js +1 -0
  22. package/dist/assets/mcp-marketplace-page-BeEQK0DL.js +9 -0
  23. package/dist/assets/mcp-marketplace-page-D6idOTLp.js +1 -0
  24. package/dist/assets/model-config-page-bNNo-XyG.js +1 -0
  25. package/dist/assets/plus-D4DsdLN-.js +1 -0
  26. package/dist/assets/{provider-scoped-model-input-Cm_a4GHf.js → provider-scoped-model-input-IlgQCsoT.js} +1 -1
  27. package/dist/assets/providers-config-page-wLo6CAJw.js +1 -0
  28. package/dist/assets/{react-BN8uzPnp.js → react-BPIsQIlO.js} +1 -1
  29. package/dist/assets/{refresh-cw-BpVcFPmJ.js → refresh-cw-CILd1vAP.js} +1 -1
  30. package/dist/assets/remote-uKEYp7AR.js +1 -0
  31. package/dist/assets/rotate-cw-wPFPg1kH.js +1 -0
  32. package/dist/assets/runtime-config-page-DDn1sP4G.js +1 -0
  33. package/dist/assets/{save-BpFW5fpk.js → save-ByJqcPTP.js} +1 -1
  34. package/dist/assets/{search-D0uO7enf.js → search-DVIV6pfD.js} +1 -1
  35. package/dist/assets/search-config-page-B-Cf4iiB.js +1 -0
  36. package/dist/assets/secrets-config-page-DPKsY8Iw.js +3 -0
  37. package/dist/assets/security-config-e9SSBlKr.js +1 -0
  38. package/dist/assets/{select-Bh-CrA4p.js → select-BdgczSNw.js} +1 -1
  39. package/dist/assets/{setting-row-BJfCHRcb.js → setting-row-BkTVUTKx.js} +1 -1
  40. package/dist/assets/{settings-2-Blzi1vr6.js → settings-2-CH5shGg_.js} +1 -1
  41. package/dist/assets/{side-dock-ZdaSrQVB.js → side-dock-BsBvcJ9i.js} +2 -2
  42. package/dist/assets/{skeleton-BLlEzebZ.js → skeleton-DeX1FKw7.js} +1 -1
  43. package/dist/assets/switch-Cv8Ekb3x.js +1 -0
  44. package/dist/assets/{tag-chip-CzGihiQx.js → tag-chip-RB9uKcoC.js} +1 -1
  45. package/dist/assets/{tooltip-CdcrBjrC.js → tooltip-oQlEN-l6.js} +1 -1
  46. package/dist/assets/{use-config-CVPgsBmU.js → use-config-l3W7y8Qz.js} +1 -1
  47. package/dist/assets/{use-confirm-dialog-CSeBk9SF.js → use-confirm-dialog-BAxaVOJI.js} +1 -1
  48. package/dist/assets/x-BBMffEN0.js +1 -0
  49. package/dist/index.html +38 -30
  50. package/index.html +12 -4
  51. package/package.json +9 -9
  52. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +29 -1
  53. package/src/app/components/layout/sidebar-items.tsx +46 -7
  54. package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
  55. package/src/app/components/layout/sidebar.tsx +84 -62
  56. package/src/app/configs/app-navigation.config.ts +49 -0
  57. package/src/app/styles/design-system.css +99 -4
  58. package/src/features/channels/components/config/channel-form.tsx +14 -11
  59. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +40 -0
  60. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -1
  61. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
  62. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +48 -0
  63. package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +55 -0
  64. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -3
  65. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +3 -4
  66. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +30 -31
  67. package/src/features/chat/components/layout/chat-sidebar.tsx +21 -7
  68. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +2 -1
  69. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
  70. package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +22 -1
  71. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
  72. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +10 -5
  73. package/src/features/chat/features/message/components/chat-message-list.container.tsx +47 -1
  74. package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
  75. package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
  76. package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +0 -11
  77. package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
  78. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
  79. package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +116 -0
  80. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +108 -46
  81. package/src/features/chat/features/session/components/chat-sidebar-session-entry.tsx +6 -0
  82. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +48 -24
  83. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +0 -3
  84. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +0 -4
  85. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +2 -2
  86. package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +25 -3
  87. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +9 -4
  88. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
  89. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
  90. package/src/features/chat/features/welcome/components/chat-welcome.tsx +0 -5
  91. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +226 -56
  92. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +1 -0
  93. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +144 -0
  94. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +99 -0
  95. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
  96. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +4 -2
  97. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +232 -21
  98. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +3 -0
  99. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +44 -1
  100. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +45 -3
  101. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +4 -0
  102. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +33 -2
  103. package/src/features/chat/managers/chat-session-list.manager.ts +32 -0
  104. package/src/features/chat/managers/chat-thread.manager.ts +2 -0
  105. package/src/features/chat/stores/chat-session-list.store.ts +28 -5
  106. package/src/features/chat/stores/chat-thread.store.ts +3 -0
  107. package/src/features/cron/components/cron-config.tsx +63 -80
  108. package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
  109. package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
  110. package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
  111. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +5 -12
  112. package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
  113. package/src/features/panel-apps/components/panel-app-list-item.tsx +6 -6
  114. package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
  115. package/src/features/panel-apps/index.ts +1 -0
  116. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +2 -10
  117. package/src/features/panel-apps/utils/panel-app-iframe.utils.ts +6 -0
  118. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +11 -3
  119. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +3 -1
  120. package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
  121. package/src/features/service-apps/components/service-apps-panel.tsx +145 -35
  122. package/src/features/settings/components/config/provider-auth-section.tsx +1 -1
  123. package/src/features/settings/components/config/provider-form.tsx +11 -8
  124. package/src/features/settings/components/config/provider-models-section.tsx +7 -7
  125. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  126. package/src/features/settings/components/config/secrets-config-form.tsx +5 -4
  127. package/src/features/settings/pages/model-config-page.tsx +26 -25
  128. package/src/features/settings/pages/providers-config-page.tsx +10 -13
  129. package/src/features/settings/pages/search-config-page.tsx +8 -5
  130. package/src/features/side-dock/components/side-dock.tsx +3 -3
  131. package/src/features/system-status/components/config/runtime-config-editor.tsx +5 -4
  132. package/src/index.css +257 -13
  133. package/src/shared/components/actions/action-link.tsx +1 -1
  134. package/src/shared/components/config-split-page.tsx +6 -6
  135. package/src/shared/components/doc-browser/__tests__/doc-browser-url.utils.test.ts +73 -0
  136. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +48 -0
  137. package/src/shared/components/doc-browser/doc-browser-context.tsx +4 -0
  138. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -2
  139. package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +2 -1
  140. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +10 -10
  141. package/src/shared/components/doc-browser/doc-browser.tsx +6 -4
  142. package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +62 -4
  143. package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +18 -0
  144. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +28 -3
  145. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +36 -0
  146. package/src/shared/components/ui/actions/form-actions.tsx +25 -0
  147. package/src/shared/components/ui/actions/icon-action-button.tsx +25 -2
  148. package/src/shared/components/ui/button.tsx +1 -1
  149. package/src/shared/components/ui/card.tsx +12 -4
  150. package/src/shared/components/ui/dialog.tsx +1 -1
  151. package/src/shared/components/ui/input.tsx +1 -1
  152. package/src/shared/components/ui/select.tsx +1 -1
  153. package/src/shared/components/ui/switch.tsx +1 -1
  154. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -1
  155. package/src/shared/components/ui/tabs.tsx +1 -1
  156. package/src/shared/components/ui/textarea.tsx +1 -1
  157. package/src/shared/hooks/use-server-path-browse.ts +26 -4
  158. package/src/shared/hooks/use-server-path-read.ts +11 -1
  159. package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
  160. package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
  161. package/src/shared/lib/i18n/locales/en-US/core.json +3 -0
  162. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +5 -0
  163. package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
  164. package/src/shared/lib/i18n/locales/zh-CN/core.json +3 -0
  165. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +5 -0
  166. package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +9 -5
  167. package/src/shared/lib/theme/index.test.ts +21 -0
  168. package/src/shared/lib/theme/index.ts +6 -4
  169. package/src/vite-env.d.ts +2 -0
  170. package/dist/assets/channels-list-page-DcsIQc6A.js +0 -8
  171. package/dist/assets/chat-page-CZ7WxPir.js +0 -1
  172. package/dist/assets/config-split-page-BWQ6_Raq.js +0 -1
  173. package/dist/assets/doc-browser-B_Tf9n70.js +0 -1
  174. package/dist/assets/doc-browser-BdZPFOVa.js +0 -1
  175. package/dist/assets/doc-browser-context-DwokemUn.js +0 -1
  176. package/dist/assets/index-BIcEw90u.js +0 -104
  177. package/dist/assets/index-BiNSTKTU.css +0 -1
  178. package/dist/assets/loader-circle-MBgNSVIH.js +0 -1
  179. package/dist/assets/mcp-marketplace-page-CLmUstLN.js +0 -9
  180. package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +0 -1
  181. package/dist/assets/model-config-page-Di0ySJD2.js +0 -1
  182. package/dist/assets/plus-vDqW5Kxp.js +0 -1
  183. package/dist/assets/providers-config-page-BAf2W0MV.js +0 -1
  184. package/dist/assets/remote-CLQ0IBM8.js +0 -1
  185. package/dist/assets/rotate-cw-CvNBv7_w.js +0 -1
  186. package/dist/assets/runtime-config-page-CflvvoDc.js +0 -1
  187. package/dist/assets/search-config-page-D0klFUXd.js +0 -1
  188. package/dist/assets/secrets-config-page-dVZ631Wp.js +0 -3
  189. package/dist/assets/security-config-C5gnlkuj.js +0 -1
  190. package/dist/assets/switch-CFLJFNSd.js +0 -1
  191. package/dist/assets/x-BF2KQ--V.js +0 -1
  192. /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-C_iP1zl_.js} +0 -0
@@ -99,7 +99,7 @@ export function ProviderModelsSection(props: ProviderModelsSectionProps) {
99
99
  ) : null}
100
100
 
101
101
  {models.length === 0 ? (
102
- <div className="rounded-xl border border-dashed border-border bg-muted/60 px-4 py-6 text-center">
102
+ <div className="rounded-xl border border-dashed border-border/65 bg-muted/30 px-4 py-6 text-center">
103
103
  <p className="text-sm text-muted-foreground">{t('providerModelsEmptyShort')}</p>
104
104
  {!showModelInput ? (
105
105
  <button
@@ -123,14 +123,14 @@ export function ProviderModelsSection(props: ProviderModelsSectionProps) {
123
123
  return (
124
124
  <div
125
125
  key={modelName}
126
- className="group inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-card px-3 py-1.5"
126
+ className="group inline-flex max-w-full items-center gap-1 rounded-full border border-border/55 bg-muted/45 px-3 py-1.5"
127
127
  >
128
128
  <span className="max-w-[140px] truncate text-sm text-foreground sm:max-w-[220px]">{modelName}</span>
129
129
  <Popover>
130
130
  <PopoverTrigger asChild>
131
131
  <button
132
132
  type="button"
133
- className="inline-flex h-5 w-5 items-center justify-center rounded-full text-muted-foreground/70 opacity-100 transition-opacity hover:bg-accent hover:text-accent-foreground md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100"
133
+ className="inline-flex h-5 w-5 items-center justify-center rounded-full text-muted-foreground/70 opacity-100 transition-opacity hover:bg-muted hover:text-foreground md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100"
134
134
  aria-label={t('providerModelThinkingTitle')}
135
135
  title={t('providerModelThinkingTitle')}
136
136
  >
@@ -138,7 +138,7 @@ export function ProviderModelsSection(props: ProviderModelsSectionProps) {
138
138
  </button>
139
139
  </PopoverTrigger>
140
140
  <PopoverContent className="w-80 space-y-3">
141
- <div className="flex items-center justify-between gap-3 rounded-lg border border-border bg-muted/60 px-3 py-2">
141
+ <div className="flex items-center justify-between gap-3 rounded-lg bg-muted/50 px-3 py-2">
142
142
  <div className="min-w-0">
143
143
  <p className="text-xs font-semibold text-foreground">{t('providerModelVisionTitle')}</p>
144
144
  <p className="text-xs text-muted-foreground">{t('providerModelVisionHint')}</p>
@@ -159,8 +159,8 @@ export function ProviderModelsSection(props: ProviderModelsSectionProps) {
159
159
  onClick={() => onToggleModelThinkingLevel(modelName, level)}
160
160
  className={`rounded-full border px-2.5 py-1 text-xs font-medium transition-colors ${
161
161
  selected
162
- ? 'border-primary bg-primary text-white'
163
- : 'border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent/70 hover:text-accent-foreground'
162
+ ? 'border-foreground/15 bg-foreground text-background'
163
+ : 'border-border/55 bg-muted/50 text-muted-foreground hover:border-border hover:bg-muted hover:text-foreground'
164
164
  }`}
165
165
  >
166
166
  {formatThinkingLevelLabel(level)}
@@ -198,7 +198,7 @@ export function ProviderModelsSection(props: ProviderModelsSectionProps) {
198
198
  <button
199
199
  type="button"
200
200
  onClick={() => onRemoveModel(modelName)}
201
- className="inline-flex h-5 w-5 items-center justify-center rounded-full text-muted-foreground/70 opacity-100 transition-opacity hover:bg-accent hover:text-accent-foreground md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100"
201
+ className="inline-flex h-5 w-5 items-center justify-center rounded-full text-muted-foreground/70 opacity-100 transition-opacity hover:bg-muted hover:text-foreground md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100"
202
202
  aria-label={t('remove')}
203
203
  >
204
204
  <X className="h-3 w-3" />
@@ -16,7 +16,7 @@ export function ProviderPillSelector(props: ProviderPillSelectorProps) {
16
16
  type="button"
17
17
  onClick={() => onChange(option.value)}
18
18
  aria-pressed={selected}
19
- className={`rounded-full border px-3 py-1.5 text-xs font-medium transition-colors ${selected ? 'border-primary bg-primary text-primary-foreground shadow-sm' : 'border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent/70 hover:text-accent-foreground'}`}
19
+ className={`rounded-full border px-3 py-1.5 text-xs font-medium transition-colors ${selected ? 'border-foreground/15 bg-foreground text-background' : 'border-border/55 bg-muted/50 text-muted-foreground hover:border-border hover:bg-muted hover:text-foreground'}`}
20
20
  >
21
21
  {option.label}
22
22
  </button>
@@ -1,6 +1,7 @@
1
1
  import { useMemo, useState } from 'react';
2
2
  import { Plus, Save, Trash2 } from 'lucide-react';
3
3
  import { Button } from '@/shared/components/ui/button';
4
+ import { FormActions } from '@/shared/components/ui/actions/form-actions';
4
5
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/shared/components/ui/card';
5
6
  import { Input } from '@/shared/components/ui/input';
6
7
  import { Label } from '@/shared/components/ui/label';
@@ -272,12 +273,12 @@ export function SecretsConfigForm(props: {
272
273
  onRemove={(index) => setState((prev) => ({ ...prev, refs: prev.refs.filter((_, cursor) => cursor !== index) }))}
273
274
  onAdd={() => setState((prev) => ({ ...prev, refs: [...prev.refs, createRefRow()] }))}
274
275
  />
275
- <div className="flex justify-end">
276
- <Button type="button" onClick={handleSave} disabled={isPending}>
277
- <Save className="mr-2 h-4 w-4" />
276
+ <FormActions>
277
+ <Button type="button" size="sm" onClick={handleSave} disabled={isPending}>
278
+ <Save className="mr-1.5 h-3.5 w-3.5" />
278
279
  {isPending ? t('saving') : t('save')}
279
280
  </Button>
280
- </div>
281
+ </FormActions>
281
282
  </PageLayout>
282
283
  );
283
284
  }
@@ -3,13 +3,14 @@ import { Card } from '@/shared/components/ui/card';
3
3
  import { Input } from '@/shared/components/ui/input';
4
4
  import { Label } from '@/shared/components/ui/label';
5
5
  import { Skeleton } from '@/shared/components/ui/skeleton';
6
+ import { FormActions } from '@/shared/components/ui/actions/form-actions';
6
7
  import { ProviderScopedModelInput } from '@/shared/components/common/provider-scoped-model-input';
7
8
  import { useConfig, useConfigSchema, useProviderTemplates, useProviders, useUpdateModel } from '@/shared/hooks/use-config';
8
9
  import { hintForPath } from '@/shared/lib/config-hints';
9
10
  import { t } from '@/shared/lib/i18n';
10
11
  import { buildProviderModelCatalog } from '@/shared/lib/provider-models';
11
12
  import { PageLayout, PageHeader } from '@/app/components/layout/page-layout';
12
- import { DOCS_DEFAULT_BASE_URL } from '@/shared/components/doc-browser/doc-browser-context';
13
+ import { getDocsUrl } from '@/shared/components/doc-browser/doc-browser-context';
13
14
  import { BookOpen, Folder, Loader2, Sparkles } from 'lucide-react';
14
15
  import { useMemo, useState } from 'react';
15
16
 
@@ -37,48 +38,48 @@ function ModelConfigForm(props: {
37
38
  event.preventDefault();
38
39
  onSubmit({ model, workspace });
39
40
  }}
40
- className="space-y-8"
41
+ className="space-y-5"
41
42
  >
42
- <div className="grid grid-cols-1 gap-8 md:grid-cols-2">
43
- <div className="rounded-2xl border border-gray-200 bg-white p-8 shadow-card">
44
- <div className="mb-8 flex items-center gap-4">
45
- <div className="flex h-10 w-10 items-center justify-center rounded-xl bg-primary text-white">
46
- <Sparkles className="h-5 w-5" />
43
+ <div className="grid grid-cols-1 gap-5 md:grid-cols-2">
44
+ <div className="rounded-2xl border border-border/75 bg-card p-6">
45
+ <div className="mb-6 flex items-center gap-3">
46
+ <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-muted text-muted-foreground">
47
+ <Sparkles className="h-4 w-4" />
47
48
  </div>
48
- <h3 className="text-lg font-bold text-gray-900">{t('defaultModel')}</h3>
49
+ <h3 className="text-base font-semibold text-foreground">{t('defaultModel')}</h3>
49
50
  </div>
50
51
  <div className="space-y-2">
51
- <Label htmlFor="model" className="text-xs font-semibold uppercase tracking-wider text-gray-500">
52
+ <Label htmlFor="model" className="text-xs font-medium text-muted-foreground">
52
53
  {modelLabel}
53
54
  </Label>
54
55
  <ProviderScopedModelInput id="model" value={model} onChange={setModel} providerCatalog={providerCatalog} modelPlaceholder={modelPlaceholder} />
55
- <p className="text-xs text-gray-400">{modelHelpText}</p>
56
- <a href={`${DOCS_DEFAULT_BASE_URL}/guide/model-selection`} className="inline-flex items-center gap-1.5 text-xs text-primary transition-colors hover:text-primary-hover">
56
+ <p className="text-xs text-muted-foreground/80">{modelHelpText}</p>
57
+ <a href={getDocsUrl('/guide/model-selection')} className="inline-flex items-center gap-1.5 text-xs text-primary transition-colors hover:text-primary-hover">
57
58
  <BookOpen className="h-3.5 w-3.5" />
58
59
  {t('channelsGuideTitle')}
59
60
  </a>
60
61
  </div>
61
62
  </div>
62
- <div className="rounded-2xl border border-gray-200 bg-white p-8 shadow-card">
63
- <div className="mb-8 flex items-center gap-4">
64
- <div className="flex h-10 w-10 items-center justify-center rounded-xl bg-primary text-white">
65
- <Folder className="h-5 w-5" />
63
+ <div className="rounded-2xl border border-border/75 bg-card p-6">
64
+ <div className="mb-6 flex items-center gap-3">
65
+ <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-muted text-muted-foreground">
66
+ <Folder className="h-4 w-4" />
66
67
  </div>
67
- <h3 className="text-lg font-bold text-gray-900">{t('workspace')}</h3>
68
+ <h3 className="text-base font-semibold text-foreground">{t('workspace')}</h3>
68
69
  </div>
69
70
  <div className="space-y-2">
70
- <Label htmlFor="workspace" className="text-xs font-semibold uppercase tracking-wider text-gray-500">
71
+ <Label htmlFor="workspace" className="text-xs font-medium text-muted-foreground">
71
72
  {workspaceLabel}
72
73
  </Label>
73
74
  <Input id="workspace" value={workspace} onChange={(event) => setWorkspace(event.target.value)} placeholder={workspacePlaceholder} className="rounded-xl" />
74
75
  </div>
75
76
  </div>
76
77
  </div>
77
- <div className="flex justify-end pt-4">
78
- <Button type="submit" disabled={isPending} size="lg">
79
- {isPending ? <Loader2 className="h-5 w-5 animate-spin" /> : t('saveChanges')}
78
+ <FormActions>
79
+ <Button type="submit" disabled={isPending} size="sm">
80
+ {isPending ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : t('saveChanges')}
80
81
  </Button>
81
- </div>
82
+ </FormActions>
82
83
  </form>
83
84
  );
84
85
  }
@@ -108,9 +109,9 @@ export function ModelConfigPage() {
108
109
  <Skeleton className="h-8 w-32" />
109
110
  <Skeleton className="h-4 w-48" />
110
111
  </div>
111
- <Card className="rounded-2xl border-gray-200 p-6">
112
- <div className="mb-6 flex items-center gap-4">
113
- <Skeleton className="h-12 w-12 rounded-xl" />
112
+ <Card hover={false} className="rounded-2xl border-border/75 p-6 shadow-none">
113
+ <div className="mb-6 flex items-center gap-3">
114
+ <Skeleton className="h-9 w-9 rounded-lg" />
114
115
  <div className="space-y-2">
115
116
  <Skeleton className="h-5 w-24" />
116
117
  <Skeleton className="h-3 w-32" />
@@ -119,7 +120,7 @@ export function ModelConfigPage() {
119
120
  <Skeleton className="mb-2 h-4 w-20" />
120
121
  <Skeleton className="h-10 w-full rounded-xl" />
121
122
  </Card>
122
- <Card className="rounded-2xl border-gray-200 p-6">
123
+ <Card hover={false} className="rounded-2xl border-border/75 p-6 shadow-none">
123
124
  <Skeleton className="mb-2 h-5 w-24" />
124
125
  <Skeleton className="h-10 w-full rounded-xl" />
125
126
  </Card>
@@ -137,7 +137,7 @@ export function ProvidersConfigPage() {
137
137
  <div className="grid max-h-[24rem] grid-cols-2 gap-2 overflow-y-auto sm:grid-cols-3">
138
138
  <button
139
139
  type="button"
140
- className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-dashed border-border bg-card px-3 py-2 text-left transition-colors hover:border-primary/40 hover:bg-accent/70"
140
+ className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-dashed border-border/70 bg-muted/20 px-3 py-2 text-left transition-colors hover:border-border hover:bg-muted/45"
141
141
  onClick={async () => {
142
142
  try {
143
143
  const result = await createProvider.mutateAsync({ data: { providerType: null } });
@@ -150,7 +150,7 @@ export function ProvidersConfigPage() {
150
150
  }
151
151
  }}
152
152
  >
153
- <LogoBadge name="custom" className="h-8 w-8 rounded-lg border border-border bg-background" />
153
+ <LogoBadge name="custom" className="h-8 w-8 rounded-lg border border-border/60 bg-muted/50" />
154
154
  <span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-foreground">
155
155
  {t('providerAddCustom')}
156
156
  </span>
@@ -159,7 +159,7 @@ export function ProvidersConfigPage() {
159
159
  <button
160
160
  key={template.providerType}
161
161
  type="button"
162
- className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-border bg-card px-3 py-2 text-left transition-colors hover:border-primary/40 hover:bg-accent/70"
162
+ className="flex min-h-20 w-full flex-col items-start gap-2 rounded-lg border border-border/55 bg-muted/15 px-3 py-2 text-left transition-colors hover:border-border/80 hover:bg-muted/40"
163
163
  onClick={async () => {
164
164
  try {
165
165
  const result = await createProvider.mutateAsync({ data: { providerType: template.providerType } });
@@ -175,7 +175,7 @@ export function ProvidersConfigPage() {
175
175
  <LogoBadge
176
176
  name={template.providerType}
177
177
  src={template.logo ? `/logos/${template.logo}` : null}
178
- className="h-8 w-8 rounded-lg border border-border bg-background"
178
+ className="h-8 w-8 rounded-lg border border-border/55 bg-background"
179
179
  imgClassName="h-4 w-4 object-contain"
180
180
  />
181
181
  <span className="line-clamp-2 min-w-0 text-xs font-semibold leading-4 text-foreground">
@@ -221,10 +221,10 @@ export function ProvidersConfigPage() {
221
221
  role="button"
222
222
  tabIndex={0}
223
223
  className={cn(
224
- 'w-full rounded-xl border p-2.5 text-left transition-all',
224
+ 'group w-full rounded-xl border p-2.5 text-left transition-colors',
225
225
  resolvedSelectedProvider === provider.providerId
226
- ? 'border-primary/35 bg-primary-50/45 text-foreground shadow-sm'
227
- : 'border-border bg-card text-muted-foreground hover:border-primary/35 hover:bg-accent/70 hover:text-accent-foreground',
226
+ ? 'border-border/70 bg-muted/65 text-foreground'
227
+ : 'border-transparent bg-transparent text-muted-foreground hover:border-border/50 hover:bg-muted/40 hover:text-foreground',
228
228
  )}
229
229
  >
230
230
  <div className="relative min-h-10">
@@ -232,10 +232,7 @@ export function ProvidersConfigPage() {
232
232
  <LogoBadge
233
233
  name={provider.providerType ?? provider.providerId}
234
234
  src={template?.logo ? `/logos/${template.logo}` : null}
235
- className={cn(
236
- 'h-10 w-10 rounded-lg border',
237
- isReady ? 'border-primary/35 bg-background' : 'border-border bg-background',
238
- )}
235
+ className="h-10 w-10 rounded-lg border border-border/55 bg-muted/40"
239
236
  imgClassName="h-5 w-5 object-contain"
240
237
  fallback={<span className="text-sm font-semibold uppercase text-muted-foreground">{provider.providerId[0]}</span>}
241
238
  />
@@ -247,7 +244,7 @@ export function ProvidersConfigPage() {
247
244
  </p>
248
245
  </div>
249
246
  </div>
250
- <div className="absolute right-0 top-0 flex items-center gap-1.5">
247
+ <div className="absolute right-0 top-0 flex items-center gap-1.5 opacity-70 transition-opacity group-hover:opacity-100">
251
248
  <div onClick={(event) => event.stopPropagation()}>
252
249
  <Switch
253
250
  checked={isEnabled}
@@ -268,7 +265,7 @@ export function ProvidersConfigPage() {
268
265
  <PopoverTrigger asChild>
269
266
  <button
270
267
  type="button"
271
- className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-muted-foreground/70 hover:bg-accent hover:text-accent-foreground"
268
+ className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-muted-foreground/70 hover:bg-muted hover:text-foreground"
272
269
  onClick={(event) => event.stopPropagation()}
273
270
  title={t('more')}
274
271
  >
@@ -2,6 +2,7 @@ import { useState } from "react";
2
2
  import { ExternalLink, KeyRound, Search as SearchIcon } from "lucide-react";
3
3
  import { PageHeader, PageLayout } from "@/app/components/layout/page-layout";
4
4
  import { Button } from "@/shared/components/ui/button";
5
+ import { FormActions } from "@/shared/components/ui/actions/form-actions";
5
6
  import { Input } from "@/shared/components/ui/input";
6
7
  import { Label } from "@/shared/components/ui/label";
7
8
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/shared/components/ui/select";
@@ -456,11 +457,13 @@ function SearchConfigForm(props: {
456
457
  />
457
458
  </ConfigSplitPaneBody>
458
459
 
459
- <ConfigSplitPaneFooter className="flex justify-end px-6 py-4">
460
- <Button type="submit" disabled={isPending}>
461
- <KeyRound className="mr-2 h-4 w-4" />
462
- {isPending ? t("saving") : t("saveChanges")}
463
- </Button>
460
+ <ConfigSplitPaneFooter>
461
+ <FormActions>
462
+ <Button type="submit" size="sm" disabled={isPending}>
463
+ <KeyRound className="mr-1.5 h-3.5 w-3.5" />
464
+ {isPending ? t("saving") : t("saveChanges")}
465
+ </Button>
466
+ </FormActions>
464
467
  </ConfigSplitPaneFooter>
465
468
  </form>
466
469
  </ConfigSplitDetailPane>
@@ -95,7 +95,7 @@ function SideDockButton({
95
95
  onClick={() => onOpen(item)}
96
96
  className={cn(
97
97
  'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors',
98
- 'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
98
+ 'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
99
99
  active
100
100
  ? 'bg-primary/10 text-primary'
101
101
  : 'bg-transparent',
@@ -113,7 +113,7 @@ function SideDockButton({
113
113
  event.stopPropagation();
114
114
  onUnpin(item);
115
115
  }}
116
- className="absolute -right-1 -top-1 hidden h-4 w-4 items-center justify-center rounded-full bg-background text-muted-foreground shadow-sm ring-1 ring-border/70 transition-colors hover:bg-muted hover:text-foreground group-hover:flex focus-visible:flex focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
116
+ className="absolute -right-1 -top-1 hidden h-4 w-4 items-center justify-center rounded-full bg-background text-muted-foreground shadow-sm ring-1 ring-border/70 transition-colors hover:bg-muted hover:text-foreground group-hover:flex focus-visible:flex focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
117
117
  >
118
118
  <X className="h-3 w-3" aria-hidden="true" />
119
119
  </button>
@@ -144,7 +144,7 @@ function SideDockActionButton({
144
144
  onClick={onClick}
145
145
  className={cn(
146
146
  'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors',
147
- 'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
147
+ 'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
148
148
  )}
149
149
  >
150
150
  <Icon className="h-5 w-5" aria-hidden="true" />
@@ -2,6 +2,7 @@ import { useMemo, useState } from 'react';
2
2
  import { Save } from 'lucide-react';
3
3
  import type { ConfigView, RuntimeConfigUpdate } from '@/shared/lib/api';
4
4
  import { Button } from '@/shared/components/ui/button';
5
+ import { FormActions } from '@/shared/components/ui/actions/form-actions';
5
6
  import { PageLayout } from '@/app/components/layout/page-layout';
6
7
  import { t } from '@/shared/lib/i18n';
7
8
  import { RuntimeConfigOverview } from '@/features/system-status/components/config/runtime-config-overview';
@@ -111,12 +112,12 @@ export function RuntimeConfigEditor({
111
112
  onRemoveBinding={(index) => setBindings((previous) => previous.filter((_, cursor) => cursor !== index))}
112
113
  onAddBinding={() => setBindings((previous) => [...previous, createEmptyRuntimeBinding()])}
113
114
  />
114
- <div className="flex justify-end">
115
- <Button type="button" onClick={handleSave} disabled={updateRuntime.isPending}>
116
- <Save className="h-4 w-4 mr-2" />
115
+ <FormActions>
116
+ <Button type="button" size="sm" onClick={handleSave} disabled={updateRuntime.isPending}>
117
+ <Save className="mr-1.5 h-3.5 w-3.5" />
117
118
  {updateRuntime.isPending ? t('saving') : t('saveRuntimeSettings')}
118
119
  </Button>
119
- </div>
120
+ </FormActions>
120
121
  </PageLayout>
121
122
  );
122
123
  }