keepyoursins's picture
Create a Quiz App, with a quiz section, and a history section.
0b82439 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QuizCraft Pro - Quiz</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs/lib/anime.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Poppins', sans-serif;
}
.glass-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.option-card {
transition: all 0.3s ease;
cursor: pointer;
}
.option-card:hover {
transform: translateY(-2px);
background: rgba(255, 255, 255, 0.15);
}
.option-card.selected {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.progress-bar {
transition: width 0.5s ease-in-out;
}
</style>
</head>
<body class="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 text-white">
<!-- Navigation -->
<nav class="glass-card rounded-lg m-4 p-4">
<div class="container mx-auto flex justify-between items-center">
<div class="flex items-center space-x-2">
<i data-feather="award" class="text-purple-400"></i>
<span class="text-xl font-bold">QuizCraft Pro</span>
</div>
<div class="flex space-x-6">
<a href="index.html" class="hover:text-purple-300 transition-colors">Home</a>
<a href="quiz.html" class="hover:text-purple-300 transition-colors">Quiz</a>
<a href="history.html" class="hover:text-purple-300 transition-colors">History</a>
</div>
</div>
</nav>
<!-- Quiz Container -->
<div class="container mx-auto px-4 py-8 max-w-4xl">
<!-- Category Selection -->
<div id="category-selection" class="glass-card p-8 rounded-xl mb-8">
<h2 class="text-3xl font-bold mb-6 text-center">Choose Your Challenge</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="option-card p-4 rounded-lg text-center border-2 border-purple-500" data-category="9">
<i data-feather="brain" class="w-8 h-8 mx-auto mb-2"></i>
<span>General Knowledge</span>
</div>
<div class="option-card p-4 rounded-lg text-center border-2 border-blue-500" data-category="17">
<i data-feather="atom" class="w-8 h-8 mx-auto mb-2"></i>
<span>Science</span>
</div>
<div class="option-card p-4 rounded-lg text-center border-2 border-green-500" data-category="22">
<i data-feather="map" class="w-8 h-8 mx-auto mb-2"></i>
<span>Geography</span>
</div>
<div class="option-card p-4 rounded-lg text-center border-2 border-yellow-500" data-category="23">
<i data-feather="book" class="w-8 h-8 mx-auto mb-2"></i>
<span>History</span>
</div>
</div>
<div class="text-center mt-6">
<button id="start-quiz" class="btn-primary px-8 py-3 rounded-full font-semibold">
Start Quiz <i data-feather="arrow-right" class="inline ml-2"></i>
</button>
</div>
</div>
<!-- Quiz Interface -->
<div id="quiz-interface" class="hidden">
<!-- Progress Bar -->
<div class="glass-card p-4 rounded-xl mb-6">
<div class="flex justify-between items-center mb-2">
<span class="text-sm">Question <span id="current-question">1</span> of 10</span>
<span id="score" class="text-sm">Score: 0</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="progress-bar" class="progress-bar h-2 rounded-full bg-gradient-to-r from-purple-400 to-pink-400" style="width: 10%"></div>
</div>
<!-- Question Card -->
<div id="question-card" class="glass-card p-8 rounded-xl mb-6">
<h2 id="question-text" class="text-2xl font-semibold mb-6 text-center"></h2>
<div id="options-container" class="grid gap-4">
<!-- Options will be dynamically inserted here -->
</div>
</div>
<!-- Navigation Buttons -->
<div class="flex justify-between">
<button id="prev-question" class="glass-card px-6 py-3 rounded-full font-semibold opacity-50 cursor-not-allowed">
<i data-feather="arrow-left" class="inline mr-2"></i>Previous
</button>
<button id="next-question" class="btn-primary px-6 py-3 rounded-full font-semibold">
Next <i data-feather="arrow-right" class="inline ml-2"></i>
</button>
</div>
</div>
<!-- Results Screen -->
<div id="results-screen" class="hidden glass-card p-8 rounded-xl text-center">
<i data-feather="award" class="w-16 h-16 mx-auto mb-4 text-yellow-400"></i>
<h2 class="text-4xl font-bold mb-4">Quiz Complete!</h2>
<div id="final-score" class="text-6xl font-bold mb-4 bg-gradient-to-r from-purple-400 to-pink-400 bg-clip-text text-transparent"></div>
<p id="performance-message" class="text-xl mb-6"></p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<button id="play-again" class="btn-primary px-6 py-3 rounded-full font-semibold">
<i data-feather="refresh-cw" class="inline mr-2"></i>Play Again
</button>
<a href="history.html" class="btn-secondary px-6 py-3 rounded-full font-semibold">
<i data-feather="bar-chart-2" class="inline mr-2"></i>View History
</a>
</div>
</div>
</div>
<script>
feather.replace();
// Quiz state
let currentCategory = null;
let currentQuestionIndex = 0;
let score = 0;
let questions = [];
let selectedOptions = new Array(10).fill(null);
// DOM Elements
const categorySelection = document.getElementById('category-selection');
const quizInterface = document.getElementById('quiz-interface');
const resultsScreen = document.getElementById('results-screen');
const startQuizBtn = document.getElementById('start-quiz');
const questionText = document.getElementById('question-text');
const optionsContainer = document.getElementById('options-container');
const currentQuestionSpan = document.getElementById('current-question');
const scoreSpan = document.getElementById('score');
const progressBar = document.getElementById('progress-bar');
const prevQuestionBtn = document.getElementById('prev-question');
const nextQuestionBtn = document.getElementById('next-question');
const finalScore = document.getElementById('final-score');
const performanceMessage = document.getElementById('performance-message');
const playAgainBtn = document.getElementById('play-again');
// Category selection
document.querySelectorAll('.option-card').forEach(card => {
card.addEventListener('click', function() {
document.querySelectorAll('.option-card').forEach(c => {
c.classList.remove('selected', 'border-white');
c.classList.add('border-opacity-50');
});
this.classList.add('selected', 'border-white');
this.classList.remove('border-opacity-50');
currentCategory = this.dataset.category;
});
});
// Start quiz
startQuizBtn.addEventListener('click', async function() {
if (!currentCategory) {
alert('Please select a category first!');
return;
}
try {
const response = await fetch(`https://opentdb.com/api.php?amount=10&category=${currentCategory}&type=multiple`);
const data = await response.json();
questions = data.results;
categorySelection.classList.add('hidden');
quizInterface.classList.remove('hidden');
loadQuestion(0);
} catch (error) {
console.error('Error fetching questions:', error);
alert('Failed to load questions. Please try again.');
}
});
// Load question
function loadQuestion(index) {
const question = questions[index];
currentQuestionIndex = index;
// Update UI
currentQuestionSpan.textContent = index + 1;
scoreSpan.textContent = `Score: ${score}`;
progressBar.style.width = `${((index + 1) / 10) * 100}%`;
// Set question text
questionText.textContent = decodeHTML(question.question);
// Create options
const allOptions = [...question.incorrect_answers, question.correct_answer]
.sort(() => Math.random() - 0.5);
optionsContainer.innerHTML = '';
allOptions.forEach((option, optionIndex) => {
const optionDiv = document.createElement('div');
optionDiv.className = `option-card p-4 rounded-lg border-2 border-gray-600 ${
selectedOptions[index] === option ? 'selected' : ''
}`;
optionDiv.innerHTML = `
<div class="flex items-center justify-between">
<span>${decodeHTML(option)}</span>
${selectedOptions[index] === option ? '<i data-feather="check" class="w-5 h-5"></i>' : ''}
</div>
`;
optionDiv.addEventListener('click', () => selectOption(option, index));
optionsContainer.appendChild(optionDiv);
});
// Update navigation buttons
prevQuestionBtn.disabled = index === 0;
prevQuestionBtn.classList.toggle('opacity-50', index === 0);
prevQuestionBtn.classList.toggle('cursor-not-allowed', index === 0);
if (index === 9) {
nextQuestionBtn.textContent = 'Finish Quiz';
nextQuestionBtn.innerHTML = 'Finish Quiz <i data-feather="check" class="inline ml-2"></i>';
} else {
nextQuestionBtn.textContent = 'Next';
nextQuestionBtn.innerHTML = 'Next <i data-feather="arrow-right" class="inline ml-2"></i>';
}
feather.replace();
}
// Select option
function selectOption(option, index) {
selectedOptions[index] = option;
const isCorrect = option === questions[index].correct_answer;
// Update score if this is a new selection
if (isCorrect && selectedOptions[index] !== option) {
score += 10;
}
loadQuestion(index); // Reload to show selection
}
// Navigation
prevQuestionBtn.addEventListener('click', () => {
if (currentQuestionIndex > 0) {
loadQuestion(currentQuestionIndex - 1);
}
});
nextQuestionBtn.addEventListener('click', () => {
if (currentQuestionIndex < 9) {
loadQuestion(currentQuestionIndex + 1);
} else {
// Show results
showResults();
}
});
// Show results
function showResults() {
quizInterface.classList.add('hidden');
resultsScreen.classList.remove('hidden');
finalScore.textContent = `${score}/100`;
if (score >= 90) {
performanceMessage.textContent = 'Outstanding! You are a quiz master! 🌟';
} else if (score >= 70) {
performanceMessage.textContent = 'Great job! You know your stuff! πŸ’ͺ';
} else if (score >= 50) {
performanceMessage.textContent = 'Good effort! Keep learning! πŸ“š';
} else {
performanceMessage.textContent = 'Nice try! Practice makes perfect! πŸ”„';
}
// Save to localStorage for history
const quizResult = {
category: document.querySelector('.selected span').textContent,
score: score,
date: new Date().toISOString(),
totalQuestions: 10
};
let history = JSON.parse(localStorage.getItem('quizHistory') || '[]');
history.unshift(quizResult);
localStorage.setItem('quizHistory', JSON.stringify(history));
}
// Play again
playAgainBtn.addEventListener('click', () => {
location.reload();
});
// Utility function to decode HTML entities
function decodeHTML(html) {
const txt = document.createElement('textarea');
txt.innerHTML = html;
return txt.value;
}
// Entrance animations
document.addEventListener('DOMContentLoaded', function() {
anime({
targets: '.glass-card',
translateY: [30, 0],
opacity: [0, 1],
duration: 800,
delay: anime.stagger(100)
});
});
</script>
</body>
</html>