@clikvn/agent-widget-embedded 0.0.10-dev → 0.0.11-dev

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 (35) hide show
  1. package/dist/commons/constants/variables.d.ts +4 -0
  2. package/dist/commons/constants/variables.d.ts.map +1 -1
  3. package/dist/components/Chat/Icons.d.ts +19 -1
  4. package/dist/components/Chat/Icons.d.ts.map +1 -1
  5. package/dist/components/Chat/Message.d.ts.map +1 -1
  6. package/dist/components/Chat/MultimodalInput.d.ts +1 -1
  7. package/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
  8. package/dist/components/Chat/SuggestedActions.d.ts +12 -0
  9. package/dist/components/Chat/SuggestedActions.d.ts.map +1 -0
  10. package/dist/features/AgentWidget/index.d.ts +8 -2
  11. package/dist/features/AgentWidget/index.d.ts.map +1 -1
  12. package/dist/hooks/useConfiguration.d.ts +8 -1
  13. package/dist/hooks/useConfiguration.d.ts.map +1 -1
  14. package/dist/index.html +12 -51
  15. package/dist/types/common.type.d.ts +6 -0
  16. package/dist/types/common.type.d.ts.map +1 -1
  17. package/dist/web.js +1 -1
  18. package/package.json +2 -1
  19. package/src/commons/constants/variables.ts +5 -0
  20. package/src/components/Chat/Chat.tsx +1 -1
  21. package/src/components/Chat/Icons.tsx +867 -1
  22. package/src/components/Chat/Message.tsx +42 -16
  23. package/src/components/Chat/MultimodalInput.tsx +136 -110
  24. package/src/components/Chat/SuggestedActions.tsx +99 -0
  25. package/src/features/AgentWidget/index.tsx +8 -2
  26. package/src/hooks/useConfiguration.tsx +8 -1
  27. package/src/types/common.type.ts +7 -0
  28. package/dist/components/Chat/AudioRecording.d.ts +0 -9
  29. package/dist/components/Chat/AudioRecording.d.ts.map +0 -1
  30. package/dist/hooks/useConnection.d.ts +0 -15
  31. package/dist/hooks/useConnection.d.ts.map +0 -1
  32. package/dist/services/user.service.d.ts +0 -3
  33. package/dist/services/user.service.d.ts.map +0 -1
  34. package/dist/types/agentType.d.ts +0 -11
  35. package/dist/types/agentType.d.ts.map +0 -1
@@ -11,6 +11,7 @@ import {
11
11
  } from '../../types/flowise.type';
12
12
  import { cn } from '../../utils/commonUtils';
13
13
  import AudioPlayer from './AudioPlayer';
14
+ import { useConfiguration } from 'hooks/useConfiguration';
14
15
 
