diff --git a/src/pages/marcos/5050.mp3 b/src/pages/marcos/5050.mp3 new file mode 100644 index 0000000..3ec0118 Binary files /dev/null and b/src/pages/marcos/5050.mp3 differ diff --git a/src/pages/marcos/App.css b/src/pages/marcos/App.css new file mode 100644 index 0000000..0743e52 --- /dev/null +++ b/src/pages/marcos/App.css @@ -0,0 +1,234 @@ +@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap"); + +:root { + /* dark shades of primary color*/ + --clr-primary-1: hsl(205, 86%, 17%); + --clr-primary-2: hsl(205, 77%, 27%); + --clr-primary-3: hsl(205, 72%, 37%); + --clr-primary-4: hsl(205, 63%, 48%); + /* primary/main color */ + --clr-primary-5: #49a6e9; + /* lighter shades of primary color */ + --clr-primary-6: hsl(205, 89%, 70%); + --clr-primary-7: hsl(205, 90%, 76%); + --clr-primary-8: hsl(205, 86%, 81%); + --clr-primary-9: hsl(205, 90%, 88%); + --clr-primary-10: hsl(205, 100%, 96%); + /* darkest grey - used for headings */ + --clr-grey-1: hsl(209, 61%, 16%); + --clr-grey-2: hsl(211, 39%, 23%); + --clr-grey-3: hsl(209, 34%, 30%); + --clr-grey-4: hsl(209, 28%, 39%); + /* grey used for paragraphs */ + --clr-grey-5: hsl(210, 22%, 49%); + --clr-grey-6: hsl(209, 23%, 60%); + --clr-grey-7: hsl(211, 27%, 70%); + --clr-grey-8: hsl(210, 31%, 80%); + --clr-grey-9: hsl(212, 33%, 89%); + --clr-grey-10: hsl(210, 36%, 96%); + --clr-white: #fff; + --clr-red-dark: hsl(360, 67%, 44%); + --clr-red-light: hsl(360, 71%, 66%); + --clr-green-dark: hsl(125, 67%, 44%); + --clr-green-light: hsl(125, 71%, 66%); + --clr-secondary: hsla(182, 63%, 54%); + --clr-black: #222; + --ff-primary: "Roboto", sans-serif; + --ff-secondary: "Open Sans", sans-serif; + --transition: all 0.3s linear; + + --ff-primary: "Roboto", sans-serif; + --ff-secondary: "Open Sans", sans-serif; +} +:focus { + outline: 3px var(--clr-grey-2) solid; +} + +*, +::after, +::before { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background: rgb(2, 0, 36); + background: linear-gradient( + 90deg, + rgba(2, 0, 36, 1) 0%, + rgba(1, 45, 120, 0.05926120448179273) 0%, + rgba(0, 38, 140, 1) 0%, + rgba(0, 32, 156, 0.6194852941176471) 55%, + rgba(0, 32, 156, 0.6194852941176471) 59% + ); + font-family: var(--ff-secondary); + padding: 1rem 0.5rem; +} +.heading { + color: var(--clr-red-light); + font-size: 2rem; +} + +.quiz-container { + max-width: 500px; + margin: 2rem auto; + padding: 20px; + background-color: var(--clr-grey-10); + border-radius: 8px; + box-shadow: 0 8px 6px rgba(16, 78, 122, 0.87); +} +.sidebar { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + margin-bottom: 1rem; +} + +button { + margin-left: 10px; + padding: 10px 16px; + border: none; + border-radius: 4px; + background-color: #4caf50; + color: #ffffff; + font-size: 14px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +button:disabled { + background-color: #cccccc; + cursor: not-allowed; +} + +h2 { + margin-bottom: 10px; + font-size: 24px; + font-weight: 600; +} + +.timer { + margin-bottom: 20px; + font-size: 16px; + font-weight: 500; +} + +p { + margin-bottom: 10px; + font-size: 16px; + line-height: 1.4; +} + +.hint { + margin-bottom: 10px; + font-size: 14px; + font-style: italic; + color: #888888; +} + +ul { + list-style-type: none; + padding: 0; +} + +li { + margin-bottom: 10px; +} + +.option-box { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); + column-gap: 2rem; +} +.option-button { + display: block; + width: 100%; + padding: 12px; + border: 2px solid #eeeeee; + border-radius: 4px; + background-color: #ffffff; + color: #333333; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.3s ease; + border-radius: 10px; + text-transform: lowercase; +} + +.option-button:hover { + background-color: var(--clr-primary-9); +} + +.option-button.correct { + background-color: var(--clr-green-dark); + color: var(--clr-white); +} + +.option-button.incorrect { + background-color: var(--clr-red-dark); + color: var(--clr-white); +} + +.selected-answer { + margin-top: 10px; + font-size: 16px; + font-weight: 500; +} + +.correct-answer { + color: #4caf50; + background: none; +} + +.incorrect-answer { + color: #f44336; +} + +.submit-button { + display: block; + width: 100%; + margin-top: 20px; + padding: 12px; + border: none; + border-radius: 4px; + background-color: #2196f3; + color: #ffffff; + font-size: 16px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.submit-button:hover { + background-color: #1976d2; +} + +.result-text { + margin-bottom: 10px; + font-size: 28px; + font-weight: 600; + text-align: center; +} + +.result-score { + margin-bottom: 20px; + font-size: 18px; + font-weight: 500; + text-align: center; +} + +.result-buttons { + display: flex; + justify-content: center; +} + +.result-buttons button { + margin-left: 10px; +} diff --git a/src/pages/marcos/App.tsx b/src/pages/marcos/App.tsx new file mode 100644 index 0000000..b54a24e --- /dev/null +++ b/src/pages/marcos/App.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import "./App.css"; +import QuizComponent from "./quizcomponents"; + +const App: React.FC = () => { + return ( +
+ +
+ ); +}; + +export default App; diff --git a/src/pages/marcos/correct.mp3 b/src/pages/marcos/correct.mp3 new file mode 100644 index 0000000..145ea8a Binary files /dev/null and b/src/pages/marcos/correct.mp3 differ diff --git a/src/pages/marcos/data.tsx b/src/pages/marcos/data.tsx new file mode 100644 index 0000000..7ae0ceb --- /dev/null +++ b/src/pages/marcos/data.tsx @@ -0,0 +1,94 @@ +interface Question { + id: number; + question: string; + options: string[]; + answer: string; + hint: string; +} + +export const initialQuestions: Question[] = [ + { + id: 1, + question: 'What is the correct HTML tag for inserting a line break?', + options: ['
', '', '', ''], + answer: '
', + hint: '
', + }, + { + id: 2, + question: 'Which attribute is used to define inline styles in HTML?', + options: ['class', 'id', 'style', 'inline'], + answer: 'style', + hint: 'style', + }, + { + id: 3, + question: 'What is the correct HTML tag for the largest heading?', + options: ['

', '', '
', ' '], + answer: '

', + hint: 'First is the biggest', + }, + { + id: 4, + question: + 'Which element is used to create an ordered numbered list in HTML?', + options: ['
    ', '
      ', '
    • ', '
      '], + answer: '
        ', + hint: '
          is for unordered list', + }, + { + id: 5, + question: 'What does the "alt" attribute in the tag provide?', + options: [ + 'It specifies the alignment of the image.', + ' It defines the alternative text for the image.', + 'It sets the border color of the image.', + 'It determines the image source URL.', + ], + answer: 'It defines the alternative text for the image.', + hint: 'To describe the image', + }, + { + id: 6, + question: 'What does the tag do in HTML?', + options: [ + 'It creates a hyperlink.', + 'to add image inside webpage/website. ', + 'It displays a video.', + 'It changes the font style.', + ], + answer: 'to add image inside webpage/website. ', + hint: 'Display an image', + }, + { + id: 7, + question: + 'Which attribute is used to specify the URL of the page that the link goes to?', + options: ['src', 'href', 'link', 'url'], + answer: 'href', + hint: 'href', + }, + { + id: 8, + question: + 'Which attribute is used to specify the URL of an external CSS file?', + options: ['src', 'href', 'link', 'url'], + answer: 'link', + hint: 'link', + }, + { + id: 9, + question: + 'Which attribute is used to make an input field mandatory in HTML?', + options: ['required', 'mandatory', 'validate', 'constraint'], + answer: 'required', + hint: 'required', + }, + { + id: 10, + question: 'Which tag is used to define a header in HTML?', + options: ['', '
          ', '

          ', ''], + answer: '<header>', + hint: 'The answer is in the question!', + }, +]; diff --git a/src/pages/marcos/idea.mp3 b/src/pages/marcos/idea.mp3 new file mode 100644 index 0000000..9bfc54f Binary files /dev/null and b/src/pages/marcos/idea.mp3 differ diff --git a/src/pages/marcos/index.tsx b/src/pages/marcos/index.tsx new file mode 100644 index 0000000..1bef622 --- /dev/null +++ b/src/pages/marcos/index.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; + +const root = ReactDOM.createRoot( + document.getElementById("root") as HTMLElement +); +root.render( + <React.StrictMode> + <App /> + </React.StrictMode> +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals diff --git a/src/pages/marcos/logo.png b/src/pages/marcos/logo.png new file mode 100644 index 0000000..3e05f8e Binary files /dev/null and b/src/pages/marcos/logo.png differ diff --git a/src/pages/marcos/quizcomponents.tsx b/src/pages/marcos/quizcomponents.tsx new file mode 100644 index 0000000..1a40c95 --- /dev/null +++ b/src/pages/marcos/quizcomponents.tsx @@ -0,0 +1,221 @@ +import React, { useState, useEffect } from "react"; +import "./App.css"; +import { initialQuestions } from "./data"; +import logo from "./logo.png"; +import correctSound from "./correct.mp3"; +import wrongSound from "./wrong.mp3"; +import ideaSound from "./idea.mp3"; +import fiftySound from "./idea.mp3"; + +const QuizGame: React.FC = () => { + const [currentQuestion, setCurrentQuestion] = useState(0); + const [score, setScore] = useState(0); + const [showResult, setShowResult] = useState(false); + const [selectedOption, setSelectedOption] = useState(""); + const [timeRemaining, setTimeRemaining] = useState(20); + const [showHint, setShowHint] = useState(false); + const [showFiftyFifty, setShowFiftyFifty] = useState(false); + const [isFiftyFiftyUsed, setFiftyFiftyUsed] = useState(false); + const [isHintUsed, setHintUsed] = useState(false); + const [questions, setQuestions] = useState([...initialQuestions]); + + const correctAudio = new Audio(correctSound); + const wrongAudio = new Audio(wrongSound); + const ideaAudio = new Audio(ideaSound); + const fiftyAudio = new Audio(fiftySound); + + useEffect(() => { + let timer: NodeJS.Timeout | null = null; + + if (timeRemaining > 0 && !showResult) { + timer = setTimeout(() => { + setTimeRemaining((prevTime) => prevTime - 1); + }, 1000); + } else if (timeRemaining === 0 && !showResult) { + handleAnswer(""); // Automatically submit answer when time runs out + } + + return () => { + if (timer) { + clearTimeout(timer); + } + }; + }, [timeRemaining, showResult]); + + const handleAnswer = (option: string) => { + const question = questions[currentQuestion]; + + if (option === question.answer) { + setScore((prevScore) => prevScore + 1); + correctAudio.play(); // Play the correct sound + } else { + wrongAudio.play(); // Play the wrong sound + } + + if (currentQuestion + 1 === questions.length) { + setShowResult(true); + } else { + setCurrentQuestion((prevQuestion) => prevQuestion + 1); + setTimeRemaining(20); // Reset timer for the next question + } + + setSelectedOption(""); + setShowHint(false); + setShowFiftyFifty(false); + }; + + const handleHint = () => { + setShowHint(true); + setHintUsed(true); + ideaAudio.play(); + }; + + const handleFiftyFifty = () => { + fiftyAudio.play(); + if (!showFiftyFifty && !showResult && !isFiftyFiftyUsed) { + const question = questions[currentQuestion]; + const correctAnswer = question.answer; + + // Randomly select two incorrect options to remove + const incorrectOptions = question.options.filter( + (option) => option !== correctAnswer + ); + const shuffledIncorrectOptions = shuffleArray(incorrectOptions); + const removedOptions = shuffledIncorrectOptions.slice(0, 2); + + const updatedOptions = question.options.filter( + (option) => + option === correctAnswer || removedOptions.indexOf(option) === -1 + ); + + question.options = updatedOptions; + + setShowFiftyFifty(true); + setFiftyFiftyUsed(true); + + const updatedQuestions = [...questions]; // Create a copy of the questions array + updatedQuestions[currentQuestion] = question; // Update the current question in the array + + setQuestions(updatedQuestions); + } + }; + + const handleRestart = () => { + setCurrentQuestion(0); + setScore(0); + setShowResult(false); + setSelectedOption(""); + setTimeRemaining(20); + setShowHint(false); + setShowFiftyFifty(false); + setFiftyFiftyUsed(false); + setHintUsed(false); + + const restoredQuestions = initialQuestions.map((question) => { + return { + ...question, + options: shuffleArray([...question.options]), // Shuffle the options + }; + }); + + setQuestions(restoredQuestions); + }; + // Utility function to shuffle an array + const shuffleArray = <T extends any>(array: T[]) => { + const shuffledArray = [...array]; + for (let i = shuffledArray.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [shuffledArray[i], shuffledArray[j]] = [ + shuffledArray[j], + shuffledArray[i], + ]; + } + return shuffledArray; + }; + + const currentQuestionObj = questions[currentQuestion]; + + return ( + <div> + <div className="logo"> + <img src={logo} alt="" /> + </div> + + <div className="quiz-container"> + <h1 className="heading">HTML</h1> + <div className="sidebar"> + <button onClick={handleHint} disabled={isHintUsed || showResult}> + Hint + </button> + <button + onClick={handleFiftyFifty} + disabled={showFiftyFifty || showResult || isFiftyFiftyUsed} + > + 50/50 + </button> + </div> + + {showResult ? ( + <div> + <h2 className="result-text">Quiz Result</h2> + <p className="result-score"> + Your Score: {score}/{questions.length} + </p> + <div className="result-buttons"> + <button onClick={handleRestart}>Restart Quiz</button> + </div> + </div> + ) : ( + <div> + <div className="timer">Time Remaining: {timeRemaining}s</div> + <h2>Question {currentQuestion + 1}</h2> + <p>{currentQuestionObj.question}</p> + {showHint && <p className="hint">{currentQuestionObj.hint}</p>} + <ul className="option-box"> + {currentQuestionObj.options.map((option) => ( + <li key={option}> + <button + className={`option-button ${ + selectedOption === option + ? option === currentQuestionObj.answer + ? "correct" + : "incorrect" + : "" + }`} + onClick={() => setSelectedOption(option)} + disabled={selectedOption !== "" || timeRemaining === 0} + > + {option} + </button> + </li> + ))} + </ul> + + {selectedOption && ( + <p className="selected-answer"> + Your Selection: {selectedOption} + {selectedOption === currentQuestionObj.answer ? ( + <span className="correct-answer">   Correct!</span> + ) : ( + <span className="incorrect-answer"> +   Incorrect! Correct Answer:{" "} + {currentQuestionObj.answer} + </span> + )} + </p> + )} + <button + className="submit-button" + onClick={() => handleAnswer(selectedOption)} + disabled={selectedOption === "" || timeRemaining === 0} + > + Next + </button> + </div> + )} + </div> + </div> + ); +}; + +export default QuizGame; diff --git a/src/pages/marcos/wrong.mp3 b/src/pages/marcos/wrong.mp3 new file mode 100644 index 0000000..af33294 Binary files /dev/null and b/src/pages/marcos/wrong.mp3 differ