Compare commits
2 Commits
41d8b98f96
...
affa042c05
| Author | SHA1 | Date | |
|---|---|---|---|
| affa042c05 | |||
| 30817c829b |
BIN
data/ghs05-corrosif.jpg
Normal file
BIN
data/ghs05-corrosif.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
data/ghs07-nocif.jpg
Normal file
BIN
data/ghs07-nocif.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
BIN
data/ghs09-environnement.jpg
Normal file
BIN
data/ghs09-environnement.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
@@ -17,7 +17,7 @@
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
padding-top: calc(70px + 2rem);
|
||||
padding-bottom: calc(52px + 2rem);
|
||||
padding-bottom: calc(84px + 2rem);
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s ease;
|
||||
overflow-y: auto;
|
||||
@@ -46,33 +46,63 @@
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* BOTTOM BAR */
|
||||
/* BOTTOM BAR (modèle BioCID) */
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
height: 52px;
|
||||
height: 84px;
|
||||
background: rgba(250, 238, 218, 0.98);
|
||||
border-top: 2px solid var(--amber);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: center;
|
||||
padding: 0 20px;
|
||||
z-index: 100;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
.slide-counter { font-size: 12px; font-family: 'Syne', sans-serif; font-weight: 600; color: var(--amber-dark); }
|
||||
.back-btn {
|
||||
background: none;
|
||||
border: 0.5px solid var(--amber);
|
||||
border-radius: 20px;
|
||||
padding: 6px 16px;
|
||||
.slide-counter {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
font-size: 12px;
|
||||
font-family: 'Syne', sans-serif;
|
||||
font-weight: 600;
|
||||
color: var(--amber-dark);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
}
|
||||
.back-btn:hover { background: rgba(186,117,23,0.08); }
|
||||
/* Boutons centralisés dans la bottom bar */
|
||||
.bar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
.footer-btn {
|
||||
font-family: 'Syne', sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
padding: 11px 24px;
|
||||
border-radius: 40px;
|
||||
border: 1.5px solid var(--amber);
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
line-height: 1;
|
||||
transition: all 0.2s;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.footer-btn:hover { transform: translateY(-1px); }
|
||||
.footer-btn:active { transform: scale(0.98); }
|
||||
.footer-btn.is-primary { background: var(--amber); color: #fff; }
|
||||
.footer-btn.is-primary:hover { background: var(--amber-dark); }
|
||||
.footer-btn.is-secondary { background: transparent; color: var(--amber-dark); }
|
||||
.footer-btn.is-secondary:hover { background: rgba(186,117,23,0.08); }
|
||||
.footer-btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; pointer-events: none; }
|
||||
@media (max-width: 560px) {
|
||||
.slide-counter { display: none; }
|
||||
.footer-btn { padding: 9px 16px; font-size: 12px; }
|
||||
}
|
||||
|
||||
/* BUTTONS */
|
||||
.btn {
|
||||
@@ -210,7 +240,7 @@
|
||||
#slide-3 {
|
||||
justify-content: flex-start;
|
||||
padding-top: calc(70px + 0.9rem);
|
||||
padding-bottom: calc(52px + 0.6rem);
|
||||
padding-bottom: calc(84px + 0.6rem);
|
||||
}
|
||||
#slide-3 .slide-title { margin: 0.1rem 0 0.15rem; font-size: clamp(19px, 2.4vw, 26px); }
|
||||
.dnd-hint { font-size: 12.5px; color: var(--text-muted); text-align: center; margin: 0 0 10px; }
|
||||
@@ -568,7 +598,8 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
|
||||
background: repeating-linear-gradient(90deg, #1a1a18 0 2px, #fff 2px 4px, #1a1a18 4px 5px, #fff 5px 9px);
|
||||
}
|
||||
.lbl-picto-wrap { display: flex; align-items: center; gap: 8px; }
|
||||
.pictos { display: flex; gap: 6px; }
|
||||
.pictos { display: flex; gap: 6px; align-items: center; }
|
||||
.ghs-img { width: 42px; height: 42px; object-fit: contain; display: block; }
|
||||
.ghs {
|
||||
width: 38px; height: 38px; position: relative;
|
||||
border: 2.5px solid #c62828; background: #fff;
|
||||
@@ -651,23 +682,10 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
|
||||
/* ---- SLIDE 7 — encadré de réponse sur le côté de l'étiquette ---- */
|
||||
#eti-stage {
|
||||
max-width: 980px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 300px;
|
||||
align-items: start;
|
||||
gap: 16px;
|
||||
max-width: 680px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
#eti-stage .label-card { grid-column: 1; grid-row: 1; }
|
||||
#eti-stage .eti-pop,
|
||||
#eti-stage .eti-side-hint { grid-column: 2; grid-row: 1; align-self: start; }
|
||||
#eti-stage .eti-pop { position: relative; inset: auto; left: auto; top: auto; max-width: none; width: 100%; }
|
||||
.eti-side-hint {
|
||||
font-size: 12.5px; color: var(--teal-dark); line-height: 1.5;
|
||||
background: var(--teal-light); border: 1px dashed var(--teal-mid);
|
||||
border-radius: 10px; padding: 12px 14px;
|
||||
}
|
||||
.eti-side-hint[hidden] { display: none; }
|
||||
|
||||
/* ---- SLIDE 7 — récapitulatif : étiquette à gauche, tableau à droite ---- */
|
||||
.recap-layout { display: flex; gap: 20px; align-items: flex-start; justify-content: center; width: 100%; max-width: 1120px; }
|
||||
@@ -678,12 +696,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
@keyframes recapSlideLeft { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: none; } }
|
||||
@keyframes recapSlideRight { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
|
||||
|
||||
@media (max-width: 820px) {
|
||||
#eti-stage { grid-template-columns: 1fr; max-width: 680px; }
|
||||
#eti-stage .eti-pop,
|
||||
#eti-stage .eti-side-hint { grid-column: 1; grid-row: auto; }
|
||||
#eti-stage .label-card { grid-row: auto; }
|
||||
}
|
||||
@media (max-width: 1000px) {
|
||||
.recap-layout { flex-direction: column; align-items: center; }
|
||||
.recap-layout #recap-stage { flex: none; max-width: 560px; width: 100%; }
|
||||
@@ -709,19 +721,19 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<!-- Progress bar -->
|
||||
<div class="progress-bar"><div class="progress-fill" id="progressFill"></div></div>
|
||||
|
||||
<!-- Phase badge -->
|
||||
<div class="phase-badge" id="phaseBadge" style="display:none"></div>
|
||||
|
||||
<!-- Bottom bar -->
|
||||
<div class="bottom-bar" id="bottomBar" style="display:none;">
|
||||
<button class="back-btn" id="backBtn" onclick="goBack()" style="display:none;">← Retour</button>
|
||||
<div class="slide-counter" id="slideCounter"></div>
|
||||
<div class="bar-actions" id="barActions"></div>
|
||||
</div>
|
||||
|
||||
<!-- Confetti -->
|
||||
<canvas id="confettiCanvas" style="position:fixed;inset:0;pointer-events:none;z-index:150;display:none;"></canvas>
|
||||
|
||||
<!-- ============ SLIDE 0 — ACCUEIL ============ -->
|
||||
<div class="slide active fade-in" id="slide-0">
|
||||
<div class="deco-circle" style="width:400px;height:400px;background:var(--amber-light);top:-100px;right:-80px;opacity:0.6;"></div>
|
||||
<div class="deco-circle" style="width:200px;height:200px;background:var(--coral-light);bottom:60px;left:-60px;opacity:0.5;"></div>
|
||||
<div class="deco-circle" style="width:200px;height:200px;background:var(--amber-light);bottom:60px;left:-60px;opacity:0.5;"></div>
|
||||
<div style="text-align:center;">
|
||||
<div class="hero-label">Certibiocide — Travaux dirigés</div>
|
||||
<div class="hero-title">FDS, FT<br>& Étiquettes</div>
|
||||
@@ -736,6 +748,10 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="section-tag">Déroulé du TD</div>
|
||||
<div class="slide-title">Trois documents, trois usages</div>
|
||||
<p class="slide-intro">Vous allez apprendre à localiser une information dans chacun des documents de référence d'un produit biocide.</p>
|
||||
<div class="info-card">
|
||||
<span>⏱️</span>
|
||||
<div>Durée ≈ 30 min. Pour chaque question, sélectionnez la <strong>zone du document</strong> où trouver l'information, puis vérifiez votre score.</div>
|
||||
</div>
|
||||
<div class="overview-grid">
|
||||
<div class="overview-card">
|
||||
<div class="overview-icon">📄</div>
|
||||
@@ -753,10 +769,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="overview-sub">Interface directe avec l'utilisateur</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<span>⏱️</span>
|
||||
<div>Durée ≈ 30 min. Pour chaque question, sélectionnez la <strong>zone du document</strong> où trouver l'information, puis vérifiez votre score.</div>
|
||||
</div>
|
||||
<div class="identity-card">
|
||||
<div class="identity-title">👥 Identification du groupe</div>
|
||||
<div class="identity-fields">
|
||||
@@ -771,7 +783,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
</div>
|
||||
<div class="identity-error" id="idGroupe-error" hidden>⚠️ Renseignez le nom du stagiaire ou du groupe pour continuer.</div>
|
||||
</div>
|
||||
<button class="btn btn-amber" onclick="startPart1()" style="margin-top:1.5rem;">Commencer la partie 1 →</button>
|
||||
</div>
|
||||
|
||||
<!-- ============ SLIDE 2 — FDS INTRO ============ -->
|
||||
@@ -784,7 +795,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<span>🎯</span>
|
||||
<div>Pour chaque question, indiquez dans quelle <strong>rubrique (1 à 16)</strong> trouver la réponse — ou « Absent » si l'information n'y figure pas. Les questions sont mélangées à chaque chargement.</div>
|
||||
</div>
|
||||
<button class="btn btn-amber" onclick="goTo(3)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
||||
</div>
|
||||
|
||||
<!-- ============ SLIDE 3 — FDS QUIZ (DRAG & DROP) ============ -->
|
||||
@@ -796,12 +806,7 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="quiz-list quiz-grid" id="fds-questions"></div>
|
||||
<div class="dnd-bank" id="fds-bank-right"></div>
|
||||
</div>
|
||||
<button class="verify-btn btn-amber" id="fds-verify" onclick="verifyFDS()" disabled>✓ Vérifier mes réponses</button>
|
||||
<div id="fds-result" class="result-message"></div>
|
||||
<div class="actions-row">
|
||||
<button class="btn btn-outline" onclick="resetFDS()">↺ Recommencer</button>
|
||||
<button class="btn btn-coral" onclick="goTo(4)">Passer à la partie 2 →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ SLIDE 4 — FT INTRO ============ -->
|
||||
@@ -814,7 +819,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<span>🎯</span>
|
||||
<div>Indiquez la <strong>section</strong> de la FT où trouver chaque information : Description, Propriétés biocides, Conditionnements, Utilisations — ou « Absent ».</div>
|
||||
</div>
|
||||
<button class="btn btn-coral" onclick="goTo(5)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
||||
</div>
|
||||
|
||||
<!-- ============ SLIDE 5 — FT : RELIER ============ -->
|
||||
@@ -827,12 +831,7 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="match-col match-left" id="ft-left"></div>
|
||||
<div class="match-col match-right" id="ft-right"></div>
|
||||
</div>
|
||||
<button class="verify-btn btn-coral" id="ft-verify" onclick="verifyFT()" disabled>✓ Vérifier mes réponses</button>
|
||||
<div id="ft-result" class="result-message"></div>
|
||||
<div class="actions-row">
|
||||
<button class="btn btn-outline" onclick="resetFT()">↺ Recommencer</button>
|
||||
<button class="btn btn-teal" onclick="goTo(6)">Passer à la partie 3 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -846,7 +845,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<span>🎯</span>
|
||||
<div>Sur une <strong>étiquette réelle</strong> (produit professionnel DÉS'INFECT), <strong>cliquez la zone</strong> qui répond à chaque question : nom commercial, pictogrammes, mention d'avertissement, phrases H, phrases P (EPI, premiers secours, élimination), contenu net et centre antipoison. Chaque clic ouvre la <strong>justification réglementaire</strong> de la zone.</div>
|
||||
</div>
|
||||
<button class="btn btn-teal" onclick="goTo(7)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
||||
</div>
|
||||
|
||||
<!-- ============ SLIDE 7 — ÉTIQUETTE CLIQUABLE (HOTSPOTS) ============ -->
|
||||
@@ -911,9 +909,9 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="lbl-picto-wrap">
|
||||
<span class="hotspot" data-zone="z-picto">
|
||||
<span class="pictos">
|
||||
<span class="ghs"><span>🐟</span></span>
|
||||
<span class="ghs"><span>🧪</span></span>
|
||||
<span class="ghs excl"><span>!</span></span>
|
||||
<img class="ghs-img" src="../data/ghs09-environnement.jpg" alt="Pictogramme SGH09 — danger pour le milieu aquatique">
|
||||
<img class="ghs-img" src="../data/ghs05-corrosif.jpg" alt="Pictogramme SGH05 — corrosif">
|
||||
<img class="ghs-img" src="../data/ghs07-nocif.jpg" alt="Pictogramme SGH07 — nocif / irritant">
|
||||
</span>
|
||||
</span>
|
||||
<span class="hotspot" data-zone="z-mention"><span class="lbl-danger">DANGER</span></span>
|
||||
@@ -923,21 +921,9 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="lbl-footer">FHER — 2, rue de Sèze, 75009 Paris — Tél. 01 23 45 67 89</div>
|
||||
</div>
|
||||
|
||||
<div class="eti-side-hint" id="eti-side-hint">👉 Cliquez une zone de l'étiquette : sa justification réglementaire s'affiche ici, à côté du bidon.</div>
|
||||
|
||||
<div class="eti-pop" id="eti-pop" hidden>
|
||||
<button class="pop-close" onclick="closeEtiPop()" aria-label="Fermer">×</button>
|
||||
<div class="pop-status" id="pop-status"></div>
|
||||
<div class="pop-title" id="pop-title"></div>
|
||||
<div class="pop-reg" id="pop-reg"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="etiquette-result" class="result-message"></div>
|
||||
<div class="actions-row">
|
||||
<button class="btn btn-outline" onclick="resetEtiquette()">↺ Recommencer</button>
|
||||
<button class="btn btn-teal" id="eti-recap-btn" onclick="showEtiRecap()" disabled>Voir le récapitulatif →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---- PANNEAU B : synthèse / check-list ---- -->
|
||||
@@ -950,11 +936,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<div class="eti-stage" id="recap-stage"></div>
|
||||
<table class="checklist-table" id="checklist-table"></table>
|
||||
</div>
|
||||
|
||||
<div class="actions-row">
|
||||
<button class="btn btn-outline" onclick="hideEtiRecap()">← Retour à l'exercice</button>
|
||||
<button class="btn btn-amber" onclick="goTo(8)">Voir la synthèse générale →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -979,19 +960,10 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
||||
<tr><td><strong>Étiquette</strong></td><td>Dangers essentiels, interface rapide</td><td>À chaque prise du produit</td><td>Tous les utilisateurs</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ul class="tips-list">
|
||||
<li><strong>FDS = Sécurité et dangers</strong> → à consulter AVANT manipulation.</li>
|
||||
<li><strong>FT = Mode d'emploi et applications</strong> → à consulter pour l'utilisation.</li>
|
||||
<li><strong>Étiquette = Interface rapide</strong> → lecture obligatoire avant ouverture du produit.</li>
|
||||
<li>Les trois documents sont <strong>complémentaires</strong>, jamais redondants — chacun cible un besoin et un public différents.</li>
|
||||
</ul>
|
||||
<div class="actions-row">
|
||||
<button class="btn btn-amber" onclick="exporterPDF()">⬇ Télécharger mes réponses (PDF)</button>
|
||||
<a href="correction-fds.html" class="btn btn-outline">✔ Corriger un rendu</a>
|
||||
</div>
|
||||
<div class="actions-row" style="margin-top:0.5rem;">
|
||||
<button class="btn btn-outline" onclick="restartAll()">↺ Recommencer</button>
|
||||
<a href="../index.html#formations" class="btn btn-outline">Retour aux exercices</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1093,6 +1065,7 @@ let etiAnswers = {}; // { zoneCible : zoneCliquée en 1re tentative } — p
|
||||
let etiFirstTry = {}; // { zoneCible : true si trouvée sans erreur }
|
||||
let etiCurError = false; // une erreur a-t-elle eu lieu sur la question courante
|
||||
let etiInit = false; // écouteur de clic posé une seule fois
|
||||
let etiRecapShown = false;// panneau récapitulatif affiché (slide 7)
|
||||
|
||||
function buildEtiquette() {
|
||||
etiOrder = shuffleArray(etiZones.map((_, i) => i));
|
||||
@@ -1107,9 +1080,10 @@ function buildEtiquette() {
|
||||
closeEtiPop();
|
||||
const r = document.getElementById('etiquette-result');
|
||||
r.className = 'result-message'; r.innerHTML = '';
|
||||
document.getElementById('eti-recap-btn').disabled = true;
|
||||
etiRecapShown = false;
|
||||
document.getElementById('eti-exercise').style.display = 'flex';
|
||||
document.getElementById('eti-recap').style.display = 'none';
|
||||
if (currentSlide === 7) renderBarActions();
|
||||
|
||||
if (!etiInit) {
|
||||
card.addEventListener('click', onEtiClick);
|
||||
@@ -1136,11 +1110,8 @@ function onEtiClick(e) {
|
||||
if (!hs) return;
|
||||
const clicked = hs.dataset.zone;
|
||||
|
||||
// Exploration libre une fois l'exercice terminé
|
||||
if (etiPos >= etiOrder.length) {
|
||||
openEtiPop(hs, 'info', clicked);
|
||||
return;
|
||||
}
|
||||
// Exercice terminé : plus d'interaction (les corrections sont dans la correction générale)
|
||||
if (etiPos >= etiOrder.length) return;
|
||||
|
||||
const target = etiZones[etiOrder[etiPos]];
|
||||
if (clicked === target.zone) {
|
||||
@@ -1148,7 +1119,6 @@ function onEtiClick(e) {
|
||||
hs.classList.add('hs-correct');
|
||||
if (etiAnswers[target.zone] === undefined) etiAnswers[target.zone] = clicked;
|
||||
etiFirstTry[target.zone] = !etiCurError;
|
||||
openEtiPop(hs, 'ok', clicked);
|
||||
etiPos++;
|
||||
etiCurError = false;
|
||||
renderEtiQuestion();
|
||||
@@ -1160,14 +1130,12 @@ function onEtiClick(e) {
|
||||
hs.classList.remove('hs-wrong'); void hs.offsetWidth; // relance l'animation
|
||||
hs.classList.add('hs-wrong');
|
||||
setTimeout(() => hs.classList.remove('hs-wrong'), 700);
|
||||
openEtiPop(hs, 'ko', clicked);
|
||||
}
|
||||
}
|
||||
|
||||
function finishEtiquette() {
|
||||
const correct = etiZones.filter(z => etiFirstTry[z.zone]).length;
|
||||
showScore(document.getElementById('etiquette-result'), correct, etiZones.length);
|
||||
document.getElementById('eti-recap-btn').disabled = false;
|
||||
const b = document.getElementById('eti-recap-btn');
|
||||
if (b) b.disabled = false;
|
||||
}
|
||||
|
||||
/* Info-bulle réglementaire positionnée près de la zone cliquée */
|
||||
@@ -1243,6 +1211,8 @@ function showEtiRecap() {
|
||||
|
||||
document.getElementById('eti-exercise').style.display = 'none';
|
||||
document.getElementById('eti-recap').style.display = 'flex';
|
||||
etiRecapShown = true;
|
||||
renderBarActions();
|
||||
|
||||
// Animation : l'étiquette glisse à gauche, le tableau apparaît à sa droite
|
||||
const rl = document.getElementById('recap-layout');
|
||||
@@ -1255,6 +1225,8 @@ function showEtiRecap() {
|
||||
function hideEtiRecap() {
|
||||
document.getElementById('eti-recap').style.display = 'none';
|
||||
document.getElementById('eti-exercise').style.display = 'flex';
|
||||
etiRecapShown = false;
|
||||
renderBarActions();
|
||||
const sa = document.querySelector('#slide-7 .scroll-area');
|
||||
if (sa) sa.scrollTop = 0;
|
||||
}
|
||||
@@ -1296,7 +1268,7 @@ function buildFtMatch() {
|
||||
|
||||
initFtMatch();
|
||||
document.getElementById('ft-svg').innerHTML = '';
|
||||
document.getElementById('ft-verify').disabled = true;
|
||||
refreshFtState();
|
||||
}
|
||||
|
||||
function resetFT() {
|
||||
@@ -1354,7 +1326,8 @@ function refreshFtState() {
|
||||
dot.closest('.match-item').classList.toggle('connected', used);
|
||||
});
|
||||
const all = ftQuestions.every(q => ftConnections[q.id] != null);
|
||||
document.getElementById('ft-verify').disabled = !all;
|
||||
const btn = document.getElementById('ft-next');
|
||||
if (btn) btn.disabled = !all;
|
||||
}
|
||||
|
||||
function initFtMatch() {
|
||||
@@ -1474,7 +1447,8 @@ function initFdsDnd() {
|
||||
function updateFdsGate() {
|
||||
const slots = document.querySelectorAll('#slide-3 .drop-slot');
|
||||
const all = Array.from(slots).every(s => (s.dataset.value || '') !== '');
|
||||
document.getElementById('fds-verify').disabled = !all;
|
||||
const btn = document.getElementById('fds-next');
|
||||
if (btn) btn.disabled = !all;
|
||||
}
|
||||
|
||||
function wireVerifyGate(containerId, btnId) {
|
||||
@@ -1676,6 +1650,7 @@ function goTo(n) {
|
||||
const sa = next.querySelector('.scroll-area');
|
||||
if (sa) sa.scrollTop = 0;
|
||||
updateUI();
|
||||
if (n === 8) setTimeout(launchConfetti, 200);
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
@@ -1691,20 +1666,73 @@ function goBack() {
|
||||
updateUI();
|
||||
}
|
||||
|
||||
/* Boutons centralisés dans la bottom bar, un jeu par slide */
|
||||
function barBtn(bar, html, cls, fn, opts) {
|
||||
opts = opts || {};
|
||||
const b = document.createElement('button');
|
||||
b.className = 'footer-btn ' + cls;
|
||||
b.innerHTML = html;
|
||||
if (opts.id) b.id = opts.id;
|
||||
if (opts.disabled) b.disabled = true;
|
||||
b.addEventListener('click', fn);
|
||||
bar.appendChild(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
function renderBarActions() {
|
||||
const bar = document.getElementById('barActions');
|
||||
if (!bar) return;
|
||||
bar.innerHTML = '';
|
||||
// Bouton retour intégré au groupe centré (sauf sur le récapitulatif, qui a son propre retour)
|
||||
if (history.length > 0 && !(currentSlide === 7 && etiRecapShown)) {
|
||||
barBtn(bar, '← Retour', 'is-secondary', goBack);
|
||||
}
|
||||
switch (currentSlide) {
|
||||
case 1:
|
||||
barBtn(bar, 'Commencer la partie 1 →', 'is-primary', startPart1);
|
||||
break;
|
||||
case 2:
|
||||
barBtn(bar, 'Répondre aux questions →', 'is-primary', () => goTo(3));
|
||||
break;
|
||||
case 3:
|
||||
barBtn(bar, '↺ Recommencer', 'is-secondary', resetFDS);
|
||||
barBtn(bar, 'Passer à la partie 2 →', 'is-primary', () => goTo(4), { id: 'fds-next' });
|
||||
updateFdsGate();
|
||||
break;
|
||||
case 4:
|
||||
barBtn(bar, 'Répondre aux questions →', 'is-primary', () => goTo(5));
|
||||
break;
|
||||
case 5:
|
||||
barBtn(bar, '↺ Recommencer', 'is-secondary', resetFT);
|
||||
barBtn(bar, 'Passer à la partie 3 →', 'is-primary', () => goTo(6), { id: 'ft-next' });
|
||||
refreshFtState();
|
||||
break;
|
||||
case 6:
|
||||
barBtn(bar, 'Répondre aux questions →', 'is-primary', () => goTo(7));
|
||||
break;
|
||||
case 7:
|
||||
if (etiRecapShown) {
|
||||
barBtn(bar, '← Retour à l\'exercice', 'is-secondary', hideEtiRecap);
|
||||
barBtn(bar, 'Voir la synthèse générale →', 'is-primary', () => goTo(8));
|
||||
} else {
|
||||
barBtn(bar, '↺ Recommencer', 'is-secondary', resetEtiquette);
|
||||
barBtn(bar, 'Terminer l\'exercice →', 'is-primary', showEtiRecap,
|
||||
{ id: 'eti-recap-btn', disabled: etiPos < etiOrder.length });
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
// Boutons placés sous le tableau comparatif, dans la slide (pas dans la bottom bar)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function updateUI() {
|
||||
document.getElementById('progressFill').style.width =
|
||||
currentSlide === 0 ? '0%' : ((currentSlide / totalSlides) * 100) + '%';
|
||||
document.getElementById('slideCounter').textContent =
|
||||
currentSlide === 0 ? '' : currentSlide + ' / ' + totalSlides;
|
||||
document.getElementById('bottomBar').style.display = currentSlide === 0 ? 'none' : 'flex';
|
||||
document.getElementById('backBtn').style.display = history.length > 0 ? 'block' : 'none';
|
||||
|
||||
const badge = document.getElementById('phaseBadge');
|
||||
const set = (bg, col, txt) => { badge.style.display = 'block'; badge.style.background = bg; badge.style.color = col; badge.textContent = txt; };
|
||||
if (currentSlide === 2 || currentSlide === 3) set('var(--amber-light)', 'var(--amber-dark)', 'Partie 1 — FDS');
|
||||
else if (currentSlide === 4 || currentSlide === 5) set('var(--coral-light)', 'var(--coral)', 'Partie 2 — FT');
|
||||
else if (currentSlide === 6 || currentSlide === 7) set('var(--teal-light)', 'var(--teal-dark)', 'Partie 3 — Étiquette');
|
||||
else badge.style.display = 'none';
|
||||
renderBarActions();
|
||||
}
|
||||
|
||||
function restartAll() {
|
||||
@@ -1719,6 +1747,79 @@ function restartAll() {
|
||||
updateUI();
|
||||
}
|
||||
|
||||
/* ======================== CONFETTIS ======================== */
|
||||
function launchConfetti() {
|
||||
const canvas = document.getElementById('confettiCanvas');
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
canvas.style.display = 'block';
|
||||
|
||||
const colors = ['#BA7517', '#D85A30', '#F5DFB8', '#633806', '#F0A855', '#E8C068', '#FF8C5A'];
|
||||
const particles = Array.from({ length: 180 }, () => ({
|
||||
x: Math.random() * canvas.width,
|
||||
y: -(Math.random() * canvas.height * 0.5),
|
||||
w: Math.random() * 10 + 5,
|
||||
h: Math.random() * 5 + 3,
|
||||
color: colors[Math.floor(Math.random() * colors.length)],
|
||||
rotation: Math.random() * Math.PI * 2,
|
||||
rotSpeed: (Math.random() - 0.5) * 0.18,
|
||||
vx: (Math.random() - 0.5) * 2.5,
|
||||
vy: Math.random() * 3 + 2,
|
||||
opacity: 1,
|
||||
shape: Math.random() < 0.4 ? 'circle' : 'rect'
|
||||
}));
|
||||
|
||||
let rafId;
|
||||
let start = null;
|
||||
const totalDuration = 3800;
|
||||
|
||||
function draw(ts) {
|
||||
if (!start) start = ts;
|
||||
const elapsed = ts - start;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
let active = false;
|
||||
|
||||
particles.forEach(p => {
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
p.vy += 0.04;
|
||||
p.rotation += p.rotSpeed;
|
||||
p.opacity = elapsed < totalDuration * 0.55
|
||||
? 1
|
||||
: Math.max(0, 1 - (elapsed - totalDuration * 0.55) / (totalDuration * 0.45));
|
||||
|
||||
if (p.y < canvas.height + 20) active = true;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(p.x, p.y);
|
||||
ctx.rotate(p.rotation);
|
||||
ctx.globalAlpha = p.opacity;
|
||||
ctx.fillStyle = p.color;
|
||||
if (p.shape === 'circle') {
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, p.w / 2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
} else {
|
||||
ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
|
||||
}
|
||||
ctx.restore();
|
||||
});
|
||||
|
||||
if (active && elapsed < totalDuration * 1.3) {
|
||||
rafId = requestAnimationFrame(draw);
|
||||
} else {
|
||||
canvas.style.display = 'none';
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
}
|
||||
|
||||
if (rafId) cancelAnimationFrame(rafId);
|
||||
rafId = requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
generateQuizzes();
|
||||
updateUI();
|
||||
|
||||
@@ -280,6 +280,18 @@
|
||||
outline: none;
|
||||
border-color: var(--amber);
|
||||
}
|
||||
/* Carte d'identité encadrée (modèle BioCID) */
|
||||
.id-card {
|
||||
background: white;
|
||||
border: 0.5px solid var(--border);
|
||||
border-radius: 16px;
|
||||
padding: 20px 22px;
|
||||
max-width: 460px;
|
||||
width: 100%;
|
||||
margin: 1.25rem auto;
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,0.04);
|
||||
}
|
||||
.id-card .id-form { margin: 0; max-width: none; }
|
||||
|
||||
/* TABLE FORM CONTROLS */
|
||||
.risk-table input, .risk-table textarea {
|
||||
@@ -673,20 +685,22 @@
|
||||
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">Avant de commencer</div>
|
||||
<div class="slide-title">Identification du groupe</div>
|
||||
<p class="slide-intro" style="margin:0.5rem auto 0;max-width:420px;">Ces informations permettront au formateur de retrouver vos réponses.</p>
|
||||
<div class="id-form" style="margin-left:auto;margin-right:auto;">
|
||||
<div class="id-field">
|
||||
<label for="inputNom">Nom du stagiaire ou du groupe</label>
|
||||
<input type="text" id="inputNom" placeholder="Ex : Groupe 3 - Dupont / Martin" autocomplete="off">
|
||||
</div>
|
||||
<div class="id-field">
|
||||
<label for="inputDate">Date de la session</label>
|
||||
<input type="date" id="inputDate">
|
||||
</div>
|
||||
<div class="id-field">
|
||||
<label>Formateur de la session</label>
|
||||
<div style="display:flex;gap:10px;margin-top:2px;">
|
||||
<button type="button" class="formateur-btn" id="btnNathan" onclick="selectFormateur('Nathan')">Nathan</button>
|
||||
<button type="button" class="formateur-btn" id="btnGauthier" onclick="selectFormateur('Gauthier')">Gauthier</button>
|
||||
<div class="id-card">
|
||||
<div class="id-form">
|
||||
<div class="id-field">
|
||||
<label for="inputNom">Nom du stagiaire ou du groupe</label>
|
||||
<input type="text" id="inputNom" placeholder="Ex : Groupe 3 - Dupont / Martin" autocomplete="off">
|
||||
</div>
|
||||
<div class="id-field">
|
||||
<label for="inputDate">Date de la session</label>
|
||||
<input type="date" id="inputDate">
|
||||
</div>
|
||||
<div class="id-field">
|
||||
<label>Formateur de la session</label>
|
||||
<div style="display:flex;gap:10px;margin-top:2px;">
|
||||
<button type="button" class="formateur-btn" id="btnNathan" onclick="selectFormateur('Nathan')">Nathan</button>
|
||||
<button type="button" class="formateur-btn" id="btnGauthier" onclick="selectFormateur('Gauthier')">Gauthier</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
<!-- Correction : page unique pour tous les exercices -->
|
||||
<div class="formation-card">
|
||||
<div class="formation-header">
|
||||
<div class="formation-icon">✔️</div>
|
||||
<div class="formation-icon">✅</div>
|
||||
<h3 class="formation-title">Corriger un exercice</h3>
|
||||
<p class="formation-subtitle">Correction des rendus</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user