- "content": "import { useEffect, useRef, useState } from 'react';\nimport { motion } from 'motion/react';\n\nconst TrueFocus = ({\n sentence = 'True Focus',\n manualMode = false,\n blurAmount = 5,\n borderColor = 'green',\n glowColor = 'rgba(0, 255, 0, 0.6)',\n animationDuration = 0.5,\n pauseBetweenAnimations = 1\n}) => {\n const words = sentence.split(' ');\n const [currentIndex, setCurrentIndex] = useState(0);\n const [lastActiveIndex, setLastActiveIndex] = useState(null);\n const containerRef = useRef(null);\n const wordRefs = useRef([]);\n const [focusRect, setFocusRect] = useState({ x: 0, y: 0, width: 0, height: 0 });\n\n useEffect(() => {\n if (!manualMode) {\n const interval = setInterval(\n () => {\n setCurrentIndex(prev => (prev + 1) % words.length);\n },\n (animationDuration + pauseBetweenAnimations) * 1000\n );\n\n return () => clearInterval(interval);\n }\n }, [manualMode, animationDuration, pauseBetweenAnimations, words.length]);\n\n useEffect(() => {\n if (currentIndex === null || currentIndex === -1) return;\n if (!wordRefs.current[currentIndex] || !containerRef.current) return;\n\n const parentRect = containerRef.current.getBoundingClientRect();\n const activeRect = wordRefs.current[currentIndex].getBoundingClientRect();\n\n setFocusRect({\n x: activeRect.left - parentRect.left,\n y: activeRect.top - parentRect.top,\n width: activeRect.width,\n height: activeRect.height\n });\n }, [currentIndex, words.length]);\n\n const handleMouseEnter = index => {\n if (manualMode) {\n setLastActiveIndex(index);\n setCurrentIndex(index);\n }\n };\n\n const handleMouseLeave = () => {\n if (manualMode) {\n setCurrentIndex(lastActiveIndex);\n }\n };\n\n return (\n <div className=\"relative flex gap-4 justify-center items-center flex-wrap\" ref={containerRef}>\n {words.map((word, index) => {\n const isActive = index === currentIndex;\n return (\n <span\n key={index}\n ref={el => (wordRefs.current[index] = el)}\n className=\"relative text-[3rem] font-black cursor-pointer\"\n style={{\n filter: manualMode\n ? isActive\n ? `blur(0px)`\n : `blur(${blurAmount}px)`\n : isActive\n ? `blur(0px)`\n : `blur(${blurAmount}px)`,\n '--border-color': borderColor,\n '--glow-color': glowColor,\n transition: `filter ${animationDuration}s ease`\n }}\n onMouseEnter={() => handleMouseEnter(index)}\n onMouseLeave={handleMouseLeave}\n >\n {word}\n </span>\n );\n })}\n\n <motion.div\n className=\"absolute top-0 left-0 pointer-events-none box-border border-0\"\n animate={{\n x: focusRect.x,\n y: focusRect.y,\n width: focusRect.width,\n height: focusRect.height,\n opacity: currentIndex >= 0 ? 1 : 0\n }}\n transition={{\n duration: animationDuration\n }}\n style={{\n '--border-color': borderColor,\n '--glow-color': glowColor\n }}\n >\n <span\n className=\"absolute w-4 h-4 border-[3px] rounded-[3px] top-[-10px] left-[-10px] border-r-0 border-b-0\"\n style={{\n borderColor: 'var(--border-color)',\n filter: 'drop-shadow(0 0 4px var(--border-color))'\n }}\n ></span>\n <span\n className=\"absolute w-4 h-4 border-[3px] rounded-[3px] top-[-10px] right-[-10px] border-l-0 border-b-0\"\n style={{\n borderColor: 'var(--border-color)',\n filter: 'drop-shadow(0 0 4px var(--border-color))'\n }}\n ></span>\n <span\n className=\"absolute w-4 h-4 border-[3px] rounded-[3px] bottom-[-10px] left-[-10px] border-r-0 border-t-0\"\n style={{\n borderColor: 'var(--border-color)',\n filter: 'drop-shadow(0 0 4px var(--border-color))'\n }}\n ></span>\n <span\n className=\"absolute w-4 h-4 border-[3px] rounded-[3px] bottom-[-10px] right-[-10px] border-l-0 border-t-0\"\n style={{\n borderColor: 'var(--border-color)',\n filter: 'drop-shadow(0 0 4px var(--border-color))'\n }}\n ></span>\n </motion.div>\n </div>\n );\n};\n\nexport default TrueFocus;\n",
0 commit comments