453 lines
16 KiB
JavaScript
453 lines
16 KiB
JavaScript
// === SYSTÈME DE NAVIGATION ===
|
|
|
|
const AppNavigation = {
|
|
currentPage: 'home',
|
|
navigationHistory: ['home'],
|
|
gamesConfig: null,
|
|
contentScanner: new ContentScanner(),
|
|
scannedContent: null,
|
|
|
|
init() {
|
|
this.loadGamesConfig();
|
|
this.initContentScanner();
|
|
this.setupEventListeners();
|
|
this.handleInitialRoute();
|
|
},
|
|
|
|
async loadGamesConfig() {
|
|
// Utilisation directe de la config par défaut (pas de fetch)
|
|
console.log('📁 Utilisation de la configuration par défaut');
|
|
this.gamesConfig = this.getDefaultConfig();
|
|
},
|
|
|
|
async initContentScanner() {
|
|
try {
|
|
console.log('🔍 Initialisation du scanner de contenu...');
|
|
this.scannedContent = await this.contentScanner.scanAllContent();
|
|
console.log(`✅ ${this.scannedContent.found.length} modules de contenu détectés automatiquement`);
|
|
} catch (error) {
|
|
console.error('Erreur scan contenu:', error);
|
|
}
|
|
},
|
|
|
|
getDefaultConfig() {
|
|
return {
|
|
games: {
|
|
'whack-a-mole': {
|
|
enabled: true,
|
|
name: 'Whack-a-Mole',
|
|
icon: '🔨',
|
|
description: 'Tape sur les bonnes réponses !'
|
|
},
|
|
'whack-a-mole-hard': {
|
|
enabled: true,
|
|
name: 'Whack-a-Mole Hard',
|
|
icon: '💥',
|
|
description: '3 moles at once, 5x3 grid, harder!'
|
|
},
|
|
'memory-match': {
|
|
enabled: true,
|
|
name: 'Memory Match',
|
|
icon: '🧠',
|
|
description: 'Find matching English-French pairs!'
|
|
},
|
|
'quiz-game': {
|
|
enabled: true,
|
|
name: 'Quiz Game',
|
|
icon: '❓',
|
|
description: 'Answer vocabulary questions!'
|
|
},
|
|
'temp-games': {
|
|
enabled: true,
|
|
name: 'Jeux Temporaires',
|
|
icon: '🎯',
|
|
description: 'Mini-jeux en développement'
|
|
},
|
|
'fill-the-blank': {
|
|
enabled: true,
|
|
name: 'Fill the Blank',
|
|
icon: '📝',
|
|
description: 'Complète les phrases en remplissant les blancs !'
|
|
},
|
|
'text-reader': {
|
|
enabled: true,
|
|
name: 'Text Reader',
|
|
icon: '📖',
|
|
description: 'Read texts sentence by sentence'
|
|
},
|
|
'adventure-reader': {
|
|
enabled: true,
|
|
name: 'Adventure Reader',
|
|
icon: '⚔️',
|
|
description: 'Zelda-style adventure with vocabulary!'
|
|
}
|
|
},
|
|
content: {
|
|
'sbs-level-8': {
|
|
enabled: true,
|
|
name: 'SBS Level 8',
|
|
icon: '📚',
|
|
description: 'Vocabulaire manuel SBS'
|
|
},
|
|
'animals': {
|
|
enabled: false,
|
|
name: 'Animals',
|
|
icon: '🐱',
|
|
description: 'Vocabulaire des animaux'
|
|
},
|
|
'colors': {
|
|
enabled: false,
|
|
name: 'Colors & Numbers',
|
|
icon: '🌈',
|
|
description: 'Couleurs et nombres'
|
|
}
|
|
}
|
|
};
|
|
},
|
|
|
|
setupEventListeners() {
|
|
// Navigation par URL
|
|
window.addEventListener('popstate', () => {
|
|
this.handleInitialRoute();
|
|
});
|
|
|
|
// Raccourcis clavier
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
this.goBack();
|
|
}
|
|
});
|
|
},
|
|
|
|
handleInitialRoute() {
|
|
const params = Utils.getUrlParams();
|
|
|
|
if (params.page === 'play' && params.game && params.content) {
|
|
this.showGamePage(params.game, params.content);
|
|
} else if (params.page === 'levels' && params.game) {
|
|
this.showLevelsPage(params.game);
|
|
} else if (params.page === 'games') {
|
|
this.showGamesPage();
|
|
} else {
|
|
this.showHomePage();
|
|
}
|
|
},
|
|
|
|
// Navigation vers une page
|
|
navigateTo(page, game = null, content = null) {
|
|
const params = { page };
|
|
if (game) params.game = game;
|
|
if (content) params.content = content;
|
|
|
|
Utils.setUrlParams(params);
|
|
|
|
// Mise à jour historique
|
|
if (this.currentPage !== page) {
|
|
this.navigationHistory.push(page);
|
|
}
|
|
|
|
this.currentPage = page;
|
|
|
|
// Affichage de la page appropriée
|
|
switch(page) {
|
|
case 'games':
|
|
this.showGamesPage();
|
|
break;
|
|
case 'levels':
|
|
this.showLevelsPage(game);
|
|
break;
|
|
case 'play':
|
|
this.showGamePage(game, content);
|
|
break;
|
|
default:
|
|
this.showHomePage();
|
|
}
|
|
|
|
this.updateBreadcrumb();
|
|
},
|
|
|
|
// Retour en arrière
|
|
goBack() {
|
|
if (this.navigationHistory.length > 1) {
|
|
this.navigationHistory.pop(); // Retirer la page actuelle
|
|
const previousPage = this.navigationHistory[this.navigationHistory.length - 1];
|
|
|
|
const params = Utils.getUrlParams();
|
|
|
|
if (previousPage === 'levels') {
|
|
this.navigateTo('levels', params.game);
|
|
} else if (previousPage === 'games') {
|
|
this.navigateTo('games');
|
|
} else {
|
|
this.navigateTo('home');
|
|
}
|
|
}
|
|
},
|
|
|
|
// Affichage page d'accueil
|
|
showHomePage() {
|
|
this.hideAllPages();
|
|
document.getElementById('home-page').classList.add('active');
|
|
this.currentPage = 'home';
|
|
},
|
|
|
|
// Affichage page sélection jeux
|
|
showGamesPage() {
|
|
this.hideAllPages();
|
|
document.getElementById('games-page').classList.add('active');
|
|
this.renderGamesGrid();
|
|
this.currentPage = 'games';
|
|
},
|
|
|
|
// Affichage page sélection niveaux
|
|
showLevelsPage(gameType) {
|
|
this.hideAllPages();
|
|
document.getElementById('levels-page').classList.add('active');
|
|
this.renderLevelsGrid(gameType);
|
|
this.currentPage = 'levels';
|
|
|
|
// Mise à jour de la description
|
|
const gameInfo = this.gamesConfig?.games[gameType];
|
|
if (gameInfo) {
|
|
document.getElementById('level-description').textContent =
|
|
`Sélectionne le contenu pour jouer à ${gameInfo.name}`;
|
|
}
|
|
},
|
|
|
|
// Affichage page de jeu
|
|
async showGamePage(gameType, contentType) {
|
|
this.hideAllPages();
|
|
document.getElementById('game-page').classList.add('active');
|
|
this.currentPage = 'play';
|
|
|
|
Utils.showLoading();
|
|
|
|
try {
|
|
await GameLoader.loadGame(gameType, contentType);
|
|
} catch (error) {
|
|
console.error('Erreur chargement jeu:', error);
|
|
Utils.showToast('Erreur lors du chargement du jeu', 'error');
|
|
this.goBack();
|
|
} finally {
|
|
Utils.hideLoading();
|
|
}
|
|
},
|
|
|
|
// Masquer toutes les pages
|
|
hideAllPages() {
|
|
document.querySelectorAll('.page').forEach(page => {
|
|
page.classList.remove('active');
|
|
});
|
|
},
|
|
|
|
// Rendu grille des jeux
|
|
renderGamesGrid() {
|
|
const grid = document.getElementById('games-grid');
|
|
grid.innerHTML = '';
|
|
|
|
if (!this.gamesConfig) return;
|
|
|
|
Object.entries(this.gamesConfig.games).forEach(([key, game]) => {
|
|
if (game.enabled) {
|
|
const card = this.createGameCard(key, game);
|
|
grid.appendChild(card);
|
|
}
|
|
});
|
|
},
|
|
|
|
// Création d'une carte de jeu
|
|
createGameCard(gameKey, gameInfo) {
|
|
const card = document.createElement('div');
|
|
card.className = 'game-card';
|
|
card.innerHTML = `
|
|
<div class="icon">${gameInfo.icon}</div>
|
|
<div class="title">${gameInfo.name}</div>
|
|
<div class="description">${gameInfo.description}</div>
|
|
`;
|
|
|
|
card.addEventListener('click', () => {
|
|
Utils.animateElement(card, 'pulse');
|
|
this.navigateTo('levels', gameKey);
|
|
});
|
|
|
|
return card;
|
|
},
|
|
|
|
// Rendu grille des niveaux
|
|
async renderLevelsGrid(gameType) {
|
|
const grid = document.getElementById('levels-grid');
|
|
grid.innerHTML = '<div class="loading-content">🔍 Recherche du contenu disponible...</div>';
|
|
|
|
try {
|
|
// Obtenir tout le contenu disponible automatiquement
|
|
const availableContent = await this.contentScanner.getAvailableContent();
|
|
|
|
if (availableContent.length === 0) {
|
|
grid.innerHTML = '<div class="no-content">Aucun contenu trouvé</div>';
|
|
return;
|
|
}
|
|
|
|
// Effacer le loading
|
|
grid.innerHTML = '';
|
|
|
|
// Filtrer par compatibilité avec le jeu si possible
|
|
const compatibleContent = await this.contentScanner.getContentByGame(gameType);
|
|
const contentToShow = compatibleContent.length > 0 ? compatibleContent : availableContent;
|
|
|
|
console.log(`📋 Affichage de ${contentToShow.length} modules pour ${gameType}`);
|
|
|
|
// Créer les cartes pour chaque contenu trouvé
|
|
contentToShow.forEach(content => {
|
|
const card = this.createLevelCard(content.id, content, gameType);
|
|
grid.appendChild(card);
|
|
});
|
|
|
|
// Ajouter info de compatibilité si filtré
|
|
if (compatibleContent.length > 0 && compatibleContent.length < availableContent.length) {
|
|
const infoDiv = document.createElement('div');
|
|
infoDiv.className = 'content-info';
|
|
infoDiv.innerHTML = `
|
|
<p><em>Affichage des contenus les plus compatibles avec ${gameType}</em></p>
|
|
<button onclick="AppNavigation.showAllContent('${gameType}')" class="show-all-btn">
|
|
Voir tous les contenus (${availableContent.length})
|
|
</button>
|
|
`;
|
|
grid.appendChild(infoDiv);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Erreur rendu levels:', error);
|
|
grid.innerHTML = '<div class="error-content">❌ Erreur lors du chargement du contenu</div>';
|
|
}
|
|
},
|
|
|
|
// Méthode pour afficher tout le contenu
|
|
async showAllContent(gameType) {
|
|
const grid = document.getElementById('levels-grid');
|
|
grid.innerHTML = '';
|
|
|
|
const availableContent = await this.contentScanner.getAvailableContent();
|
|
|
|
availableContent.forEach(content => {
|
|
const card = this.createLevelCard(content.id, content, gameType);
|
|
grid.appendChild(card);
|
|
});
|
|
},
|
|
|
|
// Création d'une carte de niveau
|
|
createLevelCard(contentKey, contentInfo, gameType) {
|
|
const card = document.createElement('div');
|
|
card.className = 'level-card';
|
|
|
|
// Calculer les statistiques à afficher
|
|
const stats = [];
|
|
if (contentInfo.stats) {
|
|
if (contentInfo.stats.vocabularyCount > 0) {
|
|
stats.push(`📚 ${contentInfo.stats.vocabularyCount} mots`);
|
|
}
|
|
if (contentInfo.stats.sentenceCount > 0) {
|
|
stats.push(`💬 ${contentInfo.stats.sentenceCount} phrases`);
|
|
}
|
|
if (contentInfo.stats.dialogueCount > 0) {
|
|
stats.push(`🎭 ${contentInfo.stats.dialogueCount} dialogues`);
|
|
}
|
|
}
|
|
|
|
// Indicateur de compatibilité
|
|
const compatibility = contentInfo.gameCompatibility?.[gameType];
|
|
const compatScore = compatibility?.score || 0;
|
|
const compatClass = compatScore > 70 ? 'high-compat' : compatScore > 40 ? 'medium-compat' : 'low-compat';
|
|
|
|
card.innerHTML = `
|
|
<div class="card-header">
|
|
<div class="icon">${contentInfo.icon}</div>
|
|
${compatibility ? `<div class="compatibility ${compatClass}" title="Compatibilité: ${compatScore}%">
|
|
${compatScore > 70 ? '🟢' : compatScore > 40 ? '🟡' : '🟠'}
|
|
</div>` : ''}
|
|
</div>
|
|
<div class="title">${contentInfo.name}</div>
|
|
<div class="description">${contentInfo.description}</div>
|
|
<div class="content-stats">
|
|
<span class="difficulty-badge difficulty-${contentInfo.difficulty}">${contentInfo.difficulty}</span>
|
|
<span class="items-count">${contentInfo.metadata.totalItems} éléments</span>
|
|
<span class="time-estimate">~${contentInfo.metadata.estimatedTime}min</span>
|
|
</div>
|
|
${stats.length > 0 ? `<div class="detailed-stats">${stats.join(' • ')}</div>` : ''}
|
|
`;
|
|
|
|
card.addEventListener('click', () => {
|
|
Utils.animateElement(card, 'pulse');
|
|
this.navigateTo('play', gameType, contentKey);
|
|
});
|
|
|
|
return card;
|
|
},
|
|
|
|
// Mise à jour du breadcrumb
|
|
updateBreadcrumb() {
|
|
const breadcrumb = document.getElementById('breadcrumb');
|
|
breadcrumb.innerHTML = '';
|
|
|
|
const params = Utils.getUrlParams();
|
|
|
|
// Accueil
|
|
const homeItem = this.createBreadcrumbItem('🏠 Accueil', 'home',
|
|
this.currentPage === 'home');
|
|
breadcrumb.appendChild(homeItem);
|
|
|
|
// Jeux
|
|
if (['games', 'levels', 'play'].includes(this.currentPage)) {
|
|
const gamesItem = this.createBreadcrumbItem('🎮 Jeux', 'games',
|
|
this.currentPage === 'games');
|
|
breadcrumb.appendChild(gamesItem);
|
|
}
|
|
|
|
// Niveaux
|
|
if (['levels', 'play'].includes(this.currentPage) && params.game) {
|
|
const gameInfo = this.gamesConfig?.games[params.game];
|
|
const levelText = gameInfo ? `${gameInfo.icon} ${gameInfo.name}` : 'Niveaux';
|
|
const levelsItem = this.createBreadcrumbItem(levelText, 'levels',
|
|
this.currentPage === 'levels');
|
|
breadcrumb.appendChild(levelsItem);
|
|
}
|
|
|
|
// Jeu en cours
|
|
if (this.currentPage === 'play' && params.content) {
|
|
const contentInfo = this.gamesConfig?.content[params.content];
|
|
const playText = contentInfo ? `🎯 ${contentInfo.name}` : 'Jeu';
|
|
const playItem = this.createBreadcrumbItem(playText, 'play', true);
|
|
breadcrumb.appendChild(playItem);
|
|
}
|
|
},
|
|
|
|
// Création d'un élément breadcrumb
|
|
createBreadcrumbItem(text, page, isActive) {
|
|
const item = document.createElement('button');
|
|
item.className = `breadcrumb-item ${isActive ? 'active' : ''}`;
|
|
item.textContent = text;
|
|
item.dataset.page = page;
|
|
|
|
if (!isActive) {
|
|
item.addEventListener('click', () => {
|
|
const params = Utils.getUrlParams();
|
|
|
|
if (page === 'home') {
|
|
this.navigateTo('home');
|
|
} else if (page === 'games') {
|
|
this.navigateTo('games');
|
|
} else if (page === 'levels') {
|
|
this.navigateTo('levels', params.game);
|
|
}
|
|
});
|
|
}
|
|
|
|
return item;
|
|
}
|
|
};
|
|
|
|
// Fonctions globales pour l'HTML
|
|
window.navigateTo = (page, game, content) => AppNavigation.navigateTo(page, game, content);
|
|
window.goBack = () => AppNavigation.goBack();
|
|
|
|
// Export
|
|
window.AppNavigation = AppNavigation; |