feat: copy button on user messages, hover on message for buttons#110
feat: copy button on user messages, hover on message for buttons#110
Conversation
WalkthroughA MessageCopyButton component was added to ChatView.tsx that copies message text to the clipboard and displays brief visual feedback. The button is integrated into the MessagesTimeline component, appearing alongside existing message actions with hover activation and layout adjustments for consistent spacing. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 2341-2344: handleCopy currently calls
navigator.clipboard.writeText without handling rejections and always sets
setCopied(true), and the timeout is never cleared on unmount; update handleCopy
to await or use .then/.catch on navigator.clipboard.writeText(text) and only
call setCopied(true) when the promise resolves, log or surface the error on
rejection and avoid setting copied on failure, store the timeout id in a ref
(e.g., copyTimeoutRef) and use clearTimeout(copyTimeoutRef.current) before
setting a new timeout, and add a cleanup (in a useEffect return) to clear the
timeout on unmount; reference handleCopy, navigator.clipboard.writeText,
setCopied and the timeout logic when making changes.
| const handleCopy = useCallback(() => { | ||
| void navigator.clipboard.writeText(text); | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); |
There was a problem hiding this comment.
Handle clipboard API errors and clean up timeout on unmount.
navigator.clipboard.writeText can reject (permission denied, insecure context). Currently, failures are silently ignored and the user sees "copied" feedback regardless. Additionally, the timeout should be cleaned up if the component unmounts.
🛡️ Proposed fix
const MessageCopyButton = memo(function MessageCopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(() => {
- void navigator.clipboard.writeText(text);
- setCopied(true);
- setTimeout(() => setCopied(false), 2000);
+ navigator.clipboard.writeText(text).then(
+ () => setCopied(true),
+ () => {
+ // Optionally show error feedback or silently fail
+ }
+ );
}, [text]);
+
+ useEffect(() => {
+ if (!copied) return;
+ const timer = setTimeout(() => setCopied(false), 2000);
+ return () => clearTimeout(timer);
+ }, [copied]);
return (🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ChatView.tsx` around lines 2341 - 2344, handleCopy
currently calls navigator.clipboard.writeText without handling rejections and
always sets setCopied(true), and the timeout is never cleared on unmount; update
handleCopy to await or use .then/.catch on navigator.clipboard.writeText(text)
and only call setCopied(true) when the promise resolves, log or surface the
error on rejection and avoid setting copied on failure, store the timeout id in
a ref (e.g., copyTimeoutRef) and use clearTimeout(copyTimeoutRef.current) before
setting a new timeout, and add a cleanup (in a useEffect return) to clear the
timeout on unmount; reference handleCopy, navigator.clipboard.writeText,
setCopied and the timeout logic when making changes.
Note
Add a copy button to user message bubbles and show message controls on hover in
apps/web/src/components/ChatView.tsxIntroduce a memoized
MessageCopyButtonthat writes text to the clipboard and togglesCopyIcon/CheckIconfor 2000ms, and update user message bubbles to reveal copy and revert controls on hover/focus with opacity transitions in ChatView.tsx.📍Where to Start
Start with the
MessageCopyButtoncomponent and its usage withinMessagesTimelinein ChatView.tsx.Macroscope summarized e09f859.
Summary by CodeRabbit