From 1782e01922f2a0cb73504a20f1a0ca766aa2cbd9 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Fri, 13 Mar 2026 12:45:58 +0200 Subject: [PATCH] chore: simplify frontend CSS and unify message rendering logic Consolidate 4 CopilotKit max-width override rules into 1 scoped to .chat-container. Remove dead pre-1.54.0 selectors and redundant browser-default styles. Unify the two render paths in MessageViewWithCitations into a single loop. Co-Authored-By: Claude Opus 4.6 --- app/frontend/app/globals.css | 41 ++-------------- app/frontend/components/Chat.tsx | 80 ++++---------------------------- 2 files changed, 14 insertions(+), 107 deletions(-) diff --git a/app/frontend/app/globals.css b/app/frontend/app/globals.css index d779984d..edf71140 100644 --- a/app/frontend/app/globals.css +++ b/app/frontend/app/globals.css @@ -36,22 +36,14 @@ a { --ring: #3b82f6; } -/* Chat message area — use full width instead of CopilotKit's max-width constraints. - Scoped to scroll area; the input area inherits CopilotKit's natural sizing. */ -.chat-scroll-area .max-w-3xl, -.chat-scroll-area [class*="cpk:max-w-3xl"], -.chat-scroll-area [class*="cpk:max-w-"] { +/* Remove CopilotKit's max-width constraints so content fills the container */ +.chat-container [class*="cpk:max-w-"], +.chat-container .max-w-3xl { max-width: 100% !important; } -/* In the empty state (no chat-scroll-area), widen only the message view container */ -.copilotKitChat [class*="cpk:max-w-3xl"]:not(:has(.copilotKitInput)) { - max-width: 100% !important; -} - -/* Empty state input — stretch to full width with horizontal margin */ -.copilotKitChat [class*="cpk:max-w-3xl"]:has(.copilotKitInput) { - max-width: 100% !important; +/* Empty state input — horizontal padding so it doesn't touch the edges */ +.chat-container [class*="cpk:max-w-3xl"]:has(.copilotKitInput) { padding: 0 1rem; } @@ -98,21 +90,6 @@ a { right: auto; } -/* Make the input stretch to full width within its padded container */ -.chat-input-area [class*="cpk:max-w-"] { - max-width: 100% !important; -} - -/* User message bubble spacing and padding */ -[data-message-id].items-end { - padding-top: 1rem; -} - -[data-message-id].items-end > .bg-muted { - color: #1e293b; - padding: 0.75rem 1.25rem; -} - /* Assistant message markdown styling */ .prose[data-message-id] { line-height: 1.6; @@ -220,14 +197,6 @@ a { font-weight: 600; } -.prose[data-message-id] strong { - font-weight: 600; -} - -.prose[data-message-id] em { - font-style: italic; -} - /* ── Chat layout ── */ .chat-wrapper { diff --git a/app/frontend/components/Chat.tsx b/app/frontend/components/Chat.tsx index 38e6618a..33919dc2 100644 --- a/app/frontend/components/Chat.tsx +++ b/app/frontend/components/Chat.tsx @@ -317,75 +317,17 @@ function MessageViewWithCitations({ ) : null; + // CopilotChatMessageView renders one element per user/assistant message. + // We interleave activity indicators (skill sub-agent tool calls) and + // optionally inject CitationBlocks after assistant responses that + // followed tool calls. return ( {({ messageElements }) => { - if (!citationsHistory.length) { - // Check if there are activity messages to render - const hasActivity = messages.some( - (msg: { role: string }) => msg.role === "activity", - ); - if (!hasActivity) { - return ( - <> - {messageElements} - {cursor} - - ); - } - - // Interleave activity indicators with CopilotKit elements - const result: React.ReactNode[] = []; - let eIdx = 0; - for (const msg of messages) { - if ( - msg.role === "activity" && - msg.activityType === "skill_tool_call" - ) { - const toolCallId = msg.content?.tool_call_id; - result.push( - , - ); - continue; - } - if (msg.role === "activity") continue; - if (msg.role !== "user" && msg.role !== "assistant") continue; - if (eIdx < messageElements.length) { - result.push(messageElements[eIdx]); - eIdx++; - } - } - while (eIdx < messageElements.length) { - result.push(messageElements[eIdx]); - eIdx++; - } - return ( - <> - {result} - {cursor} - - ); - } - - // CopilotChatMessageView renders one element per user/assistant - // message (tool messages produce nothing). We correlate elements with - // messages to inject CitationBlocks after the right assistant responses. - // Activity messages (skill sub-agent tool calls) are rendered by us - // directly, not by CopilotKit. - // - // Both search and ask tools append to citations via qa_history, - // so after each assistant text response that followed tool calls, - // we inject the next citations entry. const result: React.ReactNode[] = []; + let elemIdx = 0; let citIdx = 0; let seenToolCalls = false; - let elemIdx = 0; for (const msg of messages) { if (msg.role === "user") { @@ -405,24 +347,20 @@ function MessageViewWithCitations({ if (msg.role === "activity") { if (msg.activityType === "skill_tool_call") { const toolCallId = msg.content?.tool_call_id; - const isComplete = toolCallId - ? completedToolCallIds.has(toolCallId) - : false; result.push( , ); } - // Skip skill_tool_result — completion is shown - // on the corresponding skill_tool_call indicator continue; } - const isRendered = msg.role === "user" || msg.role === "assistant"; - if (!isRendered) continue; + if (msg.role !== "user" && msg.role !== "assistant") continue; if (elemIdx < messageElements.length) { result.push(messageElements[elemIdx]);