|
1 |
| -import { useMemo } from "react"; |
| 1 | +import { useMemo, useState } from "react"; |
2 | 2 | import { Stack, IconButton } from "@fluentui/react";
|
3 | 3 | import { useTranslation } from "react-i18next";
|
4 | 4 | import DOMPurify from "dompurify";
|
@@ -46,13 +46,34 @@ export const Answer = ({
|
46 | 46 | const parsedAnswer = useMemo(() => parseAnswerToHtml(answer, isStreaming, onCitationClicked), [answer]);
|
47 | 47 | const { t } = useTranslation();
|
48 | 48 | const sanitizedAnswerHtml = DOMPurify.sanitize(parsedAnswer.answerHtml);
|
| 49 | + const [copied, setCopied] = useState(false); |
| 50 | + |
| 51 | + const handleCopy = () => { |
| 52 | + // Single replace to remove all HTML tags to remove the citations |
| 53 | + const textToCopy = sanitizedAnswerHtml.replace(/<a [^>]*><sup>\d+<\/sup><\/a>|<[^>]+>/g, ""); |
| 54 | + |
| 55 | + navigator.clipboard |
| 56 | + .writeText(textToCopy) |
| 57 | + .then(() => { |
| 58 | + setCopied(true); |
| 59 | + setTimeout(() => setCopied(false), 2000); |
| 60 | + }) |
| 61 | + .catch(err => console.error("Failed to copy text: ", err)); |
| 62 | + }; |
49 | 63 |
|
50 | 64 | return (
|
51 | 65 | <Stack className={`${styles.answerContainer} ${isSelected && styles.selected}`} verticalAlign="space-between">
|
52 | 66 | <Stack.Item>
|
53 | 67 | <Stack horizontal horizontalAlign="space-between">
|
54 | 68 | <AnswerIcon />
|
55 | 69 | <div>
|
| 70 | + <IconButton |
| 71 | + style={{ color: "black" }} |
| 72 | + iconProps={{ iconName: copied ? "CheckMark" : "Copy" }} |
| 73 | + title={copied ? t("tooltips.copied") : t("tooltips.copy")} |
| 74 | + ariaLabel={copied ? t("tooltips.copied") : t("tooltips.copy")} |
| 75 | + onClick={handleCopy} |
| 76 | + /> |
56 | 77 | <IconButton
|
57 | 78 | style={{ color: "black" }}
|
58 | 79 | iconProps={{ iconName: "Lightbulb" }}
|
|
0 commit comments