diff --git a/src/components/common/Typewriter/Typewriter.tsx b/src/components/common/Typewriter/Typewriter.tsx new file mode 100644 index 0000000..599ff2b --- /dev/null +++ b/src/components/common/Typewriter/Typewriter.tsx @@ -0,0 +1,32 @@ +import React, { useState, useEffect } from 'react'; + +interface TypewriterProps { + text: string; + speed?: number; + onComplete?: () => void; + children?: (text: string) => React.ReactNode; +} + +export const Typewriter: React.FC = ({ text, speed = 30, onComplete, children }) => { + const [displayedText, setDisplayedText] = useState(''); + const [currentIndex, setCurrentIndex] = useState(0); + + useEffect(() => { + if (currentIndex < text.length) { + const timeout = setTimeout(() => { + setDisplayedText(prev => prev + text[currentIndex]); + setCurrentIndex(prev => prev + 1); + }, speed); + + return () => clearTimeout(timeout); + } else if (onComplete) { + onComplete(); + } + }, [currentIndex, text, speed, onComplete]); + + if (children) { + return <>{children(displayedText)}; + } + + return <>{displayedText}; +}; diff --git a/src/pages/Chat/Chat.tsx b/src/pages/Chat/Chat.tsx index 773d263..b6fe4d0 100644 --- a/src/pages/Chat/Chat.tsx +++ b/src/pages/Chat/Chat.tsx @@ -6,6 +6,7 @@ import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import aiService from '../../services/aiService'; import type { AIChatResponse, ConfirmationCard } from '../../types'; +import { Typewriter } from '../../components/common/Typewriter/Typewriter'; import './Chat.css'; interface Message { @@ -273,16 +274,26 @@ export default function Chat() { ) : ( <> - {messages.map((msg) => ( + {messages.map((msg, index) => (
{msg.role === 'assistant' ? '🪙' : '👤'}
- - {msg.content} - + {msg.role === 'assistant' && index === messages.length - 1 ? ( + + {(text) => ( + + {text} + + )} + + ) : ( + + {msg.content} + + )}
{msg.confirmationCard && (