Browse Source

Merge pull request #353 from RooVetGit/markdown_copy

Add a button to copy markdown out of the chat
Matt Rubens 1 year ago
parent
commit
88ea875bbb
3 changed files with 66 additions and 7 deletions
  1. 5 0
      .changeset/real-rockets-sort.md
  2. 1 0
      README.md
  3. 60 7
      webview-ui/src/components/chat/ChatRow.tsx

+ 5 - 0
.changeset/real-rockets-sort.md

@@ -0,0 +1,5 @@
+---
+"roo-cline": patch
+---
+
+Add a button to copy markdown out of the chat

+ 1 - 0
README.md

@@ -35,6 +35,7 @@ Give it a try and let us know what you think in the reddit: https://www.reddit.c
 - Sound effects for feedback
 - Option to use browsers of different sizes and adjust screenshot quality
 - Quick prompt copying from history
+- Copy markdown from chat messages
 - OpenRouter compression support
 - Includes current time in the system prompt
 - Uses a file system watcher to more reliably watch for file system changes

+ 60 - 7
webview-ui/src/components/chat/ChatRow.tsx

@@ -1,6 +1,6 @@
 import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
 import deepEqual from "fast-deep-equal"
-import React, { memo, useEffect, useMemo, useRef } from "react"
+import React, { memo, useEffect, useMemo, useRef, useState } from "react"
 import { useSize } from "react-use"
 import {
 	ClineApiReqInfo,
@@ -551,7 +551,7 @@ export const ChatRowContent = ({
 				case "text":
 					return (
 						<div>
-							<Markdown markdown={message.text} />
+							<Markdown markdown={message.text} partial={message.partial} />
 						</div>
 					)
 				case "user_feedback":
@@ -703,7 +703,7 @@ export const ChatRowContent = ({
 								</div>
 							)}
 							<div style={{ paddingTop: 10 }}>
-								<Markdown markdown={message.text} />
+								<Markdown markdown={message.text} partial={message.partial} />
 							</div>
 						</>
 					)
@@ -876,7 +876,7 @@ export const ChatRowContent = ({
 									{title}
 								</div>
 								<div style={{ color: "var(--vscode-charts-green)", paddingTop: 10 }}>
-									<Markdown markdown={message.text} />
+									<Markdown markdown={message.text} partial={message.partial} />
 								</div>
 							</div>
 						)
@@ -918,10 +918,63 @@ export const ProgressIndicator = () => (
 	</div>
 )
 
-const Markdown = memo(({ markdown }: { markdown?: string }) => {
+const Markdown = memo(({ markdown, partial }: { markdown?: string; partial?: boolean }) => {
+	const [isHovering, setIsHovering] = useState(false);
+
 	return (
-		<div style={{ wordBreak: "break-word", overflowWrap: "anywhere", marginBottom: -15, marginTop: -15 }}>
-			<MarkdownBlock markdown={markdown} />
+		<div
+			onMouseEnter={() => setIsHovering(true)}
+			onMouseLeave={() => setIsHovering(false)}
+			style={{ position: "relative" }}
+		>
+			<div style={{ wordBreak: "break-word", overflowWrap: "anywhere", marginBottom: -15, marginTop: -15 }}>
+				<MarkdownBlock markdown={markdown} />
+			</div>
+			{markdown && !partial && isHovering && (
+				<div
+					style={{
+						position: "absolute",
+						bottom: "-4px",
+						right: "8px",
+						opacity: 0,
+						animation: "fadeIn 0.2s ease-in-out forwards",
+						borderRadius: "4px"
+					}}
+				>
+					<style>
+						{`
+							@keyframes fadeIn {
+								from { opacity: 0; }
+								to { opacity: 1.0; }
+							}
+						`}
+					</style>
+					<VSCodeButton
+						className="copy-button"
+						appearance="icon"
+						style={{
+							height: "24px",
+							border: "none",
+							background: "var(--vscode-editor-background)",
+							transition: "background 0.2s ease-in-out"
+						}}
+						onClick={() => {
+							navigator.clipboard.writeText(markdown);
+							// Flash the button background briefly to indicate success
+							const button = document.activeElement as HTMLElement;
+							if (button) {
+								button.style.background = "var(--vscode-button-background)";
+								setTimeout(() => {
+									button.style.background = "";
+								}, 200);
+							}
+						}}
+						title="Copy as markdown"
+					>
+						<span className="codicon codicon-copy"></span>
+					</VSCodeButton>
+				</div>
+			)}
 		</div>
 	)
 })