Step-by-Step Guide: Creating a Typing Web App with CSS, HTML, and JavaScript

C++ Mastery
0
Creating a Typing Web App with CSS, HTML, and JavaScript:



Introduction:
Today we are going to learn, How to make a web application of typing using css, html and javascript. First we need to open our visual studio code or any other ide that you are using. Then we need to write the formate starting code of the web development or website development code starting formate for html.
Like given below:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Typing Web</title>
</head>
<body>

</body>
</html>



Now we need to add between body to body tag over html code for the web typing application. Like:



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Typing Web</title>
</head>
<body>
<div class="wrapper">
<input type="text" class="input-field">
<div class="content-box">
<div class="typing-text">
<p></p>
</div>
<div class="content">
<ul class="result-details">
<li class="timeLeft">
<p>time Left:</p>
<span><b>60</b>s</span>
</li>
<li class="errors">
<p>Errors:</p>
<span>0</span>
</li>
<li class="wpm">
<p>WPM:</p>
<span>0</span>
</li>
<li class="cpm">
<p>CPM:</p>
<span>0</span>
</li>
</ul>
<button>Test Again</button>
</div>
</div>
</div>

After this now add, In the head tag write <style> </style> to add a style to the app. To design the page of the HTML code.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* Import Google Font - Poppins */
@import url("https://fonts.googleapis.com/css2?family=Merriweather:wght@400;500;600;700&display=swap");

* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Merriweather", sans-serif;
}

body {
display: flex;
padding: 0 10px;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #0f172a;
}

::selection {
color: #fff;
background: deepskyblue;
}

.wrapper {
width: 770px;
padding: 35px;
background: #0f172a;
color: #f1f5f9;
border-radius: 10px;
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.05);
}

.wrapper .input-field {
opacity: 0;
z-index: -999;
position: absolute;
}

.wrapper .content-box {
padding: 13px 20px 0;
border-radius: 10px;
border: 1px solid #bfbfbf;
}

.content-box .typing-text {
overflow: hidden;
max-height: 256px;
}

.typing-text::-webkit-scrollbar {
width: 0;
}

.typing-text p {
font-size: 25px;
text-align: justify;
letter-spacing: 1px;
}

.typing-text p span {
position: relative;
}

.typing-text p span.correct {
color: lawngreen;
}

.typing-text p span.incorrect {
color: #cb3439;
outline: 1px solid #fff;
background: #ffc0cb;
border-radius: 4px;
}

.typing-text p span.active {
color: deepskyblue;
}

.typing-text p span.active::before {
position: absolute;
content: "";
height: 2px;
width: 100%;
bottom: 0;
left: 0;
opacity: 0;
border-radius: 5px;
background: deepskyblue;
animation: blink 1s ease-in-out infinite;
}

@keyframes blink {
50% {
opacity: 1;
}
}

.content-box .content {
margin-top: 17px;
display: flex;
padding: 12px 0;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
border-top: 1px solid #bfbfbf;
line-break: auto;
}

.content button {
outline: none;
border: none;
width: 105px;
color: #fff;
padding: 8px 0;
font-size: 16px;
cursor: pointer;
border-radius: 5px;
background: deepskyblue;
transition: transform 0.3s ease;
}

.content button:active {
transform: scale(0.97);
}

.content .result-details {
display: flex;
flex-wrap: wrap;
align-items: center;
width: calc(100% - 140px);
justify-content: space-between;
}

.result-details li {
display: flex;
height: 20px;
list-style: none;
position: relative;
align-items: center;
}

.result-details li:not(:first-child) {
padding-left: 22px;
border-left: 1px solid #bfbfbf;
}

.result-details li p {
font-size: 19px;
}

.result-details li span {
display: block;
font-size: 20px;
margin-left: 10px;
}

li span b {
font-weight: 500;
}

li:not(:first-child) span {
font-weight: 500;
}

.errors span {
color: #facc15;
}

