Skip to content

Commit 927adbd

Browse files
committed
Add video system with questions - exclude large video files from Git tracking
1 parent 40d40b4 commit 927adbd

File tree

7 files changed

+539
-8
lines changed

7 files changed

+539
-8
lines changed

assets/France3.mp4

-19.3 MB
Binary file not shown.

css/style.css

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,11 +1618,114 @@ input:checked + .slider:before {
16181618
/* Déjà vu précédemment, au cas où */
16191619
.success-amount { color: #2ecc71; }
16201620
.danger-amount { color: #e74c3c; }
1621+
1622+
/* Styles pour la modale vidéo avec questions */
1623+
.video-quiz-content {
1624+
max-width: 800px;
1625+
width: 90%;
1626+
}
1627+
1628+
.video-section {
1629+
margin-bottom: 2rem;
1630+
}
1631+
1632+
.video-player {
1633+
margin: 1rem 0;
1634+
border-radius: 8px;
1635+
overflow: hidden;
1636+
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
1637+
}
1638+
.video {
1639+
border: 1px solid white;
1640+
border-radius: 8px;
1641+
background-color: violet;
1642+
}
1643+
.video-player video {
1644+
width: 100%;
1645+
height: auto;
1646+
max-height: 400px;
1647+
1648+
1649+
}
1650+
1651+
.video-questions-section {
1652+
border-top: 2px solid var(--primary-color);
1653+
padding-top: 1.5rem;
1654+
}
1655+
1656+
.video-questions-section h3 {
1657+
color: var(--accent-color);
1658+
margin-bottom: 1rem;
1659+
}
1660+
1661+
#video-question-text {
1662+
font-size: 1.1rem;
1663+
margin-bottom: 1.5rem;
1664+
line-height: 1.5;
1665+
}
1666+
1667+
/* Styles pour les réponses du quiz vidéo */
1668+
#video-quiz-answers {
1669+
display: grid;
1670+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
1671+
gap: 1rem;
1672+
margin-bottom: 1rem;
1673+
}
1674+
1675+
.quiz-answer {
1676+
background: var(--secondary-color);
1677+
color: var(--light-color);
1678+
border: 2px solid var(--primary-color);
1679+
border-radius: 8px;
1680+
padding: 1rem;
1681+
text-align: center;
1682+
cursor: pointer;
1683+
transition: all 0.3s ease;
1684+
font-weight: 500;
1685+
}
1686+
1687+
.quiz-answer:hover:not(.disabled) {
1688+
background: var(--primary-color);
1689+
border-color: var(--accent-color);
1690+
box-shadow: 0 4px 12px rgba(74, 105, 189, 0.3);
1691+
transform: translateY(-2px);
1692+
}
1693+
16211694
.quiz-answer.disabled {
16221695
pointer-events: none;
16231696
opacity: 0.6;
16241697
}
16251698

1699+
.quiz-answer.correct {
1700+
background: var(--success-color) !important;
1701+
border-color: var(--success-color) !important;
1702+
color: #2c3e50 !important;
1703+
font-weight: bold;
1704+
}
1705+
1706+
.quiz-answer.wrong {
1707+
background: var(--danger-color) !important;
1708+
border-color: var(--danger-color) !important;
1709+
color: var(--light-color) !important;
1710+
font-weight: bold;
1711+
}
1712+
1713+
/* Adaptation pour mobile */
1714+
@media (max-width: 768px) {
1715+
.video-quiz-content {
1716+
width: 95%;
1717+
margin: 1rem;
1718+
}
1719+
1720+
.video-player video {
1721+
max-height: 250px;
1722+
}
1723+
1724+
#video-quiz-answers {
1725+
grid-template-columns: 1fr;
1726+
}
1727+
}
1728+
16261729
.team-option {
16271730
border: 2px solid var(--accent-color);
16281731
/* box-shadow: 0 0 10px rgba(246, 185, 59, 0.5); */
@@ -1633,10 +1736,4 @@ input:checked + .slider:before {
16331736
.team-option.current-team::after {
16341737
content: " 👑";
16351738
font-size: 0.8em;
1636-
}
1637-
1638-
@media (max-width: 768px) {
1639-
.quiz-answers {
1640-
grid-template-columns: 1fr;
1641-
}
16421739
}

index.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,31 @@ <h3 id="property-name">Maison du directeur</h3>
218218
</div>
219219
</div>
220220

221+
<!-- Modal Vidéo avec Questions -->
222+
<div id="video-quiz-modal" class="modal">
223+
<div class="modal-content video-quiz-content">
224+
<div class="video-section">
225+
<h3 id="video-title">Vidéo</h3>
226+
<div class="video-player">
227+
<video id="main-video-player" controls>
228+
<source src="" type="video/mp4">
229+
Votre navigateur ne supporte pas la lecture vidéo.
230+
</video>
231+
</div>
232+
<p id="video-description"></p>
233+
</div>
234+
235+
<!-- Section questions (cachée pendant la vidéo) -->
236+
<div id="video-questions-section" class="video-questions-section" style="display: none;">
237+
<h3>Question sur la vidéo</h3>
238+
<p id="video-question-text"></p>
239+
<div id="video-quiz-answers" class="quiz-answers">
240+
<!-- Les réponses seront ajoutées dynamiquement -->
241+
</div>
242+
</div>
243+
</div>
244+
</div>
245+
221246
<div id="win-modal" class="modal">
222247
<div class="modal-content">
223248
<div class="win-badge">
@@ -333,6 +358,7 @@ <h3>Félicitation !</h3>
333358
</div>
334359
</div> <script src="js/gameData.js"></script>
335360
<script src="js/cardData.js"></script>
361+
<script src="js/videoData.js"></script>
336362
<script src="js/gameUtils.js"></script>
337363
<script src="js/gameState.js"></script>
338364
<script src="js/modalCardFlip.js"></script>

js/gameData.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const CARD_TYPES = {
66
BIENS: "biens",
77
PDB: "pdb",
88
REDEVANCE: "redevance",
9+
VIDEO: "video",
910
LOGO: "logo",
1011
};
1112

@@ -17,16 +18,18 @@ function generateInitialBoard() {
1718
CARD_TYPES.FACTURE,
1819
CARD_TYPES.INTERACTION,
1920
CARD_TYPES.BIENS,
21+
CARD_TYPES.VIDEO,
2022
];
2123

2224
// Distribution des types de cartes (comme dans l'image) ---
2325
const typeDistribution = {
2426
[CARD_TYPES.BONUS]: 6, // cartes bonus (cadeaux)
2527
[CARD_TYPES.PDB]: 5, // cartes PDB (pdb)
2628
[CARD_TYPES.FACTURE]: 7, // cartes facture
27-
[CARD_TYPES.INTERACTION]: 5, // cartes interaction
29+
[CARD_TYPES.INTERACTION]: 4, // cartes interaction (réduit de 1)
2830
[CARD_TYPES.BIENS]: 6, // cartes biens
2931
[CARD_TYPES.REDEVANCE] : 3, // cartes redevance
32+
[CARD_TYPES.VIDEO] : 1, // 1 carte vidéo
3033
};
3134

3235
// Crée un tableau avec tous les types selon leur distribution

js/main.js

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,9 @@ function handleCellClick(cellId, cellType) {
492492
case CARD_TYPES.REDEVANCE:
493493
handleRedevanceCard();
494494
break;
495+
case CARD_TYPES.VIDEO:
496+
handleVideoCard();
497+
break;
495498
}
496499
}
497500
/**
@@ -1349,3 +1352,168 @@ function showNotification(message, duration = 3000) {
13491352
notification.classList.remove('show');
13501353
}, duration);
13511354
}
1355+
1356+
/**
1357+
* Gère l'affichage et le traitement des cartes Vidéo
1358+
*/
1359+
function handleVideoCard() {
1360+
// Vérifier s'il reste des vidéos non vues
1361+
if (!hasUnwatchedVideos()) {
1362+
// Toutes les vidéos ont été vues, donner un bonus par défaut
1363+
showNotification("Toutes les vidéos ont déjà été visionnées ! Bonus automatique.");
1364+
1365+
const gameState = getGameState();
1366+
const bonusAmount = 100;
1367+
updateTeamScore(gameState.activeTeam, bonusAmount);
1368+
1369+
const activeTeam = gameState.teams[gameState.activeTeam];
1370+
const currentPlayer = activeTeam.players[activeTeam.currentPlayer];
1371+
if (currentPlayer) {
1372+
updatePlayerTurn(
1373+
currentPlayer,
1374+
`Tour: +${bonusAmount} K (toutes les vidéos vues)`,
1375+
);
1376+
}
1377+
1378+
updateTeamsDisplay();
1379+
return;
1380+
}
1381+
1382+
// Obtenir une vidéo aléatoire non vue
1383+
const video = getRandomUnwatchedVideo();
1384+
if (!video) {
1385+
console.error("Aucune vidéo disponible");
1386+
return;
1387+
}
1388+
1389+
// Marquer la vidéo comme vue
1390+
markVideoAsWatched(video.id);
1391+
1392+
// Configurer et afficher la modale vidéo
1393+
document.getElementById("video-title").textContent = video.title;
1394+
document.getElementById("video-description").textContent = video.description;
1395+
1396+
// Configurer le lecteur vidéo
1397+
const videoPlayer = document.getElementById("main-video-player");
1398+
videoPlayer.src = `assets/${video.filename}`;
1399+
1400+
// Cacher la section questions au début
1401+
document.getElementById("video-questions-section").style.display = "none";
1402+
1403+
// Afficher la modale
1404+
toggleModal("video-quiz-modal", true);
1405+
1406+
// Stocker les données de la vidéo pour les questions
1407+
window.currentVideoData = video;
1408+
1409+
// Écouter la fin de la vidéo
1410+
videoPlayer.onended = () => {
1411+
showVideoQuestions(video);
1412+
};
1413+
1414+
// Permettre de passer la vidéo (pour les tests)
1415+
videoPlayer.onclick = () => {
1416+
if (videoPlayer.paused) {
1417+
videoPlayer.play();
1418+
} else {
1419+
videoPlayer.pause();
1420+
}
1421+
};
1422+
}
1423+
1424+
/**
1425+
* Affiche les questions après la fin d'une vidéo
1426+
*/
1427+
function showVideoQuestions(video) {
1428+
if (!video.questions || video.questions.length === 0) {
1429+
// Pas de questions, donner un bonus automatique
1430+
showNotification("Vidéo visionnée ! Bonus automatique.");
1431+
const gameState = getGameState();
1432+
updateTeamScore(gameState.activeTeam, 50);
1433+
toggleModal("video-quiz-modal", false);
1434+
updateTeamsDisplay();
1435+
return;
1436+
}
1437+
1438+
// Choisir une question aléatoire
1439+
const randomQuestion = video.questions[Math.floor(Math.random() * video.questions.length)];
1440+
1441+
// Afficher la section questions
1442+
document.getElementById("video-questions-section").style.display = "block";
1443+
document.getElementById("video-question-text").textContent = randomQuestion.question;
1444+
1445+
// Créer les boutons de réponse
1446+
const answersContainer = document.getElementById("video-quiz-answers");
1447+
answersContainer.innerHTML = "";
1448+
1449+
randomQuestion.answers.forEach((answer, index) => {
1450+
const answerButton = document.createElement("div");
1451+
answerButton.className = "quiz-answer";
1452+
answerButton.textContent = answer.text;
1453+
answerButton.onclick = (event) => handleVideoQuizAnswer(
1454+
answer.correct,
1455+
randomQuestion,
1456+
event.target
1457+
);
1458+
answersContainer.appendChild(answerButton);
1459+
});
1460+
1461+
// Faire défiler vers les questions
1462+
document.getElementById("video-questions-section").scrollIntoView({
1463+
behavior: 'smooth'
1464+
});
1465+
}
1466+
1467+
/**
1468+
* Gère la réponse à une question vidéo
1469+
*/
1470+
function handleVideoQuizAnswer(isCorrect, question, clickedButton) {
1471+
const gameState = getGameState();
1472+
1473+
// Désactiver tous les boutons de réponse
1474+
const answerButtons = document.querySelectorAll('#video-quiz-answers .quiz-answer');
1475+
answerButtons.forEach(button => {
1476+
button.classList.add('disabled');
1477+
});
1478+
1479+
// Marquer visuellement la bonne/mauvaise réponse
1480+
answerButtons.forEach(button => {
1481+
const buttonAnswer = question.answers.find(a => a.text === button.textContent);
1482+
if (buttonAnswer && buttonAnswer.correct) {
1483+
button.classList.add('correct');
1484+
} else if (button === clickedButton && !isCorrect) {
1485+
button.classList.add('wrong');
1486+
}
1487+
});
1488+
1489+
// Attendre un peu pour que l'utilisateur voie le résultat
1490+
setTimeout(() => {
1491+
toggleModal("video-quiz-modal", false);
1492+
1493+
// Calculer le bonus/malus
1494+
const amount = isCorrect ? question.correctReward : -question.wrongPenalty;
1495+
const resultText = isCorrect ? "Bonne réponse !" : "Mauvaise réponse...";
1496+
1497+
// Mettre à jour le score
1498+
updateTeamScore(gameState.activeTeam, amount);
1499+
1500+
// Ajouter à l'historique
1501+
const activeTeam = gameState.teams[gameState.activeTeam];
1502+
const currentPlayer = activeTeam.players[activeTeam.currentPlayer];
1503+
if (currentPlayer) {
1504+
updatePlayerTurn(
1505+
currentPlayer,
1506+
`Tour: ${amount > 0 ? '+' : ''}${amount} K pour Vidéo Quiz - ${resultText}`,
1507+
);
1508+
}
1509+
1510+
// Afficher le résultat
1511+
if (isCorrect) {
1512+
showNotification(`${resultText} +${question.correctReward} K`);
1513+
} else {
1514+
showNotification(`${resultText} -${question.wrongPenalty} K`);
1515+
}
1516+
1517+
updateTeamsDisplay();
1518+
}, 2000); // Attendre 2 secondes pour voir le résultat
1519+
}

js/ui.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,14 @@ function renderGameBoard() {
252252
case CARD_TYPES.LOGO:
253253
iconSvg = `La Bonne Gestion Immobilière`;
254254
break;
255+
case CARD_TYPES.VIDEO:
256+
iconSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
257+
<path d="M8 5v14l11-7z"/>
258+
<circle cx="12" cy="12" r="11" stroke="currentColor" stroke-width="2" fill="none"/>
259+
</svg>`;
260+
break;
255261
default:
256-
console.log("Type de carte non reconnu:", cellType);
262+
console.log("Type de carte non reconnu:", cell.type);
257263
}
258264

259265
iconElement.innerHTML = iconSvg;

0 commit comments

Comments
 (0)