quran
quran
HTML
<!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>Speed Typing Game</title>
<link rel="stylesheet" href="style.css">
<script src="script.js" defer></script>
</head>
<body>
<div class="wrapper">
<input type="text" class="input-field">
<div class="content-box">
<div class="typing-text">
<p id="paragraph"></p>
</div>
<div class="content">
<ul class="result-details">
<li class="time">
<p>
Time Left:
</p>
<span><b>60</b>s</span>
</li>
<li class="mistake">
<p>
Mistakes:
</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>Try Again</button>
</div>
</div>
</div>
</body>
</html>
CSS
@import url('https://fonts.googleapis.com/css2?
family=Poppins:wght@400;500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
display: flex;
padding: 0 10px;
align-items: center;
justify-content: center;
min-height: 100vh;
background: linear-gradient( #007acc, #6DD5FA, #FFFFFF);
}
#paragraph{
color: #646669;
}
.result-details{
color: white;
}
::selection {
color: #fff;
background: #007acc;
}
.wrapper {
width: 700px;
padding: 35px;
background: #1e1e1e;
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: 4px solid #007acc;
}
.content-box .typing-text {
overflow: hidden;
max-height: 256px;
}
.typing-text::-webkit-scrollbar {
width: 0;
}
.typing-text p {
font-size: 21px;
text-align: justify;
letter-spacing: 1px;
word-break: break-all;
}
.typing-text p span {
position: relative;
}
.typing-text p span.correct {
color: #d1d0c5;
}
.typing-text p span.incorrect {
color: #ca4754;
border-radius: 4px;
}
/* .typing-text p span.active {
color: #17A2B8;
} */
.typing-text p span.active::before {
position: absolute;
content: "";
height: 2px;
width: 100%;
bottom: 0;
left: 0;
opacity: 0;
border-radius: 5px;
background: #007acc;
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: 3px solid #007acc;
}
.content button {
outline: none;
border: none;
width: 105px;
color: #007acc;
padding: 8px 0;
font-size: 17px;
font-weight: 600;
cursor: pointer;
border-radius: 15px;
border: 3px solid #007acc;
background: none;
transition: transform 0.2s ease;
}
.content button:active {
transform: scale(0.89);
}
.content button:hover {
background: #FFFFFF;
}
.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: 2px solid #bfbfbf;
}
.result-details li p {
font-size: 13px;
}
.result-details li span {
display: block;
font-size: 13px;
margin-left: 10px;
}
li span b {
font-weight: 500;
}
li:not(:first-child) span {
font-weight: 500;
}
@media (max-width: 745px) {
.wrapper {
padding: 20px;
}
.content-box .content {
padding: 20px 0;
}
.content-box .typing-text {
max-height: 100%;
}
.typing-text p {
font-size: 19px;
text-align: left;
}
.content button {
width: 100%;
font-size: 15px;
padding: 10px 0;
margin-top: 20px;
}
.content .result-details {
width: 100%;
}
.result-details li:not(:first-child) {
border-left: 0;
padding: 0;
}
.result-details li p,
.result-details li span {
font-size: 15px;
}
}
@media (max-width: 518px) {
.wrapper .content-box {
padding: 10px 15px 0;
}
.typing-text p {
font-size: 13px;
}
.result-details li {
margin-bottom: 10px;
}
.content button {
margin-top: 10px;
}
}
const paragraphs = [
"Their politician was, in this moment, a notour paperback. The
sack.",
"Authors often misinterpret the lettuce as a folklore rabbi, when in
in this moment"
];
let timer;
let maxTime = 60;
let timeLeft = maxTime;
let charIndex = mistakes = isTyping = 0;
function loadParagraph() {
const ranIndex = Math.floor(Math.random() * paragraphs.length);
typingText.innerHTML = "";
paragraphs[ranIndex].split("").forEach(char => {
console.log(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")) {
mistakes--;
}
characters[charIndex].classList.remove("correct",
"incorrect");
}
} else {
if (characters[charIndex].innerText == typedChar) {
characters[charIndex].classList.add("correct");
} else {
mistakes++;
characters[charIndex].classList.add("incorrect");
}
charIndex++;
}
characters.forEach(span => span.classList.remove("active"));
characters[charIndex].classList.add("active");
wpmTag.innerText = wpm;
mistakeTag.innerText = mistakes;
cpmTag.innerText = charIndex - mistakes;
} else {
clearInterval(timer);
inpField.value = "";
}
}
function initTimer() {
if (timeLeft > 0) {
timeLeft--;
timeTag.innerText = timeLeft;
let wpm = Math.round(((charIndex - mistakes) / 5) / (maxTime -
timeLeft) * 60);
wpmTag.innerText = wpm;
} else {
clearInterval(timer);
}
}
function resetGame() {
loadParagraph();
clearInterval(timer);
timeLeft = maxTime;
charIndex = mistakes = isTyping = 0;
inpField.value = "";
timeTag.innerText = timeLeft;
wpmTag.innerText = 0;
mistakeTag.innerText = 0;
cpmTag.innerText = 0;
}
loadParagraph();
inpField.addEventListener("input", initTyping);
tryAgainBtn.addEventListener("click", resetGame);
Speech to Text
<!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"
/>
<link rel="stylesheet" href="style.css" />
<title>Speech to Text</title>
</head>
<body>
<div class="container">
<p class="heading">Speech to Text</p>
<div class="options">
<div class="anguage">
<p>Language</p>
<select name="input-language" id="language"></select>
</div>
</div>
<div class="line"></div>
<button class="btn record">
<div class="icon">
<ion-icon name="mic-outline"></ion-icon>
<img src="bars.svg" alt="" />
</div>
<p>Start Listening</p>
</button>
<p class="heading">Result :</p>
<div
class="result"
spellcheck="false"
placeholder="Text will be shown here"
>
<p class="interim"></p>
</div>
<div class="buttons">
<button class="btn clear">
<ion-icon name="trash-outline"></ion-icon>
<p>Clear</p>
</button>
<button class="btn download" disabled>
<ion-icon name="cloud-download-outline"></ion-icon>
<p>Download</p>
</button>
</div>
</div>
<!-- IONICONS -->
<script
type="module"
src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"
></script>
<script
nomodule
src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.js"
></script>
@import url(https://fonts.googleapis.com/css?
family=Poppins:100,100italic,200,200italic,300,300italic,regular,italic,5
00,500italic,600,600italic,700,700italic,800,800italic,900,900italic);
:root {
--primary-color: #356aff;
--bg-color: #fff;
--text-color: #000;
--light-text-color: #a5a5a5;
--body-bg-color: #f5f5f5;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--body-bg-color);
color: var(--text-color);
}
.container {
width: 400px;
padding: 20px;
border-radius: 10px;
background-color: var(--bg-color);
}
.container .heading {
font-size: 25px;
font-weight: 500;
margin-bottom: 10px;
}
.container .options select {
width: 100%;
padding: 10px;
border: 1px solid var(--light-text-color);
border-radius: 5px;
outline: none;
}
.container .options div:not(:last-child) select {
margin-bottom: 20px;
}
.container .options p {
font-size: 14px;
font-weight: 600;
margin-bottom: 5px;
color: var(--light-text-color);
}
.container .line {
position: relative;
width: 100%;
height: 1px;
background-color: var(--light-text-color);
opacity: 0.5;
margin: 30px 0;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
height: 60px;
padding: 20px;
width: 100%;
outline: none;
border: none;
border-radius: 5px;
font-size: 20px;
font-weight: 500;
cursor: pointer;
color: #fff;
background-color: var(--primary-color);
}
.btn ion-icon {
font-size: 30px;
}
.btn:disabled {
background-color: var(--light-text-color);
cursor: not-allowed;
}
.container .record img {
width: 30px;
height: 30px;
display: none;
}
.container .record.recording img {
display: block;
}
.container .record.recording ion-icon {
display: none;
}
.container .result {
width: 100%;
min-height: 200px;
padding: 10px;
border: 1px solid var(--light-text-color);
border-radius: 5px;
font-size: 18px;
font-weight: 500;
margin-bottom: 20px;
color: var(--text-color);
}
.container .result p {
display: inline;
margin-left: 3px;
color: var(--light-text-color);
}
.buttons {
display: flex;
gap: 20px;
}
let SpeechRecognition =
window.SpeechRecognition || window.webkitSpeechRecognition,
recognition,
recording = false;
function populateLanguages() {
languages.forEach((lang) => {
const option = document.createElement("option");
option.value = lang.code;
option.innerHTML = lang.name;
inputLanguage.appendChild(option);
});
}
populateLanguages();
function speechToText() {
try {
recognition = new SpeechRecognition();
recognition.lang = inputLanguage.value;
recognition.interimResults = true;
recordBtn.classList.add("recording");
recordBtn.querySelector("p").innerHTML = "Listening...";
recognition.start();
recognition.onresult = (event) => {
const speechResult = event.results[0][0].transcript;
//detect when intrim results
if (event.results[0].isFinal) {
result.innerHTML += " " + speechResult;
result.querySelector("p").remove();
} else {
//creative p with class interim if not already there
if (!document.querySelector(".interim")) {
const interim = document.createElement("p");
interim.classList.add("interim");
result.appendChild(interim);
}
//update the interim p with the speech result
document.querySelector(".interim").innerHTML = " " +
speechResult;
}
downloadBtn.disabled = false;
};
recognition.onspeechend = () => {
speechToText();
};
recognition.onerror = (event) => {
stopRecording();
if (event.error === "no-speech") {
alert("No speech was detected. Stopping...");
} else if (event.error === "audio-capture") {
alert(
"No microphone was found. Ensure that a microphone is
installed."
);
} else if (event.error === "not-allowed") {
alert("Permission to use microphone is blocked.");
} else if (event.error === "aborted") {
alert("Listening Stopped.");
} else {
alert("Error occurred in recognition: " + event.error);
}
};
} catch (error) {
recording = false;
console.log(error);
}
}
recordBtn.addEventListener("click", () => {
if (!recording) {
speechToText();
recording = true;
} else {
stopRecording();
}
});
function stopRecording() {
recognition.stop();
recordBtn.querySelector("p").innerHTML = "Start Listening";
recordBtn.classList.remove("recording");
recording = false;
}
function download() {
const text = result.innerText;
const filename = "speech.txt";
downloadBtn.addEventListener("click", download);
clearBtn.addEventListener("click", () => {
result.innerHTML = "";
downloadBtn.disabled = true;
});
const languages = [
{
no: "3",
name: "Arabic",
native: ""عربي,
code: "ar",
},
];