refactor(chat): add footer buttons and adjust summary display

This commit is contained in:
Bohdan Triapitsyn
2025-12-09 12:04:27 +02:00
parent e763f2ce44
commit 9bfeb054c4
@@ -327,6 +327,7 @@ const AssistantMessageBody: React.FC<Omit<MessageBodyProps, 'isUser'>> = ({
return parts.some((part) => part.type === 'step-finish' && (part as { reason?: string | null | undefined }).reason === 'stop'); return parts.some((part) => part.type === 'step-finish' && (part as { reason?: string | null | undefined }).reason === 'stop');
}, [parts]); }, [parts]);
const hasTools = toolParts.length > 0; const hasTools = toolParts.length > 0;
const hasPendingTools = React.useMemo(() => { const hasPendingTools = React.useMemo(() => {
@@ -961,39 +962,15 @@ const AssistantMessageBody: React.FC<Omit<MessageBodyProps, 'isUser'>> = ({
const summaryBody = summaryBodyRef.current; const summaryBody = summaryBodyRef.current;
const showSummaryBody = const showSummaryBody =
turnGroupingContext?.isFirstAssistantInTurn && turnGroupingContext?.isLastAssistantInTurn &&
summaryBody && summaryBody &&
summaryBody.trim().length > 0; summaryBody.trim().length > 0;
const shouldShowFooter = hasTextContent && assistantTextParts.length > 0 && hasStopFinish && isLastAssistantInTurn; const shouldShowFooter = hasTextContent && assistantTextParts.length > 0 && hasStopFinish && isLastAssistantInTurn;
const [isSummaryHovered, setIsSummaryHovered] = React.useState(false);
return ( const footerButtons = (
<div <>
className={cn(
'relative w-full group/message'
)}
style={{
contain: 'layout',
transform: 'translateZ(0)',
}}
onTouchStart={isTouchContext && canCopyMessage && hasCopyableText ? revealCopyHint : undefined}
>
<div className="px-3">
<div className="leading-normal overflow-hidden text-foreground/90 [&_p:last-child]:mb-0 [&_ul:last-child]:mb-0 [&_ol:last-child]:mb-0">
{renderedParts}
{showSummaryBody && (
<FadeInOnReveal key="summary-body">
<div className="group/assistant-text relative break-words">
<SimpleMarkdownRenderer
content={summaryBody}
/>
</div>
</FadeInOnReveal>
)}
</div>
<MessageFilesDisplay files={parts} onShowPopup={onShowPopup} />
{shouldShowFooter && (
<div className="mt-2 mb-1 flex items-center justify-end gap-2">
{onCopyMessage && ( {onCopyMessage && (
<Tooltip delayDuration={1000}> <Tooltip delayDuration={1000}>
<TooltipTrigger asChild> <TooltipTrigger asChild>
@@ -1048,9 +1025,58 @@ const AssistantMessageBody: React.FC<Omit<MessageBodyProps, 'isUser'>> = ({
</TooltipTrigger> </TooltipTrigger>
<TooltipContent sideOffset={6}>Start new session from this answer</TooltipContent> <TooltipContent sideOffset={6}>Start new session from this answer</TooltipContent>
</Tooltip> </Tooltip>
</>
);
return (
<div
className={cn(
'relative w-full group/message'
)}
style={{
contain: 'layout',
transform: 'translateZ(0)',
}}
onTouchStart={isTouchContext && canCopyMessage && hasCopyableText ? revealCopyHint : undefined}
>
<div
className="px-3"
>
<div
className="leading-normal overflow-hidden text-foreground/90 [&_p:last-child]:mb-0 [&_ul:last-child]:mb-0 [&_ol:last-child]:mb-0"
>
{renderedParts}
{showSummaryBody && (
<FadeInOnReveal key="summary-body">
<div
className="group/assistant-text relative break-words"
onMouseEnter={() => setIsSummaryHovered(true)}
onMouseLeave={() => setIsSummaryHovered(false)}
>
<SimpleMarkdownRenderer content={summaryBody} />
{shouldShowFooter && (
<div
className={cn(
"mt-2 mb-1 flex items-center justify-end gap-2 opacity-0 pointer-events-none transition-opacity duration-150 focus-within:opacity-100 focus-within:pointer-events-auto",
isSummaryHovered && "opacity-100 pointer-events-auto",
)}
>
{footerButtons}
</div> </div>
)} )}
</div> </div>
</FadeInOnReveal>
)}
</div>
<MessageFilesDisplay files={parts} onShowPopup={onShowPopup} />
{!showSummaryBody && shouldShowFooter && (
<div className="mt-2 mb-1 flex items-center justify-end gap-2 opacity-0 pointer-events-none transition-opacity duration-150 group-hover/message:opacity-100 group-hover/message:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto">
{footerButtons}
</div>
)}
</div>
</div> </div>
); );
}; };