* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 100%;
margin: 0 auto;
background: rgba(255, 255, 255, 0.98);
padding: 40px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
h1 {
color: #2c3e50;
text-align: center;
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
}
.subtitle {
text-align: center;
color: #7f8c8d;
font-size: 1.2em;
margin-bottom: 30px;
}
.subscription-form {
background: linear-gradient(135deg, #e8f4f8 0%, #d4f1f4 100%);
padding: 30px;
border-radius: 15px;
margin-bottom: 30px;
border: 2px solid rgba(52, 152, 219, 0.3);
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #2c3e50;
font-size: 1.1em;
}
input[type=”text”],
input[type=”email”] {
width: 100%;
padding: 15px;
border: 2px solid #e9ecef;
border-radius: 10px;
font-size: 16px;
transition: all 0.3s ease;
}
input:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 4px rgba(52, 152, 219, 0.1);
}
.checkbox-label {
display: flex;
align-items: center;
cursor: pointer;
}
.checkbox-label input[type=”checkbox”] {
width: 20px;
height: 20px;
margin-right: 10px;
cursor: pointer;
}
.error {
color: #e74c3c;
font-size: 14px;
margin-top: 5px;
font-weight: bold;
}
button {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
border: none;
padding: 18px 40px;
border-radius: 50px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
transition: all 0.3s ease;
box-shadow: 0 5px 20px rgba(52, 152, 219, 0.4);
display: block;
margin: 0 auto;
}
button:hover:not(:disabled) {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(52, 152, 219, 0.5);
}
button:disabled {
background: #95a5a6;
cursor: not-allowed;
transform: none;
}
.quiz-section {
display: none;
animation: fadeIn 0.5s ease;
}
.quiz-section.active {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.progress-container {
margin: 30px 0;
}
.progress-bar {
width: 100%;
height: 30px;
background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
border-radius: 15px;
overflow: hidden;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
}
.progress-fill {
height: 100%;
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
border-radius: 15px;
transition: width 0.5s ease;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 14px;
}
.grammar-notes {
background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
padding: 25px;
border-radius: 15px;
margin-bottom: 25px;
border-left: 5px solid #f39c12;
}
.grammar-notes h3 {
color: #d68910;
margin-bottom: 15px;
font-size: 1.4em;
}
.grammar-notes ul {
margin-left: 20px;
line-height: 1.8;
}
.grammar-notes li {
margin-bottom: 10px;
color: #5d4e37;
}
.example {
background: rgba(255,255,255,0.7);
padding: 10px 15px;
border-radius: 8px;
margin: 5px 0;
font-style: italic;
}
.start-section-btn {
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
margin: 20px auto;
}
.question-container {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 30px;
border-radius: 15px;
margin-bottom: 25px;
border-left: 6px solid #3498db;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.question-number {
font-weight: bold;
color: #3498db;
font-size: 1.3em;
margin-bottom: 15px;
}
.question-text {
font-size: 1.1em;
margin-bottom: 20px;
line-height: 1.6;
color: #2c3e50;
}
.fill-blank {
background: white;
border: 2px solid #3498db;
border-radius: 8px;
padding: 10px 15px;
margin: 0 8px;
min-width: 150px;
text-align: center;
font-weight: bold;
font-size: 1em;
transition: all 0.3s ease;
}
.fill-blank:focus {
outline: none;
border-color: #2980b9;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
}
.fill-blank.correct {
background: #d4edda;
border-color: #28a745;
}
.fill-blank.incorrect {
background: #f8d7da;
border-color: #dc3545;
}
.options {
display: grid;
gap: 15px;
}
.option {
display: flex;
align-items: center;
padding: 15px 20px;
background: white;
border: 2px solid #e9ecef;
border-radius: 10px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1.05em;
}
.option:hover {
border-color: #3498db;
background: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);
transform: translateX(5px);
}
.option input[type=”radio”] {
margin-right: 15px;
width: 20px;
height: 20px;
cursor: pointer;
}
.option.correct {
background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%);
border-color: #28a745;
}
.option.incorrect {
background: linear-gradient(135deg, #f8d7da 0%, #f1b0b7 100%);
border-color: #dc3545;
}
.option.correct-answer {
background: linear-gradient(135deg, #d1ecf1 0%, #bee5eb 100%);
border-color: #17a2b8;
}
.navigation-buttons {
display: flex;
justify-content: space-between;
gap: 20px;
margin-top: 30px;
}
.nav-btn {
flex: 1;
background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%);
}
.nav-btn.next {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
}
.result-container {
display: none;
background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%);
padding: 40px;
border-radius: 15px;
text-align: center;
margin-top: 30px;
border: 3px solid #28a745;
}
.score-display {
font-size: 3em;
font-weight: bold;
color: #28a745;
margin: 20px 0;
}
.feedback {
font-size: 1.3em;
margin: 20px 0;
color: #155724;
}
.mistakes-container {
background: white;
padding: 25px;
border-radius: 10px;
margin-top: 25px;
text-align: left;
}
.mistake-item {
background: #fff3cd;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
border-left: 4px solid #ffc107;
}
.certificate-container {
display: none;
margin-top: 30px;
}
#certificatePreview {
width: 100%;
background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
border: 12px solid transparent;
border-image: linear-gradient(45deg, #3498db, #2980b9, #1abc9c, #16a085) 1;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
}
.certificate-header {
text-align: center;
margin-bottom: 30px;
}
.certificate-logo {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
padding: 15px 30px;
border-radius: 50px;
display: inline-block;
font-size: 1.5em;
font-weight: bold;
margin-bottom: 20px;
}
.certificate-body {
text-align: center;
padding: 30px 0;
}
#certificateName {
font-size: 2.5em;
color: #e74c3c;
margin: 20px 0;
text-transform: uppercase;
letter-spacing: 3px;
}
#certificateScore {
font-size: 2em;
color: #27ae60;
font-weight: bold;
}
.certificate-footer {
text-align: center;
margin-top: 30px;
padding-top: 20px;
border-top: 3px solid #3498db;
}
.loading {
display: none;
text-align: center;
color: #3498db;
font-style: italic;
margin-top: 15px;
}
.instruction-box {
background: linear-gradient(135deg, #e8f4f8 0%, #d4f1f4 100%);
padding: 20px;
border-radius: 12px;
margin-bottom: 25px;
border-left: 5px solid #3498db;
}
.section-title {
color: #2c3e50;
font-size: 2em;
margin-bottom: 20px;
text-align: center;
padding-bottom: 15px;
border-bottom: 3px solid #3498db;
}
.hint {
font-size: 0.9em;
color: #7f8c8d;
font-style: italic;
margin-top: 5px;
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
h1 {
font-size: 1.8em;
}
.fill-blank {
min-width: 120px;
margin: 5px;
}
.navigation-buttons {
flex-direction: column;
}
}
🗼 Quiz Français A2
Ça vaut le détour – Tourisme et Voyage
📋 Inscription au Quiz
Ce quiz évalue vos compétences en français niveau A2 sur le thème du voyage et du tourisme.
🗼 Quiz A2 – Ça vaut le détour
Tourisme et Voyage
💡 Notes de grammaire
Formation des adverbes en -ment :
- Règle générale : Adjectif au féminin + -ment
lent → lente → lentement / heureux → heureuse → heureusement
- Adjectifs terminés en -ant : remplacer par -amment
constant → constamment / élégant → élégamment
- Adjectifs terminés en -ent : remplacer par -emment
patient → patiemment / récent → récemment
- Adjectifs terminés par une voyelle : ajouter directement -ment
vrai → vraiment / poli → poliment
📋 Instructions : Complétez les phrases avec l’adverbe formé à partir de l’adjectif entre parenthèses.
💡 Notes de grammaire
Quand utiliser l’imparfait et le passé composé ?
- IMPARFAIT : Description, habitude, action en cours
Il faisait beau. / Je visitais souvent Paris. / Pendant que je dormais…
- PASSÉ COMPOSÉ : Action ponctuelle, terminée, succession d’actions
J’ai visité le Louvre. / Il est arrivé à 10h. / Nous avons pris le train.
- CONJUGAISON IMPARFAIT : radical (nous au présent) + ais/ais/ait/ions/iez/aient
visiter → nous visitons → je visitais
- CONJUGAISON PASSÉ COMPOSÉ : avoir/être + participe passé
j’ai visité / je suis allé(e) / nous avons vu
📋 Instructions : Conjuguez les verbes entre parenthèses à l’imparfait ou au passé composé selon le contexte.
💡 Notes de grammaire
Utilisation des pronoms EN et Y :
- Pronom EN : remplace un complément introduit par DE, DU, DE LA, DES, UN, UNE
Je viens de Paris → J’en viens / J’ai acheté des souvenirs → J’en ai acheté
- Pronom Y : remplace un lieu introduit par À, EN, DANS, SUR, CHEZ
Je vais à Rome → J’y vais / Je reste en France → J’y reste
- Pronom Y : remplace aussi un complément introduit par À (chose)
Je pense à mes vacances → J’y pense
- Position : EN et Y se placent avant le verbe conjugué
J’y vais / Je n’en veux pas / Je vais y aller / Je ne peux pas en acheter
📋 Instructions : Choisissez la bonne réponse avec EN ou Y.
– Oui, je _____ vais.
– Oui, nous _____ venons.
– Oui, elle _____ habite depuis 5 ans.
– Oui, j’_____ ai acheté dix.
– Oui, il _____ pense tout le temps.
– Non merci, nous n’_____ avons pas besoin.
– Oui, ils _____ vont maintenant.
– Oui, elle _____ a pris beaucoup.
– Oui, ils _____ restent trois nuits.
– Oui, j’_____ parle à tous mes amis.
💡 Notes de grammaire
Le gérondif :
- Formation : EN + participe présent (radical de “nous” au présent + -ant)
parler → nous parlons → EN parlant / finir → nous finissons → EN finissant
- Utilisation : Exprime la simultanéité (deux actions en même temps)
Je visite le musée en écoutant le guide.
- Utilisation : Exprime la manière (comment on fait quelque chose)
On apprend en voyageant.
- Utilisation : Exprime la condition
En réservant à l’avance, tu auras un meilleur prix.
- Verbes irréguliers :
être → en étant / avoir → en ayant / savoir → en sachant
📋 Instructions : Complétez les phrases avec le gérondif du verbe entre parenthèses (EN + participe présent).
💡 Notes de vocabulaire
Vocabulaire essentiel du tourisme :
- Hébergement : hôtel, auberge de jeunesse, camping, chambre d’hôte, gîte
Je cherche un hôtel avec vue sur la mer.
- Transport : avion, train, bus, location de voiture, bateau, métro
Nous prenons le train pour aller à Lyon.
- Activités : visite guidée, excursion, randonnée, musée, monument
J’ai réservé une visite guidée du château.
- Documents : passeport, visa, billet, réservation, plan
N’oublie pas ton passeport!
- Expressions : Ça vaut le détour (ça mérite d’être visité), être dépaysé (découvrir quelque chose de différent)
📋 Instructions : Choisissez la bonne réponse concernant le vocabulaire du tourisme.
🎉 Résultats de votre Quiz A2
🎓 Certificat de Réussite
CERTIFICAT DE RÉUSSITE
Français Niveau A2
Thème: Ça vaut le détour – Tourisme et Voyage
Ce certificat est décerné à
Pour avoir démontré sa maîtrise du français niveau A2
dans les domaines suivants :
✓ Les adverbes en -ment
✓ L’alternance imparfait / passé composé
✓ Les pronoms EN et Y
✓ Le gérondif
✓ Le vocabulaire du tourisme
Score obtenu :
// Variables globales
let userData = {
prenom: ”,
nom: ”,
email: ”,
scores: {},
totalScore: 0
};
let currentSection = 0;
const totalSections = 5;
const totalQuestions = 50; // Total correcto: 50 preguntas
// Démarrage du quiz
document.getElementById(‘startButton’).addEventListener(‘click’, function() {
if (validateForm()) {
document.getElementById(‘subscriptionForm’).style.display = ‘none’;
document.getElementById(‘quizContainer’).style.display = ‘block’;
showSection(1);
window.scrollTo(0, 0);
}
});
// Validation du formulaire
function validateForm() {
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;
clearErrors();
let isValid = true;
if (!prenom) {
showError(‘prenomError’, ‘⚠️ Veuillez entrer votre prénom’);
isValid = false;
}
if (!nom) {
showError(‘nomError’, ‘⚠️ Veuillez entrer votre nom’);
isValid = false;
}
if (!email) {
showError(‘emailError’, ‘⚠️ Veuillez entrer votre email’);
isValid = false;
} else if (!/^[^s@]+@[^s@]+.[^s@]+$/.test(email)) {
showError(‘emailError’, ‘⚠️ Format d’email invalide’);
isValid = false;
}
if (!subscribe) {
showError(‘subscribeError’, ‘⚠️ Veuillez accepter de vous abonner’);
isValid = false;
}
if (isValid) {
userData.prenom = prenom;
userData.nom = nom;
userData.email = email;
}
return isValid;
}
function clearErrors() {
[‘prenomError’, ‘nomError’, ‘emailError’, ‘subscribeError’].forEach(id => {
document.getElementById(id).textContent = ”;
});
}
function showError(elementId, message) {
document.getElementById(elementId).textContent = message;
}
// Navigation entre sections
function showSection(sectionNum) {
document.querySelectorAll(‘.quiz-section’).forEach(section => {
section.classList.remove(‘active’);
});
const section = document.getElementById(`section${sectionNum}`);
if (section) {
section.classList.add(‘active’);
currentSection = sectionNum;
updateProgress();
window.scrollTo({ top: 0, behavior: ‘smooth’ });
}
}
function startSection(sectionNum) {
const questionsDiv = document.getElementById(`section${sectionNum}Questions`);
const startBtn = event.target;
if (questionsDiv && startBtn) {
questionsDiv.style.display = ‘block’;
startBtn.style.display = ‘none’;
window.scrollTo({ top: questionsDiv.offsetTop – 100, behavior: ‘smooth’ });
}
}
// Mise à jour de la barre de progression
function updateProgress() {
const progressFill = document.getElementById(‘progressFill’);
const percentage = (currentSection / totalSections) * 100;
progressFill.style.width = percentage + ‘%’;
progressFill.textContent = `Partie ${currentSection}/5`;
}
// Validation des sections
function validateSection(sectionNum) {
let sectionScore = 0;
let questionsInSection = 0;
let mistakes = [];
if (sectionNum === 1) {
// Partie 1: Adverbes en -ment (10 questions = 10 points)
questionsInSection = 10;
for (let i = 1; i <= 10; i++) {
const input = document.getElementById(`q${i}`);
const correctAnswer = input.dataset.answer.toLowerCase().trim();
const userAnswer = input.value.toLowerCase().trim();
if (normalizeAnswer(userAnswer) === normalizeAnswer(correctAnswer)) {
sectionScore++;
input.classList.add('correct');
input.classList.remove('incorrect');
} else {
input.classList.add('incorrect');
input.classList.remove('correct');
mistakes.push({
question: i,
userAnswer: input.value || 'Pas de réponse',
correctAnswer: input.dataset.answer
});
}
}
} else if (sectionNum === 2) {
// Partie 2: Imparfait/Passé composé (10 questions = 10 points)
// Cada pregunta vale 1 punto, aunque tenga 2 blancos
questionsInSection = 10;
for (let i = 11; i <= 20; i++) {
const input1 = document.getElementById(`q${i}`);
const input2 = document.getElementById(`q${i}b`);
const correct1 = normalizeAnswer(input1.value) === normalizeAnswer(input1.dataset.answer);
const correct2 = normalizeAnswer(input2.value) === normalizeAnswer(input2.dataset.answer);
// Solo cuenta como correcta si AMBAS respuestas son correctas
if (correct1 && correct2) {
sectionScore++;
input1.classList.add('correct');
input2.classList.add('correct');
} else {
if (!correct1) {
input1.classList.add('incorrect');
mistakes.push({
question: i,
part: 'première partie',
userAnswer: input1.value || 'Pas de réponse',
correctAnswer: input1.dataset.answer
});
} else {
input1.classList.add('correct');
}
if (!correct2) {
input2.classList.add('incorrect');
mistakes.push({
question: i,
part: 'deuxième partie',
userAnswer: input2.value || 'Pas de réponse',
correctAnswer: input2.dataset.answer
});
} else {
input2.classList.add('correct');
}
}
}
} else if (sectionNum === 3) {
// Partie 3: Pronoms EN et Y (10 questions = 10 points)
questionsInSection = 10;
for (let i = 21; i opt.classList.remove(‘correct’, ‘incorrect’, ‘correct-answer’));
if (selectedRadio) {
if (selectedRadio.value === correctAnswer) {
sectionScore++;
selectedRadio.closest(‘.option’).classList.add(‘correct’);
} else {
selectedRadio.closest(‘.option’).classList.add(‘incorrect’);
const correctOption = question.querySelector(`input[value=”${correctAnswer}”]`);
if (correctOption) {
correctOption.closest(‘.option’).classList.add(‘correct-answer’);
}
mistakes.push({
question: i,
userAnswer: getOptionText(selectedRadio),
correctAnswer: getOptionText(question.querySelector(`input[value=”${correctAnswer}”]`))
});
}
} else {
const correctOption = question.querySelector(`input[value=”${correctAnswer}”]`);
if (correctOption) {
correctOption.closest(‘.option’).classList.add(‘correct-answer’);
}
mistakes.push({
question: i,
userAnswer: ‘Pas de réponse’,
correctAnswer: getOptionText(question.querySelector(`input[value=”${correctAnswer}”]`))
});
}
}
}
} else if (sectionNum === 4) {
// Partie 4: Gérondif (10 questions = 10 points)
questionsInSection = 10;
for (let i = 31; i <= 40; i++) {
const input = document.getElementById(`q${i}`);
const correctAnswer = input.dataset.answer.toLowerCase().trim();
const userAnswer = input.value.toLowerCase().trim();
if (normalizeAnswer(userAnswer) === normalizeAnswer(correctAnswer)) {
sectionScore++;
input.classList.add('correct');
input.classList.remove('incorrect');
} else {
input.classList.add('incorrect');
input.classList.remove('correct');
mistakes.push({
question: i,
userAnswer: input.value || 'Pas de réponse',
correctAnswer: input.dataset.answer
});
}
}
} else if (sectionNum === 5) {
// Partie 5: Vocabulaire (10 questions = 10 points)
questionsInSection = 10;
for (let i = 41; i opt.classList.remove(‘correct’, ‘incorrect’, ‘correct-answer’));
if (selectedRadio) {
if (selectedRadio.value === correctAnswer) {
sectionScore++;
selectedRadio.closest(‘.option’).classList.add(‘correct’);
} else {
selectedRadio.closest(‘.option’).classList.add(‘incorrect’);
const correctOption = question.querySelector(`input[value=”${correctAnswer}”]`);
if (correctOption) {
correctOption.closest(‘.option’).classList.add(‘correct-answer’);
}
mistakes.push({
question: i,
userAnswer: getOptionText(selectedRadio),
correctAnswer: getOptionText(question.querySelector(`input[value=”${correctAnswer}”]`))
});
}
} else {
const correctOption = question.querySelector(`input[value=”${correctAnswer}”]`);
if (correctOption) {
correctOption.closest(‘.option’).classList.add(‘correct-answer’);
}
mistakes.push({
question: i,
userAnswer: ‘Pas de réponse’,
correctAnswer: getOptionText(question.querySelector(`input[value=”${correctAnswer}”]`))
});
}
}
}
}
userData.scores[`section${sectionNum}`] = {
score: sectionScore,
total: questionsInSection,
mistakes: mistakes
};
// Si c’est la dernière section, afficher les résultats
if (sectionNum === 5) {
showResults();
} else {
showSection(sectionNum + 1);
}
}
function getOptionText(input) {
if (!input) return ”;
return input.closest(‘.option’).textContent.trim();
}
function normalizeAnswer(answer) {
return answer.toLowerCase()
.trim()
.normalize(‘NFD’)
.replace(/[u0300-u036f]/g, ”)
.replace(/s+/g, ‘ ‘)
.replace(/’/g, “‘”);
}
// Affichage des résultats
function showResults() {
let totalCorrect = 0;
let allMistakes = [];
for (let i = 1; i = 70 ? ‘#28a745’ : percentage >= 50 ? ‘#f39c12’ : ‘#e74c3c’;
if (percentage >= 90) {
feedbackText.innerHTML = ‘🎉 Excellent ! Vous maîtrisez parfaitement le niveau A2 !’;
} else if (percentage >= 70) {
feedbackText.innerHTML = ‘👍 Très bien ! Vous avez un bon niveau A2.’;
} else if (percentage >= 50) {
feedbackText.innerHTML = ‘📚 Assez bien ! Continuez à pratiquer.’;
} else {
feedbackText.innerHTML = ‘💪 Il faut encore travailler. Révisez et réessayez !’;
}
// Afficher les erreurs
const mistakesContainer = document.getElementById(‘mistakesContainer’);
if (allMistakes.length > 0) {
let mistakesHTML = ‘
📝 Questions à revoir :
‘;
allMistakes.forEach(mistake => {
mistakesHTML += `
❌ Votre réponse: ${mistake.userAnswer}
✅ Réponse correcte: ${mistake.correctAnswer}
`;
});
mistakesContainer.innerHTML = mistakesHTML;
} else {
mistakesContainer.innerHTML = ‘
🎯 Parfait ! Toutes vos réponses sont correctes !
‘;
}
if (percentage >= 70) {
document.getElementById(‘showCertificateButton’).style.display = ‘inline-block’;
}
document.getElementById(‘resultContainer’).style.display = ‘block’;
document.getElementById(‘resultContainer’).scrollIntoView({ behavior: ‘smooth’ });
}
// Afficher le certificat
document.getElementById(‘showCertificateButton’).addEventListener(‘click’, function() {
document.getElementById(‘certificateName’).textContent = `${userData.prenom.toUpperCase()} ${userData.nom.toUpperCase()}`;
document.getElementById(‘certificateScore’).textContent = `${userData.totalScore}%`;
document.getElementById(‘certificateDate’).textContent = new Date().toLocaleDateString(‘fr-FR’, {
day: ‘numeric’,
month: ‘long’,
year: ‘numeric’
});
document.getElementById(‘certificateContainer’).style.display = ‘block’;
document.getElementById(‘certificateContainer’).scrollIntoView({ behavior: ‘smooth’ });
});
// Télécharger le certificat PDF
document.getElementById(‘downloadCertificateButton’).addEventListener(‘click’, function() {
const loading = document.getElementById(‘pdfLoading’);
const button = this;
loading.style.display = ‘block’;
button.disabled = true;
const element = document.getElementById(‘certificatePreview’);
html2canvas(element, {
scale: 2,
useCORS: true,
backgroundColor: ‘#ffffff’
}).then(canvas => {
const imgData = canvas.toDataURL(‘image/png’);
const { jsPDF } = window.jspdf;
const pdf = new jsPDF(‘landscape’, ‘mm’, ‘a4’);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const imgWidth = pdfWidth – 20;
const imgHeight = (canvas.height * imgWidth) / canvas.width;
const x = 10;
const y = (pdfHeight – imgHeight) / 2;
pdf.addImage(imgData, ‘PNG’, x, y, imgWidth, imgHeight);
pdf.setProperties({
title: `Certificat A2 – ${userData.prenom} ${userData.nom}`,
subject: ‘Certificat de réussite Français A2’,
author: ‘Français Langue Française’
});
const filename = `Certificat_A2_${userData.prenom}_${userData.nom}_${userData.totalScore}pct.pdf`;
pdf.save(filename);
loading.style.display = ‘none’;
button.disabled = false;
}).catch(error => {
console.error(‘Erreur PDF:’, error);
alert(‘Erreur lors de la génération du PDF. Veuillez réessayer.’);
loading.style.display = ‘none’;
button.disabled = false;
});
});