From b1a52f20edda9a8b2c68cea1a9de28025d3bf543 Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 15 Dec 2025 22:51:34 +0800 Subject: [PATCH] fix(web): add clipboard fallback for CodeBlock copy button in non-secure contexts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CodeBlock component was refactored in v0.25.3 to use navigator.clipboard.writeText(), which requires HTTPS or localhost. This caused the copy button to fail silently for users accessing Memos over HTTP. This fix adds a fallback to the copy-to-clipboard library (already used by all other copy operations in the codebase) when the native clipboard API is unavailable or fails, ensuring the copy button works reliably in all deployment scenarios. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- web/src/components/MemoContent/CodeBlock.tsx | 29 +++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/web/src/components/MemoContent/CodeBlock.tsx b/web/src/components/MemoContent/CodeBlock.tsx index cafa682a0..adfaaf153 100644 --- a/web/src/components/MemoContent/CodeBlock.tsx +++ b/web/src/components/MemoContent/CodeBlock.tsx @@ -1,3 +1,4 @@ +import copy from "copy-to-clipboard"; import hljs from "highlight.js"; import { CheckIcon, CopyIcon } from "lucide-react"; import { observer } from "mobx-react-lite"; @@ -82,11 +83,31 @@ export const CodeBlock = observer(({ children, className, ...props }: CodeBlockP const handleCopy = async () => { try { - await navigator.clipboard.writeText(codeContent); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + // Try native clipboard API first (requires HTTPS or localhost) + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(codeContent); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } else { + // Fallback to copy-to-clipboard library for non-secure contexts + const success = copy(codeContent); + if (success) { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } else { + console.error("Failed to copy code"); + } + } } catch (err) { - console.error("Failed to copy code:", err); + // If native API fails, try fallback + console.warn("Native clipboard failed, using fallback:", err); + const success = copy(codeContent); + if (success) { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } else { + console.error("Failed to copy code:", err); + } } };