Spaces:
Running
Running
File size: 3,305 Bytes
c10f8f8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
"use client";
import { useState, useEffect } from "react";
interface AnimatedTextProps {
className?: string;
}
export function AnimatedText({ className = "" }: AnimatedTextProps) {
const [displayText, setDisplayText] = useState("");
const [currentSuggestionIndex, setCurrentSuggestionIndex] = useState(0);
const [isTyping, setIsTyping] = useState(true);
const [showCursor, setShowCursor] = useState(true);
const [lastTypedIndex, setLastTypedIndex] = useState(-1);
const [animationComplete, setAnimationComplete] = useState(false);
// Randomize suggestions on each component mount
const [suggestions] = useState(() => {
const baseSuggestions = [
"create a stunning portfolio!",
"build a tic tac toe game!",
"design a website for my restaurant!",
"make a sleek landing page!",
"build an e-commerce store!",
"create a personal blog!",
"develop a modern dashboard!",
"design a company website!",
"build a todo app!",
"create an online gallery!",
"make a contact form!",
"build a weather app!",
];
// Fisher-Yates shuffle algorithm
const shuffled = [...baseSuggestions];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
});
useEffect(() => {
if (animationComplete) return;
let timeout: NodeJS.Timeout;
const typeText = () => {
const currentSuggestion = suggestions[currentSuggestionIndex];
if (isTyping) {
if (displayText.length < currentSuggestion.length) {
setDisplayText(currentSuggestion.slice(0, displayText.length + 1));
setLastTypedIndex(displayText.length);
timeout = setTimeout(typeText, 80);
} else {
// Finished typing, wait then start erasing
setLastTypedIndex(-1);
timeout = setTimeout(() => {
setIsTyping(false);
}, 2000);
}
}
};
timeout = setTimeout(typeText, 100);
return () => clearTimeout(timeout);
}, [
displayText,
currentSuggestionIndex,
isTyping,
suggestions,
animationComplete,
]);
// Cursor blinking effect
useEffect(() => {
if (animationComplete) {
setShowCursor(false);
return;
}
const cursorInterval = setInterval(() => {
setShowCursor((prev) => !prev);
}, 600);
return () => clearInterval(cursorInterval);
}, [animationComplete]);
useEffect(() => {
if (lastTypedIndex >= 0) {
const timeout = setTimeout(() => {
setLastTypedIndex(-1);
}, 400);
return () => clearTimeout(timeout);
}
}, [lastTypedIndex]);
return (
<p className={`font-mono ${className}`}>
Hey DeepSite,
{displayText.split("").map((char, index) => (
<span
key={`${currentSuggestionIndex}-${index}`}
className={`transition-colors duration-300 ${
index === lastTypedIndex ? "text-neutral-100" : ""
}`}
>
{char}
</span>
))}
<span
className={`${
showCursor ? "opacity-100" : "opacity-0"
} transition-opacity`}
>
|
</span>
</p>
);
}
|