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: 100%;
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;
}
.blank-input {
width: 150px;
padding: 5px;
border: 1px solid #ddd;
border-radius: 4px;
margin: 0 5px;
font-size: 16px;
}
.blank-input.correct {
background-color: #d4edda;
border-color: #c3e6cb;
}
.blank-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%;
max-width: 100%;
margin: 0 auto;
height: 500px;
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-image: url(“data:image/svg+xml,%3Csvg xmlns=’http://www.w3.org/2000/svg’ width=’200′ height=’200′ viewBox=’0 0 200 200’%3E%3Cpath fill=’%233498db’ d=’M100 0L120 80H180L130 130L150 200L100 160L50 200L70 130L20 80H80L100 0Z’/%3E%3C/svg%3E”);
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;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
}
.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;
background-image: url(“data:image/svg+xml,%3Csvg xmlns=’http://www.w3.org/2000/svg’ width=’150′ height=’120′ viewBox=’0 0 150 120’%3E%3Cpath fill=’%233498db’ fill-opacity=’0.2′ d=’M0 0L75 120L150 0Z’/%3E%3C/svg%3E”);
}
.triangle-pattern.top-right {
top: 0;
right: 0;
}
.triangle-pattern.bottom-left {
bottom: 0;
left: 0;
transform: rotate(180deg);
}
.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;
}
.exercise-type {
margin-bottom: 20px;
font-weight: bold;
color: #3498db;
}
.question-container {
margin-bottom: 15px;
}
.radio-option {
margin: 5px 0;
display: flex;
align-items: center;
}
.radio-option input[type=”radio”] {
width: auto;
margin-right: 10px;
}
.radio-option.correct {
color: #28a745;
font-weight: bold;
}
.radio-option.incorrect {
color: #dc3545;
text-decoration: line-through;
}
.matching-exercise {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
}
.matching-item {
background-color: #e8f4f8;
padding: 10px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.matching-item.selected {
background-color: #3498db;
color: white;
}
.matching-item.matched {
background-color: #d4edda;
border: 1px solid #c3e6cb;
cursor: default;
}
.matching-pair {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.matching-pair-text {
flex: 1;
}
.match-arrow {
margin: 0 10px;
font-size: 24px;
}
/* Ajout pour l’impression */
@media print {
body * {
visibility: hidden;
}
#certificatePreview, #certificatePreview * {
visibility: visible;
}
#certificatePreview {
position: absolute;
left: 0;
top: 0;
width: 100%;
border: none;
}
}
Exercice de Grammaire: Les Noms en Français
Inscrivez-vous pour commencer l’exercice
Veuillez remplir vos informations pour accéder à l’exercice.
Les Noms en Français: Genre, Nombre et Cas Particuliers
Choisissez le niveau de difficulté:
Facile
Moyen
Difficile
Ces exercices portent sur les noms en français: le genre (masculin/féminin), le nombre (singulier/pluriel), les noms de genre différent, les faux amis et les cas particuliers. Complétez les exercices suivants.
Les Noms en Français (Niveau Facile)
Complétez avec l’article défini (le/la/l’) ou indéfini (un/une) approprié:
1. J’aime beaucoup musique classique.
2. chien de mon voisin aboie tout le temps.
3. Elle a acheté nouvelle voiture.
4. arbre dans le jardin est très vieux.
5. J’ai trouvé bon livre à la bibliothèque.
Mettez ces noms au pluriel:
6. un journal → des
7. une souris → des
8. un chapeau → des
9. un enfant → des
10. un festival → des
Pour chaque phrase, sélectionnez la forme correcte du nom:
Associez chaque nom à sa signification:
Les Noms en Français (Niveau Moyen)
Complétez avec la forme correcte du pluriel:
1. Mon grand-père adore les de jazz. (festival)
2. Ces appartiennent à ma grand-mère. (bijou)
3. Il a trouvé plusieurs lors de sa plongée. (corail)
4. Les de cette actrice sont magnifiques. (œil)
5. Les de ma voiture sont usés. (pneu)
Complétez les phrases avec le bon article (le/la/un/une) selon le sens:
6. mémoire de l’étudiant était excellent. (document écrit)
7. mémoire est une faculté qui diminue avec l’âge. (capacité de se souvenir)
8. Le magicien a sorti tour de son chapeau. (astuce)
9. Nous avons visité tour historique à Paris. (construction élevée)
10. moule à gâteau est dans le placard. (ustensile de cuisine)
Choisissez la réponse correcte:
Écrivez la forme plurielle correcte des noms composés suivants:
16. un chef-d’œuvre → des
17. un garde-meuble → des
18. un passe-partout → des
19. un aller-retour → des
20. un tire-bouchon → des
Associez chaque nom à son genre et à son sens correct:
Les Noms en Français (Niveau Difficile)
Complétez avec la forme correcte du pluriel:
1. J’ai acheté plusieurs pour offrir à mes amis. (porte-monnaie)
2. Les entre les deux présidents ont été productifs. (tête-à-tête)
3. Il collectionnait les anciens. (garde-temps)
4. Les sont magnifiques après la pluie. (arc-en-ciel)
5. Les rares valent une fortune. (timbre-poste)
Complétez avec l’article correct (le/la/un/une) selon le sens:
6. vase de ma grand-mère est très ancien. (récipient)
7. vase s’accumule au fond de la rivière. (boue)
8. voile du bateau s’est déchiré pendant la tempête. (toile)
9. voile musulmane fait débat dans certains pays. (tissu)
10. mode d’emploi est difficile à comprendre. (procédure)
Choisissez la réponse correcte pour ces cas difficiles:
Écrivez la forme plurielle correcte des noms composés suivants:
16. un water-closet → des
17. un après-ski → des
18. un haut-le-cœur → des
19. un va-nu-pieds → des
20. un pied-à-terre → des
Complétez les phrases avec la forme correcte:
21. Les sont connus pour leur ponctualité. (nom de nationalité)
22. Je préfère les masqués aux soirées ordinaires. (pluriel de “bal”)
23. Les désignent les ancêtres en général. (pluriel de “aïeul”)
24. Les de lit sont des tentures décoratives. (pluriel spécifique de “ciel”)
25. J’ai lu tous les de cet auteur sur le sujet. (pluriel spécifique de “travail”)
Résultats:
Votre Certificat
Certificat d’Excellence
en Grammaire Française
Ce certificat est décerné à
Prénom Nom
pour avoir complété avec succès l’exercice
“Les Noms en Français: Genre, Nombre et Cas Particuliers”
avec un score de XX/25
Le 22 avril 2025
document.addEventListener(‘DOMContentLoaded’, function() {
// Variables globales
let currentDifficulty = ‘facile’;
let matchedPairs = [];
let matchingInProgress = false;
let selectedItem = null;
// Éléments DOM
const subscriptionForm = document.getElementById(‘subscriptionForm’);
const exerciseContainer = document.getElementById(‘exerciseContainer’);
const startButton = document.getElementById(‘startButton’);
const checkButton = document.getElementById(‘checkButton’);
const difficultySelect = document.getElementById(‘difficultySelect’);
const changeDifficultyButton = document.getElementById(‘changeDifficultyButton’);
const resultContainer = document.getElementById(‘resultContainer’);
const scoreText = document.getElementById(‘scoreText’);
const feedbackText = document.getElementById(‘feedbackText’);
const showCertificateButton = document.getElementById(‘showCertificateButton’);
const certificateContainer = document.getElementById(‘certificateContainer’);
const certificateName = document.getElementById(‘certificateName’);
const certificateScore = document.getElementById(‘certificateScore’);
const certificateDate = document.getElementById(‘certificateDate’);
const certificateQR = document.getElementById(‘certificateQR’);
const downloadCertificateButton = document.getElementById(‘downloadCertificateButton’);
const printCertificateButton = document.getElementById(‘printCertificateButton’);
const loadingText = document.getElementById(‘loadingText’);
// Initialisation des exercices de niveau
const exerciseFacile = document.getElementById(‘exerciseFacile’);
const exerciseMoyen = document.getElementById(‘exerciseMoyen’);
const exerciseDifficile = document.getElementById(‘exerciseDifficile’);
// Gestionnaire d’événements pour le bouton de démarrage
startButton.addEventListener(‘click’, function() {
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 messages d’erreur
document.getElementById(‘prenomError’).textContent = ”;
document.getElementById(‘nomError’).textContent = ”;
document.getElementById(‘emailError’).textContent = ”;
document.getElementById(‘subscribeError’).textContent = ”;
// Validation du formulaire
let valid = true;
if (prenom === ”) {
document.getElementById(‘prenomError’).textContent = ‘Veuillez entrer votre prénom.’;
valid = false;
}
if (nom === ”) {
document.getElementById(‘nomError’).textContent = ‘Veuillez entrer votre nom.’;
valid = false;
}
if (email === ”) {
document.getElementById(‘emailError’).textContent = ‘Veuillez entrer votre email.’;
valid = false;
} else if (!validateEmail(email)) {
document.getElementById(‘emailError’).textContent = ‘Veuillez entrer un email valide.’;
valid = false;
}
if (!subscribe) {
document.getElementById(‘subscribeError’).textContent = ‘Vous devez accepter de vous abonner pour continuer.’;
valid = false;
}
if (valid) {
// Masquer le formulaire et afficher l’exercice
subscriptionForm.style.display = ‘none’;
exerciseContainer.style.display = ‘block’;
// Mettre à jour le nom sur le certificat
certificateName.textContent = prenom + ‘ ‘ + nom;
// Initialiser l’exercice
showExercise(currentDifficulty);
initializeMatchingExercises();
}
});
// Validation d’email
function validateEmail(email) {
const re = /^[^s@]+@[^s@]+.[^s@]+$/;
return re.test(email);
}
// Afficher l’exercice selon le niveau de difficulté
function showExercise(difficulty) {
exerciseFacile.style.display = ‘none’;
exerciseMoyen.style.display = ‘none’;
exerciseDifficile.style.display = ‘none’;
switch (difficulty) {
case ‘facile’:
exerciseFacile.style.display = ‘block’;
break;
case ‘moyen’:
exerciseMoyen.style.display = ‘block’;
break;
case ‘difficile’:
exerciseDifficile.style.display = ‘block’;
break;
}
}
// Changer la difficulté
changeDifficultyButton.addEventListener(‘click’, function() {
currentDifficulty = difficultySelect.value;
showExercise(currentDifficulty);
resetExercise();
});
// Réinitialiser l’exercice
function resetExercise() {
// Réinitialiser les inputs
const blankInputs = document.querySelectorAll(‘.blank-input’);
blankInputs.forEach(input => {
input.value = ”;
input.classList.remove(‘correct’, ‘incorrect’);
});
// Réinitialiser les radios
const radioOptions = document.querySelectorAll(‘.radio-option’);
radioOptions.forEach(option => {
option.classList.remove(‘correct’, ‘incorrect’);
const radio = option.querySelector(‘input[type=”radio”]’);
radio.checked = false;
});
// Réinitialiser les matchings
initializeMatchingExercises();
// Masquer les résultats
resultContainer.style.display = ‘none’;
certificateContainer.style.display = ‘none’;
}
// Initialiser les exercices de matching
function initializeMatchingExercises() {
// Pour le niveau facile
if (document.getElementById(‘matchingExercise1’)) {
setupMatchingExercise(‘matchingExercise1’, ‘matchingResults1’);
}
// Pour le niveau moyen
if (document.getElementById(‘matchingExercise2’)) {
setupMatchingExercise(‘matchingExercise2’, ‘matchingResults2’);
}
}
// Configuration des exercices de matching
function setupMatchingExercise(exerciseId, resultsId) {
const matchingItems = document.querySelectorAll(`#${exerciseId} .matching-item`);
const resultsContainer = document.getElementById(resultsId);
// Réinitialiser
matchedPairs = [];
matchingInProgress = false;
selectedItem = null;
// Mélanger les éléments
const container = document.getElementById(exerciseId);
for (let i = container.children.length; i >= 0; i–) {
container.appendChild(container.children[Math.random() * i | 0]);
}
// Ajouter les écouteurs d’événements
matchingItems.forEach(item => {
item.classList.remove(‘selected’, ‘matched’);
item.addEventListener(‘click’, function() {
if (this.classList.contains(‘matched’)) return;
if (selectedItem === null) {
// Premier élément sélectionné
selectedItem = this;
this.classList.add(‘selected’);
} else {
// Deuxième élément sélectionné, vérifier s’ils correspondent
const firstGroup = selectedItem.getAttribute(‘data-group’);
const secondGroup = this.getAttribute(‘data-group’);
if (firstGroup === secondGroup) {
// Correspondance trouvée
selectedItem.classList.add(‘matched’);
this.classList.add(‘matched’);
// Enregistrer la paire
matchedPairs.push({
number: this.getAttribute(‘data-number’),
first: selectedItem.textContent,
second: this.textContent
});
// Afficher les résultats
updateMatchingResults(resultsId);
}
// Réinitialiser la sélection
selectedItem.classList.remove(‘selected’);
selectedItem = null;
}
});
});
// Vider le conteneur de résultats
resultsContainer.innerHTML = ”;
}
// Mettre à jour l’affichage des résultats de matching
function updateMatchingResults(resultsId) {
const resultsContainer = document.getElementById(resultsId);
resultsContainer.innerHTML = ”;
matchedPairs.forEach(pair => {
const pairElement = document.createElement(‘div’);
pairElement.className = ‘matching-pair’;
pairElement.innerHTML = `
`;
resultsContainer.appendChild(pairElement);
});
}
// Vérifier les réponses
checkButton.addEventListener(‘click’, function() {
// Afficher l’indicateur de chargement
loadingText.style.display = ‘inline’;
// Simuler un délai pour l’effet de vérification
setTimeout(function() {
let score = 0;
let totalQuestions = 0;
// Vérifier les inputs
const blankInputs = document.querySelectorAll(`#exercise${capitalizeFirstLetter(currentDifficulty)} .blank-input`);
blankInputs.forEach(input => {
totalQuestions++;
const correctAnswer = input.getAttribute(‘data-answer’);
if (input.value.trim().toLowerCase() === correctAnswer.toLowerCase()) {
input.classList.add(‘correct’);
input.classList.remove(‘incorrect’);
score++;
} else {
input.classList.add(‘incorrect’);
input.classList.remove(‘correct’);
}
});
// Vérifier les radios
const radioGroups = getRadioGroups(currentDifficulty);
radioGroups.forEach(group => {
totalQuestions++;
const radioOptions = document.querySelectorAll(`#exercise${capitalizeFirstLetter(currentDifficulty)} input[name=”${group}”]`);
let correct = false;
radioOptions.forEach(radio => {
const option = radio.parentElement;
if (radio.checked) {
if (radio.hasAttribute(‘data-correct’)) {
option.classList.add(‘correct’);
correct = true;
} else {
option.classList.add(‘incorrect’);
}
} else if (radio.hasAttribute(‘data-correct’)) {
option.classList.add(‘correct’);
}
});
if (correct) score++;
});
// Vérifier les matchings
const matchingScores = getMatchingScores(currentDifficulty);
score += matchingScores.score;
totalQuestions += matchingScores.total;
// Afficher les résultats
resultContainer.style.display = ‘block’;
scoreText.textContent = `Votre score: ${score}/${totalQuestions}`;
// Feedback basé sur le score
const percentage = (score / totalQuestions) * 100;
if (percentage >= 90) {
feedbackText.textContent = “Excellent! Vous maîtrisez très bien les noms en français.”;
} else if (percentage >= 75) {
feedbackText.textContent = “Très bien! Vous avez une bonne compréhension des noms en français.”;
} else if (percentage >= 60) {
feedbackText.textContent = “Bien! Continuez à pratiquer pour améliorer votre compréhension.”;
} else {
feedbackText.textContent = “Vous avez besoin de plus de pratique. Révisez les règles et réessayez!”;
}
// Mise à jour du score sur le certificat
certificateScore.textContent = `avec un score de ${score}/${totalQuestions}`;
// Masquer l’indicateur de chargement
loadingText.style.display = ‘none’;
}, 1000);
});
// Fonction pour obtenir les groupes de radio selon le niveau
function getRadioGroups(difficulty) {
switch (difficulty) {
case ‘facile’:
return [‘q11’, ‘q12’, ‘q13’, ‘q14’, ‘q15’];
case ‘moyen’:
return [‘q11m’, ‘q12m’, ‘q13m’, ‘q14m’, ‘q15m’];
case ‘difficile’:
return [‘q11d’, ‘q12d’, ‘q13d’, ‘q14d’, ‘q15d’];
default:
return [];
}
}
// Fonction pour obtenir les scores de matching selon le niveau
function getMatchingScores(difficulty) {
let score = 0;
let total = 0;
switch (difficulty) {
case ‘facile’:
total = 5; // 5 paires dans le niveau facile
score = document.querySelectorAll(‘#matchingExercise1 .matching-item.matched’).length / 2;
break;
case ‘moyen’:
total = 5; // 5 paires dans le niveau moyen
score = document.querySelectorAll(‘#matchingExercise2 .matching-item.matched’).length / 2;
break;
default:
break;
}
return { score, total };
}
// Capitaliser la première lettre
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// Afficher le certificat
showCertificateButton.addEventListener(‘click’, function() {
certificateContainer.style.display = ‘block’;
// Mettre à jour la date
const today = new Date();
const options = { year: ‘numeric’, month: ‘long’, day: ‘numeric’ };
certificateDate.textContent = today.toLocaleDateString(‘fr-FR’, options);
// Générer le QR code
generateQRCode();
});
// Générer un QR code
function generateQRCode() {
if (typeof qrcode !== ‘undefined’) {
const qr = qrcode(4, ‘L’);
qr.addData(‘Certificat de réussite en grammaire française’);
qr.make();
certificateQR.innerHTML = qr.createImgTag(4);
}
}
// Télécharger le certificat en PDF
downloadCertificateButton.addEventListener(‘click’, function() {
if (typeof html2canvas !== ‘undefined’ && typeof jspdf !== ‘undefined’) {
const { jsPDF } = jspdf;
html2canvas(document.getElementById(‘certificatePreview’)).then(canvas => {
const imgData = canvas.toDataURL(‘image/png’);
const pdf = new jsPDF(‘l’, ‘mm’, ‘a4’);
const width = pdf.internal.pageSize.getWidth();
const height = pdf.internal.pageSize.getHeight();
pdf.addImage(imgData, ‘PNG’, 0, 0, width, height);
pdf.save(‘certificat_grammaire_francaise.pdf’);
});
} else {
alert(“La fonction de téléchargement n’est pas disponible. Veuillez essayer d’imprimer le certificat à la place.”);
}
});
// Imprimer le certificat
printCertificateButton.addEventListener(‘click’, function() {
window.print();
});
});