@nextclaw/ui 0.14.2 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/assets/{api-a14tR_z1.js → api-BP_8IaxB.js} +3 -3
- package/dist/assets/{channels-list-page-CFGkm4DT.js → channels-list-page-DEh5Jjqx.js} +1 -1
- package/dist/assets/chat-page-BRB0N5WW.js +105 -0
- package/dist/assets/config-split-page-CRhlZ_pH.js +1 -0
- package/dist/assets/{confirm-dialog-ClH_Ec7n.js → confirm-dialog-DsivFJ4r.js} +2 -2
- package/dist/assets/{desktop-update-config-DPNDnVpk.js → desktop-update-config-B0w9p2ep.js} +1 -1
- package/dist/assets/{dist-BtCS2Ucq.js → dist-CikkhOlq.js} +1 -1
- package/dist/assets/{dist-CLGGLm8b.js → dist-PVA_xL1D.js} +1 -1
- package/dist/assets/doc-browser-BoNJ7-tE.js +1 -0
- package/dist/assets/doc-browser-CdJ_d4ik.js +1 -0
- package/dist/assets/{doc-browser-context-D4JwMMxK.js → doc-browser-context-MTw4EvKd.js} +1 -1
- package/dist/assets/{ellipsis-CtJXjIol.js → ellipsis-y6vDtq4M.js} +1 -1
- package/dist/assets/{external-link-CdJiG13p.js → external-link-DVJIQf_G.js} +1 -1
- package/dist/assets/index-BiE-K8-q.css +1 -0
- package/dist/assets/index-D9BAE_L_.js +105 -0
- package/dist/assets/{mcp-marketplace-page-BU0kIjhR.js → mcp-marketplace-page-B1SZNY5m.js} +1 -1
- package/dist/assets/mcp-marketplace-page-Cq_Tw42T.js +1 -0
- package/dist/assets/{model-config-page-D6hYXROd.js → model-config-page-DotaTUHb.js} +1 -1
- package/dist/assets/plus-BbZqquJe.js +1 -0
- package/dist/assets/{provider-scoped-model-input-DAX2HgmR.js → provider-scoped-model-input-DsFRuWJH.js} +1 -1
- package/dist/assets/providers-config-page-DW4tQSLN.js +1 -0
- package/dist/assets/{react-C6cZgP44.js → react-VNqT5Zp7.js} +1 -1
- package/dist/assets/remote-B8TiUfwW.js +1 -0
- package/dist/assets/rotate-cw-DjHDTkCv.js +1 -0
- package/dist/assets/{runtime-config-page-C5xKaV3i.js → runtime-config-page-S6ErRHR8.js} +1 -1
- package/dist/assets/{save-DKA0x4zk.js → save-BOJ477H-.js} +1 -1
- package/dist/assets/{search-BNlcoj5c.js → search-BEti5beA.js} +1 -1
- package/dist/assets/{search-config-page-Cq9uJ-N8.js → search-config-page-DGj5am03.js} +1 -1
- package/dist/assets/{secrets-config-page-CxSbZLBo.js → secrets-config-page--IzrIOid.js} +1 -1
- package/dist/assets/{select-CvTlDZTQ.js → select-hoj8dK4K.js} +2 -2
- package/dist/assets/{tag-chip-8ffF2y2C.js → tag-chip-T8-h-die.js} +1 -1
- package/dist/assets/{use-config-DmT0o1gv.js → use-config-CjRV2hwL.js} +1 -1
- package/dist/assets/x-D9PXs_xP.js +1 -0
- package/dist/index.html +69 -19
- package/index.html +55 -5
- package/package.json +7 -7
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +3 -3
- package/src/app/components/layout/header.tsx +3 -3
- package/src/app/components/layout/page-layout.tsx +2 -2
- package/src/app/components/layout/runtime-status-entry.tsx +7 -7
- package/src/app/components/layout/sidebar-items.tsx +10 -10
- package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
- package/src/app/components/layout/sidebar.tsx +6 -6
- package/src/app/styles/design-system.css +388 -26
- package/src/app/test/vitest-setup.ts +31 -0
- package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +3 -3
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +4 -2
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +1 -1
- package/src/features/chat/components/conversation/chat-conversation-header.tsx +7 -6
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
- package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +13 -13
- package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +2 -2
- package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +3 -3
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +14 -14
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +15 -15
- package/src/features/chat/components/layout/chat-sidebar.tsx +3 -3
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +225 -0
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +199 -0
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +28 -9
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +18 -6
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +3 -13
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +19 -3
- package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +7 -7
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +6 -6
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -5
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +4 -4
- package/src/features/chat/features/session/components/session-context-icon.tsx +2 -2
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +2 -2
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
- package/src/features/chat/features/session/components/session-run-badge.tsx +1 -1
- package/src/features/chat/features/session-type/hooks/use-chat-session-type-state.ts +10 -2
- package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +0 -7
- package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +3 -3
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +4 -4
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +14 -19
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +3 -3
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +4 -4
- package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +6 -8
- package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +1 -16
- package/src/features/panel-apps/components/panel-app-list-item.tsx +8 -8
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +4 -4
- package/src/features/panel-apps/components/panel-apps-list.tsx +20 -20
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +70 -6
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +10 -5
- package/src/features/service-apps/components/service-action-authorization-dialog.tsx +8 -8
- package/src/features/service-apps/components/service-apps-panel.tsx +24 -24
- package/src/features/settings/components/config/provider-advanced-settings-section.tsx +5 -5
- package/src/features/settings/components/config/provider-auth-section.tsx +7 -7
- package/src/features/settings/components/config/provider-form.tsx +10 -10
- package/src/features/settings/components/config/provider-models-section.tsx +16 -16
- package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
- package/src/features/settings/pages/providers-config-page.tsx +17 -17
- package/src/shared/components/config-split-page.tsx +11 -11
- package/src/shared/components/doc-browser/doc-browser-home-page.tsx +2 -2
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +4 -4
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +4 -4
- package/src/shared/components/doc-browser/doc-browser.tsx +3 -3
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +1 -1
- package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
- package/src/shared/components/ui/button.tsx +4 -4
- package/src/shared/components/ui/card.tsx +4 -4
- package/src/shared/components/ui/dialog.tsx +5 -5
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/label.tsx +1 -1
- package/src/shared/components/ui/popover.tsx +1 -1
- package/src/shared/components/ui/select.tsx +3 -3
- package/src/shared/components/ui/switch.tsx +3 -3
- package/src/shared/components/ui/tabs.tsx +4 -4
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/lib/i18n/locales/en-US/core.json +7 -2
- package/src/shared/lib/i18n/locales/zh-CN/core.json +7 -2
- package/src/shared/lib/theme/index.ts +94 -52
- package/dist/assets/chat-page-CEdavJXc.js +0 -105
- package/dist/assets/config-split-page-B5b9B0uE.js +0 -1
- package/dist/assets/doc-browser-5nMWYKBD.js +0 -1
- package/dist/assets/doc-browser-BJRLhztv.js +0 -1
- package/dist/assets/index-BDN1zzMQ.js +0 -105
- package/dist/assets/index-g3uSZXoc.css +0 -1
- package/dist/assets/mcp-marketplace-page-sMNFSq_T.js +0 -1
- package/dist/assets/plus-DPjb0piO.js +0 -1
- package/dist/assets/providers-config-page-BzAeaACA.js +0 -1
- package/dist/assets/remote-B0G80uPr.js +0 -1
- package/dist/assets/rotate-cw-DnEB1Rju.js +0 -1
- package/dist/assets/x-BiSSpgqB.js +0 -1
|
@@ -22,7 +22,10 @@ import {
|
|
|
22
22
|
} from '@/features/chat/features/conversation/hooks/use-session-conversation-controller';
|
|
23
23
|
import { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
|
|
24
24
|
import { useSessionConversationInputState } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-state';
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
SessionConversationInput,
|
|
27
|
+
type SessionConversationInputController,
|
|
28
|
+
} from './session-conversation-input';
|
|
26
29
|
|
|
27
30
|
type SessionConversationAreaProps = {
|
|
28
31
|
readonly consumeDraftIntent?: boolean;
|
|
@@ -226,14 +229,31 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
226
229
|
restoreComposer: inputActions.restoreComposer,
|
|
227
230
|
setSendError: inputActions.setSendError,
|
|
228
231
|
});
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
232
|
+
const controllerRef = useRef(controller);
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
controllerRef.current = controller;
|
|
235
|
+
}, [controller]);
|
|
236
|
+
const inputController = useMemo<SessionConversationInputController>(() => ({
|
|
237
|
+
canStopGeneration: controller.canStopGeneration,
|
|
238
|
+
isSending: controller.isSending,
|
|
239
|
+
send: () => controllerRef.current.send(),
|
|
240
|
+
sendDisabled: controller.sendDisabled,
|
|
241
|
+
stop: () => controllerRef.current.stop(),
|
|
242
|
+
stopDisabled: controller.stopDisabled,
|
|
243
|
+
}), [
|
|
244
|
+
controller.canStopGeneration,
|
|
245
|
+
controller.isSending,
|
|
246
|
+
controller.sendDisabled,
|
|
247
|
+
controller.stopDisabled,
|
|
248
|
+
]);
|
|
233
249
|
const contextWindow = useMemo(
|
|
234
250
|
() => buildChatContextWindowIndicator(readNcpContextWindowValue(agent.snapshot.contextWindow)),
|
|
235
251
|
[agent.snapshot.contextWindow],
|
|
236
252
|
);
|
|
253
|
+
const displayInputSnapshot = useMemo(() => ({
|
|
254
|
+
...inputSnapshot,
|
|
255
|
+
sendError: lastSendError ?? inputSnapshot.sendError,
|
|
256
|
+
}), [inputSnapshot, lastSendError]);
|
|
237
257
|
useSessionConversationDraftIntent({
|
|
238
258
|
consumeDraftIntent,
|
|
239
259
|
applyPromptSuggestion: inputActions.applyPromptSuggestion,
|
|
@@ -241,7 +261,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
241
261
|
const renderInput = useCallback((surface: 'default' | 'embedded') => (
|
|
242
262
|
<SessionConversationInput
|
|
243
263
|
contextWindow={contextWindow}
|
|
244
|
-
controller={
|
|
264
|
+
controller={inputController}
|
|
245
265
|
inputActions={inputActions}
|
|
246
266
|
inputQuery={inputQuery}
|
|
247
267
|
inputSnapshot={displayInputSnapshot}
|
|
@@ -249,8 +269,8 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
249
269
|
/>
|
|
250
270
|
), [
|
|
251
271
|
contextWindow,
|
|
252
|
-
controller,
|
|
253
272
|
displayInputSnapshot,
|
|
273
|
+
inputController,
|
|
254
274
|
inputActions,
|
|
255
275
|
inputQuery,
|
|
256
276
|
]);
|
|
@@ -258,8 +278,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
258
278
|
showWelcomeForDraft &&
|
|
259
279
|
!sessionKey &&
|
|
260
280
|
agent.visibleMessages.length === 0 &&
|
|
261
|
-
!agent.isHydrating
|
|
262
|
-
!controller.isSending;
|
|
281
|
+
!agent.isHydrating;
|
|
263
282
|
|
|
264
283
|
return (
|
|
265
284
|
<>
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
+
memo,
|
|
2
3
|
useCallback,
|
|
3
4
|
useEffect,
|
|
4
5
|
useMemo,
|
|
5
6
|
useRef,
|
|
6
7
|
} from 'react';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ChatInputBar,
|
|
10
|
+
type ChatContextWindowIndicator,
|
|
11
|
+
type ChatInputBarHandle,
|
|
12
|
+
} from '@nextclaw/agent-chat-ui';
|
|
8
13
|
import { isRuntimeDefaultModelValue } from '@nextclaw/shared';
|
|
9
14
|
|
|
10
15
|
import { useI18n } from '@/app/components/i18n-provider';
|
|
@@ -43,7 +48,6 @@ import {
|
|
|
43
48
|
CHAT_RECENT_SKILLS_MIN_OPTIONS,
|
|
44
49
|
} from '@/features/chat/managers/chat-recent-skills.manager';
|
|
45
50
|
|
|
46
|
-
import type { useSessionConversationController } from '@/features/chat/features/conversation/hooks/use-session-conversation-controller';
|
|
47
51
|
import { useSessionConversationInputAttachments } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-attachments';
|
|
48
52
|
import type { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
|
|
49
53
|
import type {
|
|
@@ -57,7 +61,15 @@ import {
|
|
|
57
61
|
} from '@/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils';
|
|
58
62
|
|
|
59
63
|
type SessionConversationInputQuery = ReturnType<typeof useSessionConversationInputQuery>;
|
|
60
|
-
|
|
64
|
+
|
|
65
|
+
export type SessionConversationInputController = {
|
|
66
|
+
readonly canStopGeneration: boolean;
|
|
67
|
+
readonly isSending: boolean;
|
|
68
|
+
readonly sendDisabled: boolean;
|
|
69
|
+
readonly stopDisabled: boolean;
|
|
70
|
+
readonly send: () => Promise<void> | void;
|
|
71
|
+
readonly stop: () => Promise<void> | void;
|
|
72
|
+
};
|
|
61
73
|
|
|
62
74
|
function toSkillRecords(
|
|
63
75
|
snapshotRecords: SessionSkillEntryView[],
|
|
@@ -150,14 +162,14 @@ function useSessionConversationInputCollections(params: {
|
|
|
150
162
|
|
|
151
163
|
type SessionConversationInputProps = {
|
|
152
164
|
readonly contextWindow: ChatContextWindowIndicator | null;
|
|
153
|
-
readonly controller:
|
|
165
|
+
readonly controller: SessionConversationInputController;
|
|
154
166
|
readonly inputActions: SessionConversationInputActions;
|
|
155
167
|
readonly inputQuery: SessionConversationInputQuery;
|
|
156
168
|
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
157
169
|
readonly surface?: 'default' | 'embedded';
|
|
158
170
|
};
|
|
159
171
|
|
|
160
|
-
export function SessionConversationInput(props: SessionConversationInputProps) {
|
|
172
|
+
export const SessionConversationInput = memo(function SessionConversationInput(props: SessionConversationInputProps) {
|
|
161
173
|
const {
|
|
162
174
|
contextWindow,
|
|
163
175
|
controller,
|
|
@@ -424,4 +436,4 @@ export function SessionConversationInput(props: SessionConversationInputProps) {
|
|
|
424
436
|
/>
|
|
425
437
|
</>
|
|
426
438
|
);
|
|
427
|
-
}
|
|
439
|
+
});
|
package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts
CHANGED
|
@@ -55,18 +55,6 @@ const resolveModelForSend = (value: string | null | undefined): string | undefin
|
|
|
55
55
|
return trimmed || undefined;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
const resolveProjectRootForSend = (params: {
|
|
59
|
-
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
60
|
-
readonly inputQuery: SessionConversationInputQuery;
|
|
61
|
-
readonly sessionKey: string | null;
|
|
62
|
-
}): string | null => {
|
|
63
|
-
const { inputSnapshot, inputQuery, sessionKey } = params;
|
|
64
|
-
if (!sessionKey) {
|
|
65
|
-
return inputSnapshot.pendingProjectRoot ?? inputQuery.defaultProjectRoot ?? null;
|
|
66
|
-
}
|
|
67
|
-
return inputQuery.selectedSession?.projectRoot ?? null;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
58
|
export function useSessionConversationController(params: UseSessionConversationControllerParams) {
|
|
71
59
|
const {
|
|
72
60
|
agent,
|
|
@@ -135,7 +123,9 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
135
123
|
: inputQuery.sessionTypeState.selectedSessionType,
|
|
136
124
|
projectRoot: materializationContext
|
|
137
125
|
? inputSnapshot.pendingProjectRoot
|
|
138
|
-
:
|
|
126
|
+
: sessionKey
|
|
127
|
+
? inputQuery.selectedSession?.projectRoot ?? null
|
|
128
|
+
: inputSnapshot.pendingProjectRoot,
|
|
139
129
|
requestedSkills: [...inputSnapshot.selectedSkills],
|
|
140
130
|
composerNodes: [...inputSnapshot.nodes],
|
|
141
131
|
sessionMaterialization: materializationContext
|
package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts
CHANGED
|
@@ -119,9 +119,25 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
|
|
|
119
119
|
[selectedSessionKey, sessionTypeState.selectedSessionType, sessions],
|
|
120
120
|
);
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
const defaultProjectRoot = normalizeSessionProjectRootValue(
|
|
123
|
+
config?.agents.defaults.workspace,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
return useMemo(() => ({
|
|
123
127
|
defaultModel: config?.agents.defaults.model,
|
|
124
|
-
defaultProjectRoot
|
|
128
|
+
defaultProjectRoot,
|
|
129
|
+
fallbackPreferredModel,
|
|
130
|
+
fallbackPreferredThinking,
|
|
131
|
+
isProviderStateResolved,
|
|
132
|
+
isSkillsLoading,
|
|
133
|
+
modelOptions,
|
|
134
|
+
selectedSession,
|
|
135
|
+
selectedSessionKey,
|
|
136
|
+
sessionTypeState,
|
|
137
|
+
skillRecords,
|
|
138
|
+
}), [
|
|
139
|
+
config?.agents.defaults.model,
|
|
140
|
+
defaultProjectRoot,
|
|
125
141
|
fallbackPreferredModel,
|
|
126
142
|
fallbackPreferredThinking,
|
|
127
143
|
isProviderStateResolved,
|
|
@@ -131,5 +147,5 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
|
|
|
131
147
|
selectedSessionKey,
|
|
132
148
|
sessionTypeState,
|
|
133
149
|
skillRecords,
|
|
134
|
-
|
|
150
|
+
]);
|
|
135
151
|
}
|
|
@@ -77,28 +77,28 @@ export function ChatInlinePanelAppCard({
|
|
|
77
77
|
if (!url) {
|
|
78
78
|
return (
|
|
79
79
|
<div
|
|
80
|
-
className="h-[320px] min-h-[220px] w-full animate-pulse rounded-lg border border-
|
|
80
|
+
className="h-[320px] min-h-[220px] w-full animate-pulse rounded-lg border border-border bg-muted/45"
|
|
81
81
|
style={{ maxHeight: PANEL_APP_INLINE_CARD_MAX_HEIGHT_PX }}
|
|
82
82
|
/>
|
|
83
83
|
);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
return (
|
|
87
|
-
<div className="w-full max-w-[42rem] overflow-hidden rounded-lg border border-
|
|
88
|
-
<div className="flex h-9 items-center justify-between gap-2 border-b border-
|
|
89
|
-
<div className="flex min-w-0 items-center gap-2 text-xs font-medium text-
|
|
87
|
+
<div className="w-full max-w-[42rem] overflow-hidden rounded-lg border border-border bg-card shadow-sm">
|
|
88
|
+
<div className="flex h-9 items-center justify-between gap-2 border-b border-border bg-muted/45 px-2.5">
|
|
89
|
+
<div className="flex min-w-0 items-center gap-2 text-xs font-medium text-foreground">
|
|
90
90
|
<AppWindow className="h-3.5 w-3.5 shrink-0 text-primary" />
|
|
91
91
|
<span className="truncate">{title}</span>
|
|
92
92
|
</div>
|
|
93
93
|
<IconActionButton
|
|
94
|
-
className="h-7 w-7 rounded-md text-
|
|
94
|
+
className="h-7 w-7 rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
95
95
|
icon={<Maximize2 className="h-3.5 w-3.5" />}
|
|
96
96
|
label={t('chatPanelCardExpand')}
|
|
97
97
|
onClick={openExpanded}
|
|
98
98
|
/>
|
|
99
99
|
</div>
|
|
100
100
|
<div
|
|
101
|
-
className="relative h-[420px] min-h-[220px] max-h-[min(60vh,420px)] overflow-hidden bg-
|
|
101
|
+
className="relative h-[420px] min-h-[220px] max-h-[min(60vh,420px)] overflow-hidden bg-card"
|
|
102
102
|
>
|
|
103
103
|
<iframe
|
|
104
104
|
ref={iframeRef}
|
|
@@ -107,7 +107,7 @@ export function ChatInlinePanelAppCard({
|
|
|
107
107
|
title={title}
|
|
108
108
|
sandbox={PANEL_APP_INLINE_IFRAME_SANDBOX}
|
|
109
109
|
scrolling="auto"
|
|
110
|
-
className="h-full w-full border-0 bg-
|
|
110
|
+
className="h-full w-full border-0 bg-card"
|
|
111
111
|
/>
|
|
112
112
|
</div>
|
|
113
113
|
</div>
|
|
@@ -126,13 +126,13 @@ function ChatContextCompactionDivider({
|
|
|
126
126
|
`${t("chatContextCompactionProjectedTokens")}: ${checkpoint.projectedEstimatedTokens}`,
|
|
127
127
|
].join("\n");
|
|
128
128
|
return (
|
|
129
|
-
<div className="my-4 flex items-center gap-3 text-[11px] text-
|
|
130
|
-
<div className="h-px flex-1 bg-
|
|
131
|
-
<div className="inline-flex items-center gap-2 rounded-full border border-
|
|
129
|
+
<div className="my-4 flex items-center gap-3 text-[11px] text-muted-foreground" title={title}>
|
|
130
|
+
<div className="h-px flex-1 bg-border" />
|
|
131
|
+
<div className="inline-flex items-center gap-2 rounded-full border border-border bg-muted px-3 py-1">
|
|
132
132
|
{checkpoint.status === "compressing" ? (
|
|
133
|
-
<span className="h-1.5 w-1.5 rounded-full bg-
|
|
133
|
+
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-muted-foreground" />
|
|
134
134
|
) : (
|
|
135
|
-
<span className="h-1.5 w-1.5 rounded-full bg-
|
|
135
|
+
<span className="h-1.5 w-1.5 rounded-full bg-muted-foreground/45" />
|
|
136
136
|
)}
|
|
137
137
|
<span>
|
|
138
138
|
{checkpoint.status === "compressing"
|
|
@@ -140,7 +140,7 @@ function ChatContextCompactionDivider({
|
|
|
140
140
|
: t("chatContextCompactionCompressed")}
|
|
141
141
|
</span>
|
|
142
142
|
</div>
|
|
143
|
-
<div className="h-px flex-1 bg-
|
|
143
|
+
<div className="h-px flex-1 bg-border" />
|
|
144
144
|
</div>
|
|
145
145
|
);
|
|
146
146
|
}
|
|
@@ -49,12 +49,12 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
49
49
|
<div className="flex items-center justify-between gap-2 px-2 py-0.5">
|
|
50
50
|
<div className="flex min-w-0 items-center gap-1.5">
|
|
51
51
|
<div
|
|
52
|
-
className="truncate text-[11px] font-medium uppercase tracking-wider text-
|
|
52
|
+
className="truncate text-[11px] font-medium uppercase tracking-wider text-muted-foreground"
|
|
53
53
|
title={group.projectRoot}
|
|
54
54
|
>
|
|
55
55
|
{group.projectName}
|
|
56
56
|
</div>
|
|
57
|
-
<span className="shrink-0 text-[10px] text-
|
|
57
|
+
<span className="shrink-0 text-[10px] text-muted-foreground/70">
|
|
58
58
|
{group.items.length}
|
|
59
59
|
</span>
|
|
60
60
|
</div>
|
|
@@ -70,12 +70,12 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
70
70
|
icon={<Plus className="h-3.5 w-3.5" />}
|
|
71
71
|
label={actionLabel}
|
|
72
72
|
tooltip={false}
|
|
73
|
-
className="h-7 w-7 shrink-0 rounded-lg text-
|
|
73
|
+
className="h-7 w-7 shrink-0 rounded-lg text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
74
74
|
/>
|
|
75
75
|
</PopoverTrigger>
|
|
76
76
|
<PopoverContent
|
|
77
77
|
align="end"
|
|
78
|
-
className="w-56 rounded-2xl border border-
|
|
78
|
+
className="w-56 rounded-2xl border border-border bg-popover p-1.5 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
|
|
79
79
|
>
|
|
80
80
|
<ChatSessionTypeMenu
|
|
81
81
|
options={sessionTypeOptions}
|
|
@@ -91,7 +91,7 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
91
91
|
<IconActionButton
|
|
92
92
|
icon={<Plus className="h-3.5 w-3.5" />}
|
|
93
93
|
label={actionLabel}
|
|
94
|
-
className="h-7 w-7 shrink-0 rounded-lg text-
|
|
94
|
+
className="h-7 w-7 shrink-0 rounded-lg text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
95
95
|
onClick={() => onCreateSession(preferredSessionType, group.projectRoot)}
|
|
96
96
|
/>
|
|
97
97
|
)}
|
|
@@ -25,8 +25,8 @@ type ChatSidebarSessionListProps = {
|
|
|
25
25
|
function ChatSidebarEmptyState({ label }: { label: string }) {
|
|
26
26
|
return (
|
|
27
27
|
<div className="p-4 text-center">
|
|
28
|
-
<MessageSquareText className="mx-auto mb-2 h-6 w-6 text-
|
|
29
|
-
<div className="text-xs text-
|
|
28
|
+
<MessageSquareText className="mx-auto mb-2 h-6 w-6 text-muted-foreground/45" />
|
|
29
|
+
<div className="text-xs text-muted-foreground">{label}</div>
|
|
30
30
|
</div>
|
|
31
31
|
);
|
|
32
32
|
}
|
|
@@ -42,7 +42,7 @@ export function ChatSidebarSessionList({
|
|
|
42
42
|
sessionTypeOptions,
|
|
43
43
|
}: ChatSidebarSessionListProps) {
|
|
44
44
|
if (isLoading) {
|
|
45
|
-
return <div className="p-3 text-xs text-
|
|
45
|
+
return <div className="p-3 text-xs text-muted-foreground">{t("sessionsLoading")}</div>;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
if (isProjectFirstView) {
|
|
@@ -67,7 +67,7 @@ export function ChatSidebarSessionList({
|
|
|
67
67
|
<div className="space-y-3">
|
|
68
68
|
{groups.map((group) => (
|
|
69
69
|
<div key={group.label}>
|
|
70
|
-
<div className="px-2 py-1 text-[11px] font-medium uppercase tracking-wider text-
|
|
70
|
+
<div className="px-2 py-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground/70">
|
|
71
71
|
{group.label}
|
|
72
72
|
</div>
|
|
73
73
|
<div className="space-y-0.5">{group.items.map(renderSessionItem)}</div>
|
|
@@ -17,7 +17,7 @@ export function SessionContextIconNode({ icon, className }: { icon: SessionConte
|
|
|
17
17
|
src={runtimeIconSrc ?? undefined}
|
|
18
18
|
className={cn('h-[1.125rem] w-[1.125rem]', className)}
|
|
19
19
|
imgClassName="h-full w-full object-contain"
|
|
20
|
-
fallback={<Bot className={cn('h-3 w-3 text-
|
|
20
|
+
fallback={<Bot className={cn('h-3 w-3 text-muted-foreground', className)} />}
|
|
21
21
|
/>
|
|
22
22
|
);
|
|
23
23
|
}
|
|
@@ -34,7 +34,7 @@ function ChannelLogoIcon(
|
|
|
34
34
|
src={logoSrc}
|
|
35
35
|
className={cn('h-[1.125rem] w-[1.125rem]', className)}
|
|
36
36
|
imgClassName="h-full w-full object-contain"
|
|
37
|
-
fallback={<Bot className="h-3 w-3 text-
|
|
37
|
+
fallback={<Bot className="h-3 w-3 text-muted-foreground" />}
|
|
38
38
|
/>
|
|
39
39
|
);
|
|
40
40
|
}
|
|
@@ -58,8 +58,8 @@ describe('ChatSessionProjectBadge', () => {
|
|
|
58
58
|
renderProjectBadge();
|
|
59
59
|
|
|
60
60
|
const trigger = screen.getByRole('button', { name: 'Set Project Directory' });
|
|
61
|
-
expect(trigger.className).toContain('border-
|
|
62
|
-
expect(trigger.className).toContain('text-
|
|
61
|
+
expect(trigger.className).toContain('border-border');
|
|
62
|
+
expect(trigger.className).toContain('text-muted-foreground');
|
|
63
63
|
expect(trigger.className).not.toContain('emerald');
|
|
64
64
|
});
|
|
65
65
|
|
package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import { ChatSessionProjectDialog } from './chat-session-project-dialog';
|
|
|
9
9
|
import { t } from '@/shared/lib/i18n';
|
|
10
10
|
|
|
11
11
|
const SESSION_HEADER_ACTION_GROUP_CLASS = 'flex shrink-0 items-center gap-1.5';
|
|
12
|
-
const SESSION_HEADER_ACTION_BUTTON_CLASS = 'h-7 w-7 rounded-lg
|
|
12
|
+
const SESSION_HEADER_ACTION_BUTTON_CLASS = 'h-7 w-7 shrink-0 rounded-lg text-muted-foreground/70 hover:bg-accent hover:text-accent-foreground';
|
|
13
13
|
|
|
14
14
|
type ChatSessionHeaderActionsProps = {
|
|
15
15
|
sessionKey: string;
|
|
@@ -23,7 +23,7 @@ export function ChatSessionHeaderMenuItem({
|
|
|
23
23
|
'flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50',
|
|
24
24
|
destructive
|
|
25
25
|
? 'text-destructive hover:bg-destructive/10'
|
|
26
|
-
: 'text-
|
|
26
|
+
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
|
|
27
27
|
)}
|
|
28
28
|
onClick={onClick}
|
|
29
29
|
disabled={disabled}
|
|
@@ -29,7 +29,7 @@ export function ChatSessionMetadataDialog({
|
|
|
29
29
|
return (
|
|
30
30
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
31
31
|
<DialogContent className="max-w-2xl gap-0 overflow-hidden p-0">
|
|
32
|
-
<DialogHeader className="border-b border-
|
|
32
|
+
<DialogHeader className="border-b border-border px-5 py-4 pr-12">
|
|
33
33
|
<DialogTitle className="text-base">{t('chatSessionMetadataDialogTitle')}</DialogTitle>
|
|
34
34
|
<DialogDescription className="sr-only">
|
|
35
35
|
{t('chatSessionMetadataDialogDescription')}
|
package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx
CHANGED
|
@@ -55,7 +55,7 @@ export function ChatSessionProjectBadge({
|
|
|
55
55
|
<button
|
|
56
56
|
type="button"
|
|
57
57
|
title={projectRoot ?? undefined}
|
|
58
|
-
className="min-w-0 max-w-[320px] shrink rounded-full border border-
|
|
58
|
+
className="min-w-0 max-w-[320px] shrink rounded-full border border-border bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground transition-colors hover:border-primary/35 hover:bg-accent hover:text-accent-foreground disabled:cursor-not-allowed disabled:opacity-60"
|
|
59
59
|
aria-label={t('chatSessionSetProject')}
|
|
60
60
|
disabled={isProjectPending}
|
|
61
61
|
>
|
|
@@ -72,11 +72,11 @@ export function ChatSessionProjectBadge({
|
|
|
72
72
|
style={SESSION_PROJECT_MENU_STYLE}
|
|
73
73
|
>
|
|
74
74
|
<div className="px-3 pb-2 pt-1">
|
|
75
|
-
<div className="text-[11px] font-medium uppercase tracking-wider text-
|
|
75
|
+
<div className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
|
|
76
76
|
{projectName}
|
|
77
77
|
</div>
|
|
78
78
|
{projectRoot ? (
|
|
79
|
-
<div className="mt-1 break-all text-xs text-
|
|
79
|
+
<div className="mt-1 break-all text-xs text-muted-foreground">
|
|
80
80
|
{projectRoot}
|
|
81
81
|
</div>
|
|
82
82
|
) : null}
|
|
@@ -12,7 +12,7 @@ export function SessionRunBadge({ status, className }: SessionRunBadgeProps) {
|
|
|
12
12
|
const label = status === 'running' ? t('sessionsRunStatusRunning') : t('sessionsRunStatusQueued');
|
|
13
13
|
return (
|
|
14
14
|
<span
|
|
15
|
-
className={cn('inline-flex h-3.5 w-3.5 items-center justify-center text-
|
|
15
|
+
className={cn('inline-flex h-3.5 w-3.5 items-center justify-center text-muted-foreground/70', className)}
|
|
16
16
|
title={label}
|
|
17
17
|
aria-label={label}
|
|
18
18
|
>
|
|
@@ -128,7 +128,7 @@ export function useChatSessionTypeState(params: UseChatSessionTypeStateParams):
|
|
|
128
128
|
return null;
|
|
129
129
|
}, [availableSessionTypeSet, selectedSession, selectedSessionType, selectedSessionTypeOption]);
|
|
130
130
|
|
|
131
|
-
return {
|
|
131
|
+
return useMemo(() => ({
|
|
132
132
|
sessionTypeOptions,
|
|
133
133
|
selectedSessionTypeOption,
|
|
134
134
|
defaultSessionType,
|
|
@@ -136,5 +136,13 @@ export function useChatSessionTypeState(params: UseChatSessionTypeStateParams):
|
|
|
136
136
|
canEditSessionType,
|
|
137
137
|
sessionTypeUnavailable,
|
|
138
138
|
sessionTypeUnavailableMessage
|
|
139
|
-
}
|
|
139
|
+
}), [
|
|
140
|
+
canEditSessionType,
|
|
141
|
+
defaultSessionType,
|
|
142
|
+
selectedSessionType,
|
|
143
|
+
selectedSessionTypeOption,
|
|
144
|
+
sessionTypeOptions,
|
|
145
|
+
sessionTypeUnavailable,
|
|
146
|
+
sessionTypeUnavailableMessage
|
|
147
|
+
]);
|
|
140
148
|
}
|
|
@@ -89,17 +89,10 @@ describe('ChatWelcome', () => {
|
|
|
89
89
|
defaultProjectRoot: '/Users/demo/.nextclaw/workspace',
|
|
90
90
|
onSelectProjectRoot,
|
|
91
91
|
projectOptions: [
|
|
92
|
-
{
|
|
93
|
-
projectRoot: '/Users/demo/.nextclaw/workspace',
|
|
94
|
-
projectName: 'workspace',
|
|
95
|
-
sessionCount: 0,
|
|
96
|
-
isDefault: true,
|
|
97
|
-
},
|
|
98
92
|
{
|
|
99
93
|
projectRoot: '/tmp/project-alpha',
|
|
100
94
|
projectName: 'project-alpha',
|
|
101
95
|
sessionCount: 3,
|
|
102
|
-
isDefault: false,
|
|
103
96
|
},
|
|
104
97
|
],
|
|
105
98
|
});
|
|
@@ -28,7 +28,7 @@ export function ChatWelcomeAgentPicker({
|
|
|
28
28
|
<Select value={selectedAgentId} onValueChange={onSelectAgent}>
|
|
29
29
|
<SelectTrigger
|
|
30
30
|
aria-label={t('chatDraftAgentTitle')}
|
|
31
|
-
className="h-auto w-auto min-w-0 gap-1 rounded-lg border-0 bg-transparent px-2 py-1.5 text-
|
|
31
|
+
className="h-auto w-auto min-w-0 gap-1 rounded-lg border-0 bg-transparent px-2 py-1.5 text-muted-foreground shadow-none hover:bg-accent hover:text-accent-foreground focus:ring-0"
|
|
32
32
|
>
|
|
33
33
|
<span className="sr-only">{t('chatDraftAgentTitle')}</span>
|
|
34
34
|
<div className="flex min-w-0 items-center gap-1.5">
|
|
@@ -48,7 +48,7 @@ export function ChatWelcomeAgentPicker({
|
|
|
48
48
|
</div>
|
|
49
49
|
</SelectTrigger>
|
|
50
50
|
<SelectContent
|
|
51
|
-
className="rounded-xl border-
|
|
51
|
+
className="rounded-xl border-border shadow-lg"
|
|
52
52
|
style={{ maxHeight: AGENT_PICKER_MAX_HEIGHT }}
|
|
53
53
|
>
|
|
54
54
|
{agents.map((agent) => (
|
|
@@ -60,7 +60,7 @@ export function ChatWelcomeAgentPicker({
|
|
|
60
60
|
avatarUrl={agent.avatarUrl}
|
|
61
61
|
className="h-5 w-5 shrink-0"
|
|
62
62
|
/>
|
|
63
|
-
<span className="truncate text-sm font-medium text-
|
|
63
|
+
<span className="truncate text-sm font-medium text-foreground">
|
|
64
64
|
{agent.displayName?.trim() || agent.id}
|
|
65
65
|
</span>
|
|
66
66
|
</div>
|
|
@@ -35,15 +35,15 @@ export function ChatWelcomeCapabilityGrid({
|
|
|
35
35
|
<button
|
|
36
36
|
key={capability.titleKey}
|
|
37
37
|
onClick={() => onSelectPrompt(t(capability.promptKey))}
|
|
38
|
-
className="min-w-0 rounded-2xl border border-
|
|
38
|
+
className="min-w-0 rounded-2xl border border-border bg-card p-3 text-left text-card-foreground shadow-card transition-[border-color,box-shadow,transform] hover:border-primary/30 hover:shadow-card-hover sm:p-4"
|
|
39
39
|
>
|
|
40
|
-
<div className="mb-3 flex h-9 w-9 items-center justify-center rounded-xl bg-
|
|
40
|
+
<div className="mb-3 flex h-9 w-9 items-center justify-center rounded-xl bg-accent">
|
|
41
41
|
<Icon className="h-4.5 w-4.5 text-primary" />
|
|
42
42
|
</div>
|
|
43
|
-
<div className="mb-1 text-sm font-semibold text-
|
|
43
|
+
<div className="mb-1 text-sm font-semibold text-foreground">
|
|
44
44
|
{t(capability.titleKey)}
|
|
45
45
|
</div>
|
|
46
|
-
<div className="text-[11px] leading-relaxed text-
|
|
46
|
+
<div className="text-[11px] leading-relaxed text-muted-foreground">
|
|
47
47
|
{t(capability.descKey)}
|
|
48
48
|
</div>
|
|
49
49
|
</button>
|
|
@@ -49,7 +49,7 @@ export function ChatWelcomeProjectPicker({
|
|
|
49
49
|
<PopoverTrigger asChild>
|
|
50
50
|
<button
|
|
51
51
|
type="button"
|
|
52
|
-
className="inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left font-medium text-
|
|
52
|
+
className="inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
|
|
53
53
|
title={projectRoot ?? undefined}
|
|
54
54
|
aria-label={t('chatWelcomeProjectPickerLabel')}
|
|
55
55
|
disabled={!selectable || isSaving}
|
|
@@ -57,19 +57,19 @@ export function ChatWelcomeProjectPicker({
|
|
|
57
57
|
<FolderOpen className="h-4 w-4 shrink-0" />
|
|
58
58
|
<span className="truncate">{projectLabel}</span>
|
|
59
59
|
{isDefaultProject ? (
|
|
60
|
-
<span className="shrink-0 text-xs font-normal text-
|
|
60
|
+
<span className="shrink-0 text-xs font-normal text-muted-foreground/70">
|
|
61
61
|
{t('chatWelcomeProjectDefaultBadge')}
|
|
62
62
|
</span>
|
|
63
63
|
) : null}
|
|
64
|
-
<ChevronDown className="h-3.5 w-3.5 shrink-0 text-
|
|
64
|
+
<ChevronDown className="h-3.5 w-3.5 shrink-0 text-muted-foreground/70" />
|
|
65
65
|
</button>
|
|
66
66
|
</PopoverTrigger>
|
|
67
67
|
<PopoverContent
|
|
68
68
|
align="start"
|
|
69
|
-
className="flex w-[min(20rem,calc(100vw-1rem))] flex-col overflow-hidden rounded-2xl border border-
|
|
69
|
+
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)]"
|
|
70
70
|
style={{ maxHeight: PROJECT_PICKER_MAX_HEIGHT }}
|
|
71
71
|
>
|
|
72
|
-
<div className="shrink-0 px-3 pb-2 pt-3 text-[10px] font-semibold uppercase tracking-[0.18em] text-
|
|
72
|
+
<div className="shrink-0 px-3 pb-2 pt-3 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
|
73
73
|
{t('chatWelcomeProjectRecentTitle')}
|
|
74
74
|
</div>
|
|
75
75
|
<div className="min-h-0 flex-1 overflow-y-auto px-1.5 pb-1.5">
|
|
@@ -78,51 +78,46 @@ export function ChatWelcomeProjectPicker({
|
|
|
78
78
|
<button
|
|
79
79
|
key={option.projectRoot}
|
|
80
80
|
type="button"
|
|
81
|
-
className="flex w-full min-w-0 items-start gap-2 rounded-xl px-2 py-2 text-left transition-colors hover:bg-
|
|
81
|
+
className="flex w-full min-w-0 items-start gap-2 rounded-xl px-2 py-2 text-left transition-colors hover:bg-accent"
|
|
82
82
|
title={option.projectRoot}
|
|
83
83
|
onClick={() => {
|
|
84
84
|
void selectProjectRoot(option.projectRoot);
|
|
85
85
|
}}
|
|
86
86
|
>
|
|
87
|
-
<FolderOpen className="mt-0.5 h-4 w-4 shrink-0 text-
|
|
87
|
+
<FolderOpen className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground/70" />
|
|
88
88
|
<span className="min-w-0 flex-1">
|
|
89
89
|
<span className="flex min-w-0 items-center gap-1.5">
|
|
90
|
-
<span className="truncate text-[13px] font-semibold text-
|
|
90
|
+
<span className="truncate text-[13px] font-semibold text-foreground">
|
|
91
91
|
{option.projectName}
|
|
92
92
|
</span>
|
|
93
|
-
{option.isDefault ? (
|
|
94
|
-
<span className="shrink-0 text-[10px] font-medium text-gray-400">
|
|
95
|
-
{t('chatWelcomeProjectDefaultBadge')}
|
|
96
|
-
</span>
|
|
97
|
-
) : null}
|
|
98
93
|
</span>
|
|
99
|
-
<span className="block truncate text-[11px] leading-4 text-
|
|
94
|
+
<span className="block truncate text-[11px] leading-4 text-muted-foreground">
|
|
100
95
|
{option.projectRoot}
|
|
101
96
|
</span>
|
|
102
97
|
</span>
|
|
103
98
|
{option.sessionCount > 0 ? (
|
|
104
|
-
<span className="mt-0.5 shrink-0 rounded-full bg-
|
|
99
|
+
<span className="mt-0.5 shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
105
100
|
{option.sessionCount}
|
|
106
101
|
</span>
|
|
107
102
|
) : null}
|
|
108
103
|
</button>
|
|
109
104
|
))
|
|
110
105
|
) : (
|
|
111
|
-
<div className="px-2 py-5 text-center text-xs text-
|
|
106
|
+
<div className="px-2 py-5 text-center text-xs text-muted-foreground">
|
|
112
107
|
{t('chatWelcomeProjectNoRecent')}
|
|
113
108
|
</div>
|
|
114
109
|
)}
|
|
115
110
|
</div>
|
|
116
|
-
<div className="shrink-0 border-t border-
|
|
111
|
+
<div className="shrink-0 border-t border-border p-1.5">
|
|
117
112
|
<button
|
|
118
113
|
type="button"
|
|
119
|
-
className="flex w-full items-center gap-2 rounded-xl px-2.5 py-2 text-left text-[13px] font-semibold text-
|
|
114
|
+
className="flex w-full items-center gap-2 rounded-xl px-2.5 py-2 text-left text-[13px] font-semibold text-foreground transition-colors hover:bg-accent"
|
|
120
115
|
onClick={() => {
|
|
121
116
|
setIsOpen(false);
|
|
122
117
|
onOpenProjectDialog();
|
|
123
118
|
}}
|
|
124
119
|
>
|
|
125
|
-
<FolderOpen className="h-4 w-4 shrink-0 text-
|
|
120
|
+
<FolderOpen className="h-4 w-4 shrink-0 text-muted-foreground/70" />
|
|
126
121
|
<span>{t('chatWelcomeProjectOpenFolder')}</span>
|
|
127
122
|
</button>
|
|
128
123
|
</div>
|