feat: add ChatMessage component with source links

This commit is contained in:
z2_cc 2026-05-13 11:40:21 +08:00
parent d28b46c86f
commit c7a89f9997
2 changed files with 127 additions and 0 deletions

View File

@ -0,0 +1,31 @@
import React from 'react';
import styles from './styles.module.css';
export default function ChatMessage({ message, isStreaming }) {
const isUser = message.role === 'user';
return (
<div className={`${styles.message} ${isUser ? styles.messageUser : styles.messageAssistant}`}>
<div className={`${styles.bubble} ${isUser ? styles.bubbleUser : styles.bubbleAssistant}`}>
{message.content}
{!isUser && isStreaming && <span className={styles.cursor} />}
</div>
{!isUser && message.sources && message.sources.length > 0 && (
<div className={styles.sources}>
<div className={styles.sourcesTitle}>📎 相关文档</div>
{message.sources.map((link, i) => (
<a
key={i}
className={styles.sourceLink}
href={link.path}
target="_blank"
rel="noopener noreferrer"
>
{link.breadcrumb}
</a>
))}
</div>
)}
</div>
);
}

View File

@ -0,0 +1,96 @@
.message {
margin-bottom: 12px;
display: flex;
flex-direction: column;
}
.messageUser {
align-items: flex-end;
}
.messageAssistant {
align-items: flex-start;
}
.bubble {
max-width: 85%;
padding: 10px 14px;
border-radius: 12px;
font-size: 14px;
line-height: 1.6;
word-break: break-word;
white-space: pre-wrap;
}
.bubbleUser {
background: #e8e8e8;
color: #333;
border-bottom-right-radius: 4px;
}
.bubbleAssistant {
background: #f0f4ff;
color: #333;
border-bottom-left-radius: 4px;
}
[data-theme='dark'] .bubbleUser {
background: #3a3a3a;
color: #e0e0e0;
}
[data-theme='dark'] .bubbleAssistant {
background: #2a2e4a;
color: #e0e0e0;
}
.sources {
margin-top: 8px;
padding: 8px 10px;
background: rgba(255, 255, 255, 0.6);
border: 1px solid #e0e0e0;
border-radius: 8px;
max-width: 85%;
font-size: 12px;
}
[data-theme='dark'] .sources {
background: rgba(255, 255, 255, 0.08);
border-color: #444;
}
.sourcesTitle {
color: #666;
margin-bottom: 4px;
font-weight: 500;
}
[data-theme='dark'] .sourcesTitle {
color: #aaa;
}
.sourceLink {
display: block;
color: #466aff;
text-decoration: none;
padding: 2px 0;
}
.sourceLink:hover {
text-decoration: underline;
}
.cursor {
display: inline-block;
width: 2px;
height: 16px;
background: #466aff;
margin-left: 2px;
vertical-align: text-bottom;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}