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 <noreply@anthropic.com>
This commit is contained in:
Yiorgis Gozadinos 2026-03-13 12:45:58 +02:00
parent 9e29a7e849
commit 1782e01922
No known key found for this signature in database
2 changed files with 14 additions and 107 deletions

View file

@ -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 {

View file

@ -317,75 +317,17 @@ function MessageViewWithCitations({
</div>
) : 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 (
<CopilotChatMessageView messages={messages} isRunning={isRunning}>
{({ 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(
<ActivityIndicator
key={msg.id}
message={msg}
isComplete={
toolCallId ? completedToolCallIds.has(toolCallId) : false
}
/>,
);
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(
<ActivityIndicator
key={msg.id}
message={msg}
isComplete={isComplete}
isComplete={
toolCallId ? completedToolCallIds.has(toolCallId) : false
}
/>,
);
}
// 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]);