Personal Website for @jaspermayone.com jaspermayone.com
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 5.0.0 100 lines 2.6 kB view raw
1"use client"; 2import localFont from "next/font/local"; 3import { useEffect, useState } from "react"; 4 5const CuteNotes = localFont({ 6 src: "../../public/fonts/CuteNotes.ttf", 7 display: "swap", 8 variable: "--font-cute-notes", 9}); 10 11interface AnimatedTitleProps { 12 firstWord: string; 13 secondWord?: string; 14 thirdWord?: string; 15 color?: string; 16} 17 18const AnimatedTitle = (props: AnimatedTitleProps) => { 19 const [activeIndex, setActiveIndex] = useState(-1); 20 const firstWord = props.firstWord; 21 const secondWord = props.secondWord; 22 const thirdWord = props.thirdWord; 23 const totalLength = 24 firstWord.length + 25 (secondWord ? secondWord.length : 0) + 26 (thirdWord ? thirdWord.length : 0); 27 const LETTER_DELAY = 300; 28 const CYCLE_PAUSE = 2000; 29 30 const color = props.color || "inherit"; 31 32 useEffect(() => { 33 const animate = async () => { 34 while (true) { 35 for (let i = 0; i <= totalLength; i++) { 36 setActiveIndex(i === totalLength ? -1 : i); 37 await new Promise((resolve) => setTimeout(resolve, LETTER_DELAY)); 38 } 39 await new Promise((resolve) => setTimeout(resolve, CYCLE_PAUSE)); 40 } 41 }; 42 43 animate(); 44 return () => setActiveIndex(-1); 45 }, []); 46 47 return ( 48 <h1 49 className={`m-0 text-5xl ${CuteNotes.className}`} 50 style={{ 51 margin: 0, 52 marginBottom: ".25rem", 53 fontSize: "3.5em", 54 }} 55 title={`${firstWord} ${secondWord}`} 56 > 57 {firstWord.split("").map((letter, index) => ( 58 <span 59 key={`first-${index}`} 60 className="transition-colors duration-300" 61 style={{ 62 color: index === activeIndex ? "#4299e1" : color, 63 }} 64 > 65 {letter} 66 </span> 67 ))}{" "} 68 {secondWord?.split("").map((letter, index) => ( 69 <span 70 key={`second-${index}`} 71 className="transition-colors duration-300" 72 style={{ 73 color: index + firstWord.length === activeIndex ? "#4299e1" : color, 74 }} 75 > 76 {letter} 77 </span> 78 ))}{" "} 79 {thirdWord?.split("").map((letter, index) => ( 80 <span 81 key={`third-${index}`} 82 className="transition-colors duration-300" 83 style={{ 84 color: 85 index + 86 firstWord.length + 87 (secondWord ? secondWord.length : 0) === 88 activeIndex 89 ? "#4299e1" 90 : color, 91 }} 92 > 93 {letter} 94 </span> 95 ))} 96 </h1> 97 ); 98}; 99 100export default AnimatedTitle;