+
-
Technical Details:
-
{details}
+
Technical Details:
+
{details}
)}
diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx
index c628e9e5398..cb54da37fcf 100644
--- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx
+++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx
@@ -127,31 +127,82 @@ export const IconWarning = ({ size, className = '' }: { size: number, className?
};
-export const IconLoading = ({ className = '', showTokenCount }: { className?: string, showTokenCount?: number }) => {
- const [dots, setDots] = useState(1);
+type LoadingState = 'thinking' | 'typing' | 'processing' | 'default';
+
+// Format token count with k/m suffixes for better readability
+const formatTokenCount = (count: number): string => {
+ if (count >= 1000000) {
+ return `${(count / 1000000).toFixed(1)}M`;
+ } else if (count >= 1000) {
+ return `${(count / 1000).toFixed(1)}k`;
+ }
+ return count.toString();
+}
+
+export const IconLoading = ({
+ className = '',
+ showTokenCount,
+ state = 'default',
+ inline = false
+}: {
+ className?: string,
+ showTokenCount?: number,
+ state?: LoadingState,
+ inline?: boolean
+}) => {
+ // Use CSS animations instead of JavaScript for better performance
+ const [prevTokenCount, setPrevTokenCount] = useState
(undefined);
+ const [shouldPulse, setShouldPulse] = useState(false);
useEffect(() => {
- // Optimized: Use requestAnimationFrame for smoother animation, update every 400ms
- let frameId: number;
- let lastUpdate = Date.now();
-
- const animate = () => {
- const now = Date.now();
- if (now - lastUpdate >= 400) {
- setDots(prev => prev >= 3 ? 1 : prev + 1);
- lastUpdate = now;
- }
- frameId = requestAnimationFrame(animate);
- };
+ if (showTokenCount !== undefined && showTokenCount !== prevTokenCount) {
+ setShouldPulse(true);
+ setPrevTokenCount(showTokenCount);
+ const timer = setTimeout(() => setShouldPulse(false), 300);
+ return () => clearTimeout(timer);
+ }
+ }, [showTokenCount, prevTokenCount]);
- frameId = requestAnimationFrame(animate);
- return () => cancelAnimationFrame(frameId);
- }, []);
+ const tokenText = showTokenCount !== undefined
+ ? ` (${formatTokenCount(showTokenCount)} tokens)`
+ : '';
+
+ // Different animation speeds for different states
+ const animationSpeed = state === 'thinking' ? '1.6s' : state === 'processing' ? '1.2s' : '1.4s';
- const dotsText = '.'.repeat(dots);
- const tokenText = showTokenCount !== undefined ? ` (${showTokenCount} tokens)` : '';
+ const dots = (
+
+
+
+
+
+ );
- return {dotsText}{tokenText}
;
+ return (
+
+ {dots}
+ {tokenText && (
+
+ {tokenText}
+
+ )}
+
+ );
+}
+
+// Typing cursor component for inline use at end of streaming content
+export const TypingCursor = ({ className = '' }: { className?: string }) => {
+ return (
+
+ );
}
@@ -635,9 +686,12 @@ export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Re
return