.timeLeft span {
color: #cb3439;
}
</style>
</head>
<body>
<div class="wrapper">
<input type="text" class="input-field">
<div class="content-box">
<div class="typing-text">
<p></p>
</div>
<div class="content">
<ul class="result-details">
<li class="timeLeft">
<p>time Left:</p>
<span><b>60</b>s</span>
</li>
<li class="errors">
<p>Errors:</p>
<span>0</span>
</li>
<li class="wpm">
<p>WPM:</p>
<span>0</span>
</li>
<li class="cpm">
<p>CPM:</p>
<span>0</span>
</li>
</ul>
<button>Test Again</button>
</div>
</div>
</div>

Now add javascript to the file.


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* Import Google Font - Poppins */
@import url("https://fonts.googleapis.com/css2?family=Merriweather:wght@400;500;600;700&display=swap");

* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Merriweather", sans-serif;
}

body {
display: flex;
padding: 0 10px;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #0f172a;
}

::selection {
color: #fff;
background: deepskyblue;
}

.wrapper {
width: 770px;
padding: 35px;
background: #0f172a;
color: #f1f5f9;
border-radius: 10px;
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.05);
}

.wrapper .input-field {
opacity: 0;
z-index: -999;
position: absolute;
}

.wrapper .content-box {
padding: 13px 20px 0;
border-radius: 10px;
border: 1px solid #bfbfbf;
}

.content-box .typing-text {
overflow: hidden;
max-height: 256px;
}

.typing-text::-webkit-scrollbar {
width: 0;
}

.typing-text p {
font-size: 25px;
text-align: justify;
letter-spacing: 1px;
}

.typing-text p span {
position: relative;
}

.typing-text p span.correct {
color: lawngreen;
}

.typing-text p span.incorrect {
color: #cb3439;
outline: 1px solid #fff;
background: #ffc0cb;
border-radius: 4px;
}

.typing-text p span.active {
color: deepskyblue;
}

.typing-text p span.active::before {
position: absolute;
content: "";
height: 2px;
width: 100%;
bottom: 0;
left: 0;
opacity: 0;
border-radius: 5px;
background: deepskyblue;
animation: blink 1s ease-in-out infinite;
}

@keyframes blink {
50% {
opacity: 1;
}
}

.content-box .content {
margin-top: 17px;
display: flex;
padding: 12px 0;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
border-top: 1px solid #bfbfbf;
line-break: auto;
}

.content button {
outline: none;
border: none;
width: 105px;
color: #fff;
padding: 8px 0;
font-size: 16px;
cursor: pointer;
border-radius: 5px;
background: deepskyblue;
transition: transform 0.3s ease;
}

.content button:active {
transform: scale(0.97);
}

.content .result-details {
display: flex;
flex-wrap: wrap;
align-items: center;
width: calc(100% - 140px);
justify-content: space-between;
}

.result-details li {
display: flex;
height: 20px;
list-style: none;
position: relative;
align-items: center;
}

.result-details li:not(:first-child) {
padding-left: 22px;
border-left: 1px solid #bfbfbf;
}

.result-details li p {
font-size: 19px;
}

.result-details li span {
display: block;
font-size: 20px;
margin-left: 10px;
}

li span b {
font-weight: 500;
}

li:not(:first-child) span {
font-weight: 500;
}

.errors span {
color: #facc15;
}

.timeLeft span {
color: #cb3439;
}
</style>
</head>
<body>
<div class="wrapper">
<input type="text" class="input-field">
<div class="content-box">
<div class="typing-text">
<p></p>
</div>
<div class="content">
<ul class="result-details">
<li class="timeLeft">
<p>time Left:</p>
<span><b>60</b>s</span>
</li>
<li class="errors">
<p>Errors:</p>
<span>0</span>
</li>
<li class="wpm">
<p>WPM:</p>
<span>0</span>
</li>
<li class="cpm">
<p>CPM:</p>
<span>0</span>
</li>
</ul>
<button>Test Again</button>
</div>
</div>
</div>
</body>
<script>

