Hamed744 commited on
Commit
cc076c9
·
verified ·
1 Parent(s): 61741b8

Update components/assistant-ui/thread.tsx

Browse files
Files changed (1) hide show
  1. components/assistant-ui/thread.tsx +370 -2
components/assistant-ui/thread.tsx CHANGED
@@ -1,10 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  const UserMessage: FC = () => {
2
  return (
3
  <MessagePrimitive.Root asChild>
4
  <div
5
- // highlight-start
6
  className="aui-user-message-root mx-auto grid w-full max-w-[var(--thread-max-width)] animate-in auto-rows-auto grid-cols-[auto_auto] justify-end gap-y-2 px-2 py-4 duration-150 ease-out fade-in slide-in-from-bottom-1 first:mt-3 last:mb-5 [&:where(>*)]:col-start-2"
7
- // highlight-end
8
  data-role="user"
9
  >
10
  <UserMessageAttachments />
@@ -22,4 +315,79 @@ const UserMessage: FC = () => {
22
  </div>
23
  </MessagePrimitive.Root>
24
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  };
 
1
+ import {
2
+ ArrowDownIcon,
3
+ ArrowUpIcon,
4
+ CheckIcon,
5
+ ChevronLeftIcon,
6
+ ChevronRightIcon,
7
+ CopyIcon,
8
+ PencilIcon,
9
+ RefreshCwIcon,
10
+ Square,
11
+ } from "lucide-react";
12
+
13
+ import {
14
+ ActionBarPrimitive,
15
+ BranchPickerPrimitive,
16
+ ComposerPrimitive,
17
+ ErrorPrimitive,
18
+ MessagePrimitive,
19
+ ThreadPrimitive,
20
+ } from "@assistant-ui/react";
21
+
22
+ import type { FC } from "react";
23
+ import { LazyMotion, MotionConfig, domAnimation } from "motion/react";
24
+ import * as m from "motion/react-m";
25
+
26
+ import { Button } from "@/components/ui/button";
27
+ import { MarkdownText } from "@/components/assistant-ui/markdown-text";
28
+ import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
29
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
30
+ import {
31
+ ComposerAddAttachment,
32
+ ComposerAttachments,
33
+ UserMessageAttachments,
34
+ } from "@/components/assistant-ui/attachment";
35
+
36
+ import { cn } from "@/lib/utils";
37
+
38
+ export const Thread: FC = () => {
39
+ return (
40
+ <LazyMotion features={domAnimation}>
41
+ <MotionConfig reducedMotion="user">
42
+ <ThreadPrimitive.Root
43
+ className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
44
+ style={{
45
+ ["--thread-max-width" as string]: "44rem",
46
+ }}
47
+ >
48
+ <ThreadPrimitive.Viewport className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4">
49
+ <ThreadPrimitive.If empty>
50
+ <ThreadWelcome />
51
+ </ThreadPrimitive.If>
52
+
53
+ <ThreadPrimitive.Messages
54
+ components={{
55
+ UserMessage,
56
+ EditComposer,
57
+ AssistantMessage,
58
+ }}
59
+ />
60
+
61
+ <ThreadPrimitive.If empty={false}>
62
+ <div className="aui-thread-viewport-spacer min-h-8 grow" />
63
+ </ThreadPrimitive.If>
64
+
65
+ <Composer />
66
+ </ThreadPrimitive.Viewport>
67
+ </ThreadPrimitive.Root>
68
+ </MotionConfig>
69
+ </LazyMotion>
70
+ );
71
+ };
72
+
73
+ const ThreadScrollToBottom: FC = () => {
74
+ return (
75
+ <ThreadPrimitive.ScrollToBottom asChild>
76
+ <TooltipIconButton
77
+ tooltip="رفتن به پایین"
78
+ variant="outline"
79
+ className="aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent"
80
+ >
81
+ <ArrowDownIcon />
82
+ </TooltipIconButton>
83
+ </ThreadPrimitive.ScrollToBottom>
84
+ );
85
+ };
86
+
87
+ const ThreadWelcome: FC = () => {
88
+ return (
89
+ <div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col">
90
+ <div className="aui-thread-welcome-center flex w-full flex-grow flex-col items-center justify-center">
91
+ <div className="aui-thread-welcome-message flex size-full flex-col justify-center px-8">
92
+ <m.div
93
+ initial={{ opacity: 0, y: 10 }}
94
+ animate={{ opacity: 1, y: 0 }}
95
+ exit={{ opacity: 0, y: 10 }}
96
+ className="aui-thread-welcome-message-motion-1 text-2xl font-semibold"
97
+ >
98
+ سلام!
99
+ </m.div>
100
+ <m.div
101
+ initial={{ opacity: 0, y: 10 }}
102
+ animate={{ opacity: 1, y: 0 }}
103
+ exit={{ opacity: 0, y: 10 }}
104
+ transition={{ delay: 0.1 }}
105
+ className="aui-thread-welcome-message-motion-2 text-2xl text-muted-foreground/65"
106
+ >
107
+ چطور می‌توانم کمکتان کنم؟
108
+ </m.div>
109
+ </div>
110
+ </div>
111
+ <ThreadSuggestions />
112
+ </div>
113
+ );
114
+ };
115
+
116
+ const ThreadSuggestions: FC = () => {
117
+ return (
118
+ <div className="aui-thread-welcome-suggestions grid w-full gap-2 pb-4 @md:grid-cols-2">
119
+ {[
120
+ {
121
+ title: "درباره خودت بگو",
122
+ label: "",
123
+ action: "درباره خودت برای من توضیح بده",
124
+ },
125
+ {
126
+ title: "قلاب‌های ری‌اکت را توضیح بده",
127
+ label: "مانند useState و useEffect",
128
+ action: "قلاب‌های ری‌اکت مانند useState و useEffect را توضیح بده",
129
+ },
130
+ {
131
+ title: "یک کوئری SQL بنویس",
132
+ label: "برای پیدا کردن بهترین مشتریان",
133
+ action: "یک کوئری SQL برای پیدا کردن بهترین مشتریان بنویس",
134
+ },
135
+ {
136
+ title: "یک برنامه غذایی بساز",
137
+ label: "برای کاهش وزن سالم",
138
+ action: "یک برنامه غذایی برای کاهش وزن سالم ایجاد کن",
139
+ },
140
+ ].map((suggestedAction, index) => (
141
+ <m.div
142
+ initial={{ opacity: 0, y: 20 }}
143
+ animate={{ opacity: 1, y: 0 }}
144
+ exit={{ opacity: 0, y: 20 }}
145
+ transition={{ delay: 0.05 * index }}
146
+ key={`suggested-action-${suggestedAction.title}-${index}`}
147
+ className="aui-thread-welcome-suggestion-display [&:nth-child(n+3)]:hidden @md:[&:nth-child(n+3)]:block"
148
+ >
149
+ <ThreadPrimitive.Suggestion
150
+ prompt={suggestedAction.action}
151
+ send
152
+ asChild
153
+ >
154
+ <Button
155
+ variant="ghost"
156
+ className="aui-thread-welcome-suggestion h-auto w-full flex-1 flex-wrap items-start justify-start gap-1 rounded-3xl border px-5 py-4 text-right text-sm @md:flex-col dark:hover:bg-accent/60"
157
+ aria-label={suggestedAction.action}
158
+ >
159
+ <span className="aui-thread-welcome-suggestion-text-1 font-medium">
160
+ {suggestedAction.title}
161
+ </span>
162
+ <span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground">
163
+ {suggestedAction.label}
164
+ </span>
165
+ </Button>
166
+ </ThreadPrimitive.Suggestion>
167
+ </m.div>
168
+ ))}
169
+ </div>
170
+ );
171
+ };
172
+
173
+ const Composer: FC = () => {
174
+ return (
175
+ <div className="aui-composer-wrapper sticky bottom-0 mx-auto flex w-full max-w-[var(--thread-max-width)] flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6">
176
+ <ThreadScrollToBottom />
177
+ <ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col rounded-3xl border border-border bg-muted px-1 pt-2 shadow-[0_9px_9px_0px_rgba(0,0,0,0.01),0_2px_5px_0px_rgba(0,0,0,0.06)] dark:border-muted-foreground/15">
178
+ <ComposerAttachments />
179
+ <ComposerPrimitive.Input
180
+ placeholder="پیام خود را بنویسید..."
181
+ className="aui-composer-input mb-1 max-h-32 min-h-16 w-full resize-none bg-transparent px-3.5 pt-1.5 pb-3 text-base outline-none placeholder:text-muted-foreground focus:outline-primary"
182
+ rows={1}
183
+ autoFocus
184
+ aria-label="ورودی پیام"
185
+ />
186
+ <ComposerAction />
187
+ </ComposerPrimitive.Root>
188
+ </div>
189
+ );
190
+ };
191
+
192
+ const ComposerAction: FC = () => {
193
+ return (
194
+ <div className="aui-composer-action-wrapper relative mx-1 mt-2 mb-2 flex items-center justify-between">
195
+ <ComposerAddAttachment />
196
+
197
+ <ThreadPrimitive.If running={false}>
198
+ <ComposerPrimitive.Send asChild>
199
+ <TooltipIconButton
200
+ tooltip="ارسال پیام"
201
+ side="bottom"
202
+ type="submit"
203
+ variant="default"
204
+ size="icon"
205
+ className="aui-composer-send size-[34px] rounded-full p-1"
206
+ aria-label="ارسال پیام"
207
+ >
208
+ <ArrowUpIcon className="aui-composer-send-icon size-5" />
209
+ </TooltipIconButton>
210
+ </ComposerPrimitive.Send>
211
+ </ThreadPrimitive.If>
212
+
213
+ <ThreadPrimitive.If running>
214
+ <ComposerPrimitive.Cancel asChild>
215
+ <Button
216
+ type="button"
217
+ variant="default"
218
+ size="icon"
219
+ className="aui-composer-cancel size-[34px] rounded-full border border-muted-foreground/60 hover:bg-primary/75 dark:border-muted-foreground/90"
220
+ aria-label="توقف تولید پاسخ"
221
+ >
222
+ <Square className="aui-composer-cancel-icon size-3.5 fill-white dark:fill-black" />
223
+ </Button>
224
+ </ComposerPrimitive.Cancel>
225
+ </ThreadPrimitive.If>
226
+ </div>
227
+ );
228
+ };
229
+
230
+ const MessageError: FC = () => {
231
+ return (
232
+ <MessagePrimitive.Error>
233
+ <ErrorPrimitive.Root className="aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive dark:bg-destructive/5 dark:text-red-200">
234
+ <ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
235
+ </ErrorPrimitive.Root>
236
+ </MessagePrimitive.Error>
237
+ );
238
+ };
239
+
240
+ const AssistantMessage: FC = () => {
241
+ return (
242
+ <MessagePrimitive.Root asChild>
243
+ <div
244
+ className="aui-assistant-message-root relative mx-auto w-full max-w-[var(--thread-max-width)] animate-in py-4 duration-150 ease-out fade-in slide-in-from-bottom-1 last:mb-24"
245
+ data-role="assistant"
246
+ >
247
+ <div className="aui-assistant-message-content mx-2 leading-7 break-words text-foreground">
248
+ <MessagePrimitive.Parts
249
+ components={{
250
+ Text: MarkdownText,
251
+ tools: { Fallback: ToolFallback },
252
+ }}
253
+ />
254
+ <MessageError />
255
+ </div>
256
+
257
+ <div className="aui-assistant-message-footer mt-2 ms-2 flex">
258
+ <BranchPicker />
259
+ <AssistantActionBar />
260
+ </div>
261
+ </div>
262
+ </MessagePrimitive.Root>
263
+ );
264
+ };
265
+
266
+ const AssistantActionBar: FC = () => {
267
+ return (
268
+ <ActionBarPrimitive.Root
269
+ hideWhenRunning
270
+ autohide="not-last"
271
+ autohideFloat="single-branch"
272
+ className="aui-assistant-action-bar-root col-start-3 row-start-2 -me-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm"
273
+ >
274
+ <ActionBarPrimitive.Copy asChild>
275
+ <TooltipIconButton tooltip="کپی">
276
+ <MessagePrimitive.If copied>
277
+ <CheckIcon />
278
+ </MessagePrimitive.If>
279
+ <MessagePrimitive.If copied={false}>
280
+ <CopyIcon />
281
+ </MessagePrimitive.If>
282
+ </TooltipIconButton>
283
+ </ActionBarPrimitive.Copy>
284
+ <ActionBarPrimitive.Reload asChild>
285
+ <TooltipIconButton tooltip="تلاش مجدد">
286
+ <RefreshCwIcon />
287
+ </TooltipIconButton>
288
+ </ActionBarPrimitive.Reload>
289
+ </ActionBarPrimitive.Root>
290
+ );
291
+ };
292
+
293
+ // ==========================================================
294
+ // START OF THE SECTION THAT WAS MODIFIED
295
+ // ==========================================================
296
  const UserMessage: FC = () => {
297
  return (
298
  <MessagePrimitive.Root asChild>
299
  <div
 
300
  className="aui-user-message-root mx-auto grid w-full max-w-[var(--thread-max-width)] animate-in auto-rows-auto grid-cols-[auto_auto] justify-end gap-y-2 px-2 py-4 duration-150 ease-out fade-in slide-in-from-bottom-1 first:mt-3 last:mb-5 [&:where(>*)]:col-start-2"
 
301
  data-role="user"
302
  >
303
  <UserMessageAttachments />
 
315
  </div>
316
  </MessagePrimitive.Root>
317
  );
318
+ };
319
+ // ==========================================================
320
+ // END OF THE SECTION THAT WAS MODIFIED
321
+ // ==========================================================
322
+
323
+ const UserActionBar: FC = () => {
324
+ return (
325
+ <ActionBarPrimitive.Root
326
+ hideWhenRunning
327
+ autohide="not-last"
328
+ className="aui-user-action-bar-root flex flex-col items-start"
329
+ >
330
+ <ActionBarPrimitive.Edit asChild>
331
+ <TooltipIconButton tooltip="ویرایش" className="aui-user-action-edit p-4">
332
+ <PencilIcon />
333
+ </TooltipIconButton>
334
+ </ActionBarPrimitive.Edit>
335
+ </ActionBarPrimitive.Root>
336
+ );
337
+ };
338
+
339
+ const EditComposer: FC = () => {
340
+ return (
341
+ <div className="aui-edit-composer-wrapper mx-auto flex w-full max-w-[var(--thread-max-width)] flex-col gap-4 px-2 first:mt-4">
342
+ <ComposerPrimitive.Root className="aui-edit-composer-root me-auto flex w-full max-w-7/8 flex-col rounded-xl bg-muted">
343
+ <ComposerPrimitive.Input
344
+ className="aui-edit-composer-input flex min-h-[60px] w-full resize-none bg-transparent p-4 text-foreground outline-none"
345
+ autoFocus
346
+ />
347
+
348
+ <div className="aui-edit-composer-footer mx-3 mb-3 flex items-center justify-center gap-2 self-end">
349
+ <ComposerPrimitive.Cancel asChild>
350
+ <Button variant="ghost" size="sm" aria-label="لغو ویرایش">
351
+ انصراف
352
+ </Button>
353
+ </ComposerPrimitive.Cancel>
354
+ <ComposerPrimitive.Send asChild>
355
+ <Button size="sm" aria-label="به‌روزرسانی پیام">
356
+ به‌روزرسانی
357
+ </Button>
358
+ </ComposerPrimitive.Send>
359
+ </div>
360
+ </ComposerPrimitive.Root>
361
+ </div>
362
+ );
363
+ };
364
+
365
+ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
366
+ className,
367
+ ...rest
368
+ }) => {
369
+ return (
370
+ <BranchPickerPrimitive.Root
371
+ hideWhenSingleBranch
372
+ className={cn(
373
+ "aui-branch-picker-root ms-2 -me-2 inline-flex items-center text-xs text-muted-foreground",
374
+ className,
375
+ )}
376
+ {...rest}
377
+ >
378
+ <BranchPickerPrimitive.Previous asChild>
379
+ <TooltipIconButton tooltip="قبلی">
380
+ <ChevronRightIcon />
381
+ </TooltipIconButton>
382
+ </BranchPickerPrimitive.Previous>
383
+ <span className="aui-branch-picker-state font-medium">
384
+ <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
385
+ </span>
386
+ <BranchPickerPrimitive.Next asChild>
387
+ <TooltipIconButton tooltip="بعدی">
388
+ <ChevronLeftIcon />
389
+ </TooltipIconButton>
390
+ </BranchPickerPrimitive.Next>
391
+ </BranchPickerPrimitive.Root>
392
+ );
393
  };