diff --git a/README.md b/README.md
index 512e715..d48683a 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,13 @@
![React Quiz App Template Cover Image](./src/assets/images/Xeven-Quiz-ReactJS-Quiz-App-Template.jpg)
# Xeven Quiz - ReactJS Quiz App Template
-With **Xeven Quiz**, you don't have to spend hours coding from scratch. Our template provides a solid foundation, eliminating the need to reinvent the wheel. You'll spend less time developing your app, which lets you focus on the unique. Xeven Quiz helps you follow industry best practices and coding conventions as a beginner.
+With **Xeven Quiz**, you don't have to spend hours on coding from scratch. This Quiz App template provides a solid foundation, eliminating the need to reinvent the wheel. You'll spend less time developing your app, which lets you focus on the unique.
-As a beginner developer, a quiz app is a common project. But without guidance, this simple project can become difficult. Xeven Quiz is here to change that narrative and give you the tools and knowledge you need to create a successful and efficient quiz app.
+Xeven Quiz helps you follow industry best practices and coding conventions as a beginner.
+
+As a beginner developer, a quiz app is a common project. But without guidance, this simple project can become difficult.
+
+Xeven Quiz is here to change that narrative and give you the tools and knowledge you need to create a successful and efficient quiz app.
With a strong architecture and modular design, you can easily add new features, expand your question database, and accommodate a growing user base without experiencing any setbacks.
@@ -21,23 +25,39 @@ With **ReactJS** at its core, it lets you design dynamic interfaces that automat
## React Quiz App's Theme Features
-Before I explain the technical aspects of the quiz app, let me share the wonderful features of the quiz app that is available in demo GitHub version. You can get all these features in a template and mold them according to your choice.
+Before I explain the technical aspects of the quiz app, let me share the wonderful features of the quiz app. You can get all these features in a template and mold them according to your choice.
+
+- Seamlessly switch between Light and Dark modes with just a single click from the top menu.
+
+- The user can pick a quiz topic on the first screen, like JavaScript, React, or General Knowledge.
-- Each time the quiz starts, questions will be shuffled or randomized.
- There will be a timer running when the quiz starts. If the timer finishes, the quiz will be stopped, and the user will be asked to see the result.
-- Each question has a score. For example, a difficult question has 10 marks, and an easier one has 5.
+
- The template also supports three types of questions, MCQs, True/False, and MAQs.
+
+- The template allows for adding code snippets in questions. You can easily assess the users' programming knowledge and skills.
+
+- The template allows you to create questions with images to enhance user engagement.
+
+- Each question has a score. For example, a difficult question has 10 marks, and an easier one has 5.
+
- The result screen shows how many questions the user attempted, how much he scored, how long it took, and whether he passed or failed.
+
- In result screen user can see which question had the right answer and which was wrong. The user can find the correct answer in case of a wrong answer.
## React Quiz App's Code Features
-- **TypeScript powered Components:** All components are TypeScript-built for enhanced development productivity with intelligent code completion and compile-time error checking.
-- **Easy Theme Customization:** The template provides easy theme management with IntelliSense support via Styled Components and Typescript. It allows you to customize the app's appearance without relying on hard-coded colors.
-- **Flexible Question Data Structure:** The template uses Javascript/TypeScript files to define quiz questions. This format provides a structured and flexible approach. The same format can also be used to fetch questions from an API if desired.
-- **Modular and Context Pattern:** The template follows a javascript modular and React Context pattern, promoting component reusability and maintainability.
-- **Custom Hooks for Logic Sharing:** The hook pattern lets you share logic across components. It also promotes code reuse and minimizes code clutter.
-- **Built with React Best Practices:** App follows industry-leading React practices. Our template ensures optimal structure, scalability, and maintainability.
+- **TypeScript powered Components**: All components are TypeScript-built for enhanced development productivity with intelligent code completion and compile-time error checking.
+
+- **Easy Theme Customization**: The template provides easy theme management with IntelliSense support via Styled Components and Typescript. It allows you to customize the app's appearance without relying on hard-coded colors.
+
+- **Flexible Question Data Structure**: The template uses Javascript/TypeScript files to define quiz questions. This format provides a structured and flexible approach. The same format can also be used to fetch questions from an API if desired.
+
+- **Modular and Context Pattern**: The template follows a javascript modular and React Context pattern, promoting component reusability and maintainability.
+
+- **Custom Hooks for Logic Sharing**: The hook pattern lets you share logic across components. It also promotes code reuse and minimizes code clutter.
+
+- **Built with React Best Practices**: App follows industry-leading React practices. Our template ensures optimal structure, scalability, and maintainability.
## Xeven Quiz - ReactJS Quiz App Template Code Documentations
@@ -74,18 +94,19 @@ Understanding the folder structure is essential for working with the app. Here's
### Components Architecture
-The **Xeven Quiz App** consists of 4 main screens/components that are displayed conditionally (in light version):
+The **Xeven Quiz App** consists of 5 main screens/components that are displayed conditionally:
1. Splash Screen
-2. Quiz Details Screen
-3. Questions Screen
-4. Result Screen
+2. Quiz Topics Screen
+3. Quiz Details Screen
+4. Questions Screen
+5. Result Screen
-The screens are organized in the **`components`** folder since the app does not utilize routing. If a component is reusable and can be used in multiple places within the app (e.g., Button, ModalWrapper, and CodeSnippet), it is placed in the **`components/UI`** folder. On the other hand, if a component is screen-specific and separated just to make other components smaller and more manageable, it is placed in the relevant components folder. For example, the components `QuizHeader`, `Question`, and `Answer` are inside the **`QuestionScreen`** folder.
+The screens are organized in the **`components`** folder since the app does not utilize routing. If a component is reusable and can be used in multiple places within the app (e.g., Button, ModalWrapper, and CodeSnippet), it is placed in the **`components/UI`** folder. On the other hand, if a component is screen-specific and separated just to make other components smaller and more manageable, it is placed in the relevant components folder. For example, the components `**QuizHeader**`, `**Question**`, and `**Answer**` are inside the **`QuestionScreen`** folder.
## How to customize the quiz layout and styling
-### **Changing the App Theme**
+### Changing the App Theme
To change the theme of the app, follow these steps:
@@ -102,7 +123,7 @@ To change the font of the app, follow these steps:
4. Go to the **`theme`** file and change the font name.
5. Go to the global styles and update the font in the **`body`** section.
-### **Modifying the Quiz Topic Screen or Adding New Categories**
+### Modifying the Quiz Topic Screen or Adding New Categories
To modify the Quiz Topics Screen or add new categories of topics/icons, follow these steps:
@@ -198,6 +219,38 @@ function Main() {
export default Main
```
+### Adding Pictures/Images to Questions
+
+In addition to text questions, you can also include images or pictures to enhance your questions. To add an image to a question, follow these steps:
+
+**1. Upload the Image**
+
+Start by placing your image file in the **`src/assets/images`** folder within your project directory.
+
+**2. Import the Image**
+
+Import the image in the quiz category data where you want to show it. For more details see `src/data/QuizQuestions/generalKnowledge.ts`
+
+**3. Link the Image to Your Question**
+
+Within your question object, add an image key. Then, reference the image you imported in step 2 at the top of your question.
+
+![add question with picture](./src/assets/images/add-images-to-questions.png)
+
+### How to Add Code Snippets in Questions
+
+Just like images, each question supports a **`code`** key, which is conditionally shown only if the question contains a code snippet.
+
+### How to format code snippet
+
+In the Xeven Quiz App, code snippets are pieces of code represented as text. To make them look nice and readable, we use an npm package called **`prismjs`**. This tool highlights the code with different colors so that it stands out and is easy to understand.
+
+To display code correctly, we need to pay attention to the spaces and how the code is structured, just like we do with the existing questions. This way, the code will appear neatly formatted and will be easier for users to read and comprehend.
+
+Here's an example image to illustrate the correct format for displaying code snippets:
+
+![code snippet format](./src/assets/images/code-snippet-format.png)
+
### Implementing Different Types of Quiz Questions
The Code Quiz App supports various types of quiz questions, including Multiple Choice Questions (MCQs), Multiple Answer Questions (MAQs), and True/False questions. To add different question types, you can modify the question components and their associated data structures. You can refer to the existing question formats in the **`data/QuizQuestions`** folder as examples when creating new questions.
@@ -218,10 +271,11 @@ Discover the Premium Version! Elevate your experience with the same amazing feat
### Premium Version Highlights
-- Elevate user experience by seamlessly toggling between light and dark modes with a single click from the top menu.
-- The user can pick a quiz topic on the first screen, like JavaScript, React, or Python.
+Almost all the features I have added in this GitHub open source repo.
+
+- Every time the quiz starts, the questions will be shuffled or randomized
+
- Users can skip a question if they are unsure of the answer. They can return to it later and answer it before submitting the quiz.
-- The PRO version also allows for adding code snippets in questions. You can easily assess the users' programming knowledge and skills.
## **Deploying the Quiz App to a Production Environment**
diff --git a/src/App.tsx b/src/App.tsx
index 6e59183..5fd742b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,17 +1,41 @@
+import { useState } from 'react'
import { ThemeProvider } from 'styled-components'
import Main from './components/Main'
-import QuizProvider from './context/QuizContext'
+import ToggleTheme from './components/ui/ToggleTheme'
+import QuizProvider from './context/QuizProvider'
import { GlobalStyles } from './styles/Global'
-import { theme as AppTheme } from './styles/Theme'
+import { themes } from './styles/Theme'
-const App = () => (
-
-
-
-
-
-
-)
+function App() {
+ const [currentTheme, setCurrentTheme] = useState(() => {
+ const savedTheme = localStorage.getItem('theme')
+ return savedTheme || 'light'
+ })
+
+ const toggleTheme = (e: React.ChangeEvent) => {
+ const { checked } = e.target
+ setCurrentTheme(checked ? 'dark' : 'light')
+ localStorage.setItem('theme', checked ? 'dark' : 'light')
+ }
+
+ const theme = currentTheme === 'light' ? themes.light : themes.dark
+
+ return (
+
+
+
+
+
+
+
+ )
+}
export default App
diff --git a/src/assets/icons/app-logo.svg b/src/assets/icons/app-logo.svg
index 7964adc..151adbc 100644
--- a/src/assets/icons/app-logo.svg
+++ b/src/assets/icons/app-logo.svg
@@ -1,21 +1,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/src/assets/icons/bulb.svg b/src/assets/icons/bulb.svg
new file mode 100644
index 0000000..9cad1f2
--- /dev/null
+++ b/src/assets/icons/bulb.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/icons/colored-logo.svg b/src/assets/icons/colored-logo.svg
deleted file mode 100644
index 6d642ff..0000000
--- a/src/assets/icons/colored-logo.svg
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/assets/icons/logo.svg b/src/assets/icons/logo.svg
deleted file mode 100644
index ec16e54..0000000
--- a/src/assets/icons/logo.svg
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/assets/icons/moon.svg b/src/assets/icons/moon.svg
new file mode 100644
index 0000000..85bc89b
--- /dev/null
+++ b/src/assets/icons/moon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/icons/sun.svg b/src/assets/icons/sun.svg
new file mode 100644
index 0000000..b4ebe6f
--- /dev/null
+++ b/src/assets/icons/sun.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/images/Xeven-Quiz-ReactJS-Quiz-App-Template.jpg b/src/assets/images/Xeven-Quiz-ReactJS-Quiz-App-Template.jpg
deleted file mode 100644
index 1656627..0000000
Binary files a/src/assets/images/Xeven-Quiz-ReactJS-Quiz-App-Template.jpg and /dev/null differ
diff --git a/src/assets/images/add-images-to-questions.png b/src/assets/images/add-images-to-questions.png
new file mode 100644
index 0000000..03e525d
Binary files /dev/null and b/src/assets/images/add-images-to-questions.png differ
diff --git a/src/assets/images/brand-logo.jpg b/src/assets/images/brand-logo.jpg
new file mode 100644
index 0000000..a17880e
Binary files /dev/null and b/src/assets/images/brand-logo.jpg differ
diff --git a/src/assets/images/car.jpg b/src/assets/images/car.jpg
new file mode 100644
index 0000000..eaefdb9
Binary files /dev/null and b/src/assets/images/car.jpg differ
diff --git a/src/assets/images/code-snippet-1.png b/src/assets/images/code-snippet-1.png
new file mode 100644
index 0000000..b061505
Binary files /dev/null and b/src/assets/images/code-snippet-1.png differ
diff --git a/src/assets/images/dish.jpg b/src/assets/images/dish.jpg
new file mode 100644
index 0000000..605f2da
Binary files /dev/null and b/src/assets/images/dish.jpg differ
diff --git a/src/assets/images/mosque.jpg b/src/assets/images/mosque.jpg
new file mode 100644
index 0000000..235f9ad
Binary files /dev/null and b/src/assets/images/mosque.jpg differ
diff --git a/src/assets/images/place.jpg b/src/assets/images/place.jpg
new file mode 100644
index 0000000..6da6f66
Binary files /dev/null and b/src/assets/images/place.jpg differ
diff --git a/src/assets/images/reptile.jpg b/src/assets/images/reptile.jpg
new file mode 100644
index 0000000..4991bd1
Binary files /dev/null and b/src/assets/images/reptile.jpg differ
diff --git a/src/components/Main/index.tsx b/src/components/Main/index.tsx
index b130dd8..a2e65fe 100644
--- a/src/components/Main/index.tsx
+++ b/src/components/Main/index.tsx
@@ -5,6 +5,7 @@ import { ScreenTypes } from '../../types'
import QuestionScreen from '../QuestionScreen'
import QuizDetailsScreen from '../QuizDetailsScreen'
+import QuizTopicsScreen from '../QuizTopicsScreen'
import ResultScreen from '../ResultScreen'
import SplashScreen from '../SplashScreen'
@@ -13,12 +14,13 @@ function Main() {
useEffect(() => {
setTimeout(() => {
- setCurrentScreen(ScreenTypes.QuizDetailsScreen)
+ setCurrentScreen(ScreenTypes.QuizTopicsScreen)
}, 1000)
}, [setCurrentScreen])
const screenComponents = {
[ScreenTypes.SplashScreen]: ,
+ [ScreenTypes.QuizTopicsScreen]: ,
[ScreenTypes.QuizDetailsScreen]: ,
[ScreenTypes.QuestionScreen]: ,
[ScreenTypes.ResultScreen]: ,
diff --git a/src/components/QuestionScreen/Answer/index.tsx b/src/components/QuestionScreen/Answer/index.tsx
index bd55968..9a30218 100644
--- a/src/components/QuestionScreen/Answer/index.tsx
+++ b/src/components/QuestionScreen/Answer/index.tsx
@@ -8,9 +8,9 @@ const AnswerStyle = styled.div<{ highlightAnswer: boolean }>`
font-weight: 400;
border: 1px solid
${({ highlightAnswer, theme }) =>
- highlightAnswer ? `${theme.colors.themeColor}` : `${theme.colors.lightGray}`};
+ highlightAnswer ? `${theme.colors.themeColor}` : `${theme.colors.border}`};
background-color: ${({ highlightAnswer, theme }) =>
- highlightAnswer ? `${theme.colors.lightPink}` : `${theme.colors.white}`};
+ highlightAnswer ? `${theme.colors.selectedAnswer}` : `${theme.colors.answerBg}`};
border-radius: 16px;
margin-top: clamp(13px, calc(10px + 6 * ((100vw - 600px) / 1320)), 16px);
cursor: pointer;
@@ -29,7 +29,7 @@ const AnswerStyle = styled.div<{ highlightAnswer: boolean }>`
`
const AnswerLabel = styled.label`
- padding: 16px;
+ padding: 18px;
display: flex;
cursor: pointer;
@media ${device.md} {
diff --git a/src/components/QuestionScreen/Question/index.tsx b/src/components/QuestionScreen/Question/index.tsx
index 3da6775..5c5acd1 100644
--- a/src/components/QuestionScreen/Question/index.tsx
+++ b/src/components/QuestionScreen/Question/index.tsx
@@ -3,7 +3,9 @@ import styled from 'styled-components'
import { device } from '../../../styles/BreakPoints'
+import CodeSnippet from '../../ui/CodeSnippet'
import Answer from '../Answer'
+import QuizImage from '../../ui/QuizImage'
const QuestionContainer = styled.div`
margin-top: 30px;
@@ -31,6 +33,8 @@ const QuestionStyle = styled.h2`
interface QuestionTypes {
question: string
+ code?: string
+ image?: string
type: string
choices: string[]
selectedAnswer: string[]
@@ -39,6 +43,8 @@ interface QuestionTypes {
const Question: FC = ({
question,
+ code,
+ image,
type,
choices,
selectedAnswer,
@@ -47,6 +53,10 @@ const Question: FC = ({
return (
{question}
+ {/* if question contains code snippet then show code */}
+ {code && }
+ {/* if question contains an image */}
+ {image && }
{choices.map((choice, index) => (
`
width: 900px;
min-height: 500px;
- background: ${({ theme }) => theme.colors.white};
+ background: ${({ theme }) => theme.colors.cardBackground};
border-radius: 4px;
padding: 30px 60px 80px 60px;
margin-bottom: 70px;
@@ -30,7 +30,7 @@ const QuizContainer = styled.div<{ selectedAnswer: boolean }>`
svg {
path {
fill: ${({ selectedAnswer, theme }) =>
- selectedAnswer ? `${theme.colors.white}` : `${theme.colors.darkGrayText}`};
+ selectedAnswer ? `${theme.colors.buttonText}` : `${theme.colors.darkGray}`};
}
}
}
@@ -71,7 +71,6 @@ const QuestionScreen: FC = () => {
const {
questions,
- setQuestions,
quizDetails,
result,
setResult,
@@ -83,7 +82,7 @@ const QuestionScreen: FC = () => {
const currentQuestion = questions[activeQuestion]
- const { question, type, choices, correctAnswers } = currentQuestion
+ const { question, type, choices, code, image, correctAnswers } = currentQuestion
const onClickNext = () => {
const isMatch: boolean =
@@ -107,6 +106,16 @@ const QuestionScreen: FC = () => {
const handleAnswerSelection = (e: React.ChangeEvent) => {
const { name, checked } = e.target
+ if (type === 'MAQs') {
+ if (selectedAnswer.includes(name)) {
+ setSelectedAnswer((prevSelectedAnswer) =>
+ prevSelectedAnswer.filter((element) => element !== name)
+ )
+ } else {
+ setSelectedAnswer((prevSelectedAnswer) => [...prevSelectedAnswer, name])
+ }
+ }
+
if (type === 'MCQs' || type === 'boolean') {
if (checked) {
setSelectedAnswer([name])
@@ -142,6 +151,8 @@ const QuestionScreen: FC = () => {
/>
theme.colors.themeColor};
- margin-top: 34px;
`
const DetailTextContainer = styled.div`
@@ -41,13 +44,12 @@ const QuizDetailsScreen = () => {
setCurrentScreen(ScreenTypes.QuestionScreen)
}
- // to shuffle or randomize quiz questions
- useShuffleQuestions()
-
return (
-
+
+
+
XEVEN QUIZ
@@ -63,12 +65,17 @@ const QuizDetailsScreen = () => {
Total time: {convertSeconds(totalTime)}
+
+ To save time, you can skip questions. Skipped questions will show up at the
+ end of the quiz.
+
}
iconPosition="left"
onClick={goToQuestionScreen}
+ bold
/>
diff --git a/src/components/QuizTopicsScreen/index.tsx b/src/components/QuizTopicsScreen/index.tsx
new file mode 100644
index 0000000..2313fbc
--- /dev/null
+++ b/src/components/QuizTopicsScreen/index.tsx
@@ -0,0 +1,117 @@
+import styled from 'styled-components'
+
+import { AppLogo } from '../../config/icons'
+import { useQuiz } from '../../context/QuizContext'
+import { quizTopics } from '../../data/quizTopics'
+import { device } from '../../styles/BreakPoints'
+import {
+ CenterCardContainer,
+ HighlightedText,
+ LogoContainer,
+ PageCenter,
+} from '../../styles/Global'
+import { ScreenTypes } from '../../types'
+
+import Button from '../ui/Button'
+
+const Heading = styled.h2`
+ font-size: 32px;
+ font-weight: 700;
+ margin-bottom: 20px;
+ text-align: center;
+`
+
+const DetailText = styled.p`
+ font-weight: 500;
+ font-size: 20px;
+ line-height: 29px;
+ text-align: center;
+`
+
+const SelectButtonContainer = styled.div`
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ max-width: 60%;
+ gap: 30px;
+ margin-top: 40px;
+ margin-bottom: 45px;
+ @media ${device.md} {
+ row-gap: 20px;
+ column-gap: 20px;
+ max-width: 100%;
+ }
+`
+
+interface SelectButtonProps {
+ active: boolean
+ disabled?: boolean
+}
+
+const SelectButton = styled.div`
+ background-color: ${({ disabled, theme }) =>
+ disabled ? `${theme.colors.disabledCard}` : `${theme.colors.selectTopicBg}`};
+ border: ${({ active, theme }) =>
+ active
+ ? `2px solid ${theme.colors.themeColor}`
+ : `1px solid ${theme.colors.disabledButton}`};
+ transition: background-color 0.4s ease-out;
+ border-radius: 10px;
+ padding: 14px 10px;
+ display: flex;
+ align-items: center;
+ cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
+ @media ${device.md} {
+ padding: 10px;
+ tap-highlight-color: transparent;
+ -webkit-tap-highlight-color: transparent;
+ }
+`
+
+const SelectButtonText = styled.span`
+ font-size: 18px;
+ font-weight: 600;
+ margin-left: 10px;
+ @media ${device.md} {
+ font-size: 16px;
+ font-weight: 500;
+ }
+`
+
+const QuizTopicsScreen: React.FC = () => {
+ const { quizTopic, selectQuizTopic, setCurrentScreen } = useQuiz()
+
+ const goToQuizDetailsScreen = () => {
+ setCurrentScreen(ScreenTypes.QuizDetailsScreen)
+ }
+
+ return (
+
+
+
+
+
+
+ WELCOME TO XEVEN QUIZ
+
+ Select topic below to start your Quiz.
+
+ {quizTopics.map(({ title, icon, disabled }) => (
+ !disabled && selectQuizTopic(title)}
+ disabled={disabled}
+ >
+ {icon}
+ {title}
+
+ ))}
+
+
+
+
+ )
+}
+
+export default QuizTopicsScreen
diff --git a/src/components/ResultScreen/RightAnswer/index.tsx b/src/components/ResultScreen/RightAnswer/index.tsx
index 0627b11..091f754 100644
--- a/src/components/ResultScreen/RightAnswer/index.tsx
+++ b/src/components/ResultScreen/RightAnswer/index.tsx
@@ -2,7 +2,6 @@ import { FC } from 'react'
import styled from 'styled-components'
import { HighlightedText } from '../../../styles/Global'
-import { theme } from '../../../styles/Theme'
interface RightAnswerProps {
correctAnswers: string[]
@@ -25,7 +24,7 @@ const RightAnswer: FC = ({ correctAnswers, choices }) => {
const label = String.fromCharCode(65 + choices.indexOf(item))
return (
-
+
{`${label} (${item})${index !== correctAnswers.length - 1 ? ', ' : ''}`}
)
diff --git a/src/components/ResultScreen/index.tsx b/src/components/ResultScreen/index.tsx
index c33a6e4..4dfd4a9 100644
--- a/src/components/ResultScreen/index.tsx
+++ b/src/components/ResultScreen/index.tsx
@@ -1,35 +1,30 @@
import { FC } from 'react'
import styled, { css } from 'styled-components'
-import { AppColoredLogo, Refresh } from '../../config/icons'
+import { AppLogo, Refresh } from '../../config/icons'
import { useQuiz } from '../../context/QuizContext'
import { device } from '../../styles/BreakPoints'
-import { Flex, ResizableBox } from '../../styles/Global'
+import { Flex, LogoContainer, ResizableBox } from '../../styles/Global'
import { refreshPage } from '../../utils/helpers'
import Button from '../ui/Button'
+import CodeSnippet from '../ui/CodeSnippet'
+import QuizImage from '../ui/QuizImage'
import ResultOverview from './ResultOverview'
import RightAnswer from './RightAnswer'
const ResultScreenContainer = styled.div`
max-width: 900px;
- margin: 80px auto;
+ margin: 60px auto;
@media ${device.md} {
width: 90%;
margin: 30px auto;
- }
-`
-
-const LogoContainer = styled.div`
- text-align: center;
- margin-bottom: 50px;
- @media ${device.md} {
- margin-bottom: 30px;
+ padding-top: 40px;
}
`
const InnerContainer = styled.div`
- background: ${({ theme }) => theme.colors.white};
+ background: ${({ theme }) => theme.colors.cardBackground};
border-radius: 4px;
margin: 0 auto;
margin-bottom: 40px;
@@ -72,11 +67,12 @@ interface AnswerProps {
}
const Answer = styled.li`
- border: 1px solid ${({ theme }) => theme.colors.lightGray};
+ border: 1px solid ${({ theme }) => theme.colors.border};
width: 90%;
@media ${device.md} {
width: 100%;
}
+ background: ${({ theme }) => theme.colors.answerBg};
border-radius: 16px;
font-size: clamp(16px, 5vw, 18px);
font-weight: 600;
@@ -132,13 +128,22 @@ const ResultScreen: FC = () => {
return (
-
+
{result.map(
(
- { question, choices, correctAnswers, selectedAnswer, score, isMatch },
+ {
+ question,
+ choices,
+ code,
+ image,
+ correctAnswers,
+ selectedAnswer,
+ score,
+ isMatch,
+ },
index: number
) => {
return (
@@ -149,6 +154,8 @@ const ResultScreen: FC = () => {
{question}
+ {code &&
}
+ {image &&
}
{choices.map((ans: string, index: number) => {
// Convert index to alphabet character
@@ -184,6 +191,7 @@ const ResultScreen: FC = () => {
onClick={onClickRetry}
icon={ }
iconPosition="left"
+ bold
/>
diff --git a/src/components/ui/Button/index.tsx b/src/components/ui/Button/index.tsx
index f389f47..4d7be54 100644
--- a/src/components/ui/Button/index.tsx
+++ b/src/components/ui/Button/index.tsx
@@ -7,6 +7,8 @@ interface ButtonTypes {
icon?: ReactNode
iconPosition?: 'left' | 'right'
outline?: boolean
+ bold?: boolean
+ big?: boolean
disabled?: boolean
}
@@ -16,10 +18,18 @@ const Button: FC = ({
icon,
iconPosition,
outline,
+ bold,
+ big,
disabled,
}) => {
return (
-
+
{icon && iconPosition === 'left' && {icon} }
{text}
{icon && iconPosition === 'right' && {icon} }
diff --git a/src/components/ui/Button/styled.tsx b/src/components/ui/Button/styled.tsx
index 7bcfba7..8275ea3 100644
--- a/src/components/ui/Button/styled.tsx
+++ b/src/components/ui/Button/styled.tsx
@@ -2,31 +2,36 @@ import styled from 'styled-components'
import { device } from '../../../styles/BreakPoints'
interface ButtonType {
outline?: boolean
+ bold?: boolean
+ big?: boolean
}
-export const ButtonStyle = styled.button.attrs(({ outline }: ButtonType) => ({
+export const ButtonStyle = styled.button.attrs(({ outline, bold, big }: ButtonType) => ({
outline,
+ bold,
+ big,
}))`
width: 195px;
min-height: 50px;
color: ${({ theme, outline }) =>
- outline ? theme.colors.themeColor : theme.colors.white};
+ outline ? theme.colors.outlineButtonText : theme.colors.buttonText};
background: ${({ theme, outline }) =>
- outline ? theme.colors.white : theme.colors.themeGradient};
+ outline ? theme.colors.cardBackground : theme.colors.buttonBackground};
font-size: clamp(16px, 5vw, 24px);
border: 1px solid
${({ theme, outline }) => (!outline ? 'none' : theme.colors.themeColor)};
- font-weight: 400;
+ font-weight: ${({ bold }) => (bold ? '700' : '400')};
border-radius: 9px;
display: flex;
justify-content: center;
align-items: center;
@media ${device.md} {
- width: 150px;
+ width: ${({ big }) => (big ? '180px' : '150px')};
min-height: 40px;
tap-highlight-color: transparent;
-webkit-tap-highlight-color: transparent;
}
+
&:active {
transform: scale(0.98);
box-shadow: ${({ theme }) => theme.shadows.activeButton};
@@ -34,7 +39,7 @@ export const ButtonStyle = styled.button.attrs(({ outline }: ButtonType) => ({
}
&:disabled {
background: ${({ theme }) => theme.colors.disabledButton};
- color: ${({ theme }) => theme.colors.darkGrayText};
+ color: ${({ theme }) => theme.colors.darkGray};
cursor: not-allowed;
transform: unset;
box-shadow: unset;
@@ -44,9 +49,19 @@ export const ButtonStyle = styled.button.attrs(({ outline }: ButtonType) => ({
export const IconLeft = styled.span`
margin-right: 10px;
display: flex;
+ svg {
+ path {
+ fill: ${({ theme }) => theme.colors.buttonText};
+ }
+ }
`
export const IconRight = styled.span`
margin-left: 20px;
display: flex;
+ svg {
+ path {
+ fill: ${({ theme }) => theme.colors.buttonText};
+ }
+ }
`
diff --git a/src/components/ui/CodeSnippet/index.tsx b/src/components/ui/CodeSnippet/index.tsx
new file mode 100644
index 0000000..b01b304
--- /dev/null
+++ b/src/components/ui/CodeSnippet/index.tsx
@@ -0,0 +1,29 @@
+import Prism from 'prismjs'
+import 'prismjs/themes/prism-solarizedlight.css'
+
+import React, { useEffect, useRef } from 'react'
+
+interface CodeSnippetProps {
+ code: string
+ language: string
+}
+
+const CodeSnippet: React.FC = ({ code, language }) => {
+ const codeRef = useRef(null)
+
+ useEffect(() => {
+ if (codeRef.current) {
+ Prism.highlightElement(codeRef.current)
+ }
+ }, [code])
+
+ return (
+
+
+ {code}
+
+
+ )
+}
+
+export default CodeSnippet
diff --git a/src/components/ui/ModalWrapper/index.tsx b/src/components/ui/ModalWrapper/index.tsx
index 8c5b475..77ad7b0 100644
--- a/src/components/ui/ModalWrapper/index.tsx
+++ b/src/components/ui/ModalWrapper/index.tsx
@@ -19,7 +19,7 @@ const ModalContainer = styled.div`
const ModalContent = styled.div`
width: 600px;
padding: 50px 25px;
- background-color: ${({ theme }) => theme.colors.white};
+ background: ${({ theme }) => theme.colors.cardBackground};
border-radius: 10px;
display: flex;
align-items: center;
@@ -65,7 +65,7 @@ const ModalWrapper: FC = ({
{icon}
{title}
{subtitle}
-
+
)
diff --git a/src/components/ui/QuizImage/index.tsx b/src/components/ui/QuizImage/index.tsx
new file mode 100644
index 0000000..48be194
--- /dev/null
+++ b/src/components/ui/QuizImage/index.tsx
@@ -0,0 +1,20 @@
+import { FC } from 'react'
+import styled from 'styled-components'
+
+interface QuizImageProps {
+ image: string
+}
+
+const ImageStyle = styled.img`
+ border-radius: 10px;
+ height: 400px;
+ max-width: 100%;
+ box-shadow: 6px 6px 2px ${({ theme }) => theme.colors.themeColor};
+ margin-bottom: 20px;
+`
+
+const QuizImage: FC = ({ image }) => (
+
+)
+
+export default QuizImage
diff --git a/src/components/ui/ToggleTheme/index.tsx b/src/components/ui/ToggleTheme/index.tsx
new file mode 100644
index 0000000..f2f291b
--- /dev/null
+++ b/src/components/ui/ToggleTheme/index.tsx
@@ -0,0 +1,117 @@
+import React, { FC } from 'react'
+import styled, { keyframes } from 'styled-components'
+import { Moon, Sun } from '../../../config/icons'
+
+const ToggleLabel = styled.label`
+ font-size: 16px;
+ font-weight: 700;
+ color: ${({ theme }) => theme.colors.themeText};
+ display: flex;
+ align-items: center;
+ position: absolute;
+ top: 12px;
+ right: 25px;
+`
+
+const SlideOn = keyframes`
+ 0% {
+ transform: translateX(0) scale(1);
+ }
+ 50% {
+ transform: translateX(15px) scale(1.1);
+ }
+ 100% {
+ transform: translateX(23px) scale(1);
+ }
+`
+
+const SlideOff = keyframes`
+ 0% {
+ transform: translateX(23px) scale(1);
+ }
+ 50% {
+ transform: translateX(15px) scale(1.1);
+ }
+ 100% {
+ transform: translateX(0px) scale(1);
+ }
+`
+
+const ToggleInput = styled.input`
+ visibility: hidden;
+ border: 1px solid red;
+ margin: 0;
+ &:checked + span {
+ background-color: ${({ theme }) => theme.colors.dark};
+ svg {
+ animation: ${SlideOn} 0.2s linear forwards;
+ }
+ }
+ &:checked + span::after {
+ background-color: ${({ theme }) => theme.colors.white};
+ animation: ${SlideOn} 0.2s linear forwards;
+ }
+`
+
+const Ball = styled.span`
+ width: 52px;
+ height: 26px;
+ background-color: ${({ theme }) => theme.colors.white};
+ display: inline-block;
+ cursor: pointer;
+ border-radius: 50px;
+ position: relative;
+ svg {
+ position: absolute;
+ top: 5px;
+ left: 7px;
+ z-index: 1;
+ animation: ${SlideOff} 0.2s linear forwards;
+ }
+ &::after {
+ content: '';
+ width: 21px;
+ height: 21px;
+ background-color: ${({ theme }) => theme.colors.dark};
+ border-radius: 50%;
+ display: inline-block;
+ position: absolute;
+ top: 3px;
+ left: 5px;
+ align-items: center;
+ justify-content: center;
+ animation: ${SlideOff} 0.2s linear forwards;
+ }
+`
+
+interface ToggleThemeProps {
+ onChange: (event: React.ChangeEvent) => void
+ id: string
+ value: string
+ checked: boolean
+ currentTheme: string
+}
+
+const ToggleTheme: FC = ({
+ onChange,
+ id,
+ value,
+ checked,
+ currentTheme,
+}) => {
+ return (
+
+ Mode:
+
+ {currentTheme === 'light' ? : }
+
+ )
+}
+
+export default ToggleTheme
diff --git a/src/config/icons.ts b/src/config/icons.ts
index e1b009e..dedb70d 100644
--- a/src/config/icons.ts
+++ b/src/config/icons.ts
@@ -1,10 +1,10 @@
import { ReactComponent as AppLogo } from '../assets/icons/app-logo.svg'
import { ReactComponent as CheckIcon } from '../assets/icons/check.svg'
-import { ReactComponent as AppColoredLogo } from '../assets/icons/colored-logo.svg'
import { ReactComponent as Next } from '../assets/icons/next.svg'
import { ReactComponent as Refresh } from '../assets/icons/refresh.svg'
import { ReactComponent as TimerIcon } from '../assets/icons/timer.svg'
-import { ReactComponent as Logo } from '../assets/icons/logo.svg'
import { ReactComponent as StartIcon } from '../assets/icons/start.svg'
+import { ReactComponent as Sun } from '../assets/icons/sun.svg'
+import { ReactComponent as Moon } from '../assets/icons/moon.svg'
-export { AppColoredLogo, AppLogo, CheckIcon, Next, Refresh, TimerIcon, Logo, StartIcon }
+export { AppLogo, CheckIcon, Next, Refresh, TimerIcon, StartIcon, Sun, Moon }
diff --git a/src/context/QuizContext.ts b/src/context/QuizContext.ts
new file mode 100644
index 0000000..4e57b7b
--- /dev/null
+++ b/src/context/QuizContext.ts
@@ -0,0 +1,29 @@
+import { createContext, useContext } from 'react'
+import { QuizContextTypes, ScreenTypes } from '../types'
+
+export const initialState: QuizContextTypes = {
+ currentScreen: ScreenTypes.SplashScreen,
+ setCurrentScreen: () => {},
+ quizTopic: 'React',
+ selectQuizTopic: () => {},
+ questions: [],
+ setQuestions: () => {},
+ result: [],
+ setResult: () => {},
+ timer: 15,
+ setTimer: () => {},
+ endTime: 0,
+ setEndTime: () => {},
+ quizDetails: {
+ totalQuestions: 0,
+ totalScore: 0,
+ totalTime: 0,
+ selectedQuizTopic: 'React',
+ },
+}
+
+export const QuizContext = createContext(initialState)
+
+export function useQuiz() {
+ return useContext(QuizContext)
+}
diff --git a/src/context/QuizContext.tsx b/src/context/QuizProvider.tsx
similarity index 69%
rename from src/context/QuizContext.tsx
rename to src/context/QuizProvider.tsx
index da92f3a..13ae3c0 100644
--- a/src/context/QuizContext.tsx
+++ b/src/context/QuizProvider.tsx
@@ -1,34 +1,7 @@
-import { ReactNode, createContext, useContext, useEffect, useState } from 'react'
-
+import { ReactNode, useEffect, useState } from 'react'
import { quiz } from '../data/QuizQuestions'
import { QuizContextTypes, Result, ScreenTypes } from '../types'
-
-const initialState: QuizContextTypes = {
- currentScreen: ScreenTypes.SplashScreen,
- setCurrentScreen: () => {},
- quizTopic: 'React',
- selectQuizTopic: () => {},
- questions: [],
- setQuestions: () => {},
- result: [],
- setResult: () => {},
- timer: 15,
- setTimer: () => {},
- endTime: 0,
- setEndTime: () => {},
- quizDetails: {
- totalQuestions: 0,
- totalScore: 0,
- totalTime: 0,
- selectedQuizTopic: 'React',
- },
-}
-
-export const QuizContext = createContext(initialState)
-
-export function useQuiz() {
- return useContext(QuizContext)
-}
+import { QuizContext, initialState } from './QuizContext'
type QuizProviderProps = {
children: ReactNode
diff --git a/src/data/QuizQuestions/generalKnowledge.ts b/src/data/QuizQuestions/generalKnowledge.ts
new file mode 100644
index 0000000..44edd0a
--- /dev/null
+++ b/src/data/QuizQuestions/generalKnowledge.ts
@@ -0,0 +1,76 @@
+// Question Types
+// 1. MCQs | Multiple Choice | single
+// 2. boolean | true/false | single
+// 3. MAQs | Multiple Answers | multiple
+
+import { Topic } from '.'
+import BrandLogo from '../../assets/images/brand-logo.jpg'
+import Car from '../../assets/images/car.jpg'
+import Dish from '../../assets/images/dish.jpg'
+import Mosque from '../../assets/images/mosque.jpg'
+import Place from '../../assets/images/place.jpg'
+import Reptile from '../../assets/images/reptile.jpg'
+
+export const generalKnowledge: Topic = {
+ topic: 'GeneralKnowledge',
+ level: 'Beginner',
+ totalQuestions: 6,
+ totalScore: 60,
+ totalTime: 60,
+ questions: [
+ {
+ question: 'What is the name of this reptile?',
+ image: Reptile,
+ choices: ['Snake', 'Turtle', 'Crocodile', 'Lizard'],
+ type: 'MCQs',
+ correctAnswers: ['Turtle'],
+ score: 10,
+ },
+ {
+ question: 'In which country is this historical place located?',
+ image: Place,
+ choices: ['China', 'Greece', 'India', 'Egypt'],
+ type: 'MCQs',
+ correctAnswers: ['China'],
+ score: 10,
+ },
+ {
+ question: 'This is a famous Pakistani dish. What is the name of this dish?',
+ image: Dish,
+ choices: ['Kebab', 'Haleem', 'Paya', 'Biryani'],
+ type: 'MCQs',
+ correctAnswers: ['Biryani'],
+ score: 10,
+ },
+ {
+ question: 'Which famous car is this?',
+ image: Car,
+ choices: ['Ford', 'Toyota', 'Mercedes', 'Honda'],
+ type: 'MCQs',
+ correctAnswers: ['Mercedes'],
+ score: 10,
+ },
+ {
+ question: 'To which renowned automobile brand does this logo belong?',
+ image: BrandLogo,
+ choices: ['Audi', 'Tesla', 'BMW', 'Hyundai'],
+ type: 'MCQs',
+ correctAnswers: ['Tesla'],
+ score: 10,
+ },
+ {
+ question: 'Do you recognize this iconic mosque? If so, where is it situated?',
+ image: Mosque,
+ choices: [
+ 'Faisal Mosque, Islamabad',
+ 'Sheikh Zayed Grand Mosque, UAE',
+ 'Taj Mahal, India',
+ 'Blue Mosque, Turkey',
+ ],
+
+ type: 'MCQs',
+ correctAnswers: ['Faisal Mosque, Islamabad'],
+ score: 10,
+ },
+ ],
+}
diff --git a/src/data/QuizQuestions/index.ts b/src/data/QuizQuestions/index.ts
index 8031c99..79d15ae 100644
--- a/src/data/QuizQuestions/index.ts
+++ b/src/data/QuizQuestions/index.ts
@@ -1,3 +1,6 @@
+import { generalKnowledge } from './generalKnowledge'
+import { javascript } from './javascript'
+import { python } from './python'
import { react } from './react'
// Question Types
@@ -14,6 +17,8 @@ export type Question = {
type: 'MCQs' | 'MAQs' | 'boolean'
correctAnswers: CorrectAnswers
score: number
+ code?: string
+ image?: string
}
export type Topic = {
@@ -26,5 +31,8 @@ export type Topic = {
}
export const quiz: Record = {
+ JavaScript: javascript,
React: react,
+ Python: python,
+ 'General Knowledge': generalKnowledge,
}
diff --git a/src/data/QuizQuestions/javascript.ts b/src/data/QuizQuestions/javascript.ts
new file mode 100644
index 0000000..8710122
--- /dev/null
+++ b/src/data/QuizQuestions/javascript.ts
@@ -0,0 +1,129 @@
+// Question Types
+// 1. MCQs | Multiple Choice | single
+// 2. boolean | true/false | single
+// 3. MAQs | Multiple Answers | multiple
+
+import { Topic } from '.'
+
+export const javascript: Topic = {
+ topic: 'Javascript',
+ level: 'Beginner',
+ totalQuestions: 14,
+ totalScore: 125,
+ totalTime: 240,
+ questions: [
+ {
+ question:
+ 'Which of the following are JavaScript data types? (Select all that apply)',
+ choices: ['String', 'Number', 'Function', 'Array'],
+ type: 'MAQs',
+ correctAnswers: ['String', 'Number', 'Array'],
+ score: 10,
+ },
+ {
+ question: 'The "this" keyword in JavaScript refers to the current function.',
+ choices: ['True', 'False'],
+ type: 'boolean',
+ correctAnswers: ['False'],
+ score: 5,
+ },
+ {
+ question: 'Which operator is used for strict equality comparison in JavaScript?',
+ choices: ['==', '===', '=', '!='],
+ type: 'MCQs',
+ correctAnswers: ['==='],
+ score: 10,
+ },
+ {
+ question:
+ 'Which of the following methods is used to add an element to the end of an array in JavaScript?',
+ choices: ['push()', 'pop()', 'shift()', 'unshift()'],
+ type: 'MCQs',
+ correctAnswers: ['push()'],
+ score: 10,
+ },
+ {
+ question: 'What is the value of x after executing the following code snippet?',
+ code: `let x = 5;
+x += 2;
+x *= 3;`,
+ choices: ['21', '25', '33', '35'],
+ type: 'MCQs',
+ correctAnswers: ['25'],
+ score: 10,
+ },
+ {
+ question: 'What is the output of the following code snippet?',
+ code: `console.log(typeof null);`,
+ choices: ['Object', 'Null', 'Undefined', 'NullObject'],
+ type: 'MCQs',
+ correctAnswers: ['Object'],
+ score: 10,
+ },
+ {
+ question: 'Which of the following is NOT a valid JavaScript variable name?',
+ choices: ['myVariable', '_variable', '123variable', '$variable'],
+ type: 'MCQs',
+ correctAnswers: ['123variable'],
+ score: 10,
+ },
+ {
+ question:
+ 'Which of the following methods is used to remove the last element from an array in JavaScript?',
+ choices: ['push()', 'pop()', 'shift()', 'unshift()'],
+ type: 'MCQs',
+ correctAnswers: ['pop()'],
+ score: 10,
+ },
+ {
+ question: 'JavaScript is a case-sensitive language.',
+ choices: ['True', 'False'],
+ type: 'boolean',
+ correctAnswers: ['True'],
+ score: 5,
+ },
+ {
+ question: 'What is the output of the following code snippet?',
+ code: `console.log(2 + '2');`,
+ choices: ['4', '22', '24', "'22'"],
+ type: 'MCQs',
+ correctAnswers: ['22'],
+ score: 10,
+ },
+ {
+ question: 'Which of the following is NOT a JavaScript data type?',
+ choices: ['String', 'Boolean', 'Integer', 'Object'],
+ type: 'MCQs',
+ correctAnswers: ['Integer'],
+ score: 10,
+ },
+ {
+ question:
+ 'Which of the following are valid JavaScript loop statements? (Select all that apply)',
+ choices: ['for', 'while', 'loop', 'do...while'],
+ type: 'MAQs',
+ correctAnswers: ['for', 'while', 'do...while'],
+ score: 10,
+ },
+ {
+ question: 'JavaScript is a statically typed language.',
+ choices: ['True', 'False'],
+ type: 'boolean',
+ correctAnswers: ['False'],
+ score: 5,
+ },
+ {
+ question:
+ 'Which of the following is a valid way to comment a single line in JavaScript?',
+ choices: [
+ '// This is a comment',
+ '/* This is a comment */',
+ '',
+ '# This is a comment',
+ ],
+ type: 'MCQs',
+ correctAnswers: ['// This is a comment'],
+ score: 10,
+ },
+ ],
+}
diff --git a/src/data/QuizQuestions/python.ts b/src/data/QuizQuestions/python.ts
new file mode 100644
index 0000000..6bbfa3c
--- /dev/null
+++ b/src/data/QuizQuestions/python.ts
@@ -0,0 +1,178 @@
+// Question Types
+// 1. MCQs | Multiple Choice | single
+// 2. boolean | true/false | single
+// 3. MAQs | Multiple Answers | multiple
+
+import { Topic } from '.'
+
+export const python: Topic = {
+ topic: 'Python',
+ level: 'Advanced',
+ totalQuestions: 14,
+ totalScore: 125,
+ totalTime: 360,
+ questions: [
+ {
+ question:
+ 'Which of the following are valid ways to handle exceptions in Python? (Select all that apply)',
+ choices: [
+ 'Using try-except blocks',
+ 'Using the finally block',
+ 'Using the raise statement',
+ 'Using assert statements',
+ ],
+ type: 'MAQs',
+ correctAnswers: [
+ 'Using try-except blocks',
+ 'Using the finally block',
+ 'Using the raise statement',
+ ],
+ score: 10,
+ },
+ {
+ question: 'In Python, strings are mutable objects.',
+ choices: ['True', 'False'],
+ type: 'boolean',
+ correctAnswers: ['False'],
+ score: 5,
+ },
+ {
+ question:
+ 'What is the difference between a shallow copy and a deep copy in Python?',
+ choices: [
+ 'A shallow copy creates a new object and copies the references to the original elements, while a deep copy creates a new object and recursively copies the elements',
+ 'A shallow copy creates a new object and copies the elements, while a deep copy creates a new object and references the original elements',
+ 'A shallow copy modifies the original object, while a deep copy creates a new object without modifying the original',
+ 'There is no difference between a shallow copy and a deep copy in Python',
+ ],
+ type: 'MCQs',
+ correctAnswers: [
+ 'A shallow copy creates a new object and copies the references to the original elements, while a deep copy creates a new object and recursively copies the elements',
+ ],
+ score: 10,
+ },
+ {
+ question:
+ 'Python supports multiple inheritance, allowing a class to inherit from multiple parent classes.',
+ choices: ['True', 'False'],
+ type: 'boolean',
+ correctAnswers: ['True'],
+ score: 5,
+ },
+ {
+ question: 'What is the output of the following Python code?',
+ code: 'print(list(filter(lambda x: x % 2 == 0, range(10))))',
+ choices: [
+ '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]',
+ '[0, 2, 4, 6, 8]',
+ '[1, 3, 5, 7, 9]',
+ '[0, 1, 2, 3, 4, 9]',
+ ],
+ type: 'MCQs',
+ correctAnswers: ['[0, 2, 4, 6, 8]'],
+ score: 10,
+ },
+ {
+ question: 'What is the purpose of the "__init__" method in a Python class?',
+ choices: [
+ 'To initialize the class attributes',
+ 'To define the constructor of the class',
+ 'To create a new instance of the class',
+ 'To define the destructor of the class',
+ ],
+ type: 'MCQs',
+ correctAnswers: ['To define the constructor of the class'],
+ score: 10,
+ },
+ {
+ question: 'Which of the following is NOT a built-in decorator in Python?',
+ choices: ['@staticmethod', '@classmethod', '@property', '@inheritance'],
+ type: 'MCQs',
+ correctAnswers: ['@inheritance'],
+ score: 10,
+ },
+ {
+ question:
+ 'The "pass" statement in Python is used as a placeholder and does nothing when executed.',
+ choices: ['True', 'False'],
+ type: 'boolean',
+ correctAnswers: ['True'],
+ score: 5,
+ },
+ {
+ question:
+ 'Which of the following are true about Python generators? (Select all that apply)',
+ choices: [
+ 'Generators are functions that can be paused and resumed',
+ 'Generators can only be used to generate numerical sequences',
+ 'Generators save memory by generating values on-the-fly',
+ 'Generators use the "yield" keyword to return values',
+ ],
+ type: 'MAQs',
+ correctAnswers: [
+ 'Generators are functions that can be paused and resumed',
+ 'Generators save memory by generating values on-the-fly',
+ 'Generators use the "yield" keyword to return values',
+ ],
+ score: 10,
+ },
+ {
+ question: 'What is the output of the following Python code?',
+ code: 'print(len({True: 1, False: 0, "True": 2}))',
+ choices: ['0', '1', '2', '3'],
+ type: 'MCQs',
+ correctAnswers: ['2'],
+ score: 10,
+ },
+ {
+ question: 'What is the purpose of the "with" statement in Python?',
+ choices: [
+ 'To define a context manager',
+ 'To handle exceptions',
+ 'To control the flow of a loop',
+ 'To create a new file',
+ ],
+ type: 'MCQs',
+ correctAnswers: ['To define a context manager'],
+ score: 10,
+ },
+ {
+ question:
+ 'Which of the following is NOT a valid method for string formatting in Python?',
+ choices: [
+ 'String interpolation using f-strings',
+ 'String interpolation using % operator',
+ 'String interpolation using format() method',
+ 'String interpolation using printf() function',
+ ],
+ type: 'MCQs',
+ correctAnswers: ['String interpolation using printf() function'],
+ score: 10,
+ },
+ {
+ question: 'What is the purpose of the "is" operator in Python?',
+ choices: [
+ 'To check if two objects have the same value',
+ 'To check if two objects have the same identity',
+ 'To check if two objects have the same type',
+ 'To check if two objects have the same length',
+ ],
+ type: 'MCQs',
+ correctAnswers: ['To check if two objects have the same identity'],
+ score: 10,
+ },
+ {
+ question:
+ 'Which of the following are valid ways to create a virtual environment in Python? (Select all that apply)',
+ choices: [
+ 'Using the "venv" module',
+ 'Using the "conda" package manager',
+ 'Using the "pipenv" package',
+ 'Using the "virtualenv" package',
+ ],
+ type: 'MAQs',
+ correctAnswers: ['Using the "venv" module', 'Using the "virtualenv" package'],
+ score: 10,
+ },
+ ],
+}
diff --git a/src/data/QuizQuestions/react.ts b/src/data/QuizQuestions/react.ts
index 1203493..a258e34 100644
--- a/src/data/QuizQuestions/react.ts
+++ b/src/data/QuizQuestions/react.ts
@@ -4,13 +4,14 @@
// 3. MAQs | Multiple Answers | multiple
import { Topic } from '.'
+import CodeSnippet1 from '../../assets/images/code-snippet-1.png'
export const react: Topic = {
topic: 'React',
level: 'Intermediate',
- totalQuestions: 6,
- totalScore: 45,
- totalTime: 180,
+ totalQuestions: 11,
+ totalScore: 95,
+ totalTime: 600,
questions: [
{
question: 'What is JSX in React?',
@@ -45,6 +46,48 @@ export const react: Topic = {
correctAnswers: ['To define the structure and appearance of the user interface'],
score: 10,
},
+ {
+ question:
+ 'Which of the following are valid React lifecycle methods? (Select all that apply)',
+ choices: [
+ 'componentWillMount',
+ 'componentDidMount',
+ 'componentWillUpdate',
+ 'componentDidUpdate',
+ ],
+ type: 'MAQs',
+ correctAnswers: ['componentDidMount', 'componentWillUpdate', 'componentDidUpdate'],
+ score: 10,
+ },
+ {
+ question: 'What will be the output of the following React code?',
+ code: `import React, { useState } from 'react';
+
+const Counter = () => {
+ const [count, setCount] = useState(0);
+
+ const increment = () => {
+ setCount(count + 1);
+ };
+
+ return (
+
+
Count: {count}
+
Increment
+
+ );
+};
+
+const App = () => {
+ return ;
+};
+
+export default App;`,
+ choices: ['Count: 0', 'Count: 1', 'Count: undefined', 'An error will occur'],
+ type: 'MCQs',
+ correctAnswers: ['Count: 0'],
+ score: 10,
+ },
{
question:
'In React, props are used to pass data from parent components to child components.',
@@ -53,6 +96,31 @@ export const react: Topic = {
correctAnswers: ['True'],
score: 5,
},
+ {
+ question: 'What is the output of the following code snippet?',
+ image: CodeSnippet1,
+ choices: ['0', '1', '2', 'undefined'],
+ type: 'MCQs',
+ correctAnswers: ['0'],
+ score: 10,
+ },
+ {
+ question:
+ 'Which of the following are valid ways to conditionally render content in React? (Select all that apply)',
+ choices: [
+ 'Using the if-else statement',
+ 'Using the ternary operator',
+ 'Using the switch statement',
+ 'Using the && operator',
+ ],
+ type: 'MAQs',
+ correctAnswers: [
+ 'Using the if-else statement',
+ 'Using the ternary operator',
+ 'Using the && operator',
+ ],
+ score: 10,
+ },
{
question: 'In React, what is the purpose of keys in lists?',
choices: [
@@ -65,6 +133,37 @@ export const react: Topic = {
correctAnswers: ['To provide a unique identifier for each item in the list'],
score: 10,
},
+ {
+ question: 'What will be the result of the following React code?',
+ code: `import React from 'react';
+
+class Button extends React.Component {
+ handleClick() {
+ console.log('Button clicked');
+ }
+
+ render() {
+ return Click me ;
+ }
+}
+
+const App = () => {
+ return ;
+};
+
+export default App;`,
+ choices: [
+ 'The "Button clicked" message will be logged to the console when the button is clicked',
+ 'The button will not respond to the click event',
+ 'An error will occur due to the incorrect usage of onClick',
+ 'The button will display but nothing will happen when clicked',
+ ],
+ type: 'MCQs',
+ correctAnswers: [
+ 'The "Button clicked" message will be logged to the console when the button is clicked',
+ ],
+ score: 10,
+ },
{
question: 'React uses a virtual DOM to optimize rendering performance.',
choices: ['True', 'False'],
diff --git a/src/data/quizTopics.tsx b/src/data/quizTopics.tsx
index 2efac17..0c32a91 100644
--- a/src/data/quizTopics.tsx
+++ b/src/data/quizTopics.tsx
@@ -8,6 +8,7 @@ import { ReactComponent as Kotlin } from '../assets/icons/kotlin.svg'
import { ReactComponent as Laravel } from '../assets/icons/laravel.svg'
import { ReactComponent as Python } from '../assets/icons/python.svg'
import { ReactComponent as ReactIcon } from '../assets/icons/react.svg'
+import { ReactComponent as BulbIcon } from '../assets/icons/bulb.svg'
type QuizTopic = {
title: string
@@ -28,6 +29,10 @@ export const quizTopics: QuizTopic[] = [
title: 'Python',
icon: ,
},
+ {
+ title: 'General Knowledge',
+ icon: ,
+ },
{
title: 'Gatsby',
icon: ,
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 9aa82c2..abcf277 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -1,4 +1,3 @@
-import useShuffleQuestions from './useShuffleQuestions'
import useTimer from './useTimer'
-export { useShuffleQuestions, useTimer }
+export { useTimer }
diff --git a/src/hooks/useShuffleQuestions.ts b/src/hooks/useShuffleQuestions.ts
deleted file mode 100644
index 11ddb7c..0000000
--- a/src/hooks/useShuffleQuestions.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { useEffect } from 'react'
-
-import { useQuiz } from '../context/QuizContext'
-import { ScreenTypes } from '../types'
-import { shuffleArray } from '../utils/helpers'
-
-export const useShuffleQuestions = () => {
- const { setQuestions, currentScreen, questions } = useQuiz()
-
- useEffect(() => {
- if (currentScreen === ScreenTypes.QuizDetailsScreen) {
- setQuestions(shuffleArray(questions))
- }
- }, [currentScreen])
-}
-
-export default useShuffleQuestions
diff --git a/src/logo.svg b/src/logo.svg
new file mode 100644
index 0000000..9dfc1c0
--- /dev/null
+++ b/src/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/styles/Global.ts b/src/styles/Global.ts
index 2ada69d..1f0e4c4 100644
--- a/src/styles/Global.ts
+++ b/src/styles/Global.ts
@@ -24,8 +24,8 @@ body {
text-rendering: optimizeSpeed;
font-family: ${({ theme }) => theme.fonts.anekMalayalam}, sans-serif;
font-size: 1rem;
- color: ${({ theme }) => theme.colors.text};
- background-color: ${({ theme }) => theme.colors.background};
+ color: ${({ theme }) => theme.colors.themeText};
+ background: ${({ theme }) => theme.colors.background};
line-height: 1;
overflow-x: hidden;
position: relative;
@@ -136,6 +136,7 @@ export const PageCenter = styled.div`
flex-direction: column;
align-items: center;
padding: 20px;
+ padding-top: 50px;
// due to flex direction column
${({ justifyCenter }) =>
justifyCenter &&
@@ -180,7 +181,7 @@ export const Flex = styled.div`
`
export const CenterCardContainer = styled.div`
- background: ${({ theme }) => theme.colors.white};
+ background: ${({ theme }) => theme.colors.cardBackground};
border-radius: 4px;
min-width: 773px;
min-height: 620px;
@@ -194,8 +195,26 @@ export const CenterCardContainer = styled.div`
}
`
-export const HighlightedText = styled.span`
- color: ${({ color, theme }) => (color ? color : theme.colors.themeColor)};
+export const HighlightedText = styled.span<{ themeText?: boolean }>`
+ color: ${({ themeText, theme }) =>
+ themeText ? theme.colors.themeText : theme.colors.themeColor};
+`
+
+export const LogoContainer = styled.div`
+ text-align: center;
+ margin-bottom: 50px;
+ @media ${device.md} {
+ margin-bottom: 30px;
+ }
+ svg {
+ width: 220px;
+ rect {
+ stroke: ${({ theme }) => theme.colors.appLogo};
+ }
+ path {
+ fill: ${({ theme }) => theme.colors.appLogo};
+ }
+ }
`
interface ResizableBoxProps {
diff --git a/src/styles/Theme.ts b/src/styles/Theme.ts
index 35ea79a..3aaedd2 100644
--- a/src/styles/Theme.ts
+++ b/src/styles/Theme.ts
@@ -1,42 +1,94 @@
-import { DefaultTheme } from 'styled-components'
+import { Theme } from './styled'
-export const theme: DefaultTheme = {
- colors: {
- primaryText: '#11052C', // question text color
- secondaryText: '#2D264B', // answer text color
- themeColor: '#800080',
- themeGradient: 'linear-gradient(to right,#800080, #FFC0CB)',
- text: '#000000',
- background: '#E5E5E5',
- success: '#12B40E',
- successLight: '#DDFFDC',
- danger: '#FF143E',
- dangerLight: '#FFD7DE',
- lightPink: '#FFD6FF',
- infoText: '#FF783F', // skip button text
- infoBackground: '#ffb23f26', // skip button background
- codeBackground: '#F9F9F9',
- disabledCard: '#fbf4ecbc',
- disabledButton: '#e7e8e9',
- white: '#FFFFFF',
- black: '#000000',
- grayText: '#9993A3',
- darkGrayText: '#9fa3a9',
- darkerGray: '#817a8e',
- lightGray: '#eaeaea',
- darkText: '',
+export const themes: Record = {
+ light: {
+ colors: {
+ primaryText: '#11052C', // question text color
+ secondaryText: '#2D264B', // answer text color
+ themeText: '#000000',
+ themeColor: '#800080',
+ themeGradient: 'linear-gradient(to right,#800080, #FFC0CB)',
+ background: '#E5E5E5',
+ cardBackground: '#FFFFFF',
+ selectTopicBg: '#FFFFFF',
+ appLogo: '#000000',
+ buttonText: '#FFFFFF',
+ outlineButtonText: '#800080',
+ buttonBackground: 'linear-gradient(90.04deg, #800080 0.03%, #FFC0CB 99.96%)',
+ selectedAnswer: '#FFD6FF',
+ infoText: '#FF783F', // skip tag text
+ infoBackground: '#ffb23f26', // skip tag background
+ border: '#EAEAEA',
+ answerBg: '#ffffff',
+ disabledCard: '#fbf4ecbc',
+ disabledButton: '#e7e8e9',
+ success: '#12B40E',
+ successLight: '#DDFFDC',
+ danger: '#FF143E',
+ dangerLight: '#FFD7DE',
+ white: '#FFFFFF',
+ black: '#000000',
+ dark: '#282526',
+ darkGray: '#9fa3a9',
+ darkerGray: '#817a8e',
+ },
+ fonts: {
+ anekMalayalam: 'Anek Malayalam',
+ },
+ shadows: {
+ activeButton: '3px 2px 22px 1px rgba(0, 0, 0, 0.24)',
+ },
+ paddings: {
+ container: '15px',
+ pageTop: '30px',
+ },
+ margins: {
+ pageTop: '30px',
+ },
},
- fonts: {
- anekMalayalam: 'Anek Malayalam',
- },
- shadows: {
- activeButton: '3px 2px 22px 1px rgba(0, 0, 0, 0.24)',
- },
- paddings: {
- container: '15px',
- pageTop: '30px',
- },
- margins: {
- pageTop: '30px',
+ dark: {
+ colors: {
+ primaryText: '#FFFFFF', // question text color
+ secondaryText: '#FFFFFF', // answer text color
+ themeText: '#FFFFFF',
+ themeColor: '#C000C0',
+ themeGradient: 'linear-gradient(90deg, #0e050e 0%, #281e20 100%)',
+ background: 'linear-gradient(90deg, #0e050e 0%, #281e20 100%)',
+ cardBackground: '#241a1a',
+ selectTopicBg: '#21191C',
+ appLogo: '#FFFFFF',
+ buttonText: '#000000',
+ outlineButtonText: '#ffffff',
+ buttonBackground: 'linear-gradient(90.04deg, #800080 0.03%, #FFC0CB 99.96%)',
+ selectedAnswer: '#151113',
+ infoText: '#FF783F', // skip tag text
+ infoBackground: '#ffb23f26', // skip tag background
+ border: 'transparent',
+ answerBg: '#151113',
+ disabledCard: '#00000080',
+ disabledButton: '#181214',
+ success: '#12B40E',
+ successLight: '#151113',
+ danger: '#FF143E',
+ dangerLight: '#151113',
+ white: '#FFFFFF',
+ black: '#000000',
+ dark: '#282526',
+ darkGray: '#9fa3a9',
+ darkerGray: '#817a8e',
+ },
+ fonts: {
+ anekMalayalam: 'Anek Malayalam',
+ },
+ shadows: {
+ activeButton: '3px 2px 22px 1px rgba(0, 0, 0, 0.24)',
+ },
+ paddings: {
+ container: '15px',
+ pageTop: '30px',
+ },
+ margins: {
+ pageTop: '30px',
+ },
},
}
diff --git a/src/styles/styled.d.ts b/src/styles/styled.d.ts
index 0aeda42..3fb74c1 100644
--- a/src/styles/styled.d.ts
+++ b/src/styles/styled.d.ts
@@ -1,46 +1,52 @@
// import original module declarations
import 'styled-components'
-// and extend them!
-declare module 'styled-components' {
- export interface DefaultTheme {
- colors: {
- primaryText: '#11052C' // question text color
- secondaryText: '#2D264B' // answer text color
- themeColor: '#800080'
- themeGradient: 'linear-gradient(to right,#800080, #FFC0CB)'
- text: '#000000'
- background: '#E5E5E5'
- success: '#12B40E'
- successLight: '#DDFFDC'
- danger: '#FF143E'
- dangerLight: '#FFD7DE'
- lightPink: '#FFD6FF'
- infoText: '#FF783F' // skip button text
- infoBackground: '#ffb23f26' // skip button background
- codeBackground: '#F9F9F9'
- disabledCard: '#fbf4ecbc'
- disabledButton: '#e7e8e9'
- white: '#FFFFFF'
- black: '#000000'
- grayText: '#9993A3'
- darkGrayText: '#9fa3a9'
- darkerGray: '#817a8e'
- lightGray: '#eaeaea'
- darkText: ''
- }
- fonts: {
- anekMalayalam: 'Anek Malayalam'
- }
- shadows: {
- activeButton: '3px 2px 22px 1px rgba(0, 0, 0, 0.24)'
- }
- paddings: {
- container: '15px'
- pageTop: '30px'
- }
- margins: {
- pageTop: '30px'
- }
+export interface Theme {
+ colors: {
+ primaryText: string
+ secondaryText: string
+ themeText: string
+ themeColor: string
+ themeGradient: string
+ background: string
+ cardBackground: string
+ selectTopicBg: string
+ appLogo: string
+ buttonText: string
+ outlineButtonText: string
+ buttonBackground: string
+ selectedAnswer: string
+ infoText: string
+ infoBackground: string
+ border: string
+ answerBg: string
+ disabledCard: string
+ disabledButton: string
+ success: string
+ successLight: string
+ danger: string
+ dangerLight: string
+ white: string
+ black: string
+ dark: string
+ darkGray: string
+ darkerGray: string
+ }
+ fonts: {
+ anekMalayalam: string
+ }
+ shadows: {
+ activeButton: string
+ }
+ paddings: {
+ container: string
+ pageTop: string
}
+ margins: {
+ pageTop: string
+ }
+}
+
+declare module 'styled-components' {
+ export interface DefaultTheme extends Theme {}
}
diff --git a/src/types/index.ts b/src/types/index.ts
index 9a2f05e..b99fc72 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -3,6 +3,7 @@ import { Question } from '../data/QuizQuestions'
export enum ScreenTypes {
SplashScreen,
+ QuizTopicsScreen,
QuizDetailsScreen,
QuestionScreen,
ResultScreen,
@@ -11,7 +12,6 @@ export enum ScreenTypes {
export interface Result extends Question {
selectedAnswer: string[]
isMatch: boolean
- score: number
}
export type QuizContextTypes = {