@townco/gui-template 0.1.30 → 0.1.31
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/dist/assets/{acp-sdk-4ryhpmET.js → acp-sdk-CrD5QpoU.js} +1 -1
- package/dist/assets/icons-Bzkdnur-.js +1 -0
- package/dist/assets/index-CoGA8W4S.js +6 -0
- package/dist/assets/index-DRxliRw9.css +1 -0
- package/dist/assets/{markdown-Bz1KRONC.js → markdown-PIOGdvNw.js} +1 -1
- package/dist/assets/radix-Dd4nMefT.js +5 -0
- package/dist/assets/{react-CrKZJ-ak.js → react-BxIc-aOD.js} +2 -2
- package/dist/assets/{vendor-Ccy0WTO1.js → vendor-CDPxlbZ6.js} +3 -3
- package/dist/index.html +8 -8
- package/package.json +4 -4
- package/src/ChatView.tsx +454 -0
- package/dist/assets/icons-Cd_vS0Im.js +0 -1
- package/dist/assets/index-CTl3CBlZ.js +0 -6
- package/dist/assets/index-DAh9842m.css +0 -1
- package/dist/assets/radix-R6uiGzM3.js +0 -5
package/dist/index.html
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Agent Chat</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/assets/react-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/acp-sdk-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/radix-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/icons-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/markdown-
|
|
14
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-CoGA8W4S.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-CDPxlbZ6.js">
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/assets/react-BxIc-aOD.js">
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/acp-sdk-CrD5QpoU.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/radix-Dd4nMefT.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/icons-Bzkdnur-.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="/assets/markdown-PIOGdvNw.js">
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DRxliRw9.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@townco/gui-template",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"check": "tsc --noEmit"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@townco/core": "0.0.
|
|
23
|
-
"@townco/ui": "0.1.
|
|
22
|
+
"@townco/core": "0.0.12",
|
|
23
|
+
"@townco/ui": "0.1.34",
|
|
24
24
|
"lucide-react": "^0.552.0",
|
|
25
25
|
"react": "^19.2.0",
|
|
26
26
|
"react-dom": "^19.2.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@tailwindcss/postcss": "^4.1.17",
|
|
30
|
-
"@townco/tsconfig": "0.1.
|
|
30
|
+
"@townco/tsconfig": "0.1.31",
|
|
31
31
|
"@types/react": "^19.2.2",
|
|
32
32
|
"@types/react-dom": "^19.2.2",
|
|
33
33
|
"@vitejs/plugin-react": "^5.1.0",
|
package/src/ChatView.tsx
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
2
|
+
import type { AcpClient } from "@townco/ui";
|
|
3
|
+
import {
|
|
4
|
+
useChatMessages,
|
|
5
|
+
useChatSession,
|
|
6
|
+
useChatStore,
|
|
7
|
+
useToolCalls,
|
|
8
|
+
} from "@townco/ui/core";
|
|
9
|
+
import {
|
|
10
|
+
ChatEmptyState,
|
|
11
|
+
ChatHeader,
|
|
12
|
+
ChatInputActions,
|
|
13
|
+
ChatInputAttachment,
|
|
14
|
+
ChatInputCommandMenu,
|
|
15
|
+
ChatInputField,
|
|
16
|
+
ChatInputRoot,
|
|
17
|
+
ChatInputSubmit,
|
|
18
|
+
ChatInputToolbar,
|
|
19
|
+
ChatInputVoiceInput,
|
|
20
|
+
ChatLayout,
|
|
21
|
+
type CommandMenuItem,
|
|
22
|
+
cn,
|
|
23
|
+
FilesTabContent,
|
|
24
|
+
Message,
|
|
25
|
+
MessageContent,
|
|
26
|
+
PanelTabsHeader,
|
|
27
|
+
type SourceItem,
|
|
28
|
+
SourcesTabContent,
|
|
29
|
+
Tabs,
|
|
30
|
+
TabsContent,
|
|
31
|
+
type TodoItem,
|
|
32
|
+
TodoTabContent,
|
|
33
|
+
} from "@townco/ui/gui";
|
|
34
|
+
import {
|
|
35
|
+
ArrowUp,
|
|
36
|
+
ChevronUp,
|
|
37
|
+
Code,
|
|
38
|
+
PanelRight,
|
|
39
|
+
Settings,
|
|
40
|
+
Sparkles,
|
|
41
|
+
} from "lucide-react";
|
|
42
|
+
import { useEffect, useState } from "react";
|
|
43
|
+
|
|
44
|
+
const logger = createLogger("gui");
|
|
45
|
+
|
|
46
|
+
export interface ChatViewProps {
|
|
47
|
+
client: AcpClient | null;
|
|
48
|
+
initialSessionId?: string | null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Mobile header component that uses ChatHeader context
|
|
52
|
+
function MobileHeader({
|
|
53
|
+
agentName,
|
|
54
|
+
showHeader,
|
|
55
|
+
}: {
|
|
56
|
+
agentName: string;
|
|
57
|
+
showHeader: boolean;
|
|
58
|
+
}) {
|
|
59
|
+
const { isExpanded, setIsExpanded } = ChatHeader.useChatHeaderContext();
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="flex lg:hidden items-center gap-2 flex-1">
|
|
63
|
+
{showHeader && (
|
|
64
|
+
<div className="flex items-center gap-2 flex-1">
|
|
65
|
+
<h1 className="text-heading-4 text-foreground">{agentName}</h1>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
{!showHeader && <div className="flex-1" />}
|
|
69
|
+
<button
|
|
70
|
+
type="button"
|
|
71
|
+
className="flex items-center justify-center shrink-0 cursor-pointer"
|
|
72
|
+
aria-label="Toggle menu"
|
|
73
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
74
|
+
>
|
|
75
|
+
<ChevronUp
|
|
76
|
+
className={cn(
|
|
77
|
+
"size-4 text-muted-foreground transition-transform duration-200",
|
|
78
|
+
isExpanded ? "" : "rotate-180",
|
|
79
|
+
)}
|
|
80
|
+
/>
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Header component that uses ChatLayout context (must be inside ChatLayout.Root)
|
|
87
|
+
function AppChatHeader({
|
|
88
|
+
agentName,
|
|
89
|
+
todos,
|
|
90
|
+
sources,
|
|
91
|
+
showHeader,
|
|
92
|
+
}: {
|
|
93
|
+
agentName: string;
|
|
94
|
+
todos: TodoItem[];
|
|
95
|
+
sources: SourceItem[];
|
|
96
|
+
showHeader: boolean;
|
|
97
|
+
}) {
|
|
98
|
+
const { panelSize, setPanelSize } = ChatLayout.useChatLayoutContext();
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<ChatHeader.Root
|
|
102
|
+
className={cn(
|
|
103
|
+
"border-b border-border bg-card relative lg:p-0",
|
|
104
|
+
"[border-bottom-width:0.5px]",
|
|
105
|
+
)}
|
|
106
|
+
>
|
|
107
|
+
{/* Desktop view: 64px height, padding 20px vertical, 24px left, 16px right */}
|
|
108
|
+
<div className="hidden lg:flex items-center gap-2 w-full h-16 py-5 pl-6 pr-4">
|
|
109
|
+
{showHeader && (
|
|
110
|
+
<div className="flex items-center gap-2 flex-1">
|
|
111
|
+
<h1 className="text-heading-4 text-foreground">{agentName}</h1>
|
|
112
|
+
</div>
|
|
113
|
+
)}
|
|
114
|
+
{!showHeader && <div className="flex-1" />}
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
className="flex items-center justify-center shrink-0 cursor-pointer"
|
|
118
|
+
aria-label="Toggle sidebar"
|
|
119
|
+
onClick={() => {
|
|
120
|
+
setPanelSize(panelSize === "hidden" ? "small" : "hidden");
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
<PanelRight className="size-4 text-muted-foreground" />
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
{/* Mobile view: conditionally show agent name based on showHeader */}
|
|
128
|
+
<MobileHeader agentName={agentName} showHeader={showHeader} />
|
|
129
|
+
|
|
130
|
+
{/* Expandable Panel for Mobile - always available */}
|
|
131
|
+
<ChatHeader.ExpandablePanel
|
|
132
|
+
className={cn(
|
|
133
|
+
"pt-6 pb-8 px-6",
|
|
134
|
+
"border-b border-border bg-card",
|
|
135
|
+
"shadow-[0_4px_16px_0_rgba(0,0,0,0.04)]",
|
|
136
|
+
"[border-bottom-width:0.5px]",
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
139
|
+
<Tabs defaultValue="todo" className="w-full">
|
|
140
|
+
<PanelTabsHeader
|
|
141
|
+
showIcons={true}
|
|
142
|
+
visibleTabs={["todo", "files", "sources"]}
|
|
143
|
+
variant="default"
|
|
144
|
+
/>
|
|
145
|
+
<TabsContent value="todo" className="mt-4">
|
|
146
|
+
<TodoTabContent todos={todos} />
|
|
147
|
+
</TabsContent>
|
|
148
|
+
<TabsContent value="files" className="mt-4">
|
|
149
|
+
<FilesTabContent />
|
|
150
|
+
</TabsContent>
|
|
151
|
+
<TabsContent value="sources" className="mt-4">
|
|
152
|
+
<SourcesTabContent sources={sources} />
|
|
153
|
+
</TabsContent>
|
|
154
|
+
</Tabs>
|
|
155
|
+
</ChatHeader.ExpandablePanel>
|
|
156
|
+
</ChatHeader.Root>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function ChatView({ client, initialSessionId }: ChatViewProps) {
|
|
161
|
+
// Use shared hooks from @townco/ui/core
|
|
162
|
+
const { connectionStatus, connect, sessionId } = useChatSession(
|
|
163
|
+
client,
|
|
164
|
+
initialSessionId,
|
|
165
|
+
);
|
|
166
|
+
const { messages, sendMessage } = useChatMessages(client);
|
|
167
|
+
useToolCalls(client); // Still need to subscribe to tool call events
|
|
168
|
+
const error = useChatStore((state) => state.error);
|
|
169
|
+
const [agentName, setAgentName] = useState<string>("Agent");
|
|
170
|
+
const [isLargeScreen, setIsLargeScreen] = useState(
|
|
171
|
+
typeof window !== "undefined" ? window.innerWidth >= 1024 : true,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Log connection status changes
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
logger.debug("Connection status changed", { status: connectionStatus });
|
|
177
|
+
|
|
178
|
+
if (connectionStatus === "error" && error) {
|
|
179
|
+
logger.error("Connection error occurred", { error });
|
|
180
|
+
}
|
|
181
|
+
}, [connectionStatus, error]);
|
|
182
|
+
|
|
183
|
+
// Get agent name from session metadata
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (client && sessionId) {
|
|
186
|
+
const session = client.getCurrentSession();
|
|
187
|
+
if (session?.metadata?.agentName) {
|
|
188
|
+
setAgentName(session.metadata.agentName);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}, [client, sessionId]);
|
|
192
|
+
|
|
193
|
+
// Monitor screen size changes and update isLargeScreen state
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
const mediaQuery = window.matchMedia("(min-width: 1024px)");
|
|
196
|
+
|
|
197
|
+
const handleChange = (e: MediaQueryListEvent) => {
|
|
198
|
+
setIsLargeScreen(e.matches);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Set initial value
|
|
202
|
+
setIsLargeScreen(mediaQuery.matches);
|
|
203
|
+
|
|
204
|
+
// Listen for changes
|
|
205
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
206
|
+
|
|
207
|
+
return () => {
|
|
208
|
+
mediaQuery.removeEventListener("change", handleChange);
|
|
209
|
+
};
|
|
210
|
+
}, []);
|
|
211
|
+
|
|
212
|
+
// TODO: Replace with useChatStore((state) => state.todos) when todos are added to the store
|
|
213
|
+
const todos: TodoItem[] = [];
|
|
214
|
+
|
|
215
|
+
// Dummy sources data based on Figma design
|
|
216
|
+
const sources: SourceItem[] = [
|
|
217
|
+
{
|
|
218
|
+
id: "1",
|
|
219
|
+
title: "Boeing Scores Early Wins at Dubai Airshow",
|
|
220
|
+
sourceName: "Reuters",
|
|
221
|
+
url: "https://www.reuters.com/markets/companies/BA.N",
|
|
222
|
+
snippet:
|
|
223
|
+
"DUBAI, Nov 17 (Reuters) - Boeing (BA.N), opens new tab took centre stage at day one of the Dubai Airshow on Monday, booking a $38 billion order from host carrier Emirates and clinching more deals with African carriers, while China displayed its C919 in the Middle East for the first time.",
|
|
224
|
+
favicon: "https://www.google.com/s2/favicons?domain=reuters.com&sz=32",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
id: "2",
|
|
228
|
+
title: "Boeing's Sustainable Aviation Goals Take Flight",
|
|
229
|
+
sourceName: "Forbes",
|
|
230
|
+
url: "https://www.forbes.com",
|
|
231
|
+
snippet:
|
|
232
|
+
"SEATTLE, Nov 18 (Reuters) - Boeing is making headway towards its sustainability targets, unveiling plans for a new eco-friendly aircraft design aimed at reducing emissions by 50% by 2030.",
|
|
233
|
+
favicon: "https://www.google.com/s2/favicons?domain=forbes.com&sz=32",
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: "3",
|
|
237
|
+
title: "Boeing Faces Increased Competition in Global Aviation Market",
|
|
238
|
+
sourceName: "Reuters",
|
|
239
|
+
url: "https://www.reuters.com",
|
|
240
|
+
snippet:
|
|
241
|
+
"CHICAGO, Nov 19 (Reuters) - As the global aviation industry rebounds post-pandemic, Boeing is grappling with intensified competition from rival manufacturers, particularly in the Asian market.",
|
|
242
|
+
favicon: "https://www.google.com/s2/favicons?domain=reuters.com&sz=32",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
id: "4",
|
|
246
|
+
title: "Boeing's Starliner Successfully Completes Orbital Test Flight",
|
|
247
|
+
sourceName: "The Verge",
|
|
248
|
+
url: "https://www.theverge.com",
|
|
249
|
+
snippet:
|
|
250
|
+
"NASA, Nov 20 (Reuters) - Boeing's CST-100 Starliner spacecraft achieves a significant milestone, successfully completing its orbital test flight, paving the way for future crewed missions to the International Space Station.",
|
|
251
|
+
favicon: "https://www.google.com/s2/favicons?domain=theverge.com&sz=32",
|
|
252
|
+
},
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
// Command menu items for chat input
|
|
256
|
+
const commandMenuItems: CommandMenuItem[] = [
|
|
257
|
+
{
|
|
258
|
+
id: "model-sonnet",
|
|
259
|
+
label: "Use Sonnet 4.5",
|
|
260
|
+
description: "Switch to Claude Sonnet 4.5 model",
|
|
261
|
+
icon: <Sparkles className="h-4 w-4" />,
|
|
262
|
+
category: "model",
|
|
263
|
+
onSelect: () => {
|
|
264
|
+
logger.info("User selected Sonnet 4.5 model");
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
id: "model-opus",
|
|
269
|
+
label: "Use Opus",
|
|
270
|
+
description: "Switch to Claude Opus model",
|
|
271
|
+
icon: <Sparkles className="h-4 w-4" />,
|
|
272
|
+
category: "model",
|
|
273
|
+
onSelect: () => {
|
|
274
|
+
logger.info("User selected Opus model");
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: "settings",
|
|
279
|
+
label: "Open Settings",
|
|
280
|
+
description: "Configure chat preferences",
|
|
281
|
+
icon: <Settings className="h-4 w-4" />,
|
|
282
|
+
category: "action",
|
|
283
|
+
onSelect: () => {
|
|
284
|
+
logger.info("User opened settings");
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "code-mode",
|
|
289
|
+
label: "Code Mode",
|
|
290
|
+
description: "Enable code-focused responses",
|
|
291
|
+
icon: <Code className="h-4 w-4" />,
|
|
292
|
+
category: "mode",
|
|
293
|
+
onSelect: () => {
|
|
294
|
+
logger.info("User enabled code mode");
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
];
|
|
298
|
+
|
|
299
|
+
return (
|
|
300
|
+
<ChatLayout.Root defaultPanelSize="hidden" defaultActiveTab="todo">
|
|
301
|
+
{/* Main: Vertical container for Messages + Footer */}
|
|
302
|
+
<ChatLayout.Main>
|
|
303
|
+
{/* Top Row */}
|
|
304
|
+
<AppChatHeader
|
|
305
|
+
agentName={agentName}
|
|
306
|
+
todos={todos}
|
|
307
|
+
sources={sources}
|
|
308
|
+
showHeader={messages.length > 0}
|
|
309
|
+
/>
|
|
310
|
+
|
|
311
|
+
{/* Connection Error Banner */}
|
|
312
|
+
{connectionStatus === "error" && error && (
|
|
313
|
+
<div className="border-b border-destructive/20 bg-destructive/10 px-6 py-4">
|
|
314
|
+
<div className="flex items-start justify-between gap-4">
|
|
315
|
+
<div className="flex-1">
|
|
316
|
+
<h3 className="mb-1 text-paragraph-sm font-semibold text-destructive">
|
|
317
|
+
Connection Error
|
|
318
|
+
</h3>
|
|
319
|
+
<p className="whitespace-pre-line text-paragraph-sm text-foreground">
|
|
320
|
+
{error}
|
|
321
|
+
</p>
|
|
322
|
+
</div>
|
|
323
|
+
<button
|
|
324
|
+
type="button"
|
|
325
|
+
onClick={connect}
|
|
326
|
+
className="rounded-lg bg-destructive px-4 py-2 text-paragraph-sm font-medium text-destructive-foreground transition-colors hover:bg-destructive-hover"
|
|
327
|
+
>
|
|
328
|
+
Retry
|
|
329
|
+
</button>
|
|
330
|
+
</div>
|
|
331
|
+
</div>
|
|
332
|
+
)}
|
|
333
|
+
|
|
334
|
+
{/* Body: Container for Messages + Footer + Toaster */}
|
|
335
|
+
<ChatLayout.Body>
|
|
336
|
+
{/* Messages: Scrollable message area */}
|
|
337
|
+
<ChatLayout.Messages>
|
|
338
|
+
{messages.length === 0 ? (
|
|
339
|
+
<div className="flex flex-1 items-center px-4">
|
|
340
|
+
<ChatEmptyState
|
|
341
|
+
title={agentName}
|
|
342
|
+
description="This agent can help you with your tasks. Start a conversation by typing a message below."
|
|
343
|
+
suggestedPrompts={[
|
|
344
|
+
"Search the web for the latest news on top tech company earnings, produce a summary for each company, and then a macro trend analysis of the tech industry. Use your todo list",
|
|
345
|
+
"Explain how this works",
|
|
346
|
+
"Create a new feature",
|
|
347
|
+
"Review my changes",
|
|
348
|
+
]}
|
|
349
|
+
onPromptClick={(prompt) => {
|
|
350
|
+
sendMessage(prompt);
|
|
351
|
+
logger.info("Prompt clicked", { prompt });
|
|
352
|
+
}}
|
|
353
|
+
/>
|
|
354
|
+
</div>
|
|
355
|
+
) : (
|
|
356
|
+
<div className="flex flex-col px-4">
|
|
357
|
+
{messages.map((message, index) => {
|
|
358
|
+
// Calculate dynamic spacing based on message sequence
|
|
359
|
+
const isFirst = index === 0;
|
|
360
|
+
const previousMessage = isFirst ? null : messages[index - 1];
|
|
361
|
+
|
|
362
|
+
let spacingClass = "mt-2";
|
|
363
|
+
|
|
364
|
+
if (isFirst) {
|
|
365
|
+
spacingClass = "mt-2";
|
|
366
|
+
} else if (message.role === "user") {
|
|
367
|
+
// User message usually starts a new turn
|
|
368
|
+
spacingClass =
|
|
369
|
+
previousMessage?.role === "user" ? "mt-4" : "mt-4";
|
|
370
|
+
} else if (message.role === "assistant") {
|
|
371
|
+
// Assistant message is usually a response
|
|
372
|
+
spacingClass =
|
|
373
|
+
previousMessage?.role === "assistant" ? "mt-2" : "mt-6";
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return (
|
|
377
|
+
<Message
|
|
378
|
+
key={message.id}
|
|
379
|
+
message={message}
|
|
380
|
+
className={spacingClass}
|
|
381
|
+
isLastMessage={index === messages.length - 1}
|
|
382
|
+
>
|
|
383
|
+
<MessageContent
|
|
384
|
+
message={message}
|
|
385
|
+
thinkingDisplayStyle="collapsible"
|
|
386
|
+
/>
|
|
387
|
+
</Message>
|
|
388
|
+
);
|
|
389
|
+
})}
|
|
390
|
+
</div>
|
|
391
|
+
)}
|
|
392
|
+
</ChatLayout.Messages>
|
|
393
|
+
|
|
394
|
+
{/* Footer: Input area */}
|
|
395
|
+
<ChatLayout.Footer>
|
|
396
|
+
<ChatInputRoot client={client}>
|
|
397
|
+
<ChatInputCommandMenu commands={commandMenuItems} />
|
|
398
|
+
<ChatInputField
|
|
399
|
+
placeholder="Type a message or / for commands..."
|
|
400
|
+
autoFocus
|
|
401
|
+
/>
|
|
402
|
+
<ChatInputToolbar>
|
|
403
|
+
<div className="flex items-center gap-1">
|
|
404
|
+
<ChatInputActions />
|
|
405
|
+
<ChatInputAttachment />
|
|
406
|
+
</div>
|
|
407
|
+
<div className="flex items-center gap-1">
|
|
408
|
+
<ChatInputVoiceInput />
|
|
409
|
+
<ChatInputSubmit>
|
|
410
|
+
<ArrowUp className="size-4" />
|
|
411
|
+
</ChatInputSubmit>
|
|
412
|
+
</div>
|
|
413
|
+
</ChatInputToolbar>
|
|
414
|
+
</ChatInputRoot>
|
|
415
|
+
</ChatLayout.Footer>
|
|
416
|
+
</ChatLayout.Body>
|
|
417
|
+
</ChatLayout.Main>
|
|
418
|
+
|
|
419
|
+
{/* Aside: Right side panel - only render on large screens */}
|
|
420
|
+
{isLargeScreen && (
|
|
421
|
+
<ChatLayout.Aside breakpoint="lg">
|
|
422
|
+
<Tabs defaultValue="todo" className="flex flex-col h-full">
|
|
423
|
+
{/* Desktop sidebar header (64px) */}
|
|
424
|
+
<div
|
|
425
|
+
className={cn(
|
|
426
|
+
"border-b border-border bg-card",
|
|
427
|
+
"px-6 py-2 h-16",
|
|
428
|
+
"flex items-center",
|
|
429
|
+
"[border-bottom-width:0.5px]",
|
|
430
|
+
)}
|
|
431
|
+
>
|
|
432
|
+
<PanelTabsHeader
|
|
433
|
+
showIcons={true}
|
|
434
|
+
visibleTabs={["todo", "files", "sources"]}
|
|
435
|
+
variant="compact"
|
|
436
|
+
/>
|
|
437
|
+
</div>
|
|
438
|
+
|
|
439
|
+
{/* Desktop sidebar content */}
|
|
440
|
+
<TabsContent value="todo" className="flex-1 p-4 mt-0">
|
|
441
|
+
<TodoTabContent todos={todos} />
|
|
442
|
+
</TabsContent>
|
|
443
|
+
<TabsContent value="files" className="flex-1 p-4 mt-0">
|
|
444
|
+
<FilesTabContent />
|
|
445
|
+
</TabsContent>
|
|
446
|
+
<TabsContent value="sources" className="flex-1 p-4 mt-0">
|
|
447
|
+
<SourcesTabContent sources={sources} />
|
|
448
|
+
</TabsContent>
|
|
449
|
+
</Tabs>
|
|
450
|
+
</ChatLayout.Aside>
|
|
451
|
+
)}
|
|
452
|
+
</ChatLayout.Root>
|
|
453
|
+
);
|
|
454
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as s}from"./react-CrKZJ-ak.js";const _=o=>o.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),m=o=>o.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,a,c)=>c?c.toUpperCase():a.toLowerCase()),h=o=>{const t=m(o);return t.charAt(0).toUpperCase()+t.slice(1)},i=(...o)=>o.filter((t,a,c)=>!!t&&t.trim()!==""&&c.indexOf(t)===a).join(" ").trim(),w=o=>{for(const t in o)if(t.startsWith("aria-")||t==="role"||t==="title")return!0};var g={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const u=s.forwardRef(({color:o="currentColor",size:t=24,strokeWidth:a=2,absoluteStrokeWidth:c,className:r="",children:n,iconNode:l,...d},p)=>s.createElement("svg",{ref:p,...g,width:t,height:t,stroke:o,strokeWidth:c?Number(a)*24/Number(t):a,className:i("lucide",r),...!n&&!w(d)&&{"aria-hidden":"true"},...d},[...l.map(([y,k])=>s.createElement(y,k)),...Array.isArray(n)?n:[n]]));const e=(o,t)=>{const a=s.forwardRef(({className:c,...r},n)=>s.createElement(u,{ref:n,iconNode:t,className:i(`lucide-${_(h(o))}`,`lucide-${o}`,c),...r}));return a.displayName=h(o),a};const v=[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]],I=e("arrow-down",v);const x=[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]],Z=e("arrow-up",x);const f=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],K=e("check",f);const $=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],O=e("chevron-down",$);const C=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],T=e("chevron-right",C);const M=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],X=e("chevron-up",M);const N=[["path",{d:"m7 15 5 5 5-5",key:"1hf1tw"}],["path",{d:"m7 9 5-5 5 5",key:"sgt6xg"}]],G=e("chevrons-up-down",N);const b=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],J=e("circle-check",b);const A=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],Q=e("circle",A);const j=[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]],Y=e("code",j);const q=[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]],e1=e("database",q);const z=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],t1=e("file-text",z);const L=[["path",{d:"M9 17H7A5 5 0 0 1 7 7h2",key:"8i5ue5"}],["path",{d:"M15 7h2a5 5 0 1 1 0 10h-2",key:"1b9ql8"}],["line",{x1:"8",x2:"16",y1:"12",y2:"12",key:"1jonct"}]],o1=e("link-2",L);const S=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],a1=e("loader-circle",S);const V=[["path",{d:"M12 19v3",key:"npa21l"}],["path",{d:"M19 10v2a7 7 0 0 1-14 0v-2",key:"1vc78b"}],["rect",{x:"9",y:"2",width:"6",height:"13",rx:"3",key:"s6n7sd"}]],c1=e("mic",V);const D=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M15 3v18",key:"14nvp0"}]],n1=e("panel-right",D);const H=[["path",{d:"m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551",key:"1miecu"}]],s1=e("paperclip",H);const P=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],r1=e("settings",P);const U=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],d1=e("sparkles",U);const E=[["path",{d:"M21 10.656V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h12.344",key:"2acyp4"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]],h1=e("square-check-big",E);const R=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["line",{x1:"9",x2:"15",y1:"15",y2:"9",key:"1dfufj"}]],i1=e("square-slash",R);const W=[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",key:"1ngwbx"}]],l1=e("wrench",W);const B=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],p1=e("x",B);export{I as A,T as C,e1 as D,t1 as F,o1 as L,c1 as M,s1 as P,i1 as S,l1 as W,p1 as X,h1 as a,d1 as b,r1 as c,Y as d,Z as e,X as f,n1 as g,K as h,Q as i,O as j,a1 as k,G as l,J as m};
|