Attaque2 / templates /index.html
Docfile's picture
Update templates/index.html
4404e58 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Générateur de Flashcards et Quiz</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
}
},
animation: {
'bounce-slow': 'bounce 3s linear infinite',
}
}
}
}
</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;
background-color: #f8fafc;
}
.flashcard {
perspective: 1000px;
height: 220px;
}
.flashcard-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.8s;
transform-style: preserve-3d;
}
.flashcard.flipped .flashcard-inner {
transform: rotateY(180deg);
}
.flashcard-front, .flashcard-back {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0.5rem;
padding: 1.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.flashcard-front {
background-color: #ffffff;
color: #1e293b;
border-left: 5px solid #0ea5e9;
}
.flashcard-back {
background-color: #0ea5e9;
color: white;
transform: rotateY(180deg);
}
.quiz-option {
position: relative;
padding-left: 2.5rem;
}
.quiz-option input[type="radio"] {
position: absolute;
opacity: 0;
}
.quiz-option label {
display: block;
position: relative;
padding: 1rem 1.5rem 1rem 2.5rem;
cursor: pointer;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
transition: all 0.3s ease;
}
.quiz-option label:before {
content: '';
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
border: 2px solid #cbd5e1;
transition: all 0.3s ease;
}
.quiz-option input[type="radio"]:checked + label {
background-color: #e0f2fe;
border-color: #0ea5e9;
}
.quiz-option input[type="radio"]:checked + label:before {
border-color: #0ea5e9;
background-color: #0ea5e9;
box-shadow: inset 0 0 0 4px #e0f2fe;
}
.quiz-option.correct input[type="radio"]:checked + label {
background-color: #d1fae5;
border-color: #10b981;
}
.quiz-option.correct input[type="radio"]:checked + label:before {
border-color: #10b981;
background-color: #10b981;
box-shadow: inset 0 0 0 4px #d1fae5;
}
.quiz-option.incorrect input[type="radio"]:checked + label {
background-color: #fee2e2;
border-color: #ef4444;
}
.quiz-option.incorrect input[type="radio"]:checked + label:before {
border-color: #ef4444;
background-color: #ef4444;
box-shadow: inset 0 0 0 4px #fee2e2;
}
.progress-bar-container {
width: 100%;
height: 8px;
background-color: #e2e8f0;
border-radius: 4px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: #0ea5e9;
transition: width 0.5s ease;
}
.floating-label {
position: absolute;
top: -10px;
left: 10px;
padding: 0 5px;
background-color: white;
transition: all 0.3s ease;
pointer-events: none;
}
.pulse-animation {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(14, 165, 233, 0.4);
}
70% {
box-shadow: 0 0 0 10px rgba(14, 165, 233, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(14, 165, 233, 0);
}
}
.confetti {
position: fixed;
width: 10px;
height: 10px;
background-color: #f00;
opacity: 0;
animation: confetti-fall 3s linear forwards;
}
@keyframes confetti-fall {
0% {
transform: translateY(0) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
.btn-primary {
@apply bg-primary-600 text-white px-6 py-3 rounded-lg shadow-md hover:bg-primary-700 transition duration-300 ease-in-out transform hover:-translate-y-1 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-opacity-50;
}
.btn-secondary {
@apply bg-white text-primary-600 border border-primary-600 px-6 py-3 rounded-lg shadow-md hover:bg-primary-50 transition duration-300 ease-in-out transform hover:-translate-y-1 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-opacity-50;
}
</style>
</head>
<body>
<div class="min-h-screen bg-gradient-to-b from-primary-50 to-white">
<header class="bg-white shadow-sm py-6">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between">
<a href="#" class="text-3xl font-bold text-primary-700 flex items-center">
<i class="fas fa-home mr-3 text-primary-500"></i>
Mariam Quizz
</a>
<div class="flex space-x-2">
<button id="themeToggle" class="p-2 rounded-full hover:bg-gray-100">
<i class="fas fa-moon text-gray-600"></i>
</button>
<button class="p-2 rounded-full hover:bg-gray-100">
<i class="fas fa-question-circle text-gray-600"></i>
</button>
</div>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<div class="max-w-3xl mx-auto">
<!-- Introduction -->
<div class="text-center mb-8">
<h2 class="text-4xl font-bold text-gray-800 mb-4">Apprenez plus efficacement</h2>
<p class="text-lg text-gray-600 mb-6">Créez des flashcards ou des quiz pour mémoriser n'importe quel sujet</p>
</div>
<!-- Section de configuration -->
<div class="bg-white rounded-xl shadow-lg p-8 mb-10 relative overflow-hidden">
<div class="absolute top-0 right-0 w-40 h-40 bg-primary-100 rounded-full -mr-20 -mt-20 z-0"></div>
<div class="absolute bottom-0 left-0 w-24 h-24 bg-primary-100 rounded-full -ml-12 -mb-12 z-0"></div>
<div class="relative z-10">
<h3 class="text-2xl font-semibold text-gray-800 mb-6">Que souhaitez-vous apprendre aujourd'hui ?</h3>
<div class="space-y-6">
<div class="relative">
<input type="text" id="topic" class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:border-primary-500 focus:ring focus:ring-primary-200 focus:ring-opacity-50 transition-all duration-300 pl-10" placeholder="Entrez un sujet...">
<i class="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
<div class="text-xs text-gray-500 mt-1 ml-2">Exemples: "Capitales du monde", "Photosynthèse", "Verbes irréguliers en anglais"</div>
</div>
<div>
<p class="text-gray-700 font-medium mb-3">Choisissez votre méthode d'apprentissage :</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="relative">
<input type="radio" id="typeFlashcards" name="contentType" value="flashcards" checked class="peer absolute opacity-0">
<label for="typeFlashcards" class="flex flex-col items-center justify-center p-4 border-2 border-gray-200 rounded-lg cursor-pointer transition-all duration-300 hover:bg-gray-50 peer-checked:border-primary-500 peer-checked:bg-primary-50">
<div class="w-12 h-12 rounded-full bg-primary-100 flex items-center justify-center mb-3">
<i class="fas fa-clone text-xl text-primary-600"></i>
</div>
<h4 class="font-semibold text-gray-800">Flashcards</h4>
<p class="text-sm text-gray-600 text-center mt-2">Pour mémoriser des informations par répétition</p>
</label>
</div>
<div class="relative">
<input type="radio" id="typeQuiz" name="contentType" value="quiz" class="peer absolute opacity-0">
<label for="typeQuiz" class="flex flex-col items-center justify-center p-4 border-2 border-gray-200 rounded-lg cursor-pointer transition-all duration-300 hover:bg-gray-50 peer-checked:border-primary-500 peer-checked:bg-primary-50">
<div class="w-12 h-12 rounded-full bg-primary-100 flex items-center justify-center mb-3">
<i class="fas fa-question text-xl text-primary-600"></i>
</div>
<h4 class="font-semibold text-gray-800">Quiz</h4>
<p class="text-sm text-gray-600 text-center mt-2">Pour tester vos connaissances avec des QCM</p>
</label>
</div>
</div>
</div>
<div class="flex items-center justify-between pt-2">
<div class="text-sm text-gray-500 italic">
<i class="fas fa-info-circle mr-1"></i> La génération peut prendre jusqu'à 1 minute
</div>
<button id="generateBtn" class="btn-primary flex items-center">
<span class="mr-2">Générer</span>
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Indicateur de chargement -->
<div id="loading" class="hidden">
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
<div class="flex flex-col items-center justify-center space-y-4">
<div class="relative w-24 h-24">
<div class="absolute inset-0 border-4 border-primary-100 border-t-primary-500 rounded-full animate-spin"></div>
<div class="absolute inset-0 flex items-center justify-center">
<i class="fas fa-lightbulb text-2xl text-primary-500 animate-pulse"></i>
</div>
</div>
<h3 class="text-xl font-semibold text-gray-800">Création en cours...</h3>
<p class="text-gray-600">Nous élaborons votre contenu d'apprentissage personnalisé</p>
<div class="w-full max-w-md mt-4">
<div class="progress-bar-container">
<div id="progressBar" class="progress-bar" style="width: 0%"></div>
</div>
<div id="loadingSteps" class="mt-8 text-left">
<div class="flex items-center mb-3">
<div class="w-6 h-6 rounded-full bg-primary-500 flex items-center justify-center mr-3">
<i class="fas fa-check text-white text-xs"></i>
</div>
<span class="text-sm text-gray-700">Analyse du sujet</span>
</div>
<div class="flex items-center mb-3">
<div id="step2" class="w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center mr-3">
<i class="fas fa-spinner text-white text-xs animate-spin"></i>
</div>
<span class="text-sm text-gray-500">Recherche d'informations</span>
</div>
<div class="flex items-center mb-3">
<div id="step3" class="w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center mr-3">
<i class="fas fa-hourglass text-white text-xs"></i>
</div>
<span class="text-sm text-gray-500">Création du contenu</span>
</div>
<div class="flex items-center">
<div id="step4" class="w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center mr-3">
<i class="fas fa-hourglass text-white text-xs"></i>
</div>
<span class="text-sm text-gray-500">Finalisation</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Conteneur pour les Flashcards -->
<div id="flashcardsContainer" class="mt-8 hidden">
<!-- Les flashcards seront injectées ici -->
</div>
<!-- Conteneur pour le Quiz -->
<div id="quizContainer" class="mt-8 hidden">
<!-- Les questions du quiz seront injectées ici -->
</div>
</div>
</main>
<footer class="bg-gray-900 text-white py-8 mt-20 hidden md:block">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<h2 class="text-xl font-bold flex items-center">
<i class="fas fa-brain mr-2"></i> Mémorisation Facile
</h2>
<p class="text-gray-400 text-sm mt-2">Votre outil d'apprentissage intelligent</p>
</div>
<div class="flex space-x-4">
<a href="#" class="text-gray-400 hover:text-white transition-colors"><i class="fab fa-twitter"></i></a>
<a href="#" class="text-gray-400 hover:text-white transition-colors"><i class="fab fa-facebook"></i></a>
<a href="#" class="text-gray-400 hover:text-white transition-colors"><i class="fab fa-instagram"></i></a>
<a href="#" class="text-gray-400 hover:text-white transition-colors"><i class="fab fa-youtube"></i></a>
</div>
</div>
<div class="mt-8 border-t border-gray-800 pt-6 text-sm text-gray-400 text-center">
© 2025 Mémorisation Facile. Tous droits réservés.
</div>
</div>
</footer>
</div>
<script>
const generateBtn = document.getElementById('generateBtn');
const loadingIndicator = document.getElementById('loading');
const flashcardsContainer = document.getElementById('flashcardsContainer');
const quizContainer = document.getElementById('quizContainer');
const topicInput = document.getElementById('topic');
const progressBar = document.getElementById('progressBar');
const themeToggle = document.getElementById('themeToggle');
const step2 = document.getElementById('step2');
const step3 = document.getElementById('step3');
const step4 = document.getElementById('step4');
// Gestion du thème clair/sombre
themeToggle.addEventListener('click', function() {
document.body.classList.toggle('dark-mode');
const icon = this.querySelector('i');
if (icon.classList.contains('fa-moon')) {
icon.classList.remove('fa-moon');
icon.classList.add('fa-sun');
} else {
icon.classList.remove('fa-sun');
icon.classList.add('fa-moon');
}
});
// Animation de chargement
function simulateLoading() {
let progress = 0;
const interval = setInterval(() => {
progress += 1;
progressBar.style.width = `${progress}%`;
if (progress === 25) {
step2.classList.remove('bg-gray-200');
step2.classList.add('bg-primary-500');
step2.innerHTML = '<i class="fas fa-check text-white text-xs"></i>';
} else if (progress === 60) {
step3.classList.remove('bg-gray-200');
step3.classList.add('bg-primary-500');
step3.innerHTML = '<i class="fas fa-check text-white text-xs"></i>';
step4.innerHTML = '<i class="fas fa-spinner text-white text-xs animate-spin"></i>';
} else if (progress === 95) {
step4.classList.remove('bg-gray-200');
step4.classList.add('bg-primary-500');
step4.innerHTML = '<i class="fas fa-check text-white text-xs"></i>';
}
if (progress >= 100) {
clearInterval(interval);
}
}, 50);
return interval;
}
// Fonction pour créer des confettis
function createConfetti() {
const confettiCount = 100;
const colors = ['#0ea5e9', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'];
for (let i = 0; i < confettiCount; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = `${Math.random() * 100}vw`;
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = `${Math.random() * 10 + 5}px`;
confetti.style.height = `${Math.random() * 10 + 5}px`;
confetti.style.animationDuration = `${Math.random() * 3 + 2}s`;
document.body.appendChild(confetti);
setTimeout(() => {
confetti.remove();
}, 5000);
}
}
// Gestion des flashcards
function flipCard(card) {
card.classList.toggle('flipped');
}
generateBtn.addEventListener('click', function() {
const topic = topicInput.value.trim();
if (!topic) {
// Animation de secouement sur l'input
topicInput.classList.add('border-red-500');
topicInput.classList.add('animate-bounce');
setTimeout(() => {
topicInput.classList.remove('animate-bounce');
topicInput.classList.remove('border-red-500');
}, 1000);
// Afficher un message d'erreur
const errorMsg = document.createElement('div');
errorMsg.className = 'text-red-500 text-sm mt-1 ml-2';
errorMsg.textContent = 'Veuillez entrer un sujet';
topicInput.parentElement.appendChild(errorMsg);
setTimeout(() => {
errorMsg.remove();
}, 3000);
return;
}
const contentType = document.querySelector('input[name="contentType"]:checked').value;
// Afficher le chargement et cacher les anciens résultats
loadingIndicator.classList.remove('hidden');
flashcardsContainer.classList.add('hidden');
quizContainer.classList.add('hidden');
flashcardsContainer.innerHTML = '';
quizContainer.innerHTML = '';
// Simuler l'animation de chargement
const loadingInterval = simulateLoading();
// Envoi de la requête
fetch('/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ topic, type: contentType }),
})
.then(response => {
if (!response.ok) {
throw new Error(`Erreur HTTP: ${response.status}`);
}
return response.json();
})
.then(data => {
// Assurons-nous que l'animation montre au moins 2 secondes
setTimeout(() => {
clearInterval(loadingInterval);
progressBar.style.width = '100%';
setTimeout(() => {
loadingIndicator.classList.add('hidden');
if (data.error) {
// Afficher une erreur élégante
const errorContainer = document.createElement('div');
errorContainer.className = 'bg-red-50 border-l-4 border-red-500 p-4 rounded-md mt-4';
errorContainer.innerHTML = `
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-circle text-red-500"></i>
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
${data.error}
</p>
</div>
</div>
`;
document.querySelector('.max-w-3xl').appendChild(errorContainer);
return;
}
if (contentType === 'flashcards' && data.flashcards) {
flashcardsContainer.classList.remove('hidden');
displayFlashcards(data.flashcards);
// Créer un effet de confettis
createConfetti();
} else if (contentType === 'quiz' && data.quiz) {
quizContainer.classList.remove('hidden');
displayQuiz(data.quiz);
// Créer un effet de confettis
createConfetti();
} else {
// Afficher une erreur élégante
const errorContainer = document.createElement('div');
errorContainer.className = 'bg-red-50 border-l-4 border-red-500 p-4 rounded-md mt-4';
errorContainer.innerHTML = `
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-circle text-red-500"></i>
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
Aucune donnée reçue ou format incorrect.
</p>
</div>
</div>
`;
document.querySelector('.max-w-3xl').appendChild(errorContainer);
}
}, 500);
}, 2000);
})
.catch(error => {
clearInterval(loadingInterval);
loadingIndicator.classList.add('hidden');
console.error('Erreur lors de la génération:', error);
// Afficher une erreur élégante
const errorContainer = document.createElement('div');
errorContainer.className = 'bg-red-50 border-l-4 border-red-500 p-4 rounded-md mt-4';
errorContainer.innerHTML = `
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-circle text-red-500"></i>
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
Erreur lors de la génération: ${error.message}.
</p>
</div>
</div>
`;
document.querySelector('.max-w-3xl').appendChild(errorContainer);
});
});
function displayFlashcards(flashcards) {
const header = document.createElement('div');
header.className = 'mb-8 text-center';
header.innerHTML = `
<h2 class="text-3xl font-bold text-gray-800 mb-2">Vos Flashcards (${flashcards.length})</h2>
<p >Cliquez sur une carte pour la retourner et voir la réponse.</p>
<p class="text-gray-600">
<i class="far fa-lightbulb mr-1"></i> Astuce : Essayez de répondre mentalement avant de retourner la carte
</p>
<p><div class="flex items-center justify-center space-x-4 mt-6">
</div></p>
`;
flashcardsContainer.appendChild(header);
const flashcardsGrid = document.createElement('div');
flashcardsGrid.className = 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6';
flashcardsContainer.appendChild(flashcardsGrid);
flashcards.forEach((card, index) => {
const cardElement = document.createElement('div');
cardElement.className = 'flashcard cursor-pointer';
cardElement.onclick = function() { flipCard(this); };
cardElement.innerHTML = `
<div class="flashcard-inner">
<div class="flashcard-front">
<div class="w-full">
<div class="absolute top-2 left-2 text-xs text-gray-400">#${index + 1}</div>
<h3 class="text-lg font-semibold mb-2 text-center">${card.question}</h3>
<div class="text-center mt-4">
<span class="text-xs text-gray-500">Cliquez pour voir la réponse</span>
</div>
</div>
</div>
<div class="flashcard-back">
<div class="w-full">
<div class="absolute top-2 right-2 text-xs text-white opacity-70">#${index + 1}</div>
<div class="text-center">
<p class="font-medium">${card.answer}</p>
</div>
<div class="absolute bottom-2 right-2">
<span class="text-xs text-white opacity-70">Cliquez pour retourner</span>
</div>
</div>
</div>
</div>
`;
flashcardsGrid.appendChild(cardElement);
});
// Ajouter des boutons de navigation et de contrôle
const controls = document.createElement('div');
controls.className = 'mt-10 flex flex-col items-center justify-center';
controls.innerHTML = `
<div class="flex items-center space-x-4 mb-6">
<button class="px-4 py-2 bg-primary-100 hover:bg-primary-200 text-primary-700 rounded-md transition duration-300 flex items-center">
<i class="fas fa-redo-alt mr-2"></i> Recommencer
</button>
<button id="newTopicBtn" class="px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-md transition duration-300 flex items-center">
<i class="fas fa-plus mr-2"></i> Nouveau sujet
</button>
</div>
`;
flashcardsContainer.appendChild(controls);
// Ajouter des interactions aux boutons
document.getElementById('printBtn').addEventListener('click', function() {
window.print();
});
document.getElementById('saveBtn').addEventListener('click', function() {
alert('Flashcards sauvegardées !');
});
document.getElementById('shareBtn').addEventListener('click', function() {
alert('Lien de partage copié dans le presse-papiers !');
});
document.getElementById('newTopicBtn').addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
topicInput.focus();
});
}
function displayQuiz(quizQuestions) {
const header = document.createElement('div');
header.className = 'mb-8 text-center';
header.innerHTML = `
<h2 class="text-3xl font-bold text-gray-800 mb-2">Votre Quiz (${quizQuestions.length} questions)</h2>
<p class="text-gray-600">Testez vos connaissances en répondant aux questions</p>
<div class="flex items-center justify-center mt-6">
<div class="bg-white px-4 py-2 rounded-full shadow-sm flex items-center">
<span class="text-primary-700 font-medium">Score: </span>
<span id="score" class="ml-1 text-primary-700 font-bold">0</span>
<span class="mx-1 text-gray-400">/</span>
<span class="text-gray-600">${quizQuestions.length}</span>
</div>
</div>
`;
quizContainer.appendChild(header);
// Créer un conteneur pour les questions
const questionsContainer = document.createElement('div');
questionsContainer.className = 'space-y-8';
quizContainer.appendChild(questionsContainer);
// Variable pour suivre le score
let currentScore = 0;
quizQuestions.forEach((question, qIndex) => {
const questionElement = document.createElement('div');
questionElement.className = 'bg-white rounded-xl shadow-md p-6 transition-all duration-300';
questionElement.setAttribute('id', `question-${qIndex}`);
let optionsHtml = '';
const safeCorrectAnswer = question.correctAnswer.replace(/"/g, '"');
question.options.forEach((option, oIndex) => {
optionsHtml += `
<div class="quiz-option mb-3" id="option-${qIndex}-${oIndex}">
<input type="radio" id="q${qIndex}-o${oIndex}" name="question-${qIndex}" value="${option}" data-correct="${safeCorrectAnswer}">
<label for="q${qIndex}-o${oIndex}" class="group">
${option}
<span class="hidden success-icon absolute right-4 text-green-500">
<i class="fas fa-check-circle"></i>
</span>
<span class="hidden error-icon absolute right-4 text-red-500">
<i class="fas fa-times-circle"></i>
</span>
</label>
</div>
`;
});
questionElement.innerHTML = `
<div class="flex items-center justify-between mb-4">
<span class="bg-primary-100 text-primary-800 text-xs font-medium px-2.5 py-0.5 rounded">Question ${qIndex + 1}/${quizQuestions.length}</span>
<span class="text-gray-400 text-sm">
<i class="far fa-lightbulb"></i>
</span>
</div>
<h3 class="text-xl font-medium text-gray-800 mb-4">${question.question}</h3>
<div class="options mt-5">
${optionsHtml}
</div>
<div class="explanation hidden mt-6 p-4 bg-blue-50 border border-blue-100 rounded-lg" id="explanation-${qIndex}">
<div class="flex items-start">
<div class="flex-shrink-0 mt-0.5">
<i class="fas fa-info-circle text-blue-500"></i>
</div>
<div class="ml-3">
<h4 class="text-sm font-medium text-blue-800">Explication</h4>
<div class="mt-1 text-sm text-blue-700">${question.explanation}</div>
</div>
</div>
</div>
`;
questionsContainer.appendChild(questionElement);
// Ajouter des gestionnaires d'événements pour les options
const options = questionElement.querySelectorAll('input[type="radio"]');
options.forEach((option) => {
option.addEventListener('change', function() {
const optionId = this.id;
const [_, qIdx, oIdx] = optionId.match(/q(\d+)-o(\d+)/);
const selected = this.value;
const correct = this.getAttribute('data-correct');
const explanationElement = document.getElementById(`explanation-${qIdx}`);
// Vérifier la réponse
let delay = 0; // Initialiser le délai
if (selected === correct) {
// Réponse correcte
document.getElementById(`option-${qIdx}-${oIdx}`).classList.add('correct');
currentScore++;
document.getElementById('score').textContent = currentScore;
// Afficher une animation de succès
const successIcon = this.nextElementSibling.querySelector('.success-icon');
successIcon.classList.remove('hidden');
delay = 2000; // 2 secondes pour une réponse correcte
} else {
// Réponse incorrecte
document.getElementById(`option-${qIdx}-${oIdx}`).classList.add('incorrect');
// Afficher une animation d'erreur
const errorIcon = this.nextElementSibling.querySelector('.error-icon');
errorIcon.classList.remove('hidden');
// Mettre en évidence la bonne réponse
options.forEach((opt, idx) => {
if (opt.value === correct) {
document.getElementById(`option-${qIdx}-${idx}`).classList.add('correct');
const successIcon = opt.nextElementSibling.querySelector('.success-icon');
successIcon.classList.remove('hidden');
}
});
delay = 5000; // 5 secondes pour une réponse incorrecte
}
// Désactiver toutes les autres options
options.forEach((opt) => {
if (opt !== this) {
opt.disabled = true;
}
});
// Afficher l'explication
explanationElement.classList.remove('hidden');
// Animer le passage à la question suivante
setTimeout(() => {
const nextQuestion = document.getElementById(`question-${parseInt(qIdx) + 1}`);
if (nextQuestion) {
window.scrollTo({
top: nextQuestion.offsetTop - 20,
behavior: 'smooth'
});
} else {
// C'était la dernière question, afficher un récapitulatif
if (parseInt(qIdx) === quizQuestions.length - 1) {
displayQuizResults(currentScore, quizQuestions.length);
}
}
}, delay);
});
});
});
}
function displayQuizResults(score, total) {
const percentage = (score / total) * 100;
let resultClass, resultIcon, resultMessage;
if (percentage >= 80) {
resultClass = 'bg-green-50 border-green-500 text-green-800';
resultIcon = '<i class="fas fa-trophy text-3xl text-yellow-500 mb-3"></i>';
resultMessage = 'Excellent ! Vous maîtrisez ce sujet.';
} else if (percentage >= 60) {
resultClass = 'bg-blue-50 border-blue-500 text-blue-800';
resultIcon = '<i class="fas fa-medal text-3xl text-blue-500 mb-3"></i>';
resultMessage = 'Bon travail ! Continuez vos efforts.';
} else {
resultClass = 'bg-red-50 border-red-500 text-red-800';
resultIcon = '<i class="fas fa-book-open text-3xl text-red-500 mb-3"></i>';
resultMessage = 'Continuez à étudier pour améliorer vos connaissances.';
}
const resultsElement = document.createElement('div');
resultsElement.className = `mt-10 p-6 rounded-xl shadow-lg border-l-4 ${resultClass} text-center`;
resultsElement.innerHTML = `
<div class="flex flex-col items-center">
${resultIcon}
<h3 class="text-2xl font-bold mb-2">Résultat final: ${score}/${total}</h3>
<p class="mb-4">${resultMessage}</p>
<div class="w-full max-w-xs bg-gray-200 rounded-full h-4 mb-4">
<div class="h-4 rounded-full ${percentage >= 80 ? 'bg-green-500' : percentage >= 60 ? 'bg-blue-500' : 'bg-red-500'}" style="width: ${percentage}%"></div>
</div>
<div class="flex space-x-4 mt-6">
<button id="retryQuizBtn" class="btn-secondary text-sm">
<i class="fas fa-redo mr-2"></i> Réessayer
</button>
<button id="newQuizBtn" class="btn-primary text-sm">
<i class="fas fa-plus mr-2"></i> Nouveau quiz
</button>
</div>
</div>
`;
quizContainer.appendChild(resultsElement);
// Animation de confettis si le score est bon
if (percentage >= 70) {
createConfetti();
}
// Ajouter des interactions aux boutons
document.getElementById('retryQuizBtn').addEventListener('click', function() {
const radios = document.querySelectorAll('input[type="radio"]');
radios.forEach(radio => {
radio.checked = false;
radio.disabled = false;
});
const options = document.querySelectorAll('.quiz-option');
options.forEach(option => {
option.classList.remove('correct', 'incorrect');
});
const explanations = document.querySelectorAll('.explanation');
explanations.forEach(exp => {
exp.classList.add('hidden');
});
const icons = document.querySelectorAll('.success-icon, .error-icon');
icons.forEach(icon => {
icon.classList.add('hidden');
});
resultsElement.remove();
document.getElementById('score').textContent = '0';
window.scrollTo({
top: quizContainer.offsetTop,
behavior: 'smooth'
});
});
document.getElementById('newQuizBtn').addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
topicInput.focus();
});
}
// Focus sur le champ de saisie au chargement
window.addEventListener('load', () => {
topicInput.focus();
});
</script>
</body>
</html>