From 8dcc40f01b342aa9db919fa1c3099d344cf494a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Fri, 20 Feb 2026 12:53:09 -0300 Subject: [PATCH] refactor: simplify pr --- .../kilo-ui/src/components/message-part.css | 4 +++ packages/ui/src/components/message-part.css | 18 +++++++++++ packages/ui/src/components/message-part.tsx | 30 ++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css index 7aa79677ba..5b9bfbfde4 100644 --- a/packages/kilo-ui/src/components/message-part.css +++ b/packages/kilo-ui/src/components/message-part.css @@ -5,4 +5,8 @@ [data-slot="text-part-body"] { margin-top: 0; } + + [data-slot="text-part-copy-wrapper"] { + display: none; + } } diff --git a/packages/ui/src/components/message-part.css b/packages/ui/src/components/message-part.css index af9786f00c..44db4f9aa5 100644 --- a/packages/ui/src/components/message-part.css +++ b/packages/ui/src/components/message-part.css @@ -114,6 +114,24 @@ [data-component="text-part"] { width: 100%; + [data-slot="text-part-body"] { + position: relative; + margin-top: 32px; + } + + [data-slot="text-part-copy-wrapper"] { + position: absolute; + top: -28px; + right: 8px; + opacity: 0; + transition: opacity 0.15s ease; + z-index: 1; + } + + [data-slot="text-part-body"]:hover [data-slot="text-part-copy-wrapper"] { + opacity: 1; + } + [data-component="markdown"] { margin-top: 0; font-size: var(--font-size-base); diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 6da22168fb..42dc37abc5 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -668,14 +668,42 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) { PART_MAPPING["text"] = function TextPartDisplay(props) { const data = useData() + const i18n = useI18n() const part = props.part as TextPart const displayText = () => relativizeProjectPaths((part.text ?? "").trim(), data.directory) const throttledText = createThrottledValue(displayText) + const [copied, setCopied] = createSignal(false) + + const handleCopy = async () => { + const content = displayText() + if (!content) return + await navigator.clipboard.writeText(content) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } return (
- +
+ +
+ + e.preventDefault()} + onClick={handleCopy} + aria-label={copied() ? i18n.t("ui.message.copied") : i18n.t("ui.message.copy")} + /> + +
+
)