15
16
  type PropsType = {
16
17
  chatId?: string;
@@ -35,6 +36,7 @@ export const PreviewMessage: FC<PropsType> = ({
35
36
  bot,
36
37
  enableTTS,
37
38
  }) => {
39
+ const { theme } = useConfiguration();
38
40
  const parseOutput = (outputData: any) => {
39
41
  try {
40
42
  return JSON.parse(outputData);
@@ -56,12 +58,21 @@ export const PreviewMessage: FC<PropsType> = ({
56
58
  return { customToolResults, toolResults };
57
59
  }, [message.usedTools]);
58
60
 
61
+ const role = useMemo(() => {
62
+ return getRole(message.role);
63
+ }, [message.role]);
64
+
65
+ const assistantAvatar =
66
+ role === 'user'
67
+ ? theme?.userMessage?.avatarSrc
68
+ : theme?.botMessage?.avatarSrc || bot?.avatar;
69
+
59
70
  return (
60
71
  <motion.div
61
72
  className="w-full mx-auto max-w-3xl px-4 group/message"
62
73
  initial={{ y: 5, opacity: 0 }}
63
74
  animate={{ y: 0, opacity: 1 }}
64
- data-role={getRole(message.role)}
75
+ data-role={role}
65
76
  >
66
77
  <div className="flex justify-end text-[14px]">
67
78
  {message?.fileUploads && !!message.fileUploads.length && (
@@ -70,15 +81,21 @@ export const PreviewMessage: FC<PropsType> = ({
70
81
  </div>
71
82
  <div
72
83
  className={cn(
73
- 'group-data-[role=user]/message:bg-primary group-data-[role=user]/message:text-primary-foreground flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl'
84
+ `group-data-[role=user]/message:bg-primary group-data-[role=user]/message:text-primary-foreground flex gap-4 px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl py-2 rounded-xl `
74
85
  )}
86
+ style={{
87
+ backgroundColor:
88
+ role === 'user'
89
+ ? theme?.userMessage?.backgroundColor
90
+ : theme?.botMessage?.backgroundColor || undefined,
91
+ }}
75
92
  >
76
- {message.role === 'apiMessage' && (
93
+ {theme?.botMessage?.showAvatar && message.role === 'apiMessage' && (
77
94
  <div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
78
- {bot?.avatar ? (
95
+ {assistantAvatar ? (
79
96
  <img
80
- src={bot.avatar}
81
- alt={bot.name ?? 'User Avatar'}
97
+ src={assistantAvatar}
98
+ alt={bot?.name ?? 'User Avatar'}
82
99
  width={24}
83
100
  height={24}
84
101
  className="rounded-full"
@@ -133,7 +150,15 @@ export const PreviewMessage: FC<PropsType> = ({
133
150
  {/* </div>*/}
134
151
  {/* )}*/}
135
152
  {message.content && (
136
- <div className="flex flex-col gap-4">
153
+ <div
154
+ className="flex flex-col gap-4"
155
+ style={{
156
+ color:
157
+ getRole(message.role) === 'user'
158
+ ? theme?.userMessage?.textColor
159
+ : theme?.botMessage?.textColor || undefined,
160
+ }}
161
+ >
137
162
  <Markdown usedTools={message?.usedTools}>
138
163
  {message.content as string}
139
164
  </Markdown>
@@ -151,6 +176,10 @@ export const PreviewMessage: FC<PropsType> = ({
151
176
  export const ThinkingMessage = ({ bot }: { bot: BotType | null }) => {
152
177
  const role = 'assistant';
153
178
 
179
+ const { theme } = useConfiguration();
180
+
181
+ const assistantAvatar = theme?.botMessage?.avatarSrc || bot?.avatar;
182
+
154
183
  return (
155
184
  <motion.div
156
185
  className="w-full mx-auto max-w-3xl px-4 group/message "
@@ -166,20 +195,17 @@ export const ThinkingMessage = ({ bot }: { bot: BotType | null }) => {
166
195
  }
167
196
  )}
168
197
  >
169
- <div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
170
- {bot?.avatar ? (
198
+ {theme?.botMessage?.showAvatar && (
199
+ <div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
171
200
  <img
172
- src={bot.avatar}
173
- alt={bot.name ?? 'User Avatar'}
201
+ src={assistantAvatar}
202
+ alt={bot?.name ?? 'User Avatar'}
174
203
  width={24}
175
204
  height={24}
176
205
  className="rounded-full"
177
206
  />
178
- ) : (
179
- <SparklesIcon size={14} />
180
- )}
181
- </div>
182
-
207
+ </div>
208
+ )}
183
209
  <div className="flex flex-col gap-2 w-full">
184
210
  <div className="flex flex-col gap-4 text-muted-foreground">
185
211
  Thinking...
@@ -1,3 +1,4 @@
1
+ import { motion } from 'framer-motion';
1
2
  import {
2
3
  type ChangeEvent,
3
4
  FC,
@@ -6,33 +7,38 @@ import {
6
7
  useRef,
7
8
  useState,
8
9
  } from 'react';
9
- import { motion } from 'framer-motion';
10
10
  import { useLocalStorage, useWindowSize } from 'usehooks-ts';
11
+ import { BotType } from '../../types/bot.type';
12
+ import { ChatMessageType, IFileUpload } from '../../types/flowise.type';
11
13
  import {
12
14
  cn,
13
15
  generateExtendedFileName,
14
16
  generateUUID,
15
17
  } from '../../utils/commonUtils';
16
- import { PreviewAttachment } from './PreviewAttachment';
17
18
  import {
18
19
  ArrowUpIcon,
19
- CircleDotIcon,
20
- MicrophoneIcon,
21
- PlusIcon,
20
+ CheckCirclFillIcon,
21
+ ClikCloseIcon,
22
+ ClikMessageIcon,
23
+ ClikMicrophoneIcon,
24
+ ClikPlusIcon,
25
+ ClikVolumeIcon,
26
+ ClikWaveIcon,
22
27
  StopIcon,
23
- TrashIcon,
24
- VolumeIcon,
25
28
  } from './Icons';
26
- import { ChatMessageType, IFileUpload } from '../../types/flowise.type';
27
- import { BotType } from '../../types/bot.type';
29
+ import { PreviewAttachment } from './PreviewAttachment';
28
30
 
29
31
  import { createAttachments } from '../../services/chat.service';
30
32
  import { Button } from './ui/Button';
31
33
  import { Textarea } from './ui/Textarea';
32
34
  import { useAudioRecording } from '../../hooks/useAudioRecording';
33
- import { useChatData } from '../../hooks/useChatData';
34
35
  import { useConfiguration } from '../../hooks/useConfiguration';
35
36
  import { SuggestionType } from 'types/common.type';
37
+ import SuggestedActions from './SuggestedActions';
38
+ import { LAYOUT_MODE } from 'commons/constants';
39
+
40
+ const DEFAULT_COLOR_ICON = '#595959';
41
+ const ACTIVE_COLOR_ICON = '#0A82F7';
36
42
 
37
43
  type PropsType = {
38
44
  input: string;
@@ -87,6 +93,15 @@ export const MultimodalInput: FC<PropsType> = ({
87
93
  } = useAudioRecording();
88
94
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
89
95
  const { width } = useWindowSize();
96
+
97
+ const defaultRows = theme?.suggestion?.defaultRows || 1;
98
+ const expandedRows = theme?.suggestion?.expandedRows || 2;
99
+ const suggestedActionLayoutMode =
100
+ theme?.suggestion?.layoutMode || LAYOUT_MODE.SCROLL;
101
+
102
+ const [suggestedActionRows, setSuggestedActionRows] =
103
+ useState<number>(defaultRows); // only use for scroll mode SuggestedActions
104
+
90
105
  useEffect(() => {
91
106
  if (textareaRef.current) {
92
107
  adjustHeight();
@@ -125,6 +140,8 @@ export const MultimodalInput: FC<PropsType> = ({
125
140
  const handleInput = (event: ChangeEvent<HTMLTextAreaElement>) => {
126
141
  setInput(event.target.value);
127
142
  adjustHeight();
143
+ if (suggestedActionRows !== defaultRows)
144
+ setSuggestedActionRows(defaultRows);
128
145
  };
129
146
 
130
147
  const fileInputRef = useRef<HTMLInputElement | null>(null);
@@ -241,6 +258,12 @@ export const MultimodalInput: FC<PropsType> = ({
241
258
  [setUploadQueue, uploadFile]
242
259
  );
243
260
 
261
+ const handleLogicShowFAQ = () => {
262
+ setSuggestedActionRows(
263
+ suggestedActionRows === defaultRows ? expandedRows : defaultRows
264
+ );
265
+ };
266
+
244
267
  const handleFileChange = useCallback(
245
268
  async (event: ChangeEvent<HTMLInputElement>) => {
246
269
  const files = Array.from(event.target.files || []);
@@ -289,41 +312,12 @@ export const MultimodalInput: FC<PropsType> = ({
289
312
  return (
290
313
  <div className="relative w-full flex flex-col gap-4">
291
314
  {!!suggestedActions?.length && (
292
- <div className="grid sm:grid-cols-2 gap-2 w-full">
293
- {suggestedActions.map((suggestedAction, index) => (
294
- <motion.div
295
- initial={{ opacity: 0, y: 20 }}
296
- animate={{ opacity: 1, y: 0 }}
297
- exit={{ opacity: 0, y: 20 }}
298
- transition={{ delay: 0.05 * index }}
299
- key={`suggested-action-${suggestedAction.title}-${index}`}
300
- className={index > 1 ? 'hidden sm:block' : 'block'}
301
- >
302
- <Button
303
- variant="ghost"
304
- onClick={(e) => {
305
- e.preventDefault();
306
- if (append) {
307
- append({
308
- role: 'apiMessage',
309
- content: suggestedAction.action,
310
- });
311
- }
312
- }}
313
- className="text-left border rounded-xl px-4 py-3.5 text-sm flex-1 gap-1 sm:flex-col w-full h-auto justify-start items-start"
314
- >
315
- <span className="font-medium overflow-hidden whitespace-nowrap text-ellipsis w-full group-hover:overflow-visible group-hover:whitespace-normal">
316
- {suggestedAction.title}
317
- </span>
318
- {!!suggestedAction.label && (
319
- <span className="text-muted-foreground">
320
- {suggestedAction.label}
321
- </span>
322
- )}
323
- </Button>
324
- </motion.div>
325
- ))}
326
- </div>
315
+ <SuggestedActions
316
+ suggestedActions={suggestedActions}
317
+ append={append}
318
+ layoutMode={suggestedActionLayoutMode}
319
+ suggestedActionRows={suggestedActionRows}
320
+ />
327
321
  )}
328
322
 
329
323
  <input
@@ -358,14 +352,13 @@ export const MultimodalInput: FC<PropsType> = ({
358
352
  ))}
359
353
  </div>
360
354
  )}
361
-
362
355
  <Textarea
363
356
  ref={textareaRef}
364
357
  placeholder={theme?.input?.placeholder || 'Send a message...'}
365
358
  value={input}
366
359
  onChange={handleInput}
367
360
  className={cn(
368
- 'min-h-[24px] max-h-[calc(75dvh)] overflow-hidden resize-none rounded-xl text-base bg-muted',
361
+ 'min-h-[24px] max-h-[calc(75dvh)] overflow-hidden resize-none rounded-xl text-base bg-muted bg-[#ffffff]',
369
362
  className
370
363
  )}
371
364
  rows={3}
@@ -388,7 +381,7 @@ export const MultimodalInput: FC<PropsType> = ({
388
381
 
389
382
  {isLoading ? (
390
383
  <Button
391
- className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
384
+ className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600 bg-[#000000D9]"
392
385
  onClick={(event) => {
393
386
  event.preventDefault();
394
387
  stop();
@@ -399,7 +392,7 @@ export const MultimodalInput: FC<PropsType> = ({
399
392
  </Button>
400
393
  ) : (
401
394
  <Button
402
- className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
395
+ className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600 bg-[#000000D9]"
403
396
  onClick={(event) => {
404
397
  event.preventDefault();
405
398
  handleSend();
@@ -411,69 +404,102 @@ export const MultimodalInput: FC<PropsType> = ({
411
404
  <ArrowUpIcon size={14} />
412
405
  </Button>
413
406
  )}
414
- {isRecording ? (
415
- <>
416
- <div
417
- className="rounded-full bg-background flex absolute p-1 bottom-2 right-[80px]"
418
- data-testid="input"
419
- >
420
- <div className="flex items-center gap-3">
421
- <span>
422
- <CircleDotIcon color="red" />
423
- </span>
424
- <span>{elapsedTime || '00:00'}</span>
425
- {isLoadingRecording && <span className="ml-1.5">Sending...</span>}
407
+
408
+ <div className="absolute left-2 right-2 bottom-2 flex items-center">
409
+ <Button
410
+ className="rounded-full p-1.5 h-fit m-0.5 dark:border-zinc-700"
411
+ onClick={(event) => {
412
+ event.preventDefault();
413
+ fileInputRef.current?.click();
414
+ }}
415
+ variant="outline"
416
+ disabled={isLoading || isRecording}
417
+ >
418
+ <ClikPlusIcon size={14} />
419
+ </Button>
420
+
421
+ <Button
422
+ className={`rounded-full py-1 px-2 h-fit m-0.5 dark:border-zinc-700 text-[#595959] ${suggestedActionRows === expandedRows && 'border border-[#B9C6D6] bg-[#CBE1F3] text-[#0A82F7]'} `}
423
+ onClick={(event) => {
424
+ event.preventDefault();
425
+ handleLogicShowFAQ();
426
+ }}
427
+ variant="outline"
428
+ disabled={isLoading || isRecording}
429
+ >
430
+ <ClikMessageIcon
431
+ color={
432
+ suggestedActionRows === expandedRows
433
+ ? ACTIVE_COLOR_ICON
434
+ : DEFAULT_COLOR_ICON
435
+ }
436
+ />
437
+ FAQ
438
+ </Button>
439
+
440
+ {isRecording ? (
441
+ <>
442
+ <div
443
+ className="rounded-[100px] flex items-center bg-[#F3F3F3] gap-2 p-2"
444
+ data-testid="input"
445
+ >
446
+ <Button
447
+ className="rounded-full dark:border-zinc-700 p-0 h-6"
448
+ variant="outline"
449
+ onClick={(event) => {
450
+ event.preventDefault();
451
+ onRecordingCancelled();
452
+ }}
453
+ >
454
+ <ClikCloseIcon className="!w-full !h-full" />
455
+ </Button>
456
+ <div className="flex items-center gap-2 ">
457
+ <span>
458
+ <ClikWaveIcon />
459
+ </span>
460
+ <span>{elapsedTime || '00:00'}</span>
461
+ {isLoadingRecording && (
462
+ <span className="ml-1.5">Sending...</span>
463
+ )}
464
+ </div>
465
+ <Button
466
+ className="rounded-full dark:border-zinc-700 p-0 h-6"
467
+ variant="outline"
468
+ onClick={(event) => {
469
+ event.preventDefault();
470
+ }}
471
+ >
472
+ <CheckCirclFillIcon className="!w-full !h-full" />
473
+ </Button>
426
474
  </div>
475
+ </>
476
+ ) : (
477
+ <div>
478
+ <Button
479
+ className={`rounded-full py-1 px-2 h-fit m-0.5 dark:border-zinc-700 text-[#595959] ${enableTTS ? 'text-white hover:bg-primary/90 bg-primary' : ''}`}
480
+ onClick={(event) => {
481
+ event.preventDefault();
482
+ setEnableTTS(!enableTTS);
483
+ }}
484
+ variant="outline"
485
+ disabled={isLoading}
486
+ >
487
+ <ClikVolumeIcon /> Speak
488
+ </Button>
489
+ <Button
490
+ className="rounded-full py-1 px-2 gap-[4px] h-fit m-0.5 dark:border-zinc-700 text-[#595959]"
491
+ onClick={(event) => {
492
+ event.preventDefault();
493
+ setIsRecording(true);
494
+ }}
495
+ variant="outline"
496
+ disabled={isLoading}
497
+ >
498
+ <ClikMicrophoneIcon size={14} /> Talk
499
+ </Button>
427
500
  </div>
428
- <Button
429
- className="rounded-full p-1.5 h-fit absolute bottom-2 right-11 m-0.5 dark:border-zinc-700"
430
- variant="outline"
431
- onClick={(event) => {
432
- event.preventDefault();
433
- onRecordingCancelled();
434
- }}
435
- >
436
- <TrashIcon size={14} color="red" />
437
- </Button>
438
- </>
439
- ) : (
440
- <>
441
- <Button
442
- className="rounded-full p-1.5 h-fit absolute bottom-2 right-11 m-0.5 dark:border-zinc-700"
443
- onClick={(event) => {
444
- event.preventDefault();
445
- setIsRecording(true);
446
- }}
447
- variant="outline"
448
- disabled={isLoading}
449
- >
450
- <MicrophoneIcon size={14} />
451
- </Button>
452
- <Button
453
- className={`rounded-full p-1.5 h-fit absolute bottom-2 right-[80px] m-0.5 dark:border-zinc-700 ${enableTTS ? 'text-white hover:bg-primary/90 bg-primary' : ''}`}
454
- onClick={(event) => {
455
- event.preventDefault();
456
- setEnableTTS(!enableTTS);
457
- }}
458
- variant="outline"
459
- disabled={isLoading}
460
- >
461
- <VolumeIcon />
462
- </Button>
463
- </>
464
- )}
465
-
466
- <Button
467
- className="rounded-full p-1.5 h-fit absolute bottom-2 left-2 m-0.5 dark:border-zinc-700"
468
- onClick={(event) => {
469
- event.preventDefault();
470
- fileInputRef.current?.click();
471
- }}
472
- variant="outline"
473
- disabled={isLoading || isRecording}
474
- >
475
- <PlusIcon size={14} />
476
- </Button>
501
+ )}
502
+ </div>
477
503
  </div>
478
504
  );
479
505
  };
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { SuggestionType } from 'types/common.type';
4
+ import { ChatMessageType } from 'types/flowise.type';
5
+ import { LAYOUT_MODE } from 'commons/constants';
6
+
7
+ interface SuggestedActionsProps {
8
+ suggestedActions?: SuggestionType[];
9
+ append?: (message: ChatMessageType) => Promise<void>;
10
+ layoutMode?: string;
11
+ suggestedActionRows?: number;
12
+ }
13
+
14
+ const SuggestedActions: React.FC<SuggestedActionsProps> = ({
15
+ suggestedActions,
16
+ append,
17
+ layoutMode = LAYOUT_MODE.SCROLL,
18
+ suggestedActionRows = 1,
19
+ }) => {
20
+ if (!suggestedActions?.length) return null;
21
+
22
+ const containerHeight = suggestedActionRows * 60;
23
+
24
+ const animation = {
25
+ initial: { opacity: 0, y: 20 },
26
+ animate: { opacity: 1, y: 0 },
27
+ exit: { opacity: 0, y: 20 },
28
+ };
29
+
30
+ return layoutMode === LAYOUT_MODE.GRID ? (
31
+ // UI Grid (2 columns)
32
+ <div className="grid sm:grid-cols-2 gap-2 w-full">
33
+ {suggestedActions.map((suggestedAction, index) => (
34
+ <motion.div
35
+ key={`suggested-action-${suggestedAction.title}-${index}`}
36
+ {...animation}
37
+ transition={{ delay: 0.05 * index }}
38
+ className={index > 1 ? 'hidden sm:block' : 'block'}
39
+ >
40
+ <ActionButton suggestedAction={suggestedAction} append={append} />
41
+ </motion.div>
42
+ ))}
43
+ </div>
44
+ ) : (
45
+ // UI Scroll
46
+ <div
47
+ className="w-full overflow-x-auto scrollbar-hide"
48
+ style={{ maxHeight: `${containerHeight}px` }}
49
+ >
50
+ <div
51
+ style={{
52
+ gap: '8px',
53
+ display: 'grid',
54
+ gridAutoFlow: 'column',
55
+ gridTemplateRows: `repeat(${suggestedActionRows}, minmax(0, 1fr))`,
56
+ }}
57
+ >
58
+ {suggestedActions.map((suggestedAction, index) => (
59
+ <motion.div
60
+ key={`suggested-action-${suggestedAction.title}-${index}`}
61
+ {...animation}
62
+ transition={{ delay: 0.05 * index }}
63
+ >
64
+ <ActionButton suggestedAction={suggestedAction} append={append} />
65
+ </motion.div>
66
+ ))}
67
+ </div>
68
+ </div>
69
+ );
70
+ };
71
+
72
+ interface ActionButtonProps {
73
+ suggestedAction: SuggestionType;
74
+ append?: (message: ChatMessageType) => Promise<void>;
75
+ }
76
+
77
+ const ActionButton: React.FC<ActionButtonProps> = ({
78
+ suggestedAction,
79
+ append,
80
+ }) => (
81
+ <button
82
+ onClick={(e) => {
83
+ e.preventDefault();
84
+ if (append) {
85
+ append({ role: 'apiMessage', content: suggestedAction.action });
86
+ }
87
+ }}
88
+ className="text-left border rounded-xl px-4 py-3.5 text-sm flex-1 gap-1 sm:flex-col w-full h-auto justify-start items-start"
89
+ >
90
+ <span className="font-medium overflow-hidden whitespace-nowrap text-ellipsis w-full group-hover:overflow-visible group-hover:whitespace-normal">
91
+ {suggestedAction.title}
92
+ </span>
93
+ {!!suggestedAction.label && (
94
+ <span className="text-muted-foreground">{suggestedAction.label}</span>
95
+ )}
96
+ </button>
97
+ );
98
+
99
+ export default SuggestedActions;
@@ -5,7 +5,7 @@ import Agent from '../../components/Agent';
5
5
  import { ChatDataProvider } from '../../hooks/useChatData';
6
6
  import styles from '../../assets/tailwindcss.css';
7
7
  import commonStyles from '../../assets/common.css';
8
- import { SuggestionType } from '../../types/common.type';
8
+ import { ConfigMessageType, SuggestionType } from '../../types/common.type';
9
9
 
10
10
  export type AgentWidgetType = {
11
11
  apiHost: string;
@@ -16,7 +16,13 @@ export type AgentWidgetType = {
16
16
  suggestedActions?: SuggestionType[];
17
17
  } & Record<string, unknown>;
18
18
  theme?: {
19
- avatar?: string;
19
+ botMessage?: ConfigMessageType;
20
+ userMessage?: ConfigMessageType;
21
+ suggestion?: {
22
+ defaultRows?: number; // only for scroll mode
23
+ expandedRows?: number; // only for scroll mode
24
+ layoutMode?: 'grid' | 'scroll';
25
+ };
20
26
  input?: {
21
27
  placeholder?: string;
22
28
  };
@@ -1,11 +1,18 @@
1
1
  import React, { createContext, useEffect, useState } from 'react';
2
+ import { ConfigMessageType } from 'types/common.type';
2
3
 
3
4
  type ConfigurationData = {
4
5
  apiHost: string;
5
6
  agentId: string;
6
7
  overrideConfig?: Record<string, any>;
7
8
  theme?: {
8
- avatar?: string;
9
+ suggestion?: {
10
+ defaultRows?: number; // only for scroll mode
11
+ expandedRows?: number; // only for scroll mode
12
+ layoutMode?: 'grid' | 'scroll';
13
+ };
14
+ botMessage?: ConfigMessageType;
15
+ userMessage?: ConfigMessageType;
9
16
  input?: {
10
17
  placeholder?: string;
11
18
  };
@@ -15,3 +15,10 @@ export interface SuggestionType {
15
15
  label?: string;
16
16
  action?: string;
17
17
  }
18
+
19
+ export interface ConfigMessageType {
20
+ backgroundColor?: string;
21
+ textColor?: string;
22
+ showAvatar?: boolean;
23
+ avatarSrc?: string;
24
+ }
@@ -1,9 +0,0 @@
1
- import { FC } from 'react';
2
- type Props = {
3
- addRecordingToPreviews: (blob: Blob) => void;
4
- isRecording: boolean;
5
- setIsRecording: (value: boolean) => void;
6
- };
7
- export declare const AudioRecording: FC<Props>;
8
- export {};
9
- //# sourceMappingURL=AudioRecording.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AudioRecording.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/AudioRecording.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAuB,MAAM,OAAO,CAAC;AAShD,KAAK,KAAK,GAAG;IACX,sBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C,CAAC;AACF,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,KAAK,CAiEpC,CAAC"}
@@ -1,15 +0,0 @@
1
- import React from 'react';
2
- type TokenGeneratorData = {
3
- shouldConnect: boolean;
4
- wsUrl: string;
5
- token: string;
6
- disconnect: () => Promise<void>;
7
- connect: () => Promise<void>;
8
- };
9
- export declare const ConnectionProvider: ({ children, livekitURL, }: {
10
- children: React.ReactNode;
11
- livekitURL: string;
12
- }) => import("react/jsx-runtime").JSX.Element;
13
- export declare const useConnection: () => TokenGeneratorData;
14
- export {};
15
- //# sourceMappingURL=useConnection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useConnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useConnection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAIvD,KAAK,kBAAkB,GAAG;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAMF,eAAO,MAAM,kBAAkB,8BAG5B;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,4CA6CA,CAAC;AAEF,eAAO,MAAM,aAAa,0BAMzB,CAAC"}
@@ -1,3 +0,0 @@
1
- import { UserType } from '../types/user.type';
2
- export declare const getUserInfo: (accessToken: string) => Promise<UserType>;
3
- //# sourceMappingURL=user.service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../src/services/user.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAI9C,eAAO,MAAM,WAAW,gBAAuB,MAAM,KAAG,OAAO,CAAC,QAAQ,CAUvE,CAAC"}
@@ -1,11 +0,0 @@
1
- export interface AgentType {
2
- id: string;
3
- created: string;
4
- lastModifiedDate: string;
5
- name: string;
6
- chatflowId: string;
7
- chatflowConfig: any;
8
- hidden: boolean;
9
- avatar: string;
10
- }
11
- //# sourceMappingURL=agentType.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agentType.d.ts","sourceRoot":"","sources":["../../src/types/agentType.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,GAAG,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB"}