mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
refactor(vscode-ide-companion): extract AssistantMessage as standalone component with Claude Code styles
- Extract AssistantMessage component from inline implementation - Add status prop support (default, success, error, warning, loading) - Implement bullet point indicator using CSS pseudo-elements (::before) - Use inline styles for layout to prevent Tailwind override - Add AssistantMessage.css with pseudo-element styles for different states - Import AssistantMessage.css in ClaudeCodeStyles.css Restores Claude Code DOM structure and styling: - Outer container with padding-left: 30px for bullet spacing - Bullet point colors based on status (green, red, yellow, gray) - Loading state with pulse animation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -19,19 +19,7 @@
|
||||
@import './components/Timeline.css';
|
||||
@import './components/shared/FileLink.css';
|
||||
@import './components/toolcalls/shared/DiffDisplay.css';
|
||||
|
||||
/* ===========================
|
||||
Header Styles (from Claude Code .he)
|
||||
=========================== */
|
||||
.chat-header {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--app-primary-border-color);
|
||||
padding: 6px 10px;
|
||||
gap: 4px;
|
||||
background-color: var(--app-header-background);
|
||||
justify-content: flex-start;
|
||||
user-select: none;
|
||||
}
|
||||
@import './components/messages/AssistantMessage.css';
|
||||
|
||||
/* ===========================
|
||||
Session Selector Button (from Claude Code .E)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* AssistantMessage Component Styles
|
||||
* Only pseudo-elements (::before) for bullet points
|
||||
*/
|
||||
|
||||
/* Bullet point indicator using ::before pseudo-element */
|
||||
.assistant-message-container.assistant-message-default::before,
|
||||
.assistant-message-container.assistant-message-success::before,
|
||||
.assistant-message-container.assistant-message-error::before,
|
||||
.assistant-message-container.assistant-message-warning::before,
|
||||
.assistant-message-container.assistant-message-loading::before {
|
||||
content: '\25cf';
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
padding-top: 2px;
|
||||
font-size: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Default state - secondary foreground color */
|
||||
.assistant-message-container.assistant-message-default::before {
|
||||
color: var(--app-secondary-foreground);
|
||||
}
|
||||
|
||||
/* Success state - green bullet (maps to .ge) */
|
||||
.assistant-message-container.assistant-message-success::before {
|
||||
color: #74c991;
|
||||
}
|
||||
|
||||
/* Error state - red bullet (maps to .be) */
|
||||
.assistant-message-container.assistant-message-error::before {
|
||||
color: #c74e39;
|
||||
}
|
||||
|
||||
/* Warning state - yellow/orange bullet (maps to .ue) */
|
||||
.assistant-message-container.assistant-message-warning::before {
|
||||
color: #e1c08d;
|
||||
}
|
||||
|
||||
/* Loading state - animated bullet (maps to .he) */
|
||||
.assistant-message-container.assistant-message-loading::before {
|
||||
color: var(--app-secondary-foreground);
|
||||
background-color: var(--app-secondary-background);
|
||||
animation: assistantMessagePulse 1s linear infinite;
|
||||
}
|
||||
|
||||
/* Pulse animation for loading state */
|
||||
@keyframes assistantMessagePulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@@ -6,37 +6,66 @@
|
||||
|
||||
import type React from 'react';
|
||||
import { MessageContent } from '../MessageContent.js';
|
||||
import './AssistantMessage.css';
|
||||
|
||||
interface AssistantMessageProps {
|
||||
content: string;
|
||||
timestamp: number;
|
||||
onFileClick?: (path: string) => void;
|
||||
status?: 'default' | 'success' | 'error' | 'warning' | 'loading';
|
||||
}
|
||||
|
||||
/**
|
||||
* AssistantMessage component - renders AI responses with Claude Code styling
|
||||
* Supports different states: default, success, error, warning, loading
|
||||
*
|
||||
* Claude Code DOM structure:
|
||||
* <div class="K o"><span class="i"><p>...</p></span></div>
|
||||
*
|
||||
* Styles:
|
||||
* .o - outer container with padding-left: 30px and ::before for bullet
|
||||
* .i - inner span wrapper
|
||||
*/
|
||||
export const AssistantMessage: React.FC<AssistantMessageProps> = ({
|
||||
content,
|
||||
timestamp: _timestamp,
|
||||
onFileClick,
|
||||
}) => (
|
||||
<div className="flex gap-0 items-start text-left py-2 flex-col relative animate-[fadeIn_0.2s_ease-in]">
|
||||
status = 'default',
|
||||
}) => {
|
||||
// Map status to CSS class (only for ::before pseudo-element)
|
||||
const getStatusClass = () => {
|
||||
switch (status) {
|
||||
case 'success':
|
||||
return 'assistant-message-success';
|
||||
case 'error':
|
||||
return 'assistant-message-error';
|
||||
case 'warning':
|
||||
return 'assistant-message-warning';
|
||||
case 'loading':
|
||||
return 'assistant-message-loading';
|
||||
default:
|
||||
return 'assistant-message-default';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="inline-block my-1 relative whitespace-pre-wrap rounded-md max-w-full overflow-x-auto overflow-y-hidden select-text leading-[1.5]"
|
||||
className={`assistant-message-container ${getStatusClass()}`}
|
||||
style={{
|
||||
border: '1px solid var(--app-input-border)',
|
||||
borderRadius: 'var(--corner-radius-medium)',
|
||||
backgroundColor: 'var(--app-input-background)',
|
||||
padding: '4px 6px',
|
||||
color: 'var(--app-primary-foreground)',
|
||||
width: '100%',
|
||||
alignItems: 'flex-start',
|
||||
paddingLeft: '30px',
|
||||
userSelect: 'text',
|
||||
position: 'relative',
|
||||
paddingTop: '8px',
|
||||
paddingBottom: '8px',
|
||||
}}
|
||||
>
|
||||
<span style={{ color: 'var(--app-secondary-foreground)' }}>
|
||||
<p style={{ margin: 0, color: 'var(--app-secondary-foreground)' }}>
|
||||
<MessageContent content={content} onFileClick={onFileClick} />
|
||||
</div>
|
||||
{/* Timestamp - temporarily hidden */}
|
||||
{/* <div
|
||||
className="text-xs opacity-60"
|
||||
style={{ color: 'var(--app-secondary-foreground)' }}
|
||||
>
|
||||
{new Date(timestamp).toLocaleTimeString()}
|
||||
</div> */}
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user