feat(webui): migrate AssistantMessage component

- Move AssistantMessage.tsx and AssistantMessage.css from vscode-ide-companion
- Export AssistantMessageProps and AssistantMessageStatus types
This commit is contained in:
yiliang114 2026-01-16 00:38:15 +08:00
parent 2cdfb1ffad
commit 4f0aed4d71
3 changed files with 154 additions and 0 deletions

View file

@ -0,0 +1,52 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*
* AssistantMessage Component Styles
* Pseudo-elements (::before) for bullet points and (::after) for timeline connectors
*/
/* 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 - static bullet (maps to .he) */
.assistant-message-container.assistant-message-loading::before {
color: var(--app-secondary-foreground);
background-color: var(--app-secondary-background);
}
.assistant-message-container.assistant-message-loading::after {
display: none;
}

View file

@ -0,0 +1,91 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { MessageContent } from '../MessageContent.js';
import './AssistantMessage.css';
export type AssistantMessageStatus =
| 'default'
| 'success'
| 'error'
| 'warning'
| 'loading';
export interface AssistantMessageProps {
content: string;
timestamp?: number;
onFileClick?: (path: string) => void;
status?: AssistantMessageStatus;
/** When true, render without the left status bullet (no ::before dot) */
hideStatusIcon?: boolean;
}
/**
* AssistantMessage component - renders AI responses with styling
* Supports different states: default, success, error, warning, loading
*/
export const AssistantMessage: React.FC<AssistantMessageProps> = ({
content,
timestamp: _timestamp,
onFileClick,
status = 'default',
hideStatusIcon = false,
}) => {
// Empty content not rendered directly
if (!content || content.trim().length === 0) {
return null;
}
const getStatusClass = () => {
if (hideStatusIcon) {
return '';
}
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={`qwen-message message-item assistant-message-container ${getStatusClass()}`}
style={{
width: '100%',
alignItems: 'flex-start',
paddingLeft: '30px',
userSelect: 'text',
position: 'relative',
}}
>
<span style={{ width: '100%' }}>
<div
style={{
margin: 0,
width: '100%',
wordWrap: 'break-word',
overflowWrap: 'break-word',
whiteSpace: 'normal',
}}
>
<MessageContent
content={content}
onFileClick={onFileClick}
enableFileLinks={false}
/>
</div>
</span>
</div>
);
};

View file

@ -0,0 +1,11 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
export { AssistantMessage } from './AssistantMessage.js';
export type {
AssistantMessageProps,
AssistantMessageStatus,
} from './AssistantMessage.js';