diff --git a/src/components/GithubLogo.jsx b/src/components/GithubLogo.jsx new file mode 100644 index 0000000..61085db --- /dev/null +++ b/src/components/GithubLogo.jsx @@ -0,0 +1,20 @@ +import React from "react"; + +function GithubLogo() { + return ( + + ); +} + +export default GithubLogo; \ No newline at end of file diff --git a/src/components/InfiniteTypingBoard.jsx b/src/components/InfiniteTypingBoard.jsx index 43c94f1..51367ad 100644 --- a/src/components/InfiniteTypingBoard.jsx +++ b/src/components/InfiniteTypingBoard.jsx @@ -3,13 +3,27 @@ import Timer from './Timer'; import { motion, time } from "motion/react" import TypingCompleteScreen from './TypingCompleteScreen'; - - //feature const InfiniteTypingBoard = (props) => { const [words, setWords] = useState([]) - const [quote, setQuote] = useState(props.quotes) + + // Sample quotes for infinite mode + const infiniteQuotes = [ + "The sun is shining today, and many people are outside enjoying the warm weather. Some are walking their dogs, while others are sitting on benches reading books.", + "Technology has revolutionized the way we communicate, work, and learn. From smartphones to artificial intelligence, innovation continues to shape our daily lives.", + "Reading books opens doors to new worlds and perspectives. Literature has the power to inspire, educate, and transport us to different times and places.", + "Exercise and proper nutrition are essential for maintaining good health. Regular physical activity strengthens both body and mind while improving overall well-being.", + "Music is a universal language that transcends cultural boundaries. It has the ability to evoke emotions, create memories, and bring people together across the globe.", + "Learning new skills throughout life keeps the mind sharp and opens up opportunities. Whether it's coding, cooking, or crafting, continuous growth enriches our experience.", + "Nature provides countless benefits for mental and physical health. Spending time outdoors can reduce stress, improve mood, and connect us with the natural world.", + "Friendship is one of life's greatest treasures. Good friends provide support, laughter, and companionship through both joyful and challenging times in our lives." + ]; + + // const [quote, setQuote] = useState(props.quotes); + const [quote, setQuote] = useState(props.quotes); + const [isInfiniteMode, setIsInfiniteMode] = useState(false); + const [currentQuoteIndex, setCurrentQuoteIndex] = useState(0); const [currentIdx, setCurrentIdx] = useState(0); const [typedChars, setTypedChars] = useState(""); @@ -21,21 +35,123 @@ const InfiniteTypingBoard = (props) => { const [finalTime, setFinalTime] = useState(0); const [WPM, setWPM] = useState(0) const [accuracy, setAccuracy] = useState(0) - + + // Timer settings for infinite mode + const [timerDuration, setTimerDuration] = useState(30); // Default 30 seconds + const [timeLeft, setTimeLeft] = useState(30); + const [showTimerSettings, setShowTimerSettings] = useState(false); + const [infiniteStartTime, setInfiniteStartTime] = useState(null); // Track start time for infinite mode + const [timerActive, setTimerActive] = useState(false); // Track if timer is running + + // Check if user typed the trigger phrase for infinite mode useEffect(() => { + const cleanTypedChars = typedChars.toLowerCase().replace(/\s+/g, ''); + if (cleanTypedChars.includes("infinitemodeoftyping")) { + setIsInfiniteMode(true); + setShowTimerSettings(true); // Show timer settings when entering infinite mode + // Reset stats for infinite mode + setCurrentIdx(0); + setTypedChars(""); + setWordsPressed(0); + setRightWords(0); + setTypos(0); + setTimeLeft(timerDuration); + // Set first quote for infinite mode + setQuote(infiniteQuotes[0]); + setCurrentQuoteIndex(0); + } + }, [typedChars, timerDuration]); + + // Function to start infinite mode with selected timer + const startInfiniteMode = (selectedDuration) => { + setTimerDuration(selectedDuration); + setTimeLeft(selectedDuration); + setShowTimerSettings(false); + // Initialize typing area first + setCurrentIdx(0); + setTypedChars(""); + setWordsPressed(0); + setRightWords(0); + setTypos(0); + setIsCompeleted(false); // Ensure completion is false + setFinalTime(0); + setWPM(0); + setAccuracy(0); + setQuote(infiniteQuotes[0]); + setCurrentQuoteIndex(0); + + // Start timer after a brief delay to ensure all states are reset + setTimeout(() => { + setTimerActive(true); + setInfiniteStartTime(Date.now()); + }, 100); + }; + + + // Infinite mode timer - stops when time runs out and shows results + useEffect(() => { + let timer; + if (isInfiniteMode && !isCompeleted && !showTimerSettings && timerActive && timeLeft > 0) { + timer = setInterval(() => { + setTimeLeft(prevTime => { + if (prevTime <= 1) { + // Time's up, stop the test and show results + setTimerActive(false); + const totalTime = timerDuration; // Use the full timer duration + setFinalTime(totalTime); + + // Calculate final WPM and accuracy for infinite mode + // Fixed WPM calculation: (correct chars / 5) / (time in minutes) + const timeInMinutes = totalTime / 60; + const calculatedWPM = timeInMinutes > 0 ? Math.round((rightWords / 5) / timeInMinutes) : 0; + setWPM(calculatedWPM); + + const calculatedAccuracy = wordsPressed > 0 ? parseFloat(((rightWords / wordsPressed) * 100).toFixed(2)) : 0; + setAccuracy(calculatedAccuracy); + + // Set completion after calculations are done + setTimeout(() => { + setIsCompeleted(true); + }, 100); + + return 0; + } + return prevTime - 1; + }); + }, 1000); + } + + return () => { + if (timer) clearInterval(timer); + }; + }, [isInfiniteMode, isCompeleted, showTimerSettings, timerActive, timeLeft]); + useEffect(() => { const handleKeyDown = (e) => { + // Don't process keys if timer settings are shown or test is completed + if (showTimerSettings || isCompeleted) return; + const pressedKey = e.key; - if (/^[a-zA-Z0-9\s]$/.test(pressedKey)) { + if (/^[a-zA-Z0-9\s.,!?;:'"()-]$/.test(pressedKey)) { setWordsPressed(prev => prev + 1) if (pressedKey === quote[currentIdx]) { const nextIdx = currentIdx + 1; if (nextIdx === quote.length) { - setIsCompeleted(true); + if (isInfiniteMode && timerActive) { + // In infinite mode, immediately load next quote if timer is still active + const nextIndex = (currentQuoteIndex + 1) % infiniteQuotes.length; + setCurrentQuoteIndex(nextIndex); + setQuote(infiniteQuotes[nextIndex]); + setCurrentIdx(0); + } else if (!isInfiniteMode) { + // For regular mode, calculate stats before completion + setIsCompeleted(true); + } + } else { + setCurrentIdx(nextIdx); } - setCurrentIdx(nextIdx); setTypedChars(prev => prev + pressedKey); setRightWords(prev => prev + 1) setWarning(prev => prev = true) @@ -49,22 +165,62 @@ const InfiniteTypingBoard = (props) => { document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); - }, [currentIdx, quote, words, wordsPressed]); + }, [currentIdx, quote, words, wordsPressed, isInfiniteMode, currentQuoteIndex, showTimerSettings, timerDuration, timerActive, isCompeleted]); - - // Calculate WPM when typing is completed + + // Calculate WPM when typing is completed (for regular mode only) useEffect(() => { - if (isCompeleted && finalTime > 0) { - - const timeInMinutes = finalTime / 8;//number 8 is assuring that this salculation will show word per minute and not aplbet ot keysTyped per minute. i am assumned that there is 6-7 words are commmon in words. - const calculatedWPM = Math.round(rightWords / timeInMinutes); + if (isCompeleted && finalTime > 0 && !isInfiniteMode) { + // Fixed WPM calculation for regular mode + const timeInMinutes = finalTime / 60; // Convert seconds to minutes + const calculatedWPM = timeInMinutes > 0 ? Math.round((rightWords / 5) / timeInMinutes) : 0; setWPM(calculatedWPM); - const calculatedAccuracy = ((rightWords / wordsPressed) * 100).toFixed(2); + const calculatedAccuracy = wordsPressed > 0 ? parseFloat(((rightWords / wordsPressed) * 100).toFixed(2)) : 0; setAccuracy(calculatedAccuracy); } - }, [isCompeleted, finalTime, rightWords]); - + }, [isCompeleted, finalTime, rightWords, isInfiniteMode, wordsPressed]); + + // Function to exit infinite mode + const exitInfiniteMode = () => { + setIsInfiniteMode(false); + setShowTimerSettings(false); + setTimerActive(false); + setQuote(props.quotes); + setCurrentIdx(0); + setTypedChars(""); + setWordsPressed(0); + setRightWords(0); + setTypos(0); + setTimeLeft(30); + setTimerDuration(30); + setIsCompeleted(false); + setInfiniteStartTime(null); + setFinalTime(0); + setWPM(0); + setAccuracy(0); + }; + + // Function to restart the typing test + const restartTest = () => { + if (isInfiniteMode) { + setShowTimerSettings(true); + setIsCompeleted(false); + setTimerActive(false); + setTimeLeft(timerDuration); + } else { + setIsCompeleted(false); + } + setCurrentIdx(0); + setTypedChars(""); + setWordsPressed(0); + setRightWords(0); + setTypos(0); + setFinalTime(0); + setWPM(0); + setAccuracy(0); + setInfiniteStartTime(null); + }; return ( <> @@ -72,21 +228,144 @@ const InfiniteTypingBoard = (props) => {
+ Select how long you want the typing test to last +
+