-
-
Save shricodev/deceac7ba54b9cb5b597ae4e1f3220b7 to your computer and use it in GitHub Desktop.
Basic typing test application (generated by GPT-4.5 AI Model). This gist is for one of my blog post comparison of AI Models.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use client"; | |
import { useEffect, useRef, useState } from "react"; | |
const sampleText = "The quick brown fox jumps over the lazy dog."; | |
export default function Home() { | |
const [userInput, setUserInput] = useState(""); | |
const [startTime, setStartTime] = useState<number | null>(null); | |
const [timeElapsed, setTimeElapsed] = useState(0); | |
const [intervalId, setIntervalId] = useState<NodeJS.Timeout | null>(null); | |
const inputRef = useRef<HTMLInputElement>(null); | |
useEffect(() => { | |
inputRef.current?.focus(); | |
}, []); | |
useEffect(() => { | |
if (startTime) { | |
setIntervalId( | |
setInterval(() => { | |
setTimeElapsed((Date.now() - startTime) / 1000); | |
}, 1000), | |
); | |
} | |
return () => { | |
if (intervalId) clearInterval(intervalId); | |
}; | |
}, [startTime]); | |
const handleReset = () => { | |
setUserInput(""); | |
setStartTime(null); | |
setTimeElapsed(0); | |
inputRef.current?.focus(); | |
}; | |
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
const val = e.target.value; | |
if (!startTime) setStartTime(Date.now()); | |
setUserInput(val); | |
if (val === sampleText) { | |
if (intervalId) clearInterval(intervalId); | |
} | |
}; | |
const getCharClass = (char: string, index: number) => { | |
if (!userInput[index]) return ""; | |
return char === userInput[index] | |
? "text-green-500" | |
: "text-red-500 underline"; | |
}; | |
const mistakes = sampleText | |
.slice(0, userInput.length) | |
.split("") | |
.filter((char, idx) => char !== userInput[idx]).length; | |
const wordsTyped = userInput.length / 5; // Common WPM definition: avg 5 chars per word | |
const wpmRaw = timeElapsed > 0 ? (wordsTyped / timeElapsed) * 60 : 0; | |
const wpmAdjusted = | |
timeElapsed > 0 ? ((wordsTyped - mistakes) / timeElapsed) * 60 : 0; | |
return ( | |
<main className="min-h-screen flex flex-col items-center justify-center bg-gray-900 text-white font-mono gap-4 p-4"> | |
<h1 className="text-3xl font-bold mb-4">Typing Test</h1> | |
<div className="max-w-xl"> | |
<p className="text-xl border border-gray-700 rounded p-4 select-none"> | |
{sampleText.split("").map((char, idx) => ( | |
<span key={idx} className={getCharClass(char, idx)}> | |
{char} | |
</span> | |
))} | |
</p> | |
</div> | |
<input | |
ref={inputRef} | |
value={userInput} | |
onChange={handleChange} | |
className="max-w-xl w-full rounded p-3 text-lg bg-gray-800 text-white caret-white outline-none" | |
placeholder="Start typing here..." | |
/> | |
<div className="flex gap-6 text-lg"> | |
<p>Time: {Math.floor(timeElapsed)}s</p> | |
<p>Mistakes: {mistakes}</p> | |
<p>Raw WPM: {Math.max(0, wpmRaw).toFixed(1)}</p> | |
<p>Adjusted WPM: {Math.max(0, wpmAdjusted).toFixed(1)}</p> | |
</div> | |
<button | |
onClick={handleReset} | |
className="mt-4 px-6 py-2 bg-blue-600 hover:bg-blue-700 rounded-md transition-colors" | |
> | |
Reset | |
</button> | |
</main> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment