Skip to content

Commit 395de24

Browse files
author
Dylan Huang
authored
Copy button in chat interface (#116)
* copy button for message bubbles * vite build
1 parent 88ac21a commit 395de24

File tree

6 files changed

+68
-30
lines changed

6 files changed

+68
-30
lines changed

vite-app/dist/assets/index-Bxmt9iUR.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vite-app/dist/assets/index-CmORTC9_.js.map renamed to vite-app/dist/assets/index-DbgWqpuZ.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vite-app/dist/assets/index-SA8VJz3D.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

vite-app/dist/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>EP | Log Viewer</title>
77
<link rel="icon" href="/assets/favicon-BkAAWQga.png" />
8-
<script type="module" crossorigin src="/assets/index-CmORTC9_.js"></script>
9-
<link rel="stylesheet" crossorigin href="/assets/index-SA8VJz3D.css">
8+
<script type="module" crossorigin src="/assets/index-DbgWqpuZ.js"></script>
9+
<link rel="stylesheet" crossorigin href="/assets/index-Bxmt9iUR.css">
1010
</head>
1111
<body>
1212
<div id="root"></div>

vite-app/src/components/MessageBubble.tsx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import type { Message } from "../types/eval-protocol";
22
import { useState } from "react";
3+
import Button from "./Button";
4+
import { Tooltip } from "./Tooltip";
35

46
export const MessageBubble = ({ message }: { message: Message }) => {
57
const [isExpanded, setIsExpanded] = useState(false);
8+
const [copySuccess, setCopySuccess] = useState(false);
69
const isUser = message.role === "user";
710
const isSystem = message.role === "system";
811
const isTool = message.role === "tool";
@@ -31,10 +34,20 @@ export const MessageBubble = ({ message }: { message: Message }) => {
3134
? messageContent.substring(0, 200) + "..."
3235
: messageContent;
3336

37+
const handleCopy = async () => {
38+
try {
39+
await navigator.clipboard.writeText(messageContent);
40+
setCopySuccess(true);
41+
setTimeout(() => setCopySuccess(false), 2000);
42+
} catch (err) {
43+
console.error("Failed to copy message:", err);
44+
}
45+
};
46+
3447
return (
3548
<div className={`flex ${isUser ? "justify-end" : "justify-start"} mb-1`}>
3649
<div
37-
className={`max-w-sm lg:max-w-md xl:max-w-lg px-2 py-1 border text-xs ${
50+
className={`max-w-sm lg:max-w-md xl:max-w-lg px-2 py-1 border text-xs relative ${
3851
isUser
3952
? "bg-blue-50 border-blue-200 text-blue-900"
4053
: isSystem
@@ -44,7 +57,32 @@ export const MessageBubble = ({ message }: { message: Message }) => {
4457
: "bg-yellow-50 border-yellow-200 text-yellow-900"
4558
}`}
4659
>
47-
<div className="font-semibold text-xs mb-0.5 capitalize">
60+
{/* Copy button positioned in top-right corner */}
61+
<div className="absolute top-1 right-1">
62+
<Tooltip
63+
content={copySuccess ? "Copied!" : "Copy message to clipboard"}
64+
position="top"
65+
>
66+
<Button
67+
onClick={handleCopy}
68+
size="sm"
69+
variant="secondary"
70+
className={`p-0.5 h-5 text-[10px] opacity-60 hover:opacity-100 transition-opacity cursor-pointer ${
71+
isUser
72+
? "text-blue-600 hover:bg-blue-100"
73+
: isSystem
74+
? "text-gray-600 hover:bg-gray-100"
75+
: isTool
76+
? "text-green-600 hover:bg-green-100"
77+
: "text-yellow-600 hover:bg-yellow-100"
78+
}`}
79+
>
80+
Copy
81+
</Button>
82+
</Tooltip>
83+
</div>
84+
85+
<div className="font-semibold text-xs mb-0.5 capitalize pr-8">
4886
{message.role}
4987
</div>
5088
<div className="whitespace-pre-wrap break-words overflow-hidden text-xs">

0 commit comments

Comments
 (0)