├── .gitignore
├── LICENCE
├── README.md
├── readme
├── form_desktop.webp
├── form_mobile.webp
├── form_tablet.webp
├── header.webp
├── home_desktop.webp
├── home_mobile.webp
├── home_tablet.webp
├── play_classic_desktop.webp
├── play_classic_mobile.webp
├── play_classic_tablet.webp
├── play_time_desktop.webp
├── play_time_mobile.webp
└── play_time_tablet.webp
└── source_code
├── .env.example
├── .eslintrc.json
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── bg-gamemodes.svg
├── bg-home.svg
├── categories-icons
│ ├── art.svg
│ ├── entertainment.svg
│ ├── general culture.svg
│ ├── geography.svg
│ ├── history.svg
│ ├── science.svg
│ ├── space.svg
│ └── technology.svg
├── favicon.svg
├── letters
│ ├── letter-a.svg
│ ├── letter-b.svg
│ ├── letter-c.svg
│ └── letter-d.svg
├── play_bg.webp
└── sounds
│ ├── correct_answer.mp3
│ ├── pop-down.mp3
│ ├── pop-up-off.mp3
│ ├── pop-up-on.mp3
│ ├── pop.mp3
│ ├── switch-off.mp3
│ ├── switch-on.mp3
│ ├── win.mp3
│ └── wrong_answer.mp3
├── src
├── assets
│ ├── categories.json
│ ├── fifty.svg
│ ├── questions.json
│ ├── sound-off.svg
│ ├── sound-on.svg
│ ├── star.svg
│ └── trophy.svg
├── components
│ ├── Form
│ │ ├── JsxForm.jsx
│ │ └── NewGameForm.jsx
│ ├── Home
│ │ ├── Categories.jsx
│ │ ├── GameModes.jsx
│ │ └── MainHome.jsx
│ ├── PageError.jsx
│ ├── PageFooter.jsx
│ ├── PageLoading.jsx
│ ├── Play
│ │ ├── GameInfo.jsx
│ │ ├── GameOver.jsx
│ │ └── PlayHeader.jsx
│ └── Questions
│ │ ├── QuestionSlider.jsx
│ │ ├── Questions.jsx
│ │ ├── QuestionsNavbar.jsx
│ │ └── Wildcards.jsx
├── helpers
│ ├── gameConfig.js
│ ├── getQuestions.js
│ └── playSound.js
├── pages
│ ├── _app.js
│ ├── _document.js
│ ├── api
│ │ └── questions.js
│ ├── index.js
│ └── play
│ │ └── index.js
├── store
│ ├── useBoundStore.js
│ ├── useQueries.js
│ ├── useQuestions.js
│ └── useWildcards.js
└── styles
│ └── globals.css
└── tailwind.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | /source_code/node_modules
6 | /.pnp
7 | .pnp.js
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | .next
15 | /out/
16 |
17 | # production
18 | /build
19 |
20 | # misc
21 | .DS_Store
22 | *.pem
23 |
24 | # debug
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log*
28 | .pnpm-debug.log*
29 |
30 | # local env files
31 | .env*.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Cosmo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | # 🟥🟦 Quizi 🟨🟩
10 |
11 | A quiz/trivia game with different modes and categories that you can select, as well as wildcards to help you. The questions are generated by artificial intelligence using the [Cohere API](https://dashboard.cohere.ai/welcome/register).
12 |
13 |
View Demo
14 | ·
15 |
Report Bug
16 | ·
17 |
Request Feature
18 |
19 |
20 |
21 |
22 |
23 |
24 | Table of contents
25 |
26 | - [About The Project](#about-the-project)
27 | - [Screenshots](#screenshots)
28 | - [Built With](#built-with)
29 | - [Getting Started](#getting-started)
30 | - [License](#license)
31 | - [Roadmap](#roadmap)
32 | - [Contact](#contact)
33 |
34 |
35 |
36 | ## About The Project
37 |
38 | Quizi is a quiz/trivia game made with with [Cohere](https://cohere.ai). You can select different game modes and topics, you also have wildcards. Cohere's AI will generate the questions and answers for you.
39 |
40 | > **Note:** Due to Cohere's policy change (from 100 to 5 free calls) now only some questions are generated by Cohere. The rest are pre-generated.
41 |
42 | ⬆️ Back to top
43 |
44 |
45 |
46 | ## Screenshots
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | ⬆️ Back to top
85 |
86 |
87 | ### Built With
88 |
89 | List of the frameworks, libraries and tools used to build the project.
90 |
91 | * [Next.js](https://nextjs.org/)
92 | * [React.js](https://reactjs.org/)
93 | * [Zustand](https://github.com/pmndrs/zustand) For state management
94 | * [Cohere](https://dashboard.cohere.ai/welcome/register) For the generation of questions
95 | * [Vercel](https://vercel.com/) For hosting
96 | * [Tailwind CSS](https://tailwindcss.com/) For styling
97 | * [AnimatiSS](https://xsgames.co/animatiss/) For animations (title hover, correct and wrong answer)
98 | * [Patternpad](https://patternpad.com/editor.html) For the home background pattern
99 | * [Figma](https://www.figma.com/) For the design
100 | * [React icons](https://react-icons.github.io/react-icons/) For icons
101 | * [Iconify](https://iconify.design) For the answers letters icons
102 | * [Tabler Icons](https://tablericons.com) For the categories icons
103 | * [Canvas confetti](https://www.npmjs.com/package/canvas-confetti) For the confetti animation
104 | * [Vector Halftone Maker](https://halftone.xoihazard.com) For the halftone effect
105 |
106 | ⬆️ Back to top
107 |
108 |
109 |
110 | ## Getting Started
111 |
112 | 1. Clone or fork the repo
113 | ```sh
114 | git clone https://github.com/cosmoart/quiz-game
115 | ```
116 | 2. Change directory to `source_code`
117 | ```sh
118 | cd source_code
119 | ```
120 | 3. Install NPM packages
121 | ```sh
122 | npm install
123 | ```
124 | 4. Run the project
125 | ```sh
126 | npm run dev
127 | ```
128 |
129 | If you are in development environment all the questions are pre-generated, if you want to use the Cohere API you have to create a `.env.local` file with the Cohere API key at `source_code` and comment the `if` in `source_code/src/helpers/getQuestions.js`. You can get one Cohere Api key [here](https://dashboard.cohere.ai/welcome/register).
130 |
131 | The `.env.local` file should look like this:
132 |
133 | ```
134 | COHERE_API_KEY=XXXXXXXXXXXXXXXXXX
135 | ```
136 |
137 | ⬆️ Back to top
138 |
139 |
140 |
141 |
142 | ## License
143 |
144 | Distributed under the MIT License. See [`LICENSE.txt`](https://github.com/cosmoart/quiz-game/blob/main/LICENCE) for more information.
145 |
146 | ⬆️ Back to top
147 |
148 |
149 |
150 | ## Roadmap
151 |
152 | - [ ] ~~Circle wipe transition~~
153 | - [x] Add offline mode
154 | - [x] Buttons sounds
155 | - [x] Win and Lose sounds
156 | - [ ] ~~Multi-language Support~~
157 | - [ ] ~~PWA~~
158 | - [x] Personalize the game over screen for infinite mode
159 | - [ ] ~~Personalize error page for API limit exceeded~~
160 |
161 | ⬆️ Back to top
162 |
163 |
164 | ## Contact
165 |
166 | - My website - [cosmoart.vercel.app](https://cosmoart.vercel.app)
167 | - Twitter - [@CosmoArt0](https://twitter.com/cosmoart0)
168 | - Instagram - [@cosmo_art0](https://www.instagram.com/cosmo_art0/)
169 |
170 | ⬆️ Back to top
171 |
--------------------------------------------------------------------------------
/readme/form_desktop.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/form_desktop.webp
--------------------------------------------------------------------------------
/readme/form_mobile.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/form_mobile.webp
--------------------------------------------------------------------------------
/readme/form_tablet.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/form_tablet.webp
--------------------------------------------------------------------------------
/readme/header.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/header.webp
--------------------------------------------------------------------------------
/readme/home_desktop.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/home_desktop.webp
--------------------------------------------------------------------------------
/readme/home_mobile.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/home_mobile.webp
--------------------------------------------------------------------------------
/readme/home_tablet.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/home_tablet.webp
--------------------------------------------------------------------------------
/readme/play_classic_desktop.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/play_classic_desktop.webp
--------------------------------------------------------------------------------
/readme/play_classic_mobile.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/play_classic_mobile.webp
--------------------------------------------------------------------------------
/readme/play_classic_tablet.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/play_classic_tablet.webp
--------------------------------------------------------------------------------
/readme/play_time_desktop.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/play_time_desktop.webp
--------------------------------------------------------------------------------
/readme/play_time_mobile.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/play_time_mobile.webp
--------------------------------------------------------------------------------
/readme/play_time_tablet.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/readme/play_time_tablet.webp
--------------------------------------------------------------------------------
/source_code/.env.example:
--------------------------------------------------------------------------------
1 | COHERE_API_KEY=XXXXXXXXXXXXXXXXXX
--------------------------------------------------------------------------------
/source_code/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true,
5 | "node": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:react/recommended",
10 | "plugin:@next/next/recommended",
11 | "standard"
12 | ],
13 | "overrides": [],
14 | "parserOptions": {
15 | "ecmaFeatures": {
16 | "jsx": true
17 | },
18 | "ecmaVersion": "latest",
19 | "sourceType": "module"
20 | },
21 | "plugins": ["react"],
22 | "rules": {
23 | "indent": [1, "tab"],
24 | "no-tabs": 0,
25 | "react/react-in-jsx-scope": "off",
26 | "react/prop-types": "off",
27 | "no-unused-vars": 1,
28 | "react/no-unknown-property": [
29 | 2,
30 | {
31 | "ignore": ["jsx", "global", "space"]
32 | }
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source_code/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@/*": ["./src/*"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/source_code/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: false
4 | }
5 |
6 | module.exports = nextConfig
7 |
--------------------------------------------------------------------------------
/source_code/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "quiz-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "license": "MIT",
6 | "lint": "eslint .",
7 | "scripts": {
8 | "dev": "next dev",
9 | "build": "next build",
10 | "start": "next start",
11 | "lint": "next lint"
12 | },
13 | "dependencies": {
14 | "@next/font": "13.1.5",
15 | "cohere-ai": "5.0.2",
16 | "next": "13.1.5",
17 | "react": "18.2.0",
18 | "react-canvas-confetti": "1.3.0",
19 | "react-dom": "18.2.0",
20 | "react-icons": "4.7.1",
21 | "zustand": "^4.3.8"
22 | },
23 | "devDependencies": {
24 | "autoprefixer": "^10.4.13",
25 | "eslint": "^8.34.0",
26 | "eslint-config-next": "^13.1.6",
27 | "eslint-config-standard": "^17.0.0",
28 | "eslint-plugin-import": "^2.27.5",
29 | "eslint-plugin-node": "^11.1.0",
30 | "eslint-plugin-promise": "^6.1.1",
31 | "eslint-plugin-react": "^7.32.2",
32 | "eslint-plugin-react-hooks": "^4.6.0",
33 | "postcss": "^8.4.21",
34 | "tailwindcss": "^3.2.4"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source_code/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {}
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/source_code/public/bg-gamemodes.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/bg-home.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/art.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/entertainment.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/general culture.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/geography.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/history.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/science.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/space.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/source_code/public/categories-icons/technology.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/source_code/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/letters/letter-a.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/letters/letter-b.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/letters/letter-c.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/letters/letter-d.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/public/play_bg.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/play_bg.webp
--------------------------------------------------------------------------------
/source_code/public/sounds/correct_answer.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/correct_answer.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/pop-down.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/pop-down.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/pop-up-off.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/pop-up-off.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/pop-up-on.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/pop-up-on.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/pop.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/pop.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/switch-off.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/switch-off.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/switch-on.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/switch-on.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/win.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/win.mp3
--------------------------------------------------------------------------------
/source_code/public/sounds/wrong_answer.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmoart/quiz-game/68291b4498ed642ea804b1ec44570d743bafbae3/source_code/public/sounds/wrong_answer.mp3
--------------------------------------------------------------------------------
/source_code/src/assets/categories.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "aa",
4 | "name": "History",
5 | "color": "#e6c642"
6 | },
7 | {
8 | "id": "ab",
9 | "name": "Entertainment",
10 | "color": "#f94e4e"
11 | },
12 | {
13 | "id": "ac",
14 | "name": "Technology",
15 | "color": "#685af5"
16 | },
17 | {
18 | "id": "ad",
19 | "name": "Geography",
20 | "color": "#3ce956"
21 | },
22 | {
23 | "id": "ae",
24 | "name": "Art",
25 | "color": "#307de7"
26 | },
27 | {
28 | "id": "af",
29 | "name": "Space",
30 | "color": "#a656fd"
31 | },
32 | {
33 | "id": "ah",
34 | "name": "Science",
35 | "color": "#e857ed"
36 | },
37 | {
38 | "id": "ag",
39 | "name": "General culture",
40 | "color": "#56cfef"
41 | }
42 | ]
43 |
--------------------------------------------------------------------------------
/source_code/src/assets/fifty.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/src/assets/questions.json:
--------------------------------------------------------------------------------
1 | {
2 | "History": [
3 | {
4 | "question": "In what year did the Berlin Wall fall?",
5 | "answers": ["1989", "1991", "1987", "1993"],
6 | "correctAnswer": "1989"
7 | },
8 | {
9 | "question": "The first Roman emperor to become a Christian was:",
10 | "answers": ["Constantine", "Augustus", "Julius Caesar", "Nero"],
11 | "correctAnswer": "Constantine"
12 | },
13 | {
14 | "question": "According to ancient legends, who founded Rome?",
15 | "answers": [
16 | "Romulus and Remus",
17 | "Julius Caesar",
18 | "Augustus",
19 | "Marcus Aurelius"
20 | ],
21 | "correctAnswer": "Romulus and Remus"
22 | },
23 | {
24 | "question": "Which civilization was responsible for the construction of Machu Picchu?",
25 | "answers": ["Aztecs", "Mayans", "Incas", "Inuit"],
26 | "correctAnswer": "Incas"
27 | },
28 | {
29 | "question": "Who was the first woman to win a Nobel Prize?",
30 | "answers": [
31 | "Marie Curie",
32 | "Mother Teresa",
33 | "Margaret Thatcher",
34 | "Indira Gandhi"
35 | ],
36 | "correctAnswer": "Marie Curie"
37 | },
38 | {
39 | "question": "Which of these countries was not a part of the Soviet Union?",
40 | "answers": ["Ukraine", "Georgia", "Poland", "Belarus"],
41 | "correctAnswer": "Poland"
42 | },
43 | {
44 | "question": "By what other name is the Eastern Roman Empire known?",
45 | "answers": [
46 | "The Byzantine Empire",
47 | "The Ottoman Empire",
48 | "The Persian Empire",
49 | "The Holy Roman Empire"
50 | ],
51 | "correctAnswer": "The Byzantine Empire"
52 | },
53 | {
54 | "question": "Which country was the first to send a satellite into space?",
55 | "answers": ["Russia", "USA", "China", "France"],
56 | "correctAnswer": "Russia"
57 | },
58 | {
59 | "question": "Who was the first explorer to circumnavigate the globe?",
60 | "answers": [
61 | "Christopher Columbus",
62 | "Vasco da Gama",
63 | "Magellan",
64 | "Francis Drake"
65 | ],
66 | "correctAnswer": "Magellan"
67 | },
68 | {
69 | "question": "What was the name of the document that established the United Nations?",
70 | "answers": [
71 | "The Treaty of Versailles",
72 | "The Geneva Convention",
73 | "The Charter of the United Nations",
74 | "The Magna Carta"
75 | ],
76 | "correctAnswer": "The Charter of the United Nations"
77 | },
78 | {
79 | "question": "What is the name of the goddess of victory in Greek mythology?",
80 | "answers": ["Nike", "Puma", "Adidas", "Aphrodite"],
81 | "correctAnswer": "Nike"
82 | },
83 | {
84 | "question": "How many operas did Beethoven compose?",
85 | "answers": ["1", "26", "165", "7"],
86 | "correctAnswer": "1"
87 | },
88 | {
89 | "question": "What philosopher said \"I think, therefore I am\"?",
90 | "answers": ["Descartes", "Plato", "Aristotle", "Socrates"],
91 | "correctAnswer": "Descartes"
92 | },
93 | {
94 | "question": "Which of these is not one of the Seven Wonders of the Ancient World?",
95 | "answers": [
96 | "The Great Library of Alexandria",
97 | "Colossus of Rhodes",
98 | "Lighthouse of Alexandria",
99 | "Temple of Artemis"
100 | ],
101 | "correctAnswer": "The Great Library of Alexandria"
102 | },
103 | {
104 | "question": "Which of these is not a Greek god or goddess?",
105 | "answers": ["Aphrodite", "Hera", "Athena", "Loki"],
106 | "correctAnswer": "Loki"
107 | }
108 | ],
109 | "Entertainment": [
110 | {
111 | "question": "What is the name of the clown in the movie \"It\"?",
112 | "answers": ["Pennywise", "Bozo", "Krusty", "Joker"],
113 | "correctAnswer": "Pennywise"
114 | },
115 | {
116 | "question": "What is the name of the fictional continent where the events of the TV series \"Game of Thrones\" take place?",
117 | "answers": ["Westeros", "Essos", "Sothoryos", "Ulthos"],
118 | "correctAnswer": "Westeros"
119 | },
120 | {
121 | "question": "Who played the role of Batman in the 2008 movie \"The Dark Knight\"?",
122 | "answers": [
123 | "Christian Bale",
124 | "Ben Affleck",
125 | "George Clooney",
126 | "Val Kilmer"
127 | ],
128 | "correctAnswer": "Christian Bale"
129 | },
130 | {
131 | "question": "What is the name of the fairy in the Disney movie \"Peter Pan\"?",
132 | "answers": ["Tinker Bell", "Wendy", "Vidia", "Navi"],
133 | "correctAnswer": "Tinker Bell"
134 | },
135 | {
136 | "question": "What is the name of the tiger that appears in the movie \"Life of Pi\"?",
137 | "answers": ["Richard Parker", "Tony", "Shere Khan", "Pi Patel"],
138 | "correctAnswer": "Richard Parker"
139 | },
140 | {
141 | "question": "Who wrote the novel \"One Hundred Years of Solitude\"?",
142 | "answers": [
143 | "Gabriel García Márquez",
144 | "Jorge Luis Borges",
145 | "Isabel Allende",
146 | "Octavio Paz"
147 | ],
148 | "correctAnswer": "Gabriel García Márquez"
149 | },
150 | {
151 | "question": "Which of these is not a race or species in the video game \"World of Warcraft\"?",
152 | "answers": ["Kokiri", "Undead", "Huargen", "Troll"],
153 | "correctAnswer": "Kokiri"
154 | },
155 | {
156 | "question": "How does Alice wane for the first time in the Disney movie \"Alice in Wonderland\"?",
157 | "answers": [
158 | "She drinks a potion",
159 | "She eats a cake",
160 | "She falls down a hole",
161 | "She walks through a mirror"
162 | ],
163 | "correctAnswer": "She drinks a potion"
164 | },
165 | {
166 | "question": "Who is the owner of Garfield in the comic strip \"Garfield\"?",
167 | "answers": ["Jon Arbuckle", "Odie", "Nermal", "Liz Wilson"],
168 | "correctAnswer": "Jon Arbuckle"
169 | },
170 | {
171 | "question": "In which of these animes does the main character carry his sister in a box?",
172 | "answers": [
173 | "Kimetsu no Yaiba",
174 | "Elfen Lied",
175 | "Code Geass",
176 | "Made in Abyss"
177 | ],
178 | "correctAnswer": "Kimetsu no Yaiba"
179 | },
180 | {
181 | "question": "Where is the weak point of the titans in the anime \"Attack on Titan\"?",
182 | "answers": ["Nape", "Head", "Heart", "Back"],
183 | "correctAnswer": "Nape"
184 | },
185 | {
186 | "question": "How many puppies does Perdita give birth to in the Disney movie \"101 Dalmatians\"?",
187 | "answers": ["15", "101", "99", "8"],
188 | "correctAnswer": "15"
189 | },
190 | {
191 | "question": "How many dragon balls are there in the anime \"Dragon Ball\"?",
192 | "answers": ["7", "8", "6", "12"],
193 | "correctAnswer": "7"
194 | },
195 | {
196 | "question": "In which of these movies are there aliens?",
197 | "answers": [
198 | "The Great Wall",
199 | "Big Heroes 6",
200 | "Duplicity",
201 | "Braveheart"
202 | ],
203 | "correctAnswer": "The Great Wall"
204 | },
205 | {
206 | "question": "What is the name of Misa Amane's shinigami in the anime \"Death Note\"?",
207 | "answers": ["Rem", "Ryuk", "Sidoh", "Gelus"],
208 | "correctAnswer": "Rem"
209 | }
210 | ],
211 | "Geography": [
212 | {
213 | "question": "What is the capital city of Australia?",
214 | "answers": ["Sydney", "Melbourne", "Canberra", "Brisbane"],
215 | "correctAnswer": "Canberra"
216 | },
217 | {
218 | "question": "How many stars appear on the flag of the People's Republic of China?",
219 | "answers": ["4", "5", "6", "3"],
220 | "correctAnswer": "5"
221 | },
222 | {
223 | "question": "What continent is Saudi Arabia on?",
224 | "answers": ["Asia", "Africa", "Europe", "South America"],
225 | "correctAnswer": "Asia"
226 | },
227 | {
228 | "question": "What is the name of the official language in China?",
229 | "answers": ["Mandarin", "Cantonese", "Hokkien", "Hakka"],
230 | "correctAnswer": "Mandarin"
231 | },
232 | {
233 | "question": "Which of these European countries is further west?",
234 | "answers": ["Spain", "Italy", "Greece", "Germany"],
235 | "correctAnswer": "Spain"
236 | },
237 | {
238 | "question": "How many oceans are there on Earth?",
239 | "answers": ["5", "6", "7", "8"],
240 | "correctAnswer": "5"
241 | },
242 | {
243 | "question": "What is the capital of Colombia?",
244 | "answers": ["Bogotá", "Medellín", "Cali", "Barranquilla"],
245 | "correctAnswer": "Bogotá"
246 | },
247 | {
248 | "question": "Which country is the smallest in the world",
249 | "answers": ["Vatican City", "Monaco", "Nauru", "Tuvalu"],
250 | "correctAnswer": "Vatican City"
251 | },
252 | {
253 | "question": "What is the largest country in Africa by land area?",
254 | "answers": ["Algeria", "Sudan", "Libya", "Congo"],
255 | "correctAnswer": "Algeria"
256 | },
257 | {
258 | "question": "What is the highest mountain in America?",
259 | "answers": [
260 | "Mount Denali",
261 | "Mount Logan",
262 | "Mount Saint Elias",
263 | "Pico de Orizaba"
264 | ],
265 | "correctAnswer": "Mount Denali"
266 | },
267 | {
268 | "question": "Which city is located both in Europe and Asia?",
269 | "answers": ["Istanbul", "Moscow", "Kiev", "Nicosia"],
270 | "correctAnswer": "Istanbul"
271 | },
272 | {
273 | "question": "What is the name of the world's largest reef system, located in Australia?",
274 | "answers": [
275 | "Great Barrier Reef",
276 | "Belize Barrier Reef",
277 | "Mesoamerican Barrier Reef",
278 | "Andros Barrier Reef"
279 | ],
280 | "correctAnswer": "Great Barrier Reef"
281 | },
282 | {
283 | "question": "Which river is the longest in the world?",
284 | "answers": ["Nile", "Amazon", "Yangtze", "Mississippi"],
285 | "correctAnswer": "Amazon"
286 | },
287 | {
288 | "question": "Which country is the largest by land area?",
289 | "answers": ["Russia", "Canada", "China", "United States"],
290 | "correctAnswer": "Russia"
291 | },
292 | {
293 | "question": "How many states are part of the United States?",
294 | "answers": ["50", "51", "48", "53"],
295 | "correctAnswer": "50"
296 | },
297 | {
298 | "question": "Which of these countries is not in Europe?",
299 | "answers": ["Georgia", "Moldova", "Armenia", "Azerbaijan"],
300 | "correctAnswer": "Armenia"
301 | },
302 | {
303 | "question": "What is the official currency of India?",
304 | "answers": ["Rupee", "Ruble", "Rial", "Real"],
305 | "correctAnswer": "Rupee"
306 | },
307 | {
308 | "question": "In which country is Mount Everest located?",
309 | "answers": ["Nepal", "China", "India", "Pakistan"],
310 | "correctAnswer": "Nepal"
311 | }
312 | ],
313 | "Science": [
314 | {
315 | "question": "What is the chemical symbol for gold?",
316 | "answers": ["Au", "Ag", "Cu", "Fe"],
317 | "correctAnswer": "Au"
318 | },
319 | {
320 | "question": "What is the triangle that has three equal sides called?",
321 | "answers": ["Equilateral", "Isosceles", "Scalene", "Right"],
322 | "correctAnswer": "Equilateral"
323 | },
324 | {
325 | "question": "What is an oviparous?",
326 | "answers": [
327 | "An animal that lays eggs",
328 | "An animal that gives birth",
329 | "An animal that flies",
330 | "An animal that lives in the water"
331 | ],
332 | "correctAnswer": "An animal that lays eggs"
333 | },
334 | {
335 | "question": "Cartography is the study of what?",
336 | "answers": ["Maps", "Cars", "Cats", "Carpets"],
337 | "correctAnswer": "Maps"
338 | },
339 | {
340 | "question": "If 50 is 100%, what is 90%?",
341 | "answers": ["45", "10", "100", "50"],
342 | "correctAnswer": "45"
343 | },
344 | {
345 | "question": "How many legs does a fly have?",
346 | "answers": ["6", "4", "8", "2"],
347 | "correctAnswer": "6"
348 | },
349 | {
350 | "question": "What is the smallest unit of matter?",
351 | "answers": ["Atom", "Molecule", "Cell", "Electron"],
352 | "correctAnswer": "Atom"
353 | },
354 | {
355 | "question": "What element do all acids contain?",
356 | "answers": ["Hydrogen", "Oxygen", "Helium", "Nitrogen"],
357 | "correctAnswer": "Hydrogen"
358 | },
359 | {
360 | "question": "What is the name of the process by which plants convert sunlight into energy?",
361 | "answers": [
362 | "Photosynthesis",
363 | "Respiration",
364 | "Digestion",
365 | "Fermentation"
366 | ],
367 | "correctAnswer": "Photosynthesis"
368 | },
369 | {
370 | "question": "What is the name of the force that pulls objects toward each other?",
371 | "answers": ["Gravity", "Magnetism", "Friction", "Electricity"],
372 | "correctAnswer": "Gravity"
373 | },
374 | {
375 | "question": "What is the metal found in the center of the earth?",
376 | "answers": ["Iron", "Nickel", "Copper", "Zinc"],
377 | "correctAnswer": "Iron"
378 | },
379 | {
380 | "question": "What are diamonds made of?",
381 | "answers": ["Carbon", "Glass", "Silver", "Platinum"],
382 | "correctAnswer": "Carbon"
383 | },
384 | {
385 | "question": "What is the name of the process by which a solid turns into a gas without passing through the liquid state?",
386 | "answers": [
387 | "Sublimation",
388 | "Evaporation",
389 | "Condensation",
390 | "Freezing"
391 | ],
392 | "correctAnswer": "Sublimation"
393 | },
394 | {
395 | "question": "What is the name of the protein that gives skin, hair, and nails their strength?",
396 | "answers": ["Keratin", "Collagen", "Elastin", "Myosin"],
397 | "correctAnswer": "Keratin"
398 | },
399 | {
400 | "question": "How many chemical elements are there on the periodic table?",
401 | "answers": ["118", "92", "104", "113"],
402 | "correctAnswer": "118"
403 | },
404 | {
405 | "question": "What is the first element on the periodic table?",
406 | "answers": ["Hydrogen", "Helium", "Lithium", "Oxygen"],
407 | "correctAnswer": "Hydrogen"
408 | },
409 | {
410 | "question": "What vitamin can be synthesized when exposed to sunlight?",
411 | "answers": ["Vitamin D", "Vitamin A", "Vitamin C", "Vitamin E"],
412 | "correctAnswer": "Vitamin D"
413 | },
414 | {
415 | "question": "Every how many years does Halley's Comet pass the earth?",
416 | "answers": ["75", "86", "96", "106"],
417 | "correctAnswer": "75"
418 | },
419 | {
420 | "question": "What is the only even prime number?",
421 | "answers": ["2", "14", "6", "8"],
422 | "correctAnswer": "2"
423 | },
424 | {
425 | "question": "-3 + 10 ÷ 2",
426 | "answers": ["2", "1", "4", "3.5"],
427 | "correctAnswer": "2"
428 | },
429 | {
430 | "question": "What does the gallon measure?",
431 | "answers": ["Volume", "Weight", "Distance", "Time"],
432 | "correctAnswer": "Volume"
433 | },
434 | {
435 | "question": "What does the newton measure?",
436 | "answers": ["Force", "Weight", "Distance", "Time"],
437 | "correctAnswer": "Force"
438 | }
439 | ],
440 | "Technology": [
441 | {
442 | "question": "Which company developed the programming language Java?",
443 | "answers": ["Sun Microsystems", "Microsoft", "Apple", "IBM"],
444 | "correctAnswer": "Sun Microsystems"
445 | },
446 | {
447 | "question": "How many bits is a byte?",
448 | "answers": ["8", "4", "16", "32"],
449 | "correctAnswer": "8"
450 | },
451 | {
452 | "question": "How many megabytes is a gigabyte?",
453 | "answers": [
454 | "1024",
455 | "1000",
456 | "100",
457 | "Depends on the size of the file"
458 | ],
459 | "correctAnswer": "1024"
460 | },
461 | {
462 | "question": "What is the name of the open-source operating system based on the Linux kernel?",
463 | "answers": ["Ubuntu", "Windows", "macOS", "Android"],
464 | "correctAnswer": "Ubuntu"
465 | },
466 | {
467 | "question": "What is the name of the first computer?",
468 | "answers": ["ENIAC", "UNIVAC I", "Z1", "Colossus"],
469 | "correctAnswer": "ENIAC"
470 | },
471 | {
472 | "question": "What is the name of the web browser developed by Google?",
473 | "answers": ["Chrome", "Firefox", "Safari", "Opera"],
474 | "correctAnswer": "Chrome"
475 | },
476 | {
477 | "question": "What is the name of the programming language used to create web pages?",
478 | "answers": ["JavaScript", "CSS", "PhP", "Python"],
479 | "correctAnswer": "JavaScript"
480 | },
481 | {
482 | "question": "The \".WAV\" is a format of?",
483 | "answers": ["Audio", "Video", "Image", "Document"],
484 | "correctAnswer": "Audio"
485 | },
486 | {
487 | "question": "What is the name of the first computer virus?",
488 | "answers": ["Creeper", "Elk Cloner", "Rabbit", "Stoned"],
489 | "correctAnswer": "Creeper"
490 | },
491 | {
492 | "question": "How many laws of robotics (or Asimov's laws) are there?",
493 | "answers": ["3", "4", "2", "6"],
494 | "correctAnswer": "3"
495 | },
496 | {
497 | "question": "What is the name of the first video game console?",
498 | "answers": [
499 | "Magnavox Odyssey",
500 | "Atari 2600",
501 | "Nintendo Entertainment System",
502 | "Sega Genesis"
503 | ],
504 | "correctAnswer": "Magnavox Odyssey"
505 | },
506 | {
507 | "question": "What is the best-selling video game in history?",
508 | "answers": [
509 | "Minecraft",
510 | "Tetris",
511 | "Wii Sports",
512 | "Grand Theft Auto V"
513 | ],
514 | "correctAnswer": "Minecraft"
515 | },
516 | {
517 | "question": "What color are the pigs in the video game \"Angry Birds\"?",
518 | "answers": ["Green", "Red", "Yellow", "Blue"],
519 | "correctAnswer": "Green"
520 | },
521 | {
522 | "question": "Which of these is not a champion in the video game \"League of Legends\"?",
523 | "answers": ["Gang-il", "Ahri", "Teemo", "Ryze"],
524 | "correctAnswer": "Gang-il"
525 | },
526 | {
527 | "question": "How many points do the grapes give in the video game \"Pacman\"?",
528 | "answers": ["1000", "700", "100", "400"],
529 | "correctAnswer": "1000"
530 | },
531 | {
532 | "question": "What is the name of the main character in the video game \"The Legend of Zelda\"?",
533 | "answers": ["Link", "Zelda", "Ganon", "Ganondorf"],
534 | "correctAnswer": "Link"
535 | }
536 | ],
537 | "Art": [
538 | {
539 | "question": "Who painted the famous artwork \"The Starry Night\"?",
540 | "answers": [
541 | "Vincent van Gogh",
542 | "Leonardo da Vinci",
543 | "Pablo Picasso",
544 | "Michelangelo"
545 | ],
546 | "correctAnswer": "Vincent van Gogh"
547 | },
548 | {
549 | "question": "Which sculptor made the famous sculpture \"David?\"?",
550 | "answers": [
551 | "Michelangelo",
552 | "Donatello",
553 | "Leonardo da Vinci",
554 | "Raphael"
555 | ],
556 | "correctAnswer": "Michelangelo"
557 | },
558 | {
559 | "question": "What is the best-selling album in history?",
560 | "answers": [
561 | "Thriller",
562 | "Back in Black",
563 | "The Dark Side of the Moon",
564 | "Bat Out of Hell"
565 | ],
566 | "correctAnswer": "Thriller"
567 | },
568 | {
569 | "question": "How many strings does a guitar have?",
570 | "answers": ["Six", "Four", "Twelve", "Eight"],
571 | "correctAnswer": "Six"
572 | },
573 | {
574 | "question": "What is the name of the famous statue that depicts the Greek goddess of love and beauty?",
575 | "answers": [
576 | "Venus de Milo",
577 | "David",
578 | "The Thinker",
579 | "Laocoön and His Sons"
580 | ],
581 | "correctAnswer": "Venus de Milo"
582 | },
583 | {
584 | "question": "What band is the author of the song \"Believer\"?",
585 | "answers": [
586 | "Imagine Dragons",
587 | "Coldplay",
588 | "Maroon 5",
589 | "Linkin Park"
590 | ],
591 | "correctAnswer": "Imagine Dragons"
592 | },
593 | {
594 | "question": "What is the name of the famous Italian artist who painted the ceiling of the Sistine Chapel?",
595 | "answers": [
596 | "Michelangelo",
597 | "Leonardo da Vinci",
598 | "Raphael",
599 | "Sandro Botticelli"
600 | ],
601 | "correctAnswer": "Michelangelo"
602 | },
603 | {
604 | "question": "Who is Don Quixote in love with in the play \"The Ingenious Hidalgo Don Quixote of La Mancha\"?",
605 | "answers": ["Dulcinea", "Maritornes", "Antonia", "Fernanda"],
606 | "correctAnswer": "Dulcinea"
607 | },
608 | {
609 | "question": "What is the name of the famous ballet composed by Tchaikovsky?",
610 | "answers": [
611 | "Swan Lake",
612 | "The Nutcracker",
613 | "Romeo and Juliet",
614 | "The Sleeping Beauty"
615 | ],
616 | "correctAnswer": "Swan Lake"
617 | },
618 | {
619 | "question": "Who is the author of the famous book \"The Little Prince\"?",
620 | "answers": [
621 | "Antoine de Saint-Exupéry",
622 | "Jean-Jacques Rousseau",
623 | "Voltaire",
624 | "Victor Hugo"
625 | ],
626 | "correctAnswer": "Antoine de Saint-Exupéry"
627 | },
628 | {
629 | "question": "What architectural style is Notre Dame Cathedral?",
630 | "answers": ["Gothic", "Baroque", "Renaissance", "Neoclassical"],
631 | "correctAnswer": "Gothic"
632 | },
633 | {
634 | "question": "Which famous playwright wrote the play \"Hamlet\"?",
635 | "answers": [
636 | "William Shakespeare",
637 | "Tennessee Williams",
638 | "Arthur Miller",
639 | "Samuel Beckett"
640 | ],
641 | "correctAnswer": "William Shakespeare"
642 | },
643 | {
644 | "question": "Which famous novel by George Orwell tells the story of a society where government surveillance and propaganda control all aspects of people's lives?",
645 | "answers": [
646 | "1984",
647 | "Animal Farm",
648 | "Brave New World",
649 | "Fahrenheit 451"
650 | ],
651 | "correctAnswer": "1984"
652 | },
653 | {
654 | "question": "Who is the author of the 'Harry Potter' book series?",
655 | "answers": [
656 | "J.K. Rowling",
657 | "Stephen King",
658 | "George R.R. Martin",
659 | "Dan Brown"
660 | ],
661 | "correctAnswer": "J.K. Rowling"
662 | },
663 | {
664 | "question": "In music, how many lines does a staff have?",
665 | "answers": ["Five", "Four", "Six", "Three"],
666 | "correctAnswer": "Five"
667 | }
668 | ],
669 | "Space": [
670 | {
671 | "question": "What is the largest planet in our solar system?",
672 | "answers": ["Jupiter", "Saturn", "Uranus", "Neptune"],
673 | "correctAnswer": "Jupiter"
674 | },
675 | {
676 | "question": "What is the name of the brightest star in the night sky?",
677 | "answers": [
678 | "Sirius",
679 | "Proxima Centauri",
680 | "Betelgeuse",
681 | "Aldebaran"
682 | ],
683 | "correctAnswer": "Sirius"
684 | },
685 | {
686 | "question": "What is the name of the only natural satellite of Earth?",
687 | "answers": ["Moon", "Mars", "Venus", "Jupiter"],
688 | "correctAnswer": "Moon"
689 | },
690 | {
691 | "question": "What is the name of the first artificial satellite launched into space?",
692 | "answers": ["Sputnik 1", "Explorer 1", "Vanguard 1", "Vostok 1"],
693 | "correctAnswer": "Sputnik 1"
694 | },
695 | {
696 | "question": "What is the speed of light approximately?",
697 | "answers": [
698 | "300,000 km/s",
699 | "200,000 km/s",
700 | "100,000 km/s",
701 | "400,000 km/s"
702 | ],
703 | "correctAnswer": "300,000 km/s"
704 | },
705 | {
706 | "question": "What is the name of the largest known asteroid in our solar system?",
707 | "answers": ["Ceres", "Vesta", "Pallas", "Hygiea"],
708 | "correctAnswer": "Ceres"
709 | },
710 | {
711 | "question": "What is the name of the spacecraft that landed on Mars in 2021 as part of the Mars 2020 mission?",
712 | "answers": ["Perseverance", "Curiosity", "Opportunity", "Spirit"],
713 | "correctAnswer": "Perseverance"
714 | },
715 | {
716 | "question": "How long does it take for sunlight to reach the earth?",
717 | "answers": ["8 minutes", "3.5 hours", "26 seconds", "10 seconds"],
718 | "correctAnswer": "8 minutes"
719 | },
720 | {
721 | "question": "About how many stars are there in the solar system?",
722 | "answers": ["1", "100", "100,000", "Too many to count"],
723 | "correctAnswer": "1"
724 | },
725 | {
726 | "question": "What is the most common matter in the universe?",
727 | "answers": ["Hydrogen", "Dark matter", "Helium", "Oxygen"],
728 | "correctAnswer": "Hydrogen"
729 | },
730 | {
731 | "question": "About what temperature is it in space?",
732 | "answers": ["-270°C", "-120°C", "0°C", "38°C"],
733 | "correctAnswer": "-270°C"
734 | },
735 | {
736 | "question": "Mainly which atoms do stars use in their fusion process?",
737 | "answers": ["Hydrogen", "Helium", "Oxygen", "Carbon"],
738 | "correctAnswer": "Hydrogen"
739 | },
740 | {
741 | "question": "What is inside a black hole in the movie \"Interstellar\"?",
742 | "answers": [
743 | "A fifth dimension",
744 | "A planet",
745 | "A spaceship",
746 | "Nothing"
747 | ],
748 | "correctAnswer": "A fifth dimension"
749 | },
750 | {
751 | "question": "What is the geometric figure that describes the orbit of the planets?",
752 | "answers": ["Ellipse", "Circle", "Circumference", "Square"],
753 | "correctAnswer": "Ellipse"
754 | },
755 | {
756 | "question": "How many moons does Mars have?",
757 | "answers": ["1", "2", "4", "Does not have"],
758 | "correctAnswer": "2"
759 | },
760 | {
761 | "question": "What is the name of the first man to walk on the moon?",
762 | "answers": [
763 | "Neil Armstrong",
764 | "Buzz Aldrin",
765 | "Alan Shepard",
766 | "Yuri Gagarin"
767 | ],
768 | "correctAnswer": "Neil Armstrong"
769 | }
770 | ],
771 | "General culture": [
772 | {
773 | "question": "What part of the ship does the nautical term \"starboard\" refer to?",
774 | "answers": ["Right", "Left", "Front", "Back"],
775 | "correctAnswer": "Right"
776 | },
777 | {
778 | "question": "Which river runs through London?",
779 | "answers": ["Thames", "Seine", "Danube", "Nile"],
780 | "correctAnswer": "Thames"
781 | },
782 | {
783 | "question": "Who turns into Hulk?",
784 | "answers": [
785 | "Bruce Banner",
786 | "Tony Stark",
787 | "Peter Parker",
788 | "Steve Rogers"
789 | ],
790 | "correctAnswer": "Bruce Banner"
791 | },
792 | {
793 | "question": "How many players does a soccer team have on the field?",
794 | "answers": ["11", "10", "9", "12"],
795 | "correctAnswer": "11"
796 | },
797 | {
798 | "question": "Which of these is a percussion instrument?",
799 | "answers": ["Drum", "Violin", "Flute", "Trumpet"],
800 | "correctAnswer": "Drum"
801 | },
802 | {
803 | "question": "What color is the \"G\" in the Google logo?",
804 | "answers": ["Blue", "Red", "Yellow", "Green"],
805 | "correctAnswer": "Blue"
806 | },
807 | {
808 | "question": "What holds the Oscar trophy figurine?",
809 | "answers": ["A sword", "A torch", "A book", "Nothing"],
810 | "correctAnswer": "A sword"
811 | },
812 | {
813 | "question": "What instrument does Sherlock Holmes play?",
814 | "answers": ["Violin", "Flute", "Piano", "Guitar"],
815 | "correctAnswer": "Violin"
816 | },
817 | {
818 | "question": "What is a falchion?",
819 | "answers": ["A sword", "A shield", "A helmet", "A spear"],
820 | "correctAnswer": "A sword"
821 | },
822 | {
823 | "question": "How many hearts does an octopus have?",
824 | "answers": ["3", "2", "1", "0"],
825 | "correctAnswer": "3"
826 | },
827 | {
828 | "question": "What does the Tin Woodman want in the novel \"The Wonderful Wizard of Oz\"?",
829 | "answers": ["A heart", "A brain", "Courage", "A home"],
830 | "correctAnswer": "A heart"
831 | },
832 | {
833 | "question": "What color is the hair of the protagonist in the anime \"Death Note\"?",
834 | "answers": ["Black", "Blonde", "Red", "Brown"],
835 | "correctAnswer": "Brown"
836 | },
837 | {
838 | "question": "What is the name of the holy book of Islam?",
839 | "answers": ["Quran", "Bible", "Torah", "Vedas"],
840 | "correctAnswer": "Quran"
841 | },
842 | {
843 | "question": "How old is a lustrum?",
844 | "answers": ["5 years", "10 years", "15 years", "20 years"],
845 | "correctAnswer": "5 years"
846 | },
847 | {
848 | "question": "How many sides does a hexagon have?",
849 | "answers": ["6", "5", "7", "8"],
850 | "correctAnswer": "6"
851 | }
852 | ]
853 | }
854 |
--------------------------------------------------------------------------------
/source_code/src/assets/sound-off.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/src/assets/sound-on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/src/assets/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/src/assets/trophy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source_code/src/components/Form/JsxForm.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 | import { defaultQuestions } from '@/helpers/gameConfig'
3 | import { BsSkipEndFill } from 'react-icons/bs'
4 | import { IoMdInfinite } from 'react-icons/io'
5 | import { FaHeart } from 'react-icons/fa'
6 | import fiftyImg from '@/assets/fifty.svg'
7 | import categoriesJSON from '@/assets/categories.json'
8 | import { useBoundStore } from '@/store/useBoundStore'
9 |
10 | export default function JsxForm ({ handleInputs, nowQueries }) {
11 | const { queries } = useBoundStore(state => state)
12 |
13 | const WILCARDS = [
14 | { name: 'Skip question', icon: , amount: 1 },
15 | { name: 'Delete two wrong questions', icon: , amount: 1 },
16 | { name: 'Lives', icon: , amount: 1 }
17 | ]
18 |
19 | return (
20 | <>
21 |
73 |
74 |
75 | Categories
76 |
77 |
78 | {categoriesJSON.map(category => (
79 |
80 |
86 |
87 |
88 |
89 | ))}
90 |
91 |
92 | >
93 | )
94 | }
95 |
--------------------------------------------------------------------------------
/source_code/src/components/Form/NewGameForm.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from 'react'
2 | import { useRouter } from 'next/router'
3 |
4 | import JsxForm from './JsxForm'
5 | import { IoCloseSharp } from 'react-icons/io5'
6 | import playSound from '@/helpers/playSound'
7 | import queryValidator from '@/helpers/gameConfig'
8 | import categoriesJSON from '@/assets/categories.json'
9 | import { useBoundStore } from '@/store/useBoundStore'
10 |
11 | export default function NewGameForm () {
12 | const { getQuestions, cleanQuestions, queries, setQueries, cleanWildCards } = useBoundStore(state => state)
13 | const [nowQueries, setNowQueries] = useState(queries)
14 | const router = useRouter()
15 | const dialog = useRef(null)
16 |
17 | useEffect(() => setNowQueries(queries), [queries])
18 |
19 | useEffect(() => {
20 | if (router.isReady && router.pathname === '/play') {
21 | setQueries(queryValidator(router.query))
22 | }
23 | }, [router.isReady])
24 |
25 | function handleInputs (e) {
26 | if (e.target.name === 'infinitymode' || e.target.name === 'timemode') {
27 | e.target.checked ? playSound('pop-up-on') : playSound('pop-up-off')
28 | return setNowQueries({ ...nowQueries, [e.target.name]: e.target.name === 'infinitymode' ? !e.target.checked : e.target.checked })
29 | }
30 |
31 | if (e.target.name === 'categories') {
32 | e.target.checked ? playSound('pop-up-on') : playSound('pop-up-off')
33 | return setNowQueries({ ...nowQueries, [e.target.name]: e.target.checked ? [...nowQueries.categories, e.target.value] : nowQueries.categories.filter(cat => cat !== e.target.value) })
34 | }
35 |
36 | playSound('pop')
37 | setNowQueries({ ...nowQueries, [e.target.name]: e.target.value })
38 | }
39 |
40 | function handleSubmit (e) {
41 | e.preventDefault()
42 | cleanQuestions()
43 | cleanWildCards()
44 |
45 | const query = Object.keys(nowQueries).map(key => `${key}=${nowQueries[key]}`).join('&')
46 | setQueries(queryValidator(nowQueries))
47 | router.push({ pathname: '/play', query })
48 |
49 | const cate = nowQueries.categories.map(cat => categoriesJSON.find(c => c.id === cat).name)
50 | if (router.pathname === '/play') getQuestions(cate, nowQueries.infinitymode ? 5 : nowQueries.questions)
51 |
52 | closeDialog()
53 | }
54 |
55 | function clickOutsideDialog (e) {
56 | const rect = dialog.current.getBoundingClientRect()
57 | if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) {
58 | closeDialog()
59 | }
60 | }
61 |
62 | function closeDialog () {
63 | playSound('pop-down')
64 | dialog.current.classList.add('hide')
65 | function handleAnimationEnd () {
66 | dialog.current.classList.remove('hide')
67 | dialog.current.close()
68 | dialog.current.removeEventListener('animationend', handleAnimationEnd)
69 | }
70 | dialog.current.addEventListener('animationend', handleAnimationEnd)
71 | }
72 |
73 | return (
74 | clickOutsideDialog(e)} id="newGameDialog" className='fixed top-1/2 w-5/6 sm:w-fit left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white text-slate-900 m-0 backdrop-blur-lg rounded-md py-9 px-8 md:px-11'>
75 |
76 |
77 |
78 |
79 |
86 |
87 | )
88 | }
89 |
--------------------------------------------------------------------------------
/source_code/src/components/Home/Categories.jsx:
--------------------------------------------------------------------------------
1 | import categories from '@/assets/categories.json'
2 | import Image from 'next/image'
3 |
4 | export default function Categories () {
5 | return (
6 |
7 | Categories
8 |
9 | {categories.map(category => (
10 |
11 |
12 | {category.name}
13 |
14 | ))}
15 |
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/source_code/src/components/Home/GameModes.jsx:
--------------------------------------------------------------------------------
1 | import { ImInfinite } from 'react-icons/im'
2 | import { BiTimeFive } from 'react-icons/bi'
3 | import { TbDeviceGamepad2 } from 'react-icons/tb'
4 |
5 | const gameModes = [
6 | {
7 | icon: ,
8 | title: 'Classic',
9 | description: 'Complete questions without fail to win! You have wildcards that can help you'
10 | },
11 | {
12 | icon: ,
13 | title: 'Time',
14 | description: 'Complete questions within the time limit to win! You can use wildcards'
15 | },
16 | {
17 | icon: ,
18 | title: 'Infinite',
19 | description: 'Break your record by completing as many questions as you can! You can use wildcards'
20 | }
21 | ]
22 |
23 | export default function GameModes () {
24 | return (
25 |
26 | Game modes
27 |
28 |
29 | {gameModes.map((mode, index) => (
30 |
31 | {mode.icon}
32 | {mode.title}
33 | {mode.description}
34 |
35 | ))}
36 |
37 |
38 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/source_code/src/components/Home/MainHome.jsx:
--------------------------------------------------------------------------------
1 | import categories from '@/assets/categories.json'
2 | import PageFooter from '../PageFooter'
3 | import playSound from '@/helpers/playSound'
4 |
5 | export default function MainHome () {
6 | function handleTitleHover (e) {
7 | e.target.classList.add('jello-vertical')
8 | e.target.style.color = categories[Math.floor(Math.random() * categories.length)].color
9 | e.target.addEventListener('animationend', () => e.target.classList.remove('jello-vertical'))
10 | }
11 |
12 | const handleTitleLeave = (e) => (e.target.style.color = 'white')
13 |
14 | function handlePlay () {
15 | playSound('pop')
16 | document.getElementById('newGameDialog')?.showModal()
17 | }
18 |
19 | return (
20 |
21 |
22 |
23 | {'Quizi'.split('').map((letter, index) => (
24 |
25 | {letter}
26 |
27 | ))}
28 |
29 |
30 |
31 | Play an infinite number of possible questions!
32 |
33 |
34 |
35 | Play
36 |
37 |
38 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/source_code/src/components/PageError.jsx:
--------------------------------------------------------------------------------
1 | import { useBoundStore } from '@/store/useBoundStore'
2 | import Link from 'next/link'
3 | import { BiErrorCircle, BiArrowBack } from 'react-icons/bi'
4 |
5 | export default function PageError () {
6 | const error = useBoundStore(state => state.error)
7 |
8 | return (
9 |
10 |
11 |
12 |
13 | {error[1].statusCode || 500}: {(error[1].message && error[1].message) || 'Error occured'}
14 |
15 |
16 | Ooops! Something went wrong. Please try again later or play offline.
17 |
18 |
19 |
20 |
21 | Go back to home
22 |
23 |
24 |
25 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/source_code/src/components/PageFooter.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 | import playSound from '@/helpers/playSound'
3 | import soundOn from '../assets/sound-on.svg'
4 | import soundOff from '../assets/sound-off.svg'
5 | import { useEffect, useState } from 'react'
6 | import { MdInfo } from 'react-icons/md'
7 | import { GoAlert } from 'react-icons/go'
8 | import { BsFillStarFill } from 'react-icons/bs'
9 |
10 | export default function Footer ({ alert = false }) {
11 | const [sound, setSound] = useState(false)
12 | const [showInfo, setShowInfo] = useState(false)
13 |
14 | useEffect(() => {
15 | if (!localStorage.getItem('sound')) localStorage.setItem('sound', sound)
16 | else setSound(localStorage.getItem('sound') === 'true')
17 | }, [])
18 |
19 | useEffect(() => localStorage.setItem('sound', sound), [sound])
20 |
21 | function handleClick (info = false) {
22 | info ? setShowInfo(!showInfo) : setSound(!sound)
23 | playSound('switch-on')
24 | }
25 |
26 | function handleSoundON () {
27 | setSound(true)
28 | localStorage.setItem('sound', true)
29 | playSound('switch-on')
30 | }
31 |
32 | return (
33 |
65 | )
66 | }
67 |
--------------------------------------------------------------------------------
/source_code/src/components/PageLoading.jsx:
--------------------------------------------------------------------------------
1 | export default function PageLoading () {
2 | return (
3 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/source_code/src/components/Play/GameInfo.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 | import { AiFillInfoCircle } from 'react-icons/ai'
3 | import categories from '@/assets/categories.json'
4 | import { useState } from 'react'
5 | import { useBoundStore } from '@/store/useBoundStore'
6 |
7 | export default function GameInfo () {
8 | const { queries } = useBoundStore(state => state)
9 | const [showInfo, setShowInfo] = useState(false)
10 |
11 | const mode = queries.timemode && queries.infinitymode ? 'Time | Infinity' : !queries.timemode && !queries.infinitymode ? 'Classic' : queries.timemode ? 'Time' : 'Infinity'
12 |
13 | return (
14 | <>
15 | setShowInfo(showInfo => !showInfo)} className="fixed bottom-4 top left-4 lg:hidden bg-white z-20 rounded-md p-1">
16 |
17 |
18 |
19 |
20 |
21 | {
22 | !queries.infinitymode &&
23 | {queries.questions}
24 |
25 | }
26 | {
27 | queries.timemode &&
28 | {queries.time}
29 |
30 | }
31 |
32 |
33 | {mode}
34 |
35 |
36 | {queries.categories.map(category => {
37 | const cat = categories.find(cat => cat.id === category)
38 | return
44 | })}
45 |
46 |
47 |
48 |
55 | >
56 | )
57 | }
58 |
--------------------------------------------------------------------------------
/source_code/src/components/Play/GameOver.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 | import Link from 'next/link'
3 |
4 | import { AiFillCloseCircle, AiFillCheckCircle } from 'react-icons/ai'
5 | import { useCallback, useEffect, useRef } from 'react'
6 | import { IoCloseSharp } from 'react-icons/io5'
7 | import { BiArrowBack } from 'react-icons/bi'
8 | import trophyIcon from '@/assets/trophy.svg'
9 |
10 | import playSound from '@/helpers/playSound'
11 | import ReactCanvasConfetti from 'react-canvas-confetti'
12 | import { useBoundStore } from '@/store/useBoundStore'
13 |
14 | const canvasStyles = {
15 | position: 'fixed',
16 | pointerEvents: 'none',
17 | width: '100%',
18 | height: '100%',
19 | top: 0,
20 | left: 0,
21 | zIndex: 100
22 | }
23 |
24 | export default function GameOver () {
25 | const { queries, score, win } = useBoundStore(state => state)
26 | const refAnimationInstance = useRef(null)
27 |
28 | const getInstance = useCallback((instance) => {
29 | refAnimationInstance.current = instance
30 | }, [])
31 |
32 | const makeShot = useCallback((particleRatio, opts) => {
33 | refAnimationInstance.current &&
34 | refAnimationInstance.current({
35 | ...opts,
36 | origin: { y: 0.7 },
37 | particleCount: Math.floor(200 * particleRatio)
38 | })
39 | }, [])
40 |
41 | const fire = useCallback(() => {
42 | makeShot(0.25, {
43 | spread: 26,
44 | startVelocity: 55
45 | })
46 |
47 | makeShot(0.2, {
48 | spread: 60
49 | })
50 |
51 | makeShot(0.35, {
52 | spread: 100,
53 | decay: 0.91,
54 | scalar: 0.8
55 | })
56 |
57 | makeShot(0.1, {
58 | spread: 120,
59 | startVelocity: 25,
60 | decay: 0.92,
61 | scalar: 1.2
62 | })
63 |
64 | makeShot(0.1, {
65 | spread: 120,
66 | startVelocity: 45
67 | })
68 | }, [makeShot])
69 |
70 | useEffect(() => {
71 | if (win === true) {
72 | fire()
73 | playSound('win', 0.2)
74 | }
75 | }, [win])
76 |
77 | function closeDialog () {
78 | playSound('pop', 0.2)
79 | document.getElementById('gameoverdialog').close()
80 | document.getElementById('gameoverbg').style.display = 'none'
81 | }
82 |
83 | function finalImage () {
84 | if (queries.infinitymode) return
85 | if (win === true) return
86 | return
87 | }
88 |
89 | function finalTitle () {
90 | if (queries.infinitymode) return 'Congratulations!'
91 | if (win === true) return 'You Win!'
92 | return 'You Lose!'
93 | }
94 |
95 | function finalText () {
96 | if (queries.infinitymode) return `You answered well ${score} questions!`
97 | if (win === true) return 'Congratulations! \nQuiz completed successfully.'
98 | return 'Better luck next time! \nYou can try again.'
99 | }
100 |
101 | return (
102 | <>
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | {finalImage()}
114 |
{finalTitle()}
115 |
116 | {finalText()}
117 |
118 |
119 |
120 |
121 | Go back
122 |
123 | document.getElementById('newGameDialog').showModal()} className='btn-primary px-5 md:px-10 py-3 uppercase tracking-widest rounded-md bg-blue-500 text-white'>
124 | {queries.infinitymode || win !== false ? 'Play Again' : 'Try Again'}
125 |
126 |
127 |
128 |
129 | >
130 | )
131 | }
132 |
--------------------------------------------------------------------------------
/source_code/src/components/Play/PlayHeader.jsx:
--------------------------------------------------------------------------------
1 | import { BiArrowBack } from 'react-icons/bi'
2 | import { BsArrowRepeat } from 'react-icons/bs'
3 | import Link from 'next/link'
4 | import { useBoundStore } from '@/store/useBoundStore'
5 |
6 | export default function PlayHeader () {
7 | const { cleanQuestions, cleanWildCards } = useBoundStore(state => state)
8 |
9 | return (
10 |
11 |
12 |
13 | { cleanQuestions(); cleanWildCards() }}>
14 |
15 |
16 |
17 |
18 | document.getElementById('newGameDialog').showModal()}>
19 |
20 |
21 |
22 |
23 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/source_code/src/components/Questions/QuestionSlider.jsx:
--------------------------------------------------------------------------------
1 | import { useBoundStore } from '@/store/useBoundStore'
2 | import playSound from '@/helpers/playSound'
3 | import starIcon from '@/assets/star.svg'
4 | import Image from 'next/image'
5 |
6 | export default function QuestionSlider ({ changueCurrent, setTime, getAnotherQuestions }) {
7 | const { questions, queries, loadingInfinity, setUserAnswer, error, useLivesCard, setWin, wildCards, currentQuestion, setScore, win, score } = useBoundStore(state => state)
8 |
9 | function validateAnswer (e) {
10 | const correct = e.target.textContent === questions[currentQuestion - 1].correctAnswer
11 |
12 | e.target.parentNode.classList.add(correct ? 'shake-left-right' : 'vibrate')
13 | e.target.classList.add(correct ? 'correctAnswer' : 'wrongAnswer')
14 |
15 | document.querySelectorAll(`.answers-${currentQuestion} button`).forEach(answer => {
16 | answer.disabled = true
17 | if (!correct && answer.textContent === questions[currentQuestion - 1].correctAnswer) {
18 | answer.parentNode.classList.add('shake-left-right')
19 | answer.classList.add('correctAnswer')
20 | }
21 | })
22 |
23 | playSound(correct ? 'correct_answer' : 'wrong_answer', 0.3)
24 | if (!queries.infinitymode) setUserAnswer(currentQuestion - 1, correct ? 1 : -1)
25 |
26 | if (queries.infinitymode) {
27 | if (correct) {
28 | if (score !== 1 && score % 5 === 0) getAnotherQuestions()
29 | } else {
30 | if (wildCards.lives > 0) {
31 | if (score !== 1 && score % 5 === 0) getAnotherQuestions()
32 | useLivesCard()
33 | } else return setWin(false)
34 | }
35 | } else {
36 | if (!correct) {
37 | if (wildCards.lives > 0) {
38 | useLivesCard()
39 | if (score === Number(queries.questions)) return setWin(true)
40 | } else return setWin(false)
41 | } else if (score === Number(queries.questions)) return setWin(true)
42 | }
43 |
44 | setTimeout(() => {
45 | setScore(score + 1)
46 | setTime(Number(queries.time))
47 | if (queries.infinitymode && score !== 1 && score % 5 === 0) changueCurrent(1)
48 | else changueCurrent(currentQuestion + 1)
49 | }, 1000)
50 | }
51 |
52 | if (error[0]) {
53 | return
54 | An error occurred while loading the next questions...
55 |
56 | }
57 |
58 | if (loadingInfinity || !questions) {
59 | return
60 | Loading next questions...
61 |
62 | }
63 |
64 | return (
65 |
66 | {
67 | questions.map((question, i) => {
68 | return (
69 |
70 | {
71 | question.ia &&
72 |
73 |
74 | }
75 |
76 | {question.question}
77 |
78 |
79 |
80 | {question.answers.map((answer, j) => (
81 |
82 | 24 ? 'text-sm' : ''}`}
84 | disabled={!queries.infinitymode && (score !== i + 1 || currentQuestion !== i + 1 || win !== undefined)}
85 | onClick={validateAnswer}>
86 | {answer || '---'}
87 |
88 |
89 |
90 |
91 | ))}
92 |
93 |
94 | )
95 | })
96 | }
97 |
98 | )
99 | }
100 |
--------------------------------------------------------------------------------
/source_code/src/components/Questions/Questions.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import Wildcards from './Wildcards'
3 | import GameOver from '../Play/GameOver'
4 | import QuestionsNavbar from './QuestionsNavbar'
5 | import QuestionSlider from './QuestionSlider'
6 |
7 | import categories from '@/assets/categories.json'
8 | import playSound from '@/helpers/playSound'
9 | import { useBoundStore } from '@/store/useBoundStore'
10 |
11 | export default function Questions () {
12 | const { questions, loading, loadingInfinity, currentQuestion, setCurrentQuestion, setUserAnswer, win, score, setWin, setScore, wildCards, useLivesCard, queries, getQuestions } = useBoundStore(state => state)
13 | const [time, setTime] = useState(Number(queries.time))
14 |
15 | useEffect(() => {
16 | const color = categories.find(cat => cat.name.toLowerCase() === questions[currentQuestion - 1]?.topic.toLowerCase())?.color
17 | color && (document.body.style.backgroundColor = color)
18 |
19 | function shortcuts (e) {
20 | if (!queries.infinitymode) {
21 | if (e.key === 'ArrowLeft' && currentQuestion > 1) changueCurrent(currentQuestion - 1)
22 | if (e.key === 'ArrowRight' && currentQuestion < score) changueCurrent(currentQuestion + 1)
23 | }
24 |
25 | if (e.key === 'a' || e.key === 'b' || e.key === 'c' || e.key === 'd') {
26 | const answer = ['a', 'b', 'c', 'd'].indexOf(e.key)
27 | if (answer !== -1) document.querySelector(`.answers-${queries.infinitymode ? currentQuestion : score} .answer-${answer + 1}`)?.click()
28 | }
29 | }
30 |
31 | document.addEventListener('keydown', shortcuts)
32 | return () => document.removeEventListener('keydown', shortcuts)
33 | }, [currentQuestion, score])
34 |
35 | useEffect(() => {
36 | if (win !== undefined || !queries.timemode || loading || loadingInfinity) return
37 | const timeInterval = setInterval(() => setTime(time => time > 0 ? time - 1 : time), 1000)
38 | return () => clearInterval(timeInterval)
39 | }, [queries.timemode, win, loading, loadingInfinity])
40 |
41 | useEffect(() => {
42 | if (win !== undefined || time > 0) return
43 |
44 | if (wildCards.lives < 1) {
45 | clickCorrectAnswer()
46 | setUserAnswer(score - 1, -1)
47 | playSound('wrong_answer', 0.3)
48 | setWin(false)
49 | } else {
50 | if (queries.infinitymode) {
51 | if (score !== 1 && score % 5 === 0) {
52 | clickCorrectAnswer()
53 | getAnotherQuestions()
54 | } else clickCorrectAnswer(true)
55 | } else {
56 | if (score === queries.questions) {
57 | setWin(true)
58 | clickCorrectAnswer()
59 | } else clickCorrectAnswer(true)
60 | }
61 |
62 | setUserAnswer(score - 1, 2)
63 | useLivesCard()
64 | playSound('correct_answer', 0.3)
65 | }
66 | }, [time])
67 |
68 | function getAnotherQuestions () {
69 | setTimeout(() => {
70 | setTime(Number(queries.time))
71 | changueCurrent(1)
72 | setScore(score + 1)
73 | const topics = categories.filter(category => queries.categories.find(cat => cat === category.id)).map(cat => cat.name)
74 | getQuestions(topics, 5, true)
75 | }, 1000)
76 | }
77 |
78 | function clickCorrectAnswer (addScore = false) {
79 | if (addScore) {
80 | setTimeout(() => {
81 | setScore(score + 1)
82 | setTime(Number(queries.time))
83 | setUserAnswer(score - 1, 1)
84 | changueCurrent(score + 1)
85 | }, 1000)
86 | }
87 |
88 | document.querySelectorAll(`.answers-${score} button`).forEach(answer => {
89 | answer.disabled = true
90 | if (answer.textContent === questions[score - 1].correctAnswer) {
91 | answer.classList.add('correctAnswer')
92 | answer.parentNode.classList.add('shake-left-right')
93 | }
94 | })
95 | }
96 |
97 | function changueCurrent (number) {
98 | if (number > questions.lenght || number < 1) return
99 | document.querySelectorAll('[id^="question-"]').forEach(question => {
100 | question.classList.remove('slide-left', 'slide-right')
101 | if (question.id !== `question-${number}`) {
102 | question.classList.add(Number(question.id.replace('question-', '')) < number ? 'slide-left' : 'slide-right')
103 | }
104 | })
105 | setCurrentQuestion(number)
106 | }
107 |
108 | return (
109 | <>
110 |
111 |
112 |
113 |
114 |
115 | {win !== undefined && }
116 |
117 |
118 | {
119 | queries.timemode &&
120 | {time}
121 |
122 |
123 |
124 |
125 | }
126 | >
127 | )
128 | }
129 |
--------------------------------------------------------------------------------
/source_code/src/components/Questions/QuestionsNavbar.jsx:
--------------------------------------------------------------------------------
1 | import { useBoundStore } from '@/store/useBoundStore'
2 |
3 | export default function QuestionsNavbar ({ changueCurrent }) {
4 | const { queries, questions, currentQuestion, score } = useBoundStore(state => state)
5 |
6 | if (queries.infinitymode) {
7 | return {score}
8 | }
9 |
10 | function buttonBg (i) {
11 | console.log(questions, i, questions[i])
12 | let bg = 'bg-slate-600 hover:cursor-auto'
13 | if (i + 1 === score) bg = 'bg-white text-blue-500'
14 | if (questions[i].userAnswer === 1) bg = 'bg-green-500 !text-white'
15 | if (questions[i].userAnswer === -1) bg = 'bg-red-500 !text-white'
16 | if (questions[i].userAnswer === 2) bg = 'bg-blue-500 !text-white'
17 | if (i + 1 <= score) bg += ' cursor-pointer hover:scale-105'
18 | if (i + 1 === currentQuestion) bg += ' outline outline-offset-2 hover:outline-offset-4 outline-blue-500'
19 | return bg
20 | }
21 |
22 | return (
23 |
24 | {[...Array(parseInt(questions.length))].map((_, i) => (
25 |
26 | changueCurrent(i + 1)} disabled={i + 1 > score} className={`w-8 h-8 flex items-center justify-center pt-[2px] font-medium transition-all rounded-full text-center text-sm ${buttonBg(i)}`}>{i + 1}
27 |
28 | ))}
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/source_code/src/components/Questions/Wildcards.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 | import { BsSkipEndFill } from 'react-icons/bs'
3 | import fiftyImg from '@/assets/fifty.svg'
4 | import { FaHeart } from 'react-icons/fa'
5 | import { useBoundStore } from '@/store/useBoundStore'
6 | import { useEffect } from 'react'
7 |
8 | export default function Wildcards () {
9 | const { wildCards, useSkipCard, queries, win, useHalfCard, currentQuestion, score } = useBoundStore(state => state)
10 |
11 | useEffect(() => {
12 | function shortcuts (e) {
13 | if (e.key === 's') useSkipCard()
14 | if (e.key === 'h') useHalfCard()
15 | }
16 | document.addEventListener('keydown', shortcuts)
17 | return () => document.removeEventListener('keydown', shortcuts)
18 | }, [])
19 |
20 | function disabled (type) {
21 | const finalQuestion = queries.infinitymode ? (score % 5 === 0 ? 5 : score % 5) : score
22 | return wildCards[type] < 1 || win !== undefined || currentQuestion !== finalQuestion
23 | }
24 |
25 | return (
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | x{wildCards.skip}
34 |
35 |
36 |
37 |
38 |
39 |
40 | x{wildCards.half}
41 |
42 |
43 |
44 |
45 |
46 | x{wildCards.lives}
47 |
48 |
49 |
50 |
51 |
52 | )
53 | }
54 |
--------------------------------------------------------------------------------
/source_code/src/helpers/gameConfig.js:
--------------------------------------------------------------------------------
1 | import categoriesJSON from '@/assets/categories.json'
2 |
3 | const MAX_QUESTIONS = 10
4 | const MIN_QUESTIONS = 4
5 | const TIMES = [10, 20, 30, 60]
6 | const DEFAULT_TIME = 20
7 | const DEFAULT_QUESTIONS = 5
8 | const INFINITY_MODE = false
9 | const TIME_MODE = false
10 |
11 | export default function queryValidator (query) {
12 | const { questions, time, infinitymode, timemode, categories } = query
13 | const urlQueries = {}
14 |
15 | if (questions && Number(questions)) {
16 | if (Number(questions) > MAX_QUESTIONS) urlQueries.questions = MAX_QUESTIONS
17 | else if (Number(questions) < MIN_QUESTIONS) urlQueries.questions = MIN_QUESTIONS
18 | else urlQueries.questions = Number(questions)
19 | } else urlQueries.questions = DEFAULT_QUESTIONS
20 |
21 | if (time && Number(time)) {
22 | if (Number(time) > TIMES[TIMES.length - 1]) urlQueries.time = TIMES[TIMES.length - 1]
23 | else if (Number(time) < TIMES[0]) urlQueries.time = TIMES[0]
24 | else urlQueries.time = Number(time)
25 | } else urlQueries.time = DEFAULT_TIME
26 |
27 | if (infinitymode) {
28 | if (infinitymode === 'true' || infinitymode === true) urlQueries.infinitymode = true
29 | else urlQueries.infinitymode = false
30 | } else urlQueries.infinitymode = INFINITY_MODE
31 |
32 | if (timemode) {
33 | if (timemode === 'true' || timemode === true) urlQueries.timemode = true
34 | else urlQueries.timemode = false
35 | } else urlQueries.timemode = TIME_MODE
36 |
37 | if (categories) {
38 | const categoriesArray = typeof categories === 'string' ? categories.split(',') : categories
39 | const categoriesArrayFiltered = categoriesArray.filter(category => categoriesJSON.map(category => category.id).includes(category))
40 | if (categoriesArrayFiltered.length > 0) urlQueries.categories = categoriesArrayFiltered
41 | else urlQueries.categories = categoriesJSON.map(category => category.id)
42 | } else urlQueries.categories = categoriesJSON.map(category => category.id)
43 |
44 | return urlQueries
45 | }
46 |
47 | export const defaultQuestions = {
48 | minQuestions: MIN_QUESTIONS,
49 | maxQuestions: MAX_QUESTIONS
50 | }
51 |
52 | export const defaultQuery = {
53 | questions: DEFAULT_QUESTIONS,
54 | time: DEFAULT_TIME,
55 | infinitymode: INFINITY_MODE,
56 | timemode: TIME_MODE,
57 | categories: categoriesJSON.map(category => category.id)
58 | }
59 |
--------------------------------------------------------------------------------
/source_code/src/helpers/getQuestions.js:
--------------------------------------------------------------------------------
1 | import offlineQuestions from '@/assets/questions.json'
2 |
3 | const randomArray = (arr) => arr.toSorted(() => 0.5 - Math.random())
4 |
5 | export default async function getQuestions (topics, qNumber) {
6 | const randomTopics = randomArray(topics)
7 | const messyTopics = []
8 | for (let i = 0; i < qNumber; i++) messyTopics.push(randomTopics[i % topics.length])
9 |
10 | function getOfflineQuestions () {
11 | const questionsPerTopic = {}
12 | messyTopics.forEach(topic => {
13 | questionsPerTopic[topic] = (questionsPerTopic[topic] || 0) + 1
14 | })
15 |
16 | const questions = []
17 | Object.keys(questionsPerTopic).forEach(topic => {
18 | randomArray(offlineQuestions[topic]).slice(0, questionsPerTopic[topic]).forEach(question => {
19 | questions.push({
20 | ...question,
21 | topic,
22 | answers: randomArray(question.answers),
23 | userAnswer: undefined,
24 | ia: false
25 | })
26 | })
27 | })
28 |
29 | return questions
30 | }
31 |
32 | if (process.env.NODE_ENV === 'development') {
33 | return new Promise((resolve, reject) => {
34 | setTimeout(() => {
35 | // const error = new Error('Custom error')
36 | // error.statusCode = 350
37 | // reject(error)
38 |
39 | resolve(randomArray(getOfflineQuestions()))
40 | }, 1 * 1000)
41 | })
42 | }
43 |
44 | const iaQuestions = fetch('/api/questions', {
45 | method: 'POST',
46 | headers: {
47 | 'Content-Type': 'application/json'
48 | },
49 | body: JSON.stringify({ topics: messyTopics.slice(0, 3) })
50 | }).then(res => res.json())
51 | .then(data => {
52 | if (data.statusCode >= 400) {
53 | const error = new Error(data.message)
54 | error.statusCode = data.status
55 | throw error
56 | } else return data
57 | })
58 | .catch(err => {
59 | console.log(err)
60 | throw err
61 | })
62 |
63 | return iaQuestions
64 | .then(iaQuestions => randomArray([
65 | ...iaQuestions,
66 | ...getOfflineQuestions().slice(iaQuestions.length)
67 | ]))
68 | .catch(() => randomArray(getOfflineQuestions()))
69 | }
70 |
--------------------------------------------------------------------------------
/source_code/src/helpers/playSound.js:
--------------------------------------------------------------------------------
1 | export default function playSound (sound, volume = 0.25) {
2 | if (localStorage.getItem('sound') === 'true') {
3 | const audio = new Audio(`/sounds/${sound}.mp3`)
4 | audio.volume = volume
5 | audio.play()
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/source_code/src/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '@/styles/globals.css'
2 | import { Rubik } from '@next/font/google'
3 | import Head from 'next/head'
4 | import NewGameForm from '@/components/Form/NewGameForm'
5 | const rubik = Rubik({ subsets: ['latin'] })
6 |
7 | export default function App ({ Component, pageProps }) {
8 | return (
9 | <>
10 |
11 |
12 |
13 |
14 |
15 |
20 | >
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/source_code/src/pages/_document.js:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document'
2 |
3 | export default function Document () {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 | {/* */}
11 |
12 |
13 |
14 |
15 |
16 | {/* */}
17 |
18 |
19 |
20 |
21 |
22 |
23 | {/* */}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/source_code/src/pages/api/questions.js:
--------------------------------------------------------------------------------
1 | import offlineQuestions from '@/assets/questions.json'
2 | const cohere = require('cohere-ai')
3 | cohere.init(process.env.COHERE_API_KEY)
4 |
5 | function defaultPromt () {
6 | const topics = Object.keys(offlineQuestions)
7 | const random3Topics = topics.sort(() => Math.random() - Math.random()).slice(0, 3)
8 | const randomQuestions = random3Topics.map(topic => {
9 | const randomQuestion = {
10 | ...offlineQuestions[topic][Math.floor(Math.random() * offlineQuestions[topic].length)],
11 | topic
12 | }
13 | return randomQuestion
14 | })
15 |
16 | const text = randomQuestions.reduce((acc, question, index) => {
17 | const questionText = `question: ${question.question}\ntopic: ${question.topic}\n${question.answers.map(answer => `-${answer}`).join('\n')}\ncorrect: ${question.correctAnswer}\n\n`
18 | if (index === randomQuestions.length - 1) return acc + questionText.slice(0, -1)
19 | return acc + questionText
20 | }, '')
21 |
22 | return 'Generate 3 questions, ' + random3Topics.map(topic => `1 about ${topic}`).join(', ') + '. Each question has 4 answers (1 correct and 3 incorrect).\n---\n' + text + '---\n'
23 | }
24 |
25 | export default function handler (req, res) {
26 | if (req.method !== 'POST') return res.status(405).json({ message: 'Only POST requests allowed', statusCode: 405 })
27 | if (!req.body.topics) return res.status(400).json({ message: 'Topics are required', statusCode: 400 })
28 |
29 | const promt = defaultPromt() + defaultPromt() + 'Generate 3 questions, ' + req.body.topics.map(topic => `1 about ${topic}`).join(', ') + '. Each question has 4 answers (1 correct and 3 incorrect).\n---'
30 |
31 | setTimeout(() => {
32 | res.status(500).json({ message: 'Request timed out', statusCode: 500 })
33 | }, 10 * 1000)
34 |
35 | cohere.generate({
36 | model: 'command',
37 | prompt: promt,
38 | max_tokens: 450,
39 | temperature: 0.8,
40 | k: 0,
41 | stop_sequences: ['---'],
42 | return_likelihoods: 'NONE'
43 | })
44 | .then(response => {
45 | if (response.statusCode >= 400) {
46 | return res.status(500).json({
47 | message: response.body.message || 'Something went wrong',
48 | statusCode: response.statusCode || 500
49 | })
50 | }
51 | res.status(200).json(response.body.generations[0].text.split('\n\n').map(question => {
52 | if (question.startsWith('\n')) question = question.slice(1)
53 | if (question.endsWith('\n')) question = question.slice(0, -1)
54 | const questionArray = question.split('\n')
55 | const questionObject = {
56 | question: questionArray[0].split('question: ')[1]?.trim(),
57 | topic: questionArray[1].split('topic: ')[1]?.trim(),
58 | answers: questionArray.slice(2, 6).map(answer => answer.split('-')[1]?.trim()),
59 | correctAnswer: questionArray[6].split('correct: ')[1]?.trim(),
60 | userAnswer: undefined,
61 | ia: true
62 | }
63 | return questionObject
64 | }))
65 | })
66 | .catch(err => {
67 | console.log(err)
68 | const message = err.body.message || 'Something went wrong'
69 | const statusCode = err.statusCode || 500
70 | return res.status(500).json({ message, statusCode })
71 | })
72 | }
73 |
--------------------------------------------------------------------------------
/source_code/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import MainHome from '@/components/Home/MainHome'
3 | import GameModes from '@/components/Home/GameModes'
4 | import Categories from '@/components/Home/Categories'
5 | import { useEffect } from 'react'
6 |
7 | export default function Main () {
8 | useEffect(() => { window.onbeforeunload = () => null }, [])
9 |
10 | return (
11 | <>
12 |
13 | Quizi
14 |
15 |
16 |
17 |
18 |
30 | >
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/source_code/src/pages/play/index.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import { useRouter } from 'next/router'
3 | import Head from 'next/head'
4 |
5 | import PageLoading from '@/components/PageLoading'
6 | import PageError from '@/components/PageError'
7 | import PlayHeader from '@/components/Play/PlayHeader'
8 | import GameInfo from '@/components/Play/GameInfo'
9 | import Footer from '@/components/PageFooter'
10 | import Questions from '@/components/Questions/Questions'
11 |
12 | import queryValidator from '@/helpers/gameConfig'
13 | import categories from '@/assets/categories.json'
14 | import { useBoundStore } from '@/store/useBoundStore'
15 |
16 | export default function Play () {
17 | const { loading, error, getQuestions, setQueries } = useBoundStore(state => state)
18 | const router = useRouter()
19 |
20 | useEffect(() => {
21 | if (router.isReady) {
22 | const validQuery = queryValidator(router.query)
23 | const cate = validQuery.categories.map(cat => categories.find(c => c.id === cat).name)
24 | setQueries(validQuery)
25 | getQuestions(cate, validQuery.infinitymode ? 5 : validQuery.questions)
26 | }
27 | }, [router.isReady])
28 |
29 | useEffect(() => { window.onbeforeunload = () => 'Are you sure you want to leave?' }, [])
30 |
31 | return (
32 | <>
33 | Quizi | Play
34 | {loading && }
35 | {error[0] && }
36 | {!loading && !error[0] && <>
37 |
38 |
39 |
40 |
41 |
55 | >
56 | }
57 | >
58 | )
59 | }
60 |
--------------------------------------------------------------------------------
/source_code/src/store/useBoundStore.js:
--------------------------------------------------------------------------------
1 | import { create } from 'zustand'
2 | import { useWildcardsStore } from './useWildcards'
3 | import { useQueriesStore } from './useQueries'
4 | import { useQuestionsStore } from './useQuestions'
5 |
6 | export const useBoundStore = create((...a) => ({
7 | ...useWildcardsStore(...a),
8 | ...useQueriesStore(...a),
9 | ...useQuestionsStore(...a)
10 | }))
11 |
--------------------------------------------------------------------------------
/source_code/src/store/useQueries.js:
--------------------------------------------------------------------------------
1 | import { defaultQuery } from '@/helpers/gameConfig'
2 |
3 | export const useQueriesStore = (set) => ({
4 | queries: defaultQuery,
5 | setQueries: (queries) => set({ queries })
6 | })
7 |
--------------------------------------------------------------------------------
/source_code/src/store/useQuestions.js:
--------------------------------------------------------------------------------
1 | import getQuestions from '@/helpers/getQuestions'
2 |
3 | export const useQuestionsStore = (set, get) => ({
4 | questions: [],
5 | loading: false,
6 | loadingInfinity: false,
7 | error: [false, ''],
8 | currentQuestion: 1,
9 | score: 1,
10 | win: undefined,
11 | getQuestions: (topics, number, infinity) => {
12 | infinity ? set({ loadingInfinity: true }) : set({ loading: true })
13 | getQuestions(topics, number)
14 | .then(data => set({ questions: data }))
15 | .catch(err => set({ error: [true, err] }))
16 | .finally(() => infinity ? set({ loadingInfinity: false }) : set({ loading: false }))
17 | },
18 | setCurrentQuestion: (number) => set({ currentQuestion: number }),
19 | setUserAnswer: (question, answer) => {
20 | if (get().queries.infinitymode) return
21 | set(state => {
22 | const questions = [...state.questions]
23 | questions[question].userAnswer = answer
24 | return { questions }
25 | })
26 | },
27 | cleanQuestions: () => set({ questions: [], score: 1, currentQuestion: 1, win: undefined }),
28 | setScore: (score) => set({ score }),
29 | setWin: (win) => set({ win })
30 | })
31 |
--------------------------------------------------------------------------------
/source_code/src/store/useWildcards.js:
--------------------------------------------------------------------------------
1 | const defaultWildCards = { skip: 1, half: 1, lives: 1 }
2 |
3 | export const useWildcardsStore = (set, get) => ({
4 | wildCards: defaultWildCards,
5 | useSkipCard: () => {
6 | document.querySelectorAll(`.answers-${get().currentQuestion} button`).forEach(answer => {
7 | if (answer.textContent === get().questions[get().currentQuestion - 1].correctAnswer) {
8 | answer.click()
9 | }
10 | })
11 | get().setUserAnswer(get().currentQuestion - 1, 2)
12 | set(state => ({ wildCards: { ...state.wildCards, skip: state.wildCards.skip - 1 } }))
13 | },
14 | useHalfCard: () => {
15 | set(state => ({ wildCards: { ...state.wildCards, half: state.wildCards.half - 1 } }))
16 |
17 | const answers = document.querySelectorAll(`.answers-${get().currentQuestion} button`)
18 | const correct = get().questions[get().currentQuestion - 1].correctAnswer
19 | const wrongs = [...answers].filter(answer => answer.textContent !== correct)
20 |
21 | wrongs.sort(() => Math.random() - 0.5).slice(0, 2).forEach(wrong => {
22 | wrong.classList.add('wrongAnswer')
23 | wrong.parentNode.classList.add('vibrate')
24 | wrong.disabled = true
25 | })
26 | },
27 | useLivesCard: () => set(state => ({ wildCards: { ...state.wildCards, lives: state.wildCards.lives - 1 } })),
28 | cleanWildCards: () => set({ wildCards: defaultWildCards })
29 | })
30 |
--------------------------------------------------------------------------------
/source_code/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | #__next {
6 | min-height: 100vh;
7 | }
8 | html {
9 | scroll-behavior: smooth;
10 | }
11 | dialog::backdrop {
12 | backdrop-filter: blur(3px);
13 | }
14 | body {
15 | transition: all 0.3s ease-in-out;
16 | overflow-x: hidden;
17 | }
18 |
19 | .mainHome {
20 | background: rgb(28, 35, 58) url('/bg-home.svg');
21 | background-size: 70%;
22 | }
23 | .disabled {
24 | filter: grayscale(1);
25 | cursor: not-allowed;
26 | }
27 | .progressBar::-webkit-scrollbar {
28 | height: 5px;
29 | }
30 | .progressBar::after {
31 | width: calc((100% / var(--segments)) * var(--current));
32 | }
33 |
34 | /* Pulse animation ============================= */
35 | .pulse_animation {
36 | animation: pulse 1s infinite;
37 | }
38 | @keyframes pulse {
39 | 0% {
40 | scale: 1;
41 | background: rgb(236, 52, 52);
42 | color: white;
43 | }
44 | 50% {
45 | scale: 1.1;
46 | background: white;
47 | color: rgb(236, 52, 52);
48 | }
49 | 100% {
50 | scale: 1;
51 | background: rgb(236, 52, 52);
52 | color: white;
53 | }
54 | }
55 |
56 | /* Slides ============================ */
57 | .slide-left {
58 | transform: translateX(-100%);
59 | opacity: 0;
60 | pointer-events: none;
61 | }
62 | .slide-right {
63 | transform: translateX(100%);
64 | opacity: 0;
65 | pointer-events: none;
66 | }
67 |
68 | /* Loader ============================ */
69 | .loader {
70 | width: 100px;
71 | height: 100px;
72 | }
73 | .loader path {
74 | fill: #2563eb;
75 | transform-origin: center;
76 | animation: rotate 1.5s linear infinite;
77 | }
78 | .loaderreverse {
79 | animation-direction: reverse !important;
80 | }
81 |
82 | @keyframes rotate {
83 | to {
84 | transform: rotate(360deg);
85 | }
86 | from {
87 | transform: rotate(0deg);
88 | }
89 | }
90 |
91 | /* btn-primary ============================ */
92 | .btn-primary {
93 | transform-style: preserve-3d;
94 | transition: all 150ms cubic-bezier(0, 0, 0.58, 1);
95 | }
96 |
97 | .btn-primary::before {
98 | border-radius: inherit;
99 | transform: translate3d(0, 0.75em, -1em);
100 | transition: all 150ms cubic-bezier(0, 0, 0.58, 1);
101 | }
102 |
103 | .btn-primary:hover {
104 | background: #5490f1;
105 | transform: translate(0, 0.25em);
106 | }
107 | .btn-primary:hover::before {
108 | transform: translate3d(0, 0.5em, -1em);
109 | }
110 |
111 | .btn-primary:active {
112 | background: #cee5ff;
113 | transform: translate(0em, 0.75em);
114 | }
115 |
116 | .btn-primary:active::before {
117 | transform: translate3d(0, 0, -0.1em);
118 | }
119 | .btn-primary:disabled:hover {
120 | background: #3b82f6;
121 | transform: translate(0, 0);
122 | }
123 | .btn-primary:disabled:hover::before {
124 | transform: translate3d(0, 0.75em, -1em);
125 | }
126 |
127 | @layer components {
128 | .btn-primary {
129 | @apply relative tracking-wider font-bold bg-[#3b82f6] text-center text-white rounded-md px-4 py-2 transition-all before:absolute before:w-full before:h-full before:top-[-3px] before:left-0 before:right-0 before:bottom-0 before:bg-[#2563eb];
130 | }
131 | .wrongAnswer {
132 | @apply before:bg-red-700 !bg-[#e11d48];
133 | }
134 | .correctAnswer {
135 | @apply before:bg-green-600 !bg-[#22c55e];
136 | }
137 | }
138 |
139 | /* Dialog ============================ */
140 | dialog[open] {
141 | animation: show 0.3s ease;
142 | }
143 | dialog.hide {
144 | animation: hide 0.2s ease;
145 | }
146 | @keyframes show {
147 | from {
148 | opacity: 0;
149 | transform: translate(-50%, -50%) scale(0.2);
150 | }
151 | to {
152 | opacity: 1;
153 | transform: translate(-50%, -50%) scale(1);
154 | }
155 | }
156 | @keyframes hide {
157 | to {
158 | transform: translate(-50%, -50%) scale(0.2);
159 | opacity: 0;
160 | }
161 | }
162 |
163 | /* Input range ============================ */
164 | input[type='range'] {
165 | -webkit-appearance: none;
166 | appearance: none;
167 | width: 100%;
168 | height: 0.5rem;
169 | background: #d1d5db;
170 | border-radius: 0.5rem;
171 | }
172 | input[type='range']::-webkit-slider-thumb {
173 | -webkit-appearance: none;
174 | appearance: none;
175 | width: 1.5rem;
176 | height: 1.5rem;
177 | border-radius: 50%;
178 | background: #2563eb;
179 | }
180 | input[type='range']:not(:disabled)::-webkit-slider-thumb {
181 | cursor: e-resize;
182 | }
183 | input[type='range']::-moz-range-thumb {
184 | width: 1.5rem;
185 | height: 1.5rem;
186 | border-radius: 50%;
187 | background: #2563eb;
188 | cursor: pointer;
189 | }
190 |
191 | /* Scroll ============================ */
192 | ::-webkit-scrollbar {
193 | width: 6px;
194 | }
195 | ::-webkit-scrollbar-track {
196 | background: #ffffff;
197 | }
198 | ::-webkit-scrollbar-thumb {
199 | background: linear-gradient(0deg, #2563eb, #685af5);
200 | border-radius: 5px;
201 | }
202 | ::-webkit-scrollbar-thumb:hover {
203 | background: #87adff;
204 | }
205 |
206 | /* Focus ============================ */
207 | :focus-visible {
208 | outline: 5px dashed #0f172a;
209 | outline-offset: 2px;
210 | border-radius: 4px;
211 | }
212 | input:focus-visible {
213 | opacity: 1;
214 | }
215 |
216 | /* Checkbox ========================= */
217 | .cbx,
218 | .cbx2 {
219 | position: relative;
220 | width: 25px;
221 | height: 25px;
222 | border: 1px solid #c8ccd4;
223 | background: #d1d5db;
224 | border-radius: 3px;
225 | transition: background 0.1s ease;
226 | cursor: pointer;
227 | display: block;
228 | }
229 |
230 | .cbx:after,
231 | .cbx2:after {
232 | content: '';
233 | position: absolute;
234 | top: 3px;
235 | left: 8px;
236 | width: 7px;
237 | height: 14px;
238 | opacity: 0;
239 | transform: rotate(45deg) scale(0);
240 | border-right: 3px solid #fff;
241 | border-bottom: 3px solid #fff;
242 | transition: all 0.3s ease;
243 | transition-delay: 0.15s;
244 | }
245 |
246 | .lbl {
247 | margin-left: 5px;
248 | vertical-align: middle;
249 | cursor: pointer;
250 | }
251 |
252 | #cbx:checked ~ .cbx,
253 | #cbx2:checked ~ .cbx2 {
254 | border-color: transparent;
255 | background: #2563eb;
256 | animation: jello-vertical 0.3s ease;
257 | }
258 |
259 | #cbx:checked ~ .cbx:after,
260 | #cbx2:checked ~ .cbx2:after {
261 | opacity: 1;
262 | transform: rotate(45deg) scale(1);
263 | }
264 |
265 | .cntr {
266 | position: absolute;
267 | top: -2rem;
268 | left: 6.5rem;
269 | }
270 |
271 | /* Animations */
272 | /* ----------------------------------------------
273 | Generated by AnimatiSS
274 | Licensed under FreeBSD License
275 | URL: https://xsgames.co/animatiss
276 | Twitter: @xsgames_
277 | ---------------------------------------------- */
278 | /* For correct answer */
279 | .shake-left-right {
280 | animation: shake-left-right 0.6s linear both;
281 | }
282 | @keyframes shake-left-right {
283 | 0%,
284 | 100% {
285 | transform: rotate(0deg);
286 | transform-origin: 50% 50%;
287 | }
288 | 20% {
289 | transform: rotate(8deg);
290 | }
291 | 40% {
292 | transform: rotate(-8deg);
293 | }
294 | 60% {
295 | transform: rotate(8deg);
296 | }
297 | 80% {
298 | transform: rotate(-8deg);
299 | }
300 | }
301 | /* For wrong answer */
302 | .vibrate {
303 | animation: vibrate 0.3s linear both;
304 | }
305 | @keyframes vibrate {
306 | 0% {
307 | transform: translate(0);
308 | }
309 | 20% {
310 | transform: translate(-2px, 2px);
311 | }
312 | 40% {
313 | transform: translate(-2px, -2px);
314 | }
315 | 60% {
316 | transform: translate(2px, 2px);
317 | }
318 | 80% {
319 | transform: translate(2px, -2px);
320 | }
321 | 100% {
322 | transform: translate(0);
323 | }
324 | }
325 | /* For title "Quizi" hover */
326 | .jello-vertical {
327 | animation: jello-vertical 0.6s linear both;
328 | }
329 | @keyframes jello-vertical {
330 | 0% {
331 | transform: scale3d(1, 1, 1);
332 | }
333 | 30% {
334 | transform: scale3d(0.75, 1.25, 1);
335 | }
336 | 40% {
337 | transform: scale3d(1.25, 0.75, 1);
338 | }
339 | 50% {
340 | transform: scale3d(0.85, 1.15, 1);
341 | }
342 | 65% {
343 | transform: scale3d(1.05, 0.95, 1);
344 | }
345 | 75% {
346 | transform: scale3d(0.95, 1.05, 1);
347 | }
348 | 100% {
349 | transform: scale3d(1, 1, 1);
350 | }
351 | }
352 |
353 | /* Countdown =================*/
354 | .countdown {
355 | transform: rotateZ(-90deg);
356 | }
357 | .countdown circle {
358 | stroke-dasharray: 174px;
359 | stroke-dashoffset: 0px;
360 | stroke-linecap: round;
361 | stroke-width: 5px;
362 | fill: none;
363 | }
364 |
--------------------------------------------------------------------------------
/source_code/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./src/**/*.{js,ts,jsx,tsx}'],
4 | theme: {
5 | extend: {}
6 | },
7 | plugins: []
8 | }
9 |
--------------------------------------------------------------------------------