const paragraphs = [
"One dollar and eighty-seven cents. That was all. And sixty cents of it was in pennies. Pennies saved one and two at a time by bulldozing the grocer and the vegetable man and the butcher until one’s cheeks burned with the silent imputation of parsimony that such close dealing implied. One dollar and eighty-seven cents. And the next day would be Christmas...",
"There was a leak in the boat. Nobody had yet noticed it, and nobody would for the next couple of hours. This was a problem since the boat was heading out to sea and while the leak was quite small at the moment, it would be much larger when it was ultimately discovered. John had planned it exactly this way.",
"The paper was blank. It shouldn't have been. There should have been writing on the paper, at least a paragraph if not more. The fact that the writing wasn't there was frustrating. Actually, it was even more than frustrating. It was downright distressing.", "The coin hovered in the air, spinning over and over again. It reached its peak and began to descend. Both boys were pleading with it to land a certain way but the coin had already made up its mind on what it was going to do.",
"I'll talk to you tomorrow in more detail at our meeting, but I think I've found a solution to our problem. It's not exactly legal, but it won't land us in jail for the rest of our lives either. Are you willing to take the chance? Monroe asked his partner over the phone.",
"There was a time when he would have embraced the change that was coming. In his youth, he sought adventure and the unknown, but that had been years ago. He wished he could go back and learn to find the excitement that came with change but it was useless. That curiosity had long left him to where he had come to loathe anything that put him out of his comfort zone."
];

const typingText = document.querySelector(".typing-text p"),
inpField = document.querySelector(".wrapper .input-field"),
tryAgainBtn = document.querySelector(".content button"),
timeTag = document.querySelector(".timeLeft span b"),
errorTag = document.querySelector(".errors span"),
wpmTag = document.querySelector(".wpm span"),
cpmTag = document.querySelector(".cpm span");

let timer,
maxTime = 60,
timeLeft = maxTime,
charIndex = errors = isTyping = 0;

function loadParagraph() {
const ranIndex = Math.floor(Math.random() * paragraphs.length);
typingText.innerHTML = "";
paragraphs[ranIndex].split("").forEach(char => {
let span = `<span>${char}</span>`
typingText.innerHTML += span;
});
typingText.querySelectorAll("span")[0].classList.add("active");
document.addEventListener("keydown", () => inpField.focus());
typingText.addEventListener("click", () => inpField.focus());
}

function initTyping() {
let characters = typingText.querySelectorAll("span");
let typedChar = inpField.value.split("")[charIndex];
if (charIndex < characters.length - 1 && timeLeft > 0) {
if (!isTyping) {
timer = setInterval(initTimer, 1000);
isTyping = true;
}
if (typedChar == null) {
if (charIndex > 0) {
charIndex--;
if (characters[charIndex].classList.contains("incorrect")) {
errors--;
}
characters[charIndex].classList.remove("correct", "incorrect");
}
} else {
if (characters[charIndex].innerText == typedChar) {
characters[charIndex].classList.add("correct");
} else {
errors++;
characters[charIndex].classList.add("incorrect");
}
charIndex++;
}
characters.forEach(span => span.classList.remove("active"));
characters[charIndex].classList.add("active");

let wpm = Math.round(((charIndex - errors) / 5) / (maxTime - timeLeft) * 60);
wpm = wpm < 0 || !wpm || wpm === Infinity ? 0 : wpm;

wpmTag.innerText = wpm;
errorTag.innerText = errors;
cpmTag.innerText = charIndex - errors;
} else {
clearInterval(timer);
inpField.value = "";
}
}

function initTimer() {
if (timeLeft > 0) {
timeLeft--;
timeTag.innerText = timeLeft;
let wpm = Math.round(((charIndex - errors) / 5) / (maxTime - timeLeft) * 60);
wpmTag.innerText = wpm;
} else {
clearInterval(timer);
}
}

function resetTest() {
loadParagraph();
clearInterval(timer);
timeLeft = maxTime;
charIndex = errors = isTyping = 0;
inpField.value = "";
timeTag.innerText = timeLeft;
wpmTag.innerText = 0;
errorTag.innerText = 03;
cpmTag.innerText = 0;
}

loadParagraph();
inpField.addEventListener("input", initTyping);
tryAgainBtn.addEventListener("click", resetTest);
</script>
</html>

Post a Comment

0Comments
Post a Comment (0)