diff --git a/frontend/src/components/CopyButton.tsx b/frontend/src/components/CopyButton.tsx
new file mode 100644
index 00000000..e28fdcaf
--- /dev/null
+++ b/frontend/src/components/CopyButton.tsx
@@ -0,0 +1,45 @@
+import { useState } from 'react';
+import Copy from './../assets/copy.svg?react';
+import CheckMark from './../assets/checkmark.svg?react';
+import copy from 'copy-to-clipboard';
+
+export default function CoppyButton({ text }: { text: string }) {
+ const [copied, setCopied] = useState(false);
+ const [isCopyHovered, setIsCopyHovered] = useState(false);
+
+ const handleCopyClick = (text: string) => {
+ copy(text);
+ setCopied(true);
+ // Reset copied to false after a few seconds
+ setTimeout(() => {
+ setCopied(false);
+ }, 3000);
+ };
+
+ return (
+
+ {copied ? (
+ setIsCopyHovered(true)}
+ onMouseLeave={() => setIsCopyHovered(false)}
+ />
+ ) : (
+ {
+ handleCopyClick(text);
+ }}
+ onMouseEnter={() => setIsCopyHovered(true)}
+ onMouseLeave={() => setIsCopyHovered(false)}
+ />
+ )}
+
+ );
+}
diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx
index bce831f7..9877db66 100644
--- a/frontend/src/conversation/ConversationBubble.tsx
+++ b/frontend/src/conversation/ConversationBubble.tsx
@@ -1,15 +1,14 @@
import { forwardRef, useState } from 'react';
import Avatar from '../components/Avatar';
+import CoppyButton from '../components/CopyButton';
import remarkGfm from 'remark-gfm';
import { FEEDBACK, MESSAGE_TYPE } from './conversationModels';
import classes from './ConversationBubble.module.css';
import Alert from './../assets/alert.svg';
import Like from './../assets/like.svg?react';
import Dislike from './../assets/dislike.svg?react';
-import Copy from './../assets/copy.svg?react';
-import CheckMark from './../assets/checkmark.svg?react';
+
import ReactMarkdown from 'react-markdown';
-import copy from 'copy-to-clipboard';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import DocsGPT3 from '../assets/cute_docsgpt3.svg';
@@ -30,29 +29,19 @@ const ConversationBubble = forwardRef<
ref,
) {
const [openSource, setOpenSource] = useState(null);
- const [copied, setCopied] = useState(false);
- const handleCopyClick = (text: string) => {
- copy(text);
- setCopied(true);
- // Reset copied to false after a few seconds
- setTimeout(() => {
- setCopied(false);
- }, 3000);
- };
- const [isCopyHovered, setIsCopyHovered] = useState(false);
const [isLikeHovered, setIsLikeHovered] = useState(false);
const [isDislikeHovered, setIsDislikeHovered] = useState(false);
const [isLikeClicked, setIsLikeClicked] = useState(false);
const [isDislikeClicked, setIsDislikeClicked] = useState(false);
let bubble;
-
+
if (type === 'QUESTION') {
bubble = (
-
+
{message}
@@ -95,14 +84,24 @@ const ConversationBubble = forwardRef<
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
-
- {String(children).replace(/\n$/, '')}
-
+
+
+ {String(children).replace(/\n$/, '')}
+
+
+
+
+
) : (
{children}
@@ -172,7 +171,7 @@ const ConversationBubble = forwardRef<
{sources?.map((source, index) => (
-
- {copied ? (
- setIsCopyHovered(true)}
- onMouseLeave={() => setIsCopyHovered(false)}
- />
- ) : (
- {
- handleCopyClick(message);
- }}
- onMouseEnter={() => setIsCopyHovered(true)}
- onMouseLeave={() => setIsCopyHovered(false)}
- >
- )}
-
+