From 4aa75ce14ba8c313cd7d321b8fc4b4dcdb9427e1 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 7 May 2025 15:08:00 +0200 Subject: [PATCH] ui: try to save text with formatting in secure contexts --- .../app/components/Kai/components/ChatMsg.tsx | 2 +- .../components/ui/CopyButton/CopyButton.js | 27 ++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/frontend/app/components/Kai/components/ChatMsg.tsx b/frontend/app/components/Kai/components/ChatMsg.tsx index 72a6e664e..cd5289a35 100644 --- a/frontend/app/components/Kai/components/ChatMsg.tsx +++ b/frontend/app/components/Kai/components/ChatMsg.tsx @@ -102,7 +102,7 @@ export function ChatMsg({ onFeedback('dislike', messageId)}> - + bodyRef.current?.innerHTML} isIcon format={'text/html'} /> diff --git a/frontend/app/components/ui/CopyButton/CopyButton.js b/frontend/app/components/ui/CopyButton/CopyButton.js index a6c10e410..52652ae2f 100644 --- a/frontend/app/components/ui/CopyButton/CopyButton.js +++ b/frontend/app/components/ui/CopyButton/CopyButton.js @@ -10,15 +10,36 @@ function CopyButton({ btnText = 'copy', size = 'small', isIcon = false, + format = 'text/plain', }) { const [copied, setCopied] = useState(false); - const copyHandler = () => { - setCopied(true); - copy(content); + const reset = () => { setTimeout(() => { setCopied(false); }, 1000); + } + const copyHandler = () => { + setCopied(true); + const contentIsGetter = typeof content === 'function' + const textContent = contentIsGetter ? content() : content; + const isHttps = window.location.protocol === 'https:'; + if (!isHttps) { + copy(textContent); + reset(); + return; + } + const blob = new Blob([textContent], { type: format }); + const cbItem = new ClipboardItem({ + [format]: blob + }) + navigator.clipboard.write([cbItem]) + .catch(e => { + copy(textContent); + }) + .finally(() => { + reset() + }) }; if (isIcon) {