Refonte de la slide 3 FDS en glisser-déposer
- Renomme la carte formation en 'FDS, FT & Étiquettes' - Slide 3 : deux colonnes de huit questions, banques d'étiquettes (rubriques 1 à 16 + Absent) de part et d'autre à glisser-déposer dans chaque case (repli au clic pour le tactile) - Bloque la vérification tant que les seize cases ne sont pas remplies - Retire l'étiquette 'Partie 1/3' et remonte le titre pour éviter le défilement - Ordre d'affichage après correction : réponse, emoji, case
This commit is contained in:
@@ -196,6 +196,73 @@
|
|||||||
|
|
||||||
/* QUIZ ROWS */
|
/* QUIZ ROWS */
|
||||||
.quiz-list { width: 100%; max-width: 720px; display: flex; flex-direction: column; gap: 12px; }
|
.quiz-list { width: 100%; max-width: 720px; display: flex; flex-direction: column; gap: 12px; }
|
||||||
|
.quiz-list.quiz-grid {
|
||||||
|
max-width: 1080px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.quiz-list.quiz-grid { grid-template-columns: 1fr; max-width: 720px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SLIDE 3 — DRAG & DROP */
|
||||||
|
#slide-3 {
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding-top: calc(70px + 0.9rem);
|
||||||
|
padding-bottom: calc(52px + 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; }
|
||||||
|
.dnd-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||||
|
align-items: start;
|
||||||
|
gap: 14px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
#slide-3 .quiz-grid { gap: 8px; }
|
||||||
|
#slide-3 .verify-btn { padding: 9px 26px; }
|
||||||
|
#slide-3 .actions-row { margin-top: 0.8rem; }
|
||||||
|
.dnd-bank { display: grid; grid-template-columns: 1fr; gap: 6px; align-content: start; }
|
||||||
|
.dnd-tile {
|
||||||
|
font-family: 'Syne', sans-serif;
|
||||||
|
font-size: 12px; font-weight: 800;
|
||||||
|
padding: 8px 10px; min-width: 66px; text-align: center;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--amber-light); color: var(--amber-dark);
|
||||||
|
border: 1px solid var(--amber);
|
||||||
|
cursor: grab; user-select: none;
|
||||||
|
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||||
|
}
|
||||||
|
.dnd-tile:hover { transform: translateY(-1px); box-shadow: 0 4px 10px rgba(186,117,23,0.15); }
|
||||||
|
.dnd-tile:active { cursor: grabbing; }
|
||||||
|
.dnd-tile.armed { outline: 2px solid var(--amber-dark); box-shadow: 0 0 0 3px rgba(186,117,23,0.18); }
|
||||||
|
.dnd-tile.dragging { opacity: 0.4; }
|
||||||
|
#slide-3 .answer-row { padding: 6px 12px; gap: 10px; }
|
||||||
|
#slide-3 .question-num { min-width: 26px; height: 26px; font-size: 11px; }
|
||||||
|
#slide-3 .question-text { font-size: 13px; }
|
||||||
|
.drop-slot {
|
||||||
|
min-width: 92px; min-height: 36px;
|
||||||
|
border: 2px dashed var(--amber); border-radius: 8px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-family: 'Syne', sans-serif; font-size: 12px; font-weight: 800;
|
||||||
|
color: var(--amber-dark); background: var(--amber-light);
|
||||||
|
cursor: pointer; flex-shrink: 0;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
.drop-slot::before { content: 'Déposez ici'; font-weight: 600; font-size: 11px; opacity: 0.55; }
|
||||||
|
.drop-slot.filled { border-style: solid; background: white; }
|
||||||
|
.drop-slot.filled::before { content: none; }
|
||||||
|
.drop-slot.drag-over { border-color: var(--amber-dark); background: white; transform: scale(1.04); }
|
||||||
|
.drop-slot.slot-correct { border-color: #2e7d32; color: #2e7d32; }
|
||||||
|
.drop-slot.slot-wrong { border-color: #c62828; color: #c62828; }
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.dnd-layout { grid-template-columns: 1fr; }
|
||||||
|
.dnd-bank { grid-template-columns: repeat(auto-fill, minmax(60px, 1fr)); }
|
||||||
|
}
|
||||||
.answer-row {
|
.answer-row {
|
||||||
background: white;
|
background: white;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
@@ -259,6 +326,7 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
.verify-btn:hover { transform: translateY(-1px); }
|
.verify-btn:hover { transform: translateY(-1px); }
|
||||||
|
.verify-btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
|
||||||
|
|
||||||
.result-message {
|
.result-message {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
@@ -471,17 +539,19 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
|
|||||||
<button class="btn btn-amber" onclick="goTo(3)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
<button class="btn btn-amber" onclick="goTo(3)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ============ SLIDE 3 — FDS QUIZ ============ -->
|
<!-- ============ SLIDE 3 — FDS QUIZ (DRAG & DROP) ============ -->
|
||||||
<div class="slide" id="slide-3">
|
<div class="slide" id="slide-3">
|
||||||
<div class="scroll-area">
|
<div class="slide-title">Où trouver l'information ?</div>
|
||||||
<div class="section-tag">Partie 1 / 3 — FDS</div>
|
<p class="dnd-hint">Glissez-déposez la bonne rubrique dans chaque case — ou cliquez une étiquette puis une case.</p>
|
||||||
<div class="slide-title">Où trouver l'information ?</div>
|
<div class="dnd-layout">
|
||||||
<div class="quiz-list" id="fds-questions"></div>
|
<div class="dnd-bank" id="fds-bank-left"></div>
|
||||||
<button class="verify-btn btn-amber" onclick="verifyFDS()">✓ Vérifier mes réponses</button>
|
<div class="quiz-list quiz-grid" id="fds-questions"></div>
|
||||||
<div id="fds-result" class="result-message"></div>
|
<div class="dnd-bank" id="fds-bank-right"></div>
|
||||||
<div class="actions-row">
|
</div>
|
||||||
<button class="btn btn-coral" onclick="goTo(4)">Passer à la partie 2 →</button>
|
<button class="verify-btn btn-amber" id="fds-verify" onclick="verifyFDS()" disabled>✓ Vérifier mes réponses</button>
|
||||||
</div>
|
<div id="fds-result" class="result-message"></div>
|
||||||
|
<div class="actions-row">
|
||||||
|
<button class="btn btn-coral" onclick="goTo(4)">Passer à la partie 2 →</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -504,7 +574,7 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
|
|||||||
<div class="section-tag" style="background:var(--coral-light);color:var(--coral);">Partie 2 / 3 — FT</div>
|
<div class="section-tag" style="background:var(--coral-light);color:var(--coral);">Partie 2 / 3 — FT</div>
|
||||||
<div class="slide-title">Sections de la fiche technique</div>
|
<div class="slide-title">Sections de la fiche technique</div>
|
||||||
<div class="quiz-list" id="ft-questions"></div>
|
<div class="quiz-list" id="ft-questions"></div>
|
||||||
<button class="verify-btn btn-coral" onclick="verifyFT()">✓ Vérifier mes réponses</button>
|
<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 id="ft-result" class="result-message"></div>
|
||||||
<div class="actions-row">
|
<div class="actions-row">
|
||||||
<button class="btn btn-teal" onclick="goTo(6)">Passer à la partie 3 →</button>
|
<button class="btn btn-teal" onclick="goTo(6)">Passer à la partie 3 →</button>
|
||||||
@@ -531,7 +601,7 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
|
|||||||
<div class="section-tag" style="background:var(--teal-light);color:var(--teal-dark);">Partie 3 / 3 — Étiquette</div>
|
<div class="section-tag" style="background:var(--teal-light);color:var(--teal-dark);">Partie 3 / 3 — Étiquette</div>
|
||||||
<div class="slide-title">Zones de l'étiquette</div>
|
<div class="slide-title">Zones de l'étiquette</div>
|
||||||
<div class="quiz-list" id="etiquette-questions"></div>
|
<div class="quiz-list" id="etiquette-questions"></div>
|
||||||
<button class="verify-btn btn-teal" onclick="verifyEtiquette()">✓ Vérifier mes réponses</button>
|
<button class="verify-btn btn-teal" id="eti-verify" onclick="verifyEtiquette()" disabled>✓ Vérifier mes réponses</button>
|
||||||
<div id="etiquette-result" class="result-message"></div>
|
<div id="etiquette-result" class="result-message"></div>
|
||||||
<div class="actions-row">
|
<div class="actions-row">
|
||||||
<button class="btn btn-amber" onclick="goTo(8)">Voir la synthèse →</button>
|
<button class="btn btn-amber" onclick="goTo(8)">Voir la synthèse →</button>
|
||||||
@@ -644,14 +714,8 @@ function buildRow(qNum, selectId, answerAttr, text, options, badgeStyle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateQuizzes() {
|
function generateQuizzes() {
|
||||||
// FDS — shuffled, 16 rubriques
|
// FDS — glisser-déposer : banques d'étiquettes + cases de dépôt
|
||||||
const rubriqueOpts = Array.from({ length: 16 }, (_, i) => ({ value: String(i + 1), label: 'Rubrique ' + (i + 1) }));
|
buildFdsDnd();
|
||||||
rubriqueOpts.push({ value: 'absent', label: 'Absent' });
|
|
||||||
const fdsC = document.getElementById('fds-questions');
|
|
||||||
fdsC.innerHTML = '';
|
|
||||||
shuffleArray(fdsQuestions).forEach((q, i) => {
|
|
||||||
fdsC.innerHTML += buildRow(i + 1, 'fds' + q.id, q.answer, q.text, rubriqueOpts, 'background:var(--amber-light);color:var(--amber-dark);');
|
|
||||||
});
|
|
||||||
|
|
||||||
// FT
|
// FT
|
||||||
const ftOpts = ftOptions.map(o => ({ value: o, label: o }));
|
const ftOpts = ftOptions.map(o => ({ value: o, label: o }));
|
||||||
@@ -670,6 +734,100 @@ function generateQuizzes() {
|
|||||||
etiquetteQuestions.forEach((q, i) => {
|
etiquetteQuestions.forEach((q, i) => {
|
||||||
etiC.innerHTML += buildRow(i + 1, 'eti' + q.id, q.answer, q.text, etiOpts, 'background:var(--teal-light);color:var(--teal-dark);');
|
etiC.innerHTML += buildRow(i + 1, 'eti' + q.id, q.answer, q.text, etiOpts, 'background:var(--teal-light);color:var(--teal-dark);');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bloque la vérification tant que toutes les questions ne sont pas répondues
|
||||||
|
wireVerifyGate('ft-questions', 'ft-verify');
|
||||||
|
wireVerifyGate('etiquette-questions', 'eti-verify');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- FDS : glisser-déposer ---- */
|
||||||
|
function buildFdsDnd() {
|
||||||
|
const tile = (v, l) => `<div class="dnd-tile" draggable="true" data-value="${v}" data-label="${l}">${l}</div>`;
|
||||||
|
let left = '', right = '';
|
||||||
|
for (let i = 1; i <= 8; i++) left += tile(String(i), 'R' + i);
|
||||||
|
for (let i = 9; i <= 16; i++) right += tile(String(i), 'R' + i);
|
||||||
|
right += tile('absent', 'Absent');
|
||||||
|
document.getElementById('fds-bank-left').innerHTML = left;
|
||||||
|
document.getElementById('fds-bank-right').innerHTML = right;
|
||||||
|
|
||||||
|
const fdsC = document.getElementById('fds-questions');
|
||||||
|
fdsC.innerHTML = '';
|
||||||
|
shuffleArray(fdsQuestions).forEach((q, i) => {
|
||||||
|
fdsC.innerHTML += `
|
||||||
|
<div class="answer-row">
|
||||||
|
<div class="question-num" style="background:var(--amber-light);color:var(--amber-dark);">Q${i + 1}</div>
|
||||||
|
<div class="question-text">${q.text}</div>
|
||||||
|
<div class="drop-slot" id="fds${q.id}" data-answer="${q.answer}" data-value=""></div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
initFdsDnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initFdsDnd() {
|
||||||
|
const slide = document.getElementById('slide-3');
|
||||||
|
const tiles = slide.querySelectorAll('.dnd-tile');
|
||||||
|
const slots = slide.querySelectorAll('.drop-slot');
|
||||||
|
let armed = null;
|
||||||
|
|
||||||
|
const resetResults = () => {
|
||||||
|
slide.querySelectorAll('.answer-label, .answer-icon').forEach(e => e.remove());
|
||||||
|
slide.querySelectorAll('.drop-slot').forEach(s => s.classList.remove('slot-correct', 'slot-wrong'));
|
||||||
|
const r = document.getElementById('fds-result');
|
||||||
|
r.className = 'result-message'; r.innerHTML = '';
|
||||||
|
};
|
||||||
|
const fill = (slot, v, l) => {
|
||||||
|
slot.dataset.value = v; slot.textContent = l; slot.classList.add('filled');
|
||||||
|
resetResults(); updateFdsGate();
|
||||||
|
};
|
||||||
|
const clear = (slot) => {
|
||||||
|
slot.dataset.value = ''; slot.textContent = ''; slot.classList.remove('filled');
|
||||||
|
resetResults(); updateFdsGate();
|
||||||
|
};
|
||||||
|
|
||||||
|
tiles.forEach(t => {
|
||||||
|
t.addEventListener('dragstart', e => {
|
||||||
|
e.dataTransfer.setData('text/plain', JSON.stringify({ v: t.dataset.value, l: t.dataset.label }));
|
||||||
|
t.classList.add('dragging');
|
||||||
|
});
|
||||||
|
t.addEventListener('dragend', () => t.classList.remove('dragging'));
|
||||||
|
t.addEventListener('click', () => {
|
||||||
|
if (armed === t) { t.classList.remove('armed'); armed = null; return; }
|
||||||
|
if (armed) armed.classList.remove('armed');
|
||||||
|
armed = t; t.classList.add('armed');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
slots.forEach(s => {
|
||||||
|
s.addEventListener('dragover', e => { e.preventDefault(); s.classList.add('drag-over'); });
|
||||||
|
s.addEventListener('dragleave', () => s.classList.remove('drag-over'));
|
||||||
|
s.addEventListener('drop', e => {
|
||||||
|
e.preventDefault(); s.classList.remove('drag-over');
|
||||||
|
try { const d = JSON.parse(e.dataTransfer.getData('text/plain')); fill(s, d.v, d.l); } catch (_) {}
|
||||||
|
});
|
||||||
|
s.addEventListener('click', () => {
|
||||||
|
if (armed) { fill(s, armed.dataset.value, armed.dataset.label); armed.classList.remove('armed'); armed = null; }
|
||||||
|
else if (s.classList.contains('filled')) { clear(s); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
updateFdsGate();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wireVerifyGate(containerId, btnId) {
|
||||||
|
const container = document.getElementById(containerId);
|
||||||
|
const btn = document.getElementById(btnId);
|
||||||
|
if (!container || !btn) return;
|
||||||
|
const selects = Array.from(container.querySelectorAll('select'));
|
||||||
|
const update = () => { btn.disabled = !selects.every(s => s.value !== ''); };
|
||||||
|
selects.forEach(s => s.addEventListener('change', update));
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================== VÉRIFICATION ======================== */
|
/* ======================== VÉRIFICATION ======================== */
|
||||||
@@ -686,7 +844,7 @@ function showInlineResult(selectEl, isCorrect, isUnanswered, correctAnswerText)
|
|||||||
const icon = document.createElement('div');
|
const icon = document.createElement('div');
|
||||||
icon.className = 'answer-icon';
|
icon.className = 'answer-icon';
|
||||||
icon.textContent = isUnanswered ? '❓' : (isCorrect ? '✅' : '❌');
|
icon.textContent = isUnanswered ? '❓' : (isCorrect ? '✅' : '❌');
|
||||||
selectEl.after(icon);
|
selectEl.before(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showScore(resultDiv, correct, total) {
|
function showScore(resultDiv, correct, total) {
|
||||||
@@ -709,19 +867,38 @@ function showScore(resultDiv, correct, total) {
|
|||||||
function verifyFDS() {
|
function verifyFDS() {
|
||||||
let correct = 0;
|
let correct = 0;
|
||||||
fdsQuestions.forEach(q => {
|
fdsQuestions.forEach(q => {
|
||||||
const select = document.getElementById('fds' + q.id);
|
const slot = document.getElementById('fds' + q.id);
|
||||||
const userAnswer = select.value;
|
const userAnswer = slot.dataset.value || '';
|
||||||
const expected = q.answer.split(',');
|
const expected = q.answer.split(',');
|
||||||
const isCorrect = expected.includes(userAnswer);
|
const isCorrect = expected.includes(userAnswer);
|
||||||
const labelText = expected.length > 1
|
const labelText = expected.length > 1
|
||||||
? 'Rubriques ' + expected.join(' et ')
|
? 'Rubriques ' + expected.join(' et ')
|
||||||
: (expected[0] === 'absent' ? 'Absent' : 'Rubrique ' + expected[0]);
|
: (expected[0] === 'absent' ? 'Absent' : 'Rubrique ' + expected[0]);
|
||||||
if (isCorrect) correct++;
|
if (isCorrect) correct++;
|
||||||
showInlineResult(select, isCorrect, userAnswer === '', labelText);
|
showSlotResult(slot, isCorrect, userAnswer === '', labelText);
|
||||||
});
|
});
|
||||||
showScore(document.getElementById('fds-result'), correct, fdsQuestions.length);
|
showScore(document.getElementById('fds-result'), correct, fdsQuestions.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSlotResult(slot, isCorrect, isUnanswered, correctAnswerText) {
|
||||||
|
const row = slot.closest('.answer-row');
|
||||||
|
row.querySelector('.answer-label')?.remove();
|
||||||
|
row.querySelector('.answer-icon')?.remove();
|
||||||
|
slot.classList.remove('slot-correct', 'slot-wrong');
|
||||||
|
|
||||||
|
const label = document.createElement('div');
|
||||||
|
label.className = 'answer-label';
|
||||||
|
label.textContent = correctAnswerText;
|
||||||
|
slot.before(label);
|
||||||
|
|
||||||
|
const icon = document.createElement('div');
|
||||||
|
icon.className = 'answer-icon';
|
||||||
|
icon.textContent = isUnanswered ? '❓' : (isCorrect ? '✅' : '❌');
|
||||||
|
slot.before(icon);
|
||||||
|
|
||||||
|
if (!isUnanswered) slot.classList.add(isCorrect ? 'slot-correct' : 'slot-wrong');
|
||||||
|
}
|
||||||
|
|
||||||
function verifyFT() {
|
function verifyFT() {
|
||||||
let correct = 0;
|
let correct = 0;
|
||||||
ftQuestions.forEach(q => {
|
ftQuestions.forEach(q => {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
<div class="formation-card">
|
<div class="formation-card">
|
||||||
<div class="formation-header">
|
<div class="formation-header">
|
||||||
<div class="formation-icon">📋</div>
|
<div class="formation-icon">📋</div>
|
||||||
<h3 class="formation-title">FDS & Étiquettes</h3>
|
<h3 class="formation-title">FDS, FT & Étiquettes</h3>
|
||||||
<p class="formation-subtitle">Aller plus loin</p>
|
<p class="formation-subtitle">Aller plus loin</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="formation-body">
|
<div class="formation-body">
|
||||||
|
|||||||
Reference in New Issue
Block a user