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/Timeline.css';
|
||||||
@import './components/shared/FileLink.css';
|
@import './components/shared/FileLink.css';
|
||||||
@import './components/toolcalls/shared/DiffDisplay.css';
|
@import './components/toolcalls/shared/DiffDisplay.css';
|
||||||
|
@import './components/messages/AssistantMessage.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
/* ===========================
|
||||||
Session Selector Button (from Claude Code .E)
|
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 type React from 'react';
|
||||||
import { MessageContent } from '../MessageContent.js';
|
import { MessageContent } from '../MessageContent.js';
|
||||||
|
import './AssistantMessage.css';
|
||||||
|
|
||||||
interface AssistantMessageProps {
|
interface AssistantMessageProps {
|
||||||
content: string;
|
content: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
onFileClick?: (path: string) => void;
|
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> = ({
|
export const AssistantMessage: React.FC<AssistantMessageProps> = ({
|
||||||
content,
|
content,
|
||||||
timestamp: _timestamp,
|
timestamp: _timestamp,
|
||||||
onFileClick,
|
onFileClick,
|
||||||
}) => (
|
status = 'default',
|
||||||
<div className="flex gap-0 items-start text-left py-2 flex-col relative animate-[fadeIn_0.2s_ease-in]">
|
}) => {
|
||||||
|
// 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
|
<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={{
|
style={{
|
||||||
border: '1px solid var(--app-input-border)',
|
width: '100%',
|
||||||
borderRadius: 'var(--corner-radius-medium)',
|
alignItems: 'flex-start',
|
||||||
backgroundColor: 'var(--app-input-background)',
|
paddingLeft: '30px',
|
||||||
padding: '4px 6px',
|
userSelect: 'text',
|
||||||
color: 'var(--app-primary-foreground)',
|
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} />
|
<MessageContent content={content} onFileClick={onFileClick} />
|
||||||
</div>
|
</p>
|
||||||
{/* Timestamp - temporarily hidden */}
|
</span>
|
||||||
{/* <div
|
|
||||||
className="text-xs opacity-60"
|
|
||||||
style={{ color: 'var(--app-secondary-foreground)' }}
|
|
||||||
>
|
|
||||||
{new Date(timestamp).toLocaleTimeString()}
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user