feat: add copy button in code snippet

pull/955/head
jang_yoonsu 5 months ago
parent 889a050f25
commit 3767d14e5c

@ -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<number | null>(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 = (
<div ref={ref} className={`flex flex-row-reverse self-end ${className}`}>
<Avatar className="mt-2 text-2xl" avatar="🧑‍💻"></Avatar>
<div className="mr-2 ml-10 flex items-center rounded-3xl bg-purple-30 p-3.5 text-white">
<div className="ml-10 mr-2 flex items-center rounded-3xl bg-purple-30 p-3.5 text-white">
<ReactMarkdown className="whitespace-pre-wrap break-normal leading-normal">
{message}
</ReactMarkdown>
@ -94,19 +83,28 @@ const ConversationBubble = forwardRef<
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
PreTag="div"
language={match[1]}
{...props}
style={vscDarkPlus}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className ? className : ''} {...props}>
{children}
</code>
return (
<div className="relative">
{!inline && match ? (
<SyntaxHighlighter
PreTag="div"
language={match[1]}
{...props}
style={vscDarkPlus}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className ? className : ''} {...props}>
{children}
</code>
)}
<div className="absolute right-3 top-3">
<CoppyButton
text={String(children).replace(/\n$/, '')}
/>
</div>
</div>
);
},
ul({ children }) {
@ -172,7 +170,7 @@ const ConversationBubble = forwardRef<
{sources?.map((source, index) => (
<div
key={index}
className={`max-w-xs sm:max-w-sm md:max-w-md cursor-pointer rounded-[28px] py-1 px-4 ${
className={`max-w-xs cursor-pointer rounded-[28px] px-4 py-1 sm:max-w-sm md:max-w-md ${
openSource === index
? 'bg-[#007DFF]'
: 'bg-[#D7EBFD] hover:bg-[#BFE1FF]'
@ -203,31 +201,7 @@ const ConversationBubble = forwardRef<
${type !== 'ERROR' ? 'group-hover:lg:visible' : ''}`}
>
<div className="absolute left-2 top-4">
<div
className={`flex items-center justify-center rounded-full p-2
${
isCopyHovered
? 'bg-[#EEEEEE] dark:bg-purple-taupe'
: 'bg-[#ffffff] dark:bg-transparent'
}`}
>
{copied ? (
<CheckMark
className="cursor-pointer stroke-green-2000"
onMouseEnter={() => setIsCopyHovered(true)}
onMouseLeave={() => setIsCopyHovered(false)}
/>
) : (
<Copy
className={`cursor-pointer fill-none`}
onClick={() => {
handleCopyClick(message);
}}
onMouseEnter={() => setIsCopyHovered(true)}
onMouseLeave={() => setIsCopyHovered(false)}
></Copy>
)}
</div>
<CoppyButton text={message} />
</div>
</div>
<div

Loading…
Cancel
Save