diff --git a/src/components/message/message-list-view.tsx b/src/components/message/message-list-view.tsx index 2785917..8e98094 100644 --- a/src/components/message/message-list-view.tsx +++ b/src/components/message/message-list-view.tsx @@ -19,8 +19,19 @@ import { MessageThread, MessageThreadScrollButton, } from "@/components/ai-elements/message-thread" -import { Message, MessageContent } from "@/components/ai-elements/message" -import { ChevronDown, ChevronRight, Info, Loader2 } from "lucide-react" +import { + Message, + MessageContent, + MessageAction, +} from "@/components/ai-elements/message" +import { + CheckIcon, + ChevronDown, + ChevronRight, + CopyIcon, + Info, + Loader2, +} from "lucide-react" import { useTranslations } from "next-intl" import { buildPlanKey, @@ -103,6 +114,54 @@ const CollapsibleSystemMessage = memo(function CollapsibleSystemMessage({ ) }) +function extractTextFromParts(parts: AdaptedContentPart[]): string { + return parts + .filter((p): p is { type: "text"; text: string } => p.type === "text") + .map((p) => p.text) + .join("\n") +} + +const UserMessageCopyButton = memo(function UserMessageCopyButton({ + parts, +}: { + parts: AdaptedContentPart[] +}) { + const t = useTranslations("Folder.chat.messageList") + const [isCopied, setIsCopied] = useState(false) + const timeoutRef = useRef(0) + + const handleCopy = useCallback(async () => { + if (isCopied) return + const text = extractTextFromParts(parts) + if (!text) return + try { + await navigator.clipboard.writeText(text) + setIsCopied(true) + timeoutRef.current = window.setTimeout(() => setIsCopied(false), 2000) + } catch { + // ignore + } + }, [parts, isCopied]) + + useEffect( + () => () => { + window.clearTimeout(timeoutRef.current) + }, + [] + ) + + return ( + + {isCopied ? : } + + ) +}) + const HistoricalMessageGroup = memo(function HistoricalMessageGroup({ group, dimmed = false, @@ -122,9 +181,18 @@ const HistoricalMessageGroup = memo(function HistoricalMessageGroup({ {group.role === "user" && group.images.length > 0 ? ( ) : null} - - - + {group.role === "user" ? ( +
+ + + + +
+ ) : ( + + + + )} {group.role === "user" && group.resources.length > 0 ? ( ) : null} diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index ee58d27..b2bb063 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1467,7 +1467,9 @@ "loading": "جارٍ التحميل...", "error": "خطأ: {message}", "emptyConversation": "لا توجد رسائل في هذه المحادثة.", - "systemMessage": "رسالة النظام" + "systemMessage": "رسالة النظام", + "copyMessage": "نسخ", + "copied": "تم النسخ" }, "liveTurnStats": { "thinking": "جارٍ التفكير...", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 2820b0d..2f9a618 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1467,7 +1467,9 @@ "loading": "Lädt...", "error": "Fehler: {message}", "emptyConversation": "Keine Nachrichten in dieser Unterhaltung.", - "systemMessage": "Systemnachricht" + "systemMessage": "Systemnachricht", + "copyMessage": "Kopieren", + "copied": "Kopiert" }, "liveTurnStats": { "thinking": "Denkt nach...", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 2d4de2c..ca90348 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1467,7 +1467,9 @@ "loading": "Loading...", "error": "Error: {message}", "emptyConversation": "No messages in this conversation.", - "systemMessage": "System message" + "systemMessage": "System message", + "copyMessage": "Copy", + "copied": "Copied" }, "liveTurnStats": { "thinking": "Thinking...", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index eef60ef..310f1cd 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -1467,7 +1467,9 @@ "loading": "Cargando...", "error": "Error del chat: {message}", "emptyConversation": "No hay mensajes en esta conversación.", - "systemMessage": "Mensaje del sistema" + "systemMessage": "Mensaje del sistema", + "copyMessage": "Copiar", + "copied": "Copiado" }, "liveTurnStats": { "thinking": "Pensando...", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 7dd4719..d053de4 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1467,7 +1467,9 @@ "loading": "Chargement...", "error": "Erreur : {message}", "emptyConversation": "Aucun message dans cette conversation.", - "systemMessage": "Message système" + "systemMessage": "Message système", + "copyMessage": "Copier", + "copied": "Copié" }, "liveTurnStats": { "thinking": "Réflexion...", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index ad65657..7f71f10 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -1467,7 +1467,9 @@ "loading": "読み込み中...", "error": "エラー: {message}", "emptyConversation": "この会話にはメッセージがありません。", - "systemMessage": "システムメッセージ" + "systemMessage": "システムメッセージ", + "copyMessage": "コピー", + "copied": "コピー済み" }, "liveTurnStats": { "thinking": "考え中...", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index 2d1f239..d03bb4d 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -1467,7 +1467,9 @@ "loading": "불러오는 중...", "error": "오류: {message}", "emptyConversation": "이 대화에는 메시지가 없습니다.", - "systemMessage": "시스템 메시지" + "systemMessage": "시스템 메시지", + "copyMessage": "복사", + "copied": "복사됨" }, "liveTurnStats": { "thinking": "생각 중...", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 343034c..6793a7e 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1467,7 +1467,9 @@ "loading": "Carregando...", "error": "Erro: {message}", "emptyConversation": "Nenhuma mensagem nesta conversa.", - "systemMessage": "Mensagem do sistema" + "systemMessage": "Mensagem do sistema", + "copyMessage": "Copiar", + "copied": "Copiado" }, "liveTurnStats": { "thinking": "Pensando...", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 59d7b48..a4c09e0 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -1467,7 +1467,9 @@ "loading": "加载中...", "error": "错误:{message}", "emptyConversation": "当前会话暂无消息。", - "systemMessage": "系统消息" + "systemMessage": "系统消息", + "copyMessage": "复制", + "copied": "已复制" }, "liveTurnStats": { "thinking": "思考中...", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 794746d..c0c3b78 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -1467,7 +1467,9 @@ "loading": "載入中...", "error": "錯誤:{message}", "emptyConversation": "目前會話暫無訊息。", - "systemMessage": "系統訊息" + "systemMessage": "系統訊息", + "copyMessage": "複製", + "copied": "已複製" }, "liveTurnStats": { "thinking": "思考中...",