From 60666564cc70ce5e61c59142e6a4714d413b6ee5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 1 Apr 2026 07:26:24 +0000 Subject: [PATCH 1/2] Add copy-to-clipboard action for proposed plan card Co-authored-by: Julius Marminge --- apps/web/src/components/chat/ProposedPlanCard.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/web/src/components/chat/ProposedPlanCard.tsx b/apps/web/src/components/chat/ProposedPlanCard.tsx index c8956b9cfa..077b3aecaf 100644 --- a/apps/web/src/components/chat/ProposedPlanCard.tsx +++ b/apps/web/src/components/chat/ProposedPlanCard.tsx @@ -25,6 +25,7 @@ import { } from "../ui/dialog"; import { toastManager } from "../ui/toast"; import { readNativeApi } from "~/nativeApi"; +import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; export const ProposedPlanCard = memo(function ProposedPlanCard({ planMarkdown, @@ -39,6 +40,15 @@ export const ProposedPlanCard = memo(function ProposedPlanCard({ const [isSaveDialogOpen, setIsSaveDialogOpen] = useState(false); const [savePath, setSavePath] = useState(""); const [isSavingToWorkspace, setIsSavingToWorkspace] = useState(false); + const { copyToClipboard, isCopied } = useCopyToClipboard({ + onError: (error) => { + toastManager.add({ + type: "error", + title: "Could not copy plan", + description: error instanceof Error ? error.message : "An error occurred while copying.", + }); + }, + }); const savePathInputId = useId(); const title = proposedPlanTitle(planMarkdown) ?? "Proposed plan"; const lineCount = planMarkdown.split("\n").length; @@ -54,6 +64,10 @@ export const ProposedPlanCard = memo(function ProposedPlanCard({ downloadPlanAsTextFile(downloadFilename, saveContents); }; + const handleCopyPlan = () => { + copyToClipboard(saveContents); + }; + const openSaveDialog = () => { if (!workspaceRoot) { toastManager.add({ @@ -127,6 +141,7 @@ export const ProposedPlanCard = memo(function ProposedPlanCard({