From d7d005e71fe10476db7fa57d4f8211c7e02e42e3 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 16 Feb 2026 19:20:14 -0700 Subject: [PATCH] Add copy button --- web/public/locales/en/common.json | 1 + web/src/components/chat/ChatMessage.tsx | 49 ++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/web/public/locales/en/common.json b/web/public/locales/en/common.json index f75e0c97d..1181554af 100644 --- a/web/public/locales/en/common.json +++ b/web/public/locales/en/common.json @@ -129,6 +129,7 @@ "cancel": "Cancel", "close": "Close", "copy": "Copy", + "copiedToClipboard": "Copied to clipboard", "back": "Back", "history": "History", "fullscreen": "Fullscreen", diff --git a/web/src/components/chat/ChatMessage.tsx b/web/src/components/chat/ChatMessage.tsx index 48117221f..3e87a495e 100644 --- a/web/src/components/chat/ChatMessage.tsx +++ b/web/src/components/chat/ChatMessage.tsx @@ -1,4 +1,14 @@ import ReactMarkdown from "react-markdown"; +import { useTranslation } from "react-i18next"; +import copy from "copy-to-clipboard"; +import { toast } from "sonner"; +import { FaCopy } from "react-icons/fa"; +import { Button } from "@/components/ui/button"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; type MessageBubbleProps = { @@ -7,18 +17,47 @@ type MessageBubbleProps = { }; export function MessageBubble({ role, content }: MessageBubbleProps) { + const { t } = useTranslation(["views/chat", "common"]); const isUser = role === "user"; + const handleCopy = () => { + const text = content?.trim() || ""; + if (!text) return; + if (copy(text)) { + toast.success(t("button.copiedToClipboard", { ns: "common" })); + } + }; + return (
- {isUser ? content : {content}} +
+ {isUser ? content : {content}} +
+ + + + + {t("button.copy", { ns: "common" })} +
); }