diff --git a/exercices/Exo_FDS.html b/exercices/Exo_FDS.html index 3ab178d..4926658 100644 --- a/exercices/Exo_FDS.html +++ b/exercices/Exo_FDS.html @@ -196,6 +196,73 @@ /* QUIZ ROWS */ .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 { background: white; 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; } .verify-btn:hover { transform: translateY(-1px); } +.verify-btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; } .result-message { margin-top: 4px; @@ -471,17 +539,19 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px - +
-
- -
Où trouver l'information ?
-
- -
-
- -
+
Où trouver l'information ?
+

Glissez-déposez la bonne rubrique dans chaque case — ou cliquez une étiquette puis une case.

+
+
+
+
+
+ +
+
+
@@ -504,7 +574,7 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
Partie 2 / 3 — FT
Sections de la fiche technique
- +
@@ -531,7 +601,7 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
Zones de l'étiquette
- +
@@ -644,14 +714,8 @@ function buildRow(qNum, selectId, answerAttr, text, options, badgeStyle) { } function generateQuizzes() { - // FDS — shuffled, 16 rubriques - const rubriqueOpts = Array.from({ length: 16 }, (_, i) => ({ value: String(i + 1), label: 'Rubrique ' + (i + 1) })); - 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);'); - }); + // FDS — glisser-déposer : banques d'étiquettes + cases de dépôt + buildFdsDnd(); // FT const ftOpts = ftOptions.map(o => ({ value: o, label: o })); @@ -670,6 +734,100 @@ function generateQuizzes() { 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);'); }); + + // 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) => `
${l}
`; + 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 += ` +
+
Q${i + 1}
+
${q.text}
+
+
`; + }); + + 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 ======================== */ @@ -686,7 +844,7 @@ function showInlineResult(selectEl, isCorrect, isUnanswered, correctAnswerText) const icon = document.createElement('div'); icon.className = 'answer-icon'; icon.textContent = isUnanswered ? '❓' : (isCorrect ? '✅' : '❌'); - selectEl.after(icon); + selectEl.before(icon); } function showScore(resultDiv, correct, total) { @@ -709,19 +867,38 @@ function showScore(resultDiv, correct, total) { function verifyFDS() { let correct = 0; fdsQuestions.forEach(q => { - const select = document.getElementById('fds' + q.id); - const userAnswer = select.value; + const slot = document.getElementById('fds' + q.id); + const userAnswer = slot.dataset.value || ''; const expected = q.answer.split(','); const isCorrect = expected.includes(userAnswer); const labelText = expected.length > 1 ? 'Rubriques ' + expected.join(' et ') : (expected[0] === 'absent' ? 'Absent' : 'Rubrique ' + expected[0]); if (isCorrect) correct++; - showInlineResult(select, isCorrect, userAnswer === '', labelText); + showSlotResult(slot, isCorrect, userAnswer === '', labelText); }); 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() { let correct = 0; ftQuestions.forEach(q => { diff --git a/index.html b/index.html index 03b8511..cfdf9a5 100644 --- a/index.html +++ b/index.html @@ -103,7 +103,7 @@
📋
-

FDS & Étiquettes

+

FDS, FT & Étiquettes

Aller plus loin