├── countdown.mp3 ├── style.css ├── index.html └── script.js /countdown.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opensource-coding/Javascript-Quiz-App/HEAD/countdown.mp3 -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Poppins:100,100italic,200,200italic,300,300italic,regular,italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | font-family: "Poppins", sans-serif; 8 | } 9 | body { 10 | min-height: 100vh; 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | background: #dddfeb; 15 | } 16 | .container { 17 | position: relative; 18 | width: 100%; 19 | max-width: 400px; 20 | background: #1f2847; 21 | padding: 30px; 22 | overflow: hidden; 23 | border-radius: 10px; 24 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 25 | } 26 | 27 | .heading { 28 | text-align: center; 29 | font-size: 40px; 30 | color: #fff; 31 | margin-bottom: 50px; 32 | } 33 | label { 34 | display: block; 35 | font-size: 12px; 36 | margin-bottom: 10px; 37 | color: #fff; 38 | } 39 | select { 40 | width: 100%; 41 | padding: 10px; 42 | border: none; 43 | text-transform: capitalize; 44 | border-radius: 5px; 45 | margin-bottom: 20px; 46 | background: #fff; 47 | color: #1f2847; 48 | font-size: 14px; 49 | } 50 | .start-screen .btn { 51 | margin-top: 50px; 52 | } 53 | .hide { 54 | display: none; 55 | } 56 | .timer { 57 | width: 100%; 58 | height: 100px; 59 | display: flex; 60 | align-items: center; 61 | justify-content: center; 62 | flex-direction: column; 63 | margin-bottom: 30px; 64 | } 65 | .timer .progress { 66 | position: relative; 67 | width: 100%; 68 | height: 40px; 69 | background: transparent; 70 | border-radius: 30px; 71 | overflow: hidden; 72 | margin-bottom: 10px; 73 | border: 3px solid #3f4868; 74 | } 75 | .timer .progress .progress-bar { 76 | width: 100%; 77 | height: 100%; 78 | border-radius: 30px; 79 | overflow: hidden; 80 | background: linear-gradient(to right, #ea517c, #b478f1); 81 | transition: 1s linear; 82 | } 83 | .timer .progress .progress-text { 84 | position: absolute; 85 | top: 50%; 86 | left: 50%; 87 | transform: translate(-50%, -50%); 88 | color: #fff; 89 | font-size: 16px; 90 | font-weight: 500; 91 | } 92 | 93 | .question-wrapper .number { 94 | color: #a2aace; 95 | font-size: 25px; 96 | font-weight: 500; 97 | margin-bottom: 20px; 98 | } 99 | .question-wrapper .number .total { 100 | color: #576081; 101 | font-size: 18px; 102 | } 103 | .question-wrapper .question { 104 | color: #fff; 105 | font-size: 20px; 106 | font-weight: 500; 107 | margin-bottom: 20px; 108 | } 109 | 110 | .answer-wrapper .answer { 111 | width: 100%; 112 | height: 60px; 113 | padding: 20px; 114 | border-radius: 10px; 115 | color: #fff; 116 | border: 3px solid #3f4868; 117 | display: flex; 118 | align-items: center; 119 | justify-content: space-between; 120 | margin-bottom: 20px; 121 | cursor: pointer; 122 | transition: 0.3s linear; 123 | } 124 | .answer .checkbox { 125 | width: 20px; 126 | height: 20px; 127 | border-radius: 50%; 128 | border: 3px solid #3f4868; 129 | display: flex; 130 | align-items: center; 131 | justify-content: center; 132 | transition: all 0.3s; 133 | } 134 | .answer .checkbox i { 135 | color: #fff; 136 | font-size: 10px; 137 | opacity: 0; 138 | transition: all 0.3s; 139 | } 140 | .answer:hover:not(.checked) .checkbox, 141 | .answer.selected .checkbox { 142 | background-color: #0c80ef; 143 | border-color: #0c80ef; 144 | } 145 | .answer.selected .checkbox i { 146 | opacity: 1; 147 | } 148 | .answer.correct { 149 | border-color: #0cef2a; 150 | } 151 | .answer.wrong { 152 | border-color: #fc3939; 153 | } 154 | .question-wrapper, 155 | .answer-wrapper { 156 | margin-bottom: 50px; 157 | } 158 | .btn { 159 | width: 100%; 160 | height: 60px; 161 | background: #0c80ef; 162 | border: none; 163 | border-radius: 10px; 164 | color: #fff; 165 | font-size: 18px; 166 | font-weight: 500; 167 | cursor: pointer; 168 | transition: 0.3s linear; 169 | } 170 | .btn:hover { 171 | background: #0a6bc5; 172 | } 173 | .btn:disabled { 174 | background: #576081; 175 | cursor: not-allowed; 176 | } 177 | .btn.next { 178 | display: none; 179 | } 180 | 181 | .end-screen .score { 182 | color: #fff; 183 | font-size: 25px; 184 | font-weight: 500; 185 | margin-bottom: 80px; 186 | text-align: center; 187 | } 188 | .score .score-text { 189 | color: #a2aace; 190 | font-size: 16px; 191 | font-weight: 500; 192 | margin-bottom: 120px; 193 | } 194 | 195 | @media (max-width: 468px) { 196 | .container { 197 | min-height: 100vh; 198 | max-width: 100%; 199 | border-radius: 0; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 15 | Quiz App 16 | 17 | 18 |
19 |
20 |

Quiz App

21 |
22 | 23 | 32 | 33 | 53 | 54 | 60 | 61 | 69 |
70 | 71 |
72 |
73 |
74 |
75 |
76 | 77 |
78 |
79 |
80 |
81 | Question 1 82 | /10 83 |
84 |
This is a question This is a question?
85 |
86 |
87 |
88 | answer 89 | 90 | 91 | 92 |
93 |
94 | 95 | 96 |
97 |
98 |

Quiz App

99 |
100 | Your score: 101 |
102 | 0 103 | /10 104 |
105 |
106 | 107 |
108 |
109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const progressBar = document.querySelector(".progress-bar"), 2 | progressText = document.querySelector(".progress-text"); 3 | 4 | const progress = (value) => { 5 | const percentage = (value / time) * 100; 6 | progressBar.style.width = `${percentage}%`; 7 | progressText.innerHTML = `${value}`; 8 | }; 9 | 10 | const startBtn = document.querySelector(".start"), 11 | numQuestions = document.querySelector("#num-questions"), 12 | category = document.querySelector("#category"), 13 | difficulty = document.querySelector("#difficulty"), 14 | timePerQuestion = document.querySelector("#time"), 15 | quiz = document.querySelector(".quiz"), 16 | startScreen = document.querySelector(".start-screen"); 17 | 18 | let questions = [], 19 | time = 30, 20 | score = 0, 21 | currentQuestion, 22 | timer; 23 | 24 | const startQuiz = () => { 25 | const num = numQuestions.value, 26 | cat = category.value, 27 | diff = difficulty.value; 28 | loadingAnimation(); 29 | const url = `https://opentdb.com/api.php?amount=${num}&category=${cat}&difficulty=${diff}&type=multiple`; 30 | fetch(url) 31 | .then((res) => res.json()) 32 | .then((data) => { 33 | questions = data.results; 34 | setTimeout(() => { 35 | startScreen.classList.add("hide"); 36 | quiz.classList.remove("hide"); 37 | currentQuestion = 1; 38 | showQuestion(questions[0]); 39 | }, 1000); 40 | }); 41 | }; 42 | 43 | startBtn.addEventListener("click", startQuiz); 44 | 45 | const showQuestion = (question) => { 46 | const questionText = document.querySelector(".question"), 47 | answersWrapper = document.querySelector(".answer-wrapper"); 48 | questionNumber = document.querySelector(".number"); 49 | 50 | questionText.innerHTML = question.question; 51 | 52 | const answers = [ 53 | ...question.incorrect_answers, 54 | question.correct_answer.toString(), 55 | ]; 56 | answersWrapper.innerHTML = ""; 57 | answers.sort(() => Math.random() - 0.5); 58 | answers.forEach((answer) => { 59 | answersWrapper.innerHTML += ` 60 |
61 | ${answer} 62 | 63 | 64 | 65 |
66 | `; 67 | }); 68 | 69 | questionNumber.innerHTML = ` Question ${ 70 | questions.indexOf(question) + 1 71 | } 72 | /${questions.length}`; 73 | //add event listener to each answer 74 | const answersDiv = document.querySelectorAll(".answer"); 75 | answersDiv.forEach((answer) => { 76 | answer.addEventListener("click", () => { 77 | if (!answer.classList.contains("checked")) { 78 | answersDiv.forEach((answer) => { 79 | answer.classList.remove("selected"); 80 | }); 81 | answer.classList.add("selected"); 82 | submitBtn.disabled = false; 83 | } 84 | }); 85 | }); 86 | 87 | time = timePerQuestion.value; 88 | startTimer(time); 89 | }; 90 | 91 | const startTimer = (time) => { 92 | timer = setInterval(() => { 93 | if (time === 3) { 94 | playAdudio("countdown.mp3"); 95 | } 96 | if (time >= 0) { 97 | progress(time); 98 | time--; 99 | } else { 100 | checkAnswer(); 101 | } 102 | }, 1000); 103 | }; 104 | 105 | const loadingAnimation = () => { 106 | startBtn.innerHTML = "Loading"; 107 | const loadingInterval = setInterval(() => { 108 | if (startBtn.innerHTML.length === 10) { 109 | startBtn.innerHTML = "Loading"; 110 | } else { 111 | startBtn.innerHTML += "."; 112 | } 113 | }, 500); 114 | }; 115 | function defineProperty() { 116 | var osccred = document.createElement("div"); 117 | osccred.innerHTML = 118 | "A Project By Open Source Coding"; 119 | osccred.style.position = "absolute"; 120 | osccred.style.bottom = "0"; 121 | osccred.style.right = "0"; 122 | osccred.style.fontSize = "10px"; 123 | osccred.style.color = "#ccc"; 124 | osccred.style.fontFamily = "sans-serif"; 125 | osccred.style.padding = "5px"; 126 | osccred.style.background = "#fff"; 127 | osccred.style.borderTopLeftRadius = "5px"; 128 | osccred.style.borderBottomRightRadius = "5px"; 129 | osccred.style.boxShadow = "0 0 5px #ccc"; 130 | document.body.appendChild(osccred); 131 | } 132 | 133 | defineProperty(); 134 | 135 | const submitBtn = document.querySelector(".submit"), 136 | nextBtn = document.querySelector(".next"); 137 | submitBtn.addEventListener("click", () => { 138 | checkAnswer(); 139 | }); 140 | 141 | nextBtn.addEventListener("click", () => { 142 | nextQuestion(); 143 | submitBtn.style.display = "block"; 144 | nextBtn.style.display = "none"; 145 | }); 146 | 147 | const checkAnswer = () => { 148 | clearInterval(timer); 149 | const selectedAnswer = document.querySelector(".answer.selected"); 150 | if (selectedAnswer) { 151 | const answer = selectedAnswer.querySelector(".text").innerHTML; 152 | console.log(currentQuestion); 153 | if (answer === questions[currentQuestion - 1].correct_answer) { 154 | score++; 155 | selectedAnswer.classList.add("correct"); 156 | } else { 157 | selectedAnswer.classList.add("wrong"); 158 | const correctAnswer = document 159 | .querySelectorAll(".answer") 160 | .forEach((answer) => { 161 | if ( 162 | answer.querySelector(".text").innerHTML === 163 | questions[currentQuestion - 1].correct_answer 164 | ) { 165 | answer.classList.add("correct"); 166 | } 167 | }); 168 | } 169 | } else { 170 | const correctAnswer = document 171 | .querySelectorAll(".answer") 172 | .forEach((answer) => { 173 | if ( 174 | answer.querySelector(".text").innerHTML === 175 | questions[currentQuestion - 1].correct_answer 176 | ) { 177 | answer.classList.add("correct"); 178 | } 179 | }); 180 | } 181 | const answersDiv = document.querySelectorAll(".answer"); 182 | answersDiv.forEach((answer) => { 183 | answer.classList.add("checked"); 184 | }); 185 | 186 | submitBtn.style.display = "none"; 187 | nextBtn.style.display = "block"; 188 | }; 189 | 190 | const nextQuestion = () => { 191 | if (currentQuestion < questions.length) { 192 | currentQuestion++; 193 | showQuestion(questions[currentQuestion - 1]); 194 | } else { 195 | showScore(); 196 | } 197 | }; 198 | 199 | const endScreen = document.querySelector(".end-screen"), 200 | finalScore = document.querySelector(".final-score"), 201 | totalScore = document.querySelector(".total-score"); 202 | const showScore = () => { 203 | endScreen.classList.remove("hide"); 204 | quiz.classList.add("hide"); 205 | finalScore.innerHTML = score; 206 | totalScore.innerHTML = `/ ${questions.length}`; 207 | }; 208 | 209 | const restartBtn = document.querySelector(".restart"); 210 | restartBtn.addEventListener("click", () => { 211 | window.location.reload(); 212 | }); 213 | 214 | const playAdudio = (src) => { 215 | const audio = new Audio(src); 216 | audio.play(); 217 | }; 218 | --------------------------------------------------------------------------------