body {
font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
max-width: 100%;
margin: 0 auto;
padding: 20px;
background-color: #f9f9f9;
}
h1, h2, h3 {
color: #2c3e50;
}
.container {
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
max-width: 1000px;
margin: 0 auto;
}
.subscription-form {
background-color: #e8f4f8;
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
}
.exercise-container {
display: none;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
button {
background-color: #3498db;
color: white;
border: none;
padding: 12px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #2980b9;
}
.exercise-text {
line-height: 2;
font-size: 18px;
}
.pluriel-input {
width: 150px;
padding: 5px;
border: 1px solid #ddd;
border-radius: 4px;
margin: 0 5px;
font-size: 16px;
}
.pluriel-input.correct {
background-color: #d4edda;
border-color: #c3e6cb;
}
.pluriel-input.incorrect {
background-color: #f8d7da;
border-color: #f5c6cb;
}
.result {
margin-top: 30px;
padding: 20px;
background-color: #eafaf1;
border-radius: 8px;
display: none;
}
.certificate {
text-align: center;
margin-top: 30px;
padding: 20px;
border: 2px solid #2c3e50;
border-radius: 8px;
display: none;
}
.difficulty-selector {
margin-bottom: 20px;
}
.error {
color: red;
font-size: 14px;
}
#certificatePreview {
position: relative;
width: 100%;
height: 450px;
background-color: #fff;
border: 10px solid transparent;
border-image: linear-gradient(45deg, #3498db, #2980b9, #1abc9c, #16a085, #27ae60) 1;
box-sizing: border-box;
overflow: hidden;
margin-bottom: 20px;
}
.certificate-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0.07;
z-index: 0;
background-position: center;
background-repeat: no-repeat;
background-size: 70%;
}
.certificate-content {
position: relative;
z-index: 1;
padding: 20px;
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.certificate-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.certificate-title {
flex-grow: 1;
text-align: center;
}
.certificate-logo {
width: 120px;
height: 60px;
background-color: #3498db;
border-radius: 5px;
}
.certificate-footer {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.certificate-qr {
width: 120px;
height: 120px;
display: flex;
justify-content: center;
align-items: center;
background-color: #f9f9f9;
border: 1px solid #ddd;
}
.certificate-qr img {
max-width: 100%;
max-height: 100%;
}
.certificate-signature {
flex-grow: 1;
text-align: center;
}
.triangle-pattern {
position: absolute;
width: 150px;
height: 120px;
}
.triangle-pattern.top-right {
top: 0;
right: 0;
}
.triangle-pattern.bottom-left {
bottom: 0;
left: 0;
}
.info-tooltip {
display: inline-block;
position: relative;
margin-left: 5px;
cursor: help;
}
.info-tooltip:after {
content: “?”;
display: inline-block;
width: 18px;
height: 18px;
line-height: 18px;
text-align: center;
border-radius: 50%;
background-color: #3498db;
color: white;
font-weight: bold;
font-size: 14px;
}
.info-tooltip .tooltip-text {
visibility: hidden;
width: 250px;
background-color: #2c3e50;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -125px;
opacity: 0;
transition: opacity 0.3s;
}
.info-tooltip:hover .tooltip-text {
visibility: visible;
opacity: 1;
}
.loading {
display: none;
margin-top: 15px;
font-style: italic;
color: #666;
}
.exercise-level {
margin-bottom: 20px;
}
Exercice de Grammaire: Le Singulier et Pluriel des Noms en Français
Inscrivez-vous pour commencer l’exercice
Veuillez vous abonner et remplir vos informations pour accéder à l’exercice.
Convertissez les noms du singulier au pluriel
Choisissez le niveau de difficulté:
Facile
Moyen
Difficile
Pour chaque nom au singulier, écrivez sa forme au pluriel.
Du Singulier au Pluriel (Niveau Facile)
1. livre →
2. table →
3. maison →
4. jardin →
5. fleur →
6. arbre →
7. voiture →
8. vélo →
9. chaise →
10. stylo →
11. école →
12. pain →
13. garçon →
14. ami →
15. rue →
16. pomme →
17. montagne →
18. porte →
19. fenêtre →
20. banane →
21. chat →
22. chien →
23. crayon →
24. cahier →
25. bouteille →
Du Singulier au Pluriel (Niveau Moyen)
1. journal →
2. animal →
3. cheveu →
4. travail →
5. jeu →
6. pneu →
7. genou →
8. conseil →
9. clou →
10. bijou →
11. canal →
12. festival →
13. cheval →
14. éventail →
15. détail →
16. caillou →
17. hibou →
18. local →
19. métal →
20. signal →
21. général →
22. tuyau →
23. hôpital →
24. feu →
25. eau →
Du Singulier au Pluriel (Niveau Difficile)
1. œil →
2. ciel →
3. bal →
4. corail →
5. vitrail →
6. portail →
7. trou →
8. aïeul →
9. émail →
10. landau →
11. soupirail →
12. rail →
13. travail →
14. bocal →
15. carnaval →
16. récital →
17. bail →
18. gouvernail →
19. ail →
20. épouvantail →
21. vantail →
22. bleu →
23. pou →
24. email →
25. capital →
Résultats
Certificat de réussite
Certificat d’Excellence
Maîtrise du Pluriel des Noms en Français
Ce certificat est décerné à
pour avoir complété avec succès l’exercice sur
le pluriel des noms en français au niveau
avec un score de
Date:
document.addEventListener(‘DOMContentLoaded’, function() {
// S’assurer que jsPDF est disponible
if (typeof window.jspdf === ‘undefined’) {
window.jspdf = window.jsPDF;
}
// Références aux éléments DOM
const subscriptionForm = document.getElementById(‘subscriptionForm’);
const exerciseContainer = document.getElementById(‘exerciseContainer’);
const startButton = document.getElementById(‘startButton’);
const verifyButton = document.getElementById(‘verifyButton’);
const difficultySelect = document.getElementById(‘difficultySelect’);
const changeDifficultyButton = document.getElementById(‘changeDifficultyButton’);
const resultContainer = document.getElementById(‘resultContainer’);
const resultText = document.getElementById(‘resultText’);
const mistakesContainer = document.getElementById(‘mistakesContainer’);
const showCertificateButton = document.getElementById(‘showCertificateButton’);
const certificateContainer = document.getElementById(‘certificateContainer’);
const downloadCertificateButton = document.getElementById(‘downloadCertificateButton’);
const pdfLoading = document.getElementById(‘pdfLoading’);
// Informations de l’utilisateur
let userData = {
prenom: ”,
nom: ”,
email: ”,
difficulty: ‘facile’,
score: 0
};
// Fonction pour afficher l’exercice selon le niveau de difficulté
function showExerciseByDifficulty(difficulty) {
// Masquer tous les exercices
document.querySelectorAll(‘.exercise-level’).forEach(el => {
el.style.display = ‘none’;
});
// Afficher l’exercice correspondant à la difficulté
const exerciseId = ‘exercise’ + difficulty.charAt(0).toUpperCase() + difficulty.slice(1);
document.getElementById(exerciseId).style.display = ‘block’;
userData.difficulty = difficulty;
}
// Démarrer l’exercice
startButton.addEventListener(‘click’, function() {
// Valider le formulaire
const prenom = document.getElementById(‘prenom’).value.trim();
const nom = document.getElementById(‘nom’).value.trim();
const email = document.getElementById(‘email’).value.trim();
const subscribe = document.getElementById(‘subscribe’).checked;
// Réinitialiser les erreurs
document.getElementById(‘prenomError’).textContent = ”;
document.getElementById(‘nomError’).textContent = ”;
document.getElementById(‘emailError’).textContent = ”;
document.getElementById(‘subscribeError’).textContent = ”;
let isValid = true;
// Vérification des champs
if (!prenom) {
document.getElementById(‘prenomError’).textContent = ‘Veuillez entrer votre prénom’;
isValid = false;
}
if (!nom) {
document.getElementById(‘nomError’).textContent = ‘Veuillez entrer votre nom’;
isValid = false;
}
if (!email) {
document.getElementById(‘emailError’).textContent = ‘Veuillez entrer votre email’;
isValid = false;
} else if (!/^[^s@]+@[^s@]+.[^s@]+$/.test(email)) {
document.getElementById(‘emailError’).textContent = ‘Veuillez entrer un email valide’;
isValid = false;
}
if (!subscribe) {
document.getElementById(‘subscribeError’).textContent = ‘Veuillez accepter de vous abonner’;
isValid = false;
}
if (isValid) {
// Enregistrer les informations de l’utilisateur
userData.prenom = prenom;
userData.nom = nom;
userData.email = email;
// Masquer le formulaire et afficher l’exercice
subscriptionForm.style.display = ‘none’;
exerciseContainer.style.display = ‘block’;
// Afficher l’exercice selon la difficulté choisie
showExerciseByDifficulty(userData.difficulty);
}
});
// Changer la difficulté
changeDifficultyButton.addEventListener(‘click’, function() {
const difficulty = difficultySelect.value;
showExerciseByDifficulty(difficulty);
});
// Vérifier les réponses
verifyButton.addEventListener(‘click’, function() {
let correctAnswers = 0;
const totalQuestions = document.querySelectorAll(`#exercise${userData.difficulty.charAt(0).toUpperCase() + userData.difficulty.slice(1)} .pluriel-input`).length;
const mistakes = [];
// Vérifier chaque réponse
document.querySelectorAll(`#exercise${userData.difficulty.charAt(0).toUpperCase() + userData.difficulty.slice(1)} .pluriel-input`).forEach(input => {
const userAnswer = input.value.trim().toLowerCase();
const correctAnswer = input.dataset.answer.toLowerCase();
const questionNumber = input.dataset.number;
// Retirer les classes précédentes
input.classList.remove(‘correct’, ‘incorrect’);
if (userAnswer === correctAnswer) {
input.classList.add(‘correct’);
correctAnswers++;
} else {
input.classList.add(‘incorrect’);
const wordElement = input.previousElementSibling;
const word = wordElement.textContent.trim();
mistakes.push({
number: questionNumber,
word: word,
userAnswer: userAnswer,
correctAnswer: correctAnswer
});
}
});
// Calculer le score
const score = Math.round((correctAnswers / totalQuestions) * 100);
userData.score = score;
// Afficher les résultats
resultContainer.style.display = ‘block’;
resultText.innerHTML = `Vous avez obtenu un score de ${score}% (${correctAnswers} réponses correctes sur ${totalQuestions}).`;
// Afficher les erreurs
mistakesContainer.innerHTML = ”;
if (mistakes.length > 0) {
const mistakesTitle = document.createElement(‘h4’);
mistakesTitle.textContent = ‘Erreurs à corriger:’;
mistakesContainer.appendChild(mistakesTitle);
const mistakesList = document.createElement(‘ul’);
mistakes.forEach(mistake => {
const mistakeItem = document.createElement(‘li’);
mistakeItem.innerHTML = `Question ${mistake.number}: ${mistake.word} → votre réponse: “${mistake.userAnswer}”, réponse correcte: “${mistake.correctAnswer}”`;
mistakesList.appendChild(mistakeItem);
});
mistakesContainer.appendChild(mistakesList);
}
// Afficher le bouton du certificat si le score est supérieur à 70%
if (score >= 70) {
showCertificateButton.style.display = ‘block’;
} else {
showCertificateButton.style.display = ‘none’;
}
});
// Afficher le certificat
showCertificateButton.addEventListener(‘click’, function() {
certificateContainer.style.display = ‘block’;
resultContainer.style.display = ‘none’;
// Remplir les informations du certificat
document.getElementById(‘certificateName’).textContent = `${userData.prenom} ${userData.nom}`;
document.getElementById(‘certificateLevel’).textContent = userData.difficulty;
document.getElementById(‘certificateScore’).textContent = `${userData.score}%`;
const today = new Date();
const options = { year: ‘numeric’, month: ‘long’, day: ‘numeric’ };
document.getElementById(‘certificateDate’).textContent = today.toLocaleDateString(‘fr-FR’, options);
// Générer un QR code
const qrValue = `nom=${userData.nom}&prenom=${userData.prenom}&email=${userData.email}&score=${userData.score}&niveau=${userData.difficulty}`;
const qrContainer = document.querySelector(‘.certificate-qr’);
qrContainer.innerHTML = ”;
var qr = qrcode(4, ‘L’);
qr.addData(qrValue);
qr.make();
qrContainer.innerHTML = qr.createImgTag(4);
// Ajouter une image de fond
document.querySelector(‘.certificate-background’).style.backgroundImage = “url(‘/api/placeholder/800/600’)”;
// Ajouter des triangles décoratifs
document.querySelectorAll(‘.triangle-pattern’).forEach(el => {
let svg = document.createElementNS(“http://www.w3.org/2000/svg”, “svg”);
svg.setAttribute(‘width’, ‘100%’);
svg.setAttribute(‘height’, ‘100%’);
svg.setAttribute(‘viewBox’, ‘0 0 150 120’);
for (let i = 0; i {
const imgData = canvas.toDataURL(‘image/png’);
const pdf = new jspdf.jsPDF({
orientation: ‘landscape’,
unit: ‘mm’,
});
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, ‘PNG’, 0, 0, pdfWidth, pdfHeight);
pdf.save(`Certificat_Francais_${userData.prenom}_${userData.nom}.pdf`);
pdfLoading.style.display = ‘none’;
});
}, 500);
});
// Initialiser l’affichage
showExerciseByDifficulty(‘facile’);
});