Merge pull request #7 from KGAudioLab/fix/2025-08-12-misc

added a subtle wave animation to the 'processing...' text.
This commit is contained in:
Xiaohan-Tian
2025-08-15 19:34:39 -07:00
committed by GitHub
3 changed files with 74 additions and 17 deletions
+26
View File
@@ -1964,3 +1964,29 @@ textarea {
@keyframes globalSpinner { @keyframes globalSpinner {
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
/* Processing wave animation */
.processing-wave {
background: linear-gradient(
90deg,
rgba(135, 206, 250, 0.5) 0%,
rgba(135, 206, 250, 0.8) 25%,
rgb(171, 218, 250) 50%,
rgba(135, 206, 250, 0.8) 75%,
rgba(135, 206, 250, 0.5) 100%
);
background-size: 200% 100%;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: wave 2s linear infinite;
}
@keyframes wave {
0% {
background-position: 200% 0%;
}
100% {
background-position: -200% 0%;
}
}
+4 -4
View File
@@ -276,7 +276,7 @@ const ChatBox: React.FC<ChatBoxProps> = ({ isVisible }) => {
setMessages(prev => [...prev, { setMessages(prev => [...prev, {
id: assistantMsgId, id: assistantMsgId,
role: 'assistant', role: 'assistant',
content: 'processing... 0 tokens received. click here to abort.', content: '<span class="processing-wave">Processing...</span> 0 tokens received. click here to abort.',
isStreaming: true, isStreaming: true,
tokenCount: 0 tokenCount: 0
}]); }]);
@@ -304,7 +304,7 @@ const ChatBox: React.FC<ChatBoxProps> = ({ isVisible }) => {
// Update streaming message with token count and abort link // Update streaming message with token count and abort link
setMessages(prev => prev.map(msg => setMessages(prev => prev.map(msg =>
msg.id === assistantMsgId msg.id === assistantMsgId
? { ...msg, content: `processing... ${tokenCount} tokens received. click here to abort.`, tokenCount } ? { ...msg, content: `<span class="processing-wave">Processing...</span> ${tokenCount} tokens received. click here to abort.`, tokenCount }
: msg : msg
)); ));
} else if (chunk.type === 'done') { } else if (chunk.type === 'done') {
@@ -396,7 +396,7 @@ const ChatBox: React.FC<ChatBoxProps> = ({ isVisible }) => {
setMessages(prev => [...prev, { setMessages(prev => [...prev, {
id: assistantMsgId, id: assistantMsgId,
role: 'assistant', role: 'assistant',
content: 'processing... 0 tokens received. click here to abort.', content: '<span class="processing-wave">Processing...</span> 0 tokens received. click here to abort.',
isStreaming: true, isStreaming: true,
tokenCount: 0 tokenCount: 0
}]); }]);
@@ -441,7 +441,7 @@ const ChatBox: React.FC<ChatBoxProps> = ({ isVisible }) => {
// Update streaming message with token count and abort link // Update streaming message with token count and abort link
setMessages(prev => prev.map(msg => setMessages(prev => prev.map(msg =>
msg.id === assistantMsgId msg.id === assistantMsgId
? { ...msg, content: `processing... ${tokenCount} tokens received. click here to abort.`, tokenCount } ? { ...msg, content: `<span class="processing-wave">Processing...</span> ${tokenCount} tokens received. click here to abort.`, tokenCount }
: msg : msg
)); ));
} else if (chunk.type === 'done') { } else if (chunk.type === 'done') {
+44 -13
View File
@@ -113,19 +113,50 @@ const AssistantMessage: React.FC<AssistantMessageProps> = ({ content, isStreamin
// Handle special abort link for streaming messages // Handle special abort link for streaming messages
const renderContent = () => { const renderContent = () => {
if (isStreaming && onAbort && content.includes('click here to abort')) { if (isStreaming && onAbort && content.includes('click here to abort')) {
const parts = content.split('click here to abort'); // Check if content has the processing wave HTML
return ( const hasProcessingWave = content.includes('<span class="processing-wave">Processing...</span>');
<span>
{parts[0]} if (hasProcessingWave) {
<button // Parse the content to handle both the wave animation and abort link
onClick={onAbort} const parts = content.split('click here to abort');
className="abort-link" const beforeAbort = parts[0];
> const afterAbort = parts[1];
click here to abort
</button> // Replace the HTML span with JSX
{parts[1]} const processedBefore = beforeAbort.replace(
</span> '<span class="processing-wave">Processing...</span>',
); ''
);
return (
<span>
<span className="processing-wave">Processing...</span>
{processedBefore}
<button
onClick={onAbort}
className="abort-link"
>
click here to abort
</button>
{afterAbort}
</span>
);
} else {
// Original logic for non-wave processing messages
const parts = content.split('click here to abort');
return (
<span>
{parts[0]}
<button
onClick={onAbort}
className="abort-link"
>
click here to abort
</button>
{parts[1]}
</span>
);
}
} }
const processedContent = processContentWithXMLExpanders(content); const processedContent = processContentWithXMLExpanders(content);