Class_generator/index.html
StillHammer 1f8688c4aa Fix WebSocket logging system and add comprehensive network features
- Fix WebSocket server to properly broadcast logs to all connected clients
- Integrate professional logging system with real-time WebSocket interface
- Add network status indicator with DigitalOcean Spaces connectivity
- Implement AWS Signature V4 authentication for private bucket access
- Add JSON content loader with backward compatibility to JS modules
- Restore navigation breadcrumb system with comprehensive logging
- Add multiple content formats: JSON + JS with automatic discovery
- Enhance top bar with logger toggle and network status indicator
- Remove deprecated temp-games module and clean up unused files

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-15 23:05:14 +08:00

307 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cours d'Anglais Interactif</title>
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/navigation.css">
<link rel="stylesheet" href="css/games.css">
</head>
<body>
<!-- Top Bar with Network Status -->
<div class="top-bar">
<div class="top-bar-title">🎓 Cours d'Anglais Interactif</div>
<div class="network-status" id="network-status">
<div class="network-indicator connecting" id="network-indicator"></div>
<span class="network-status-text" id="network-status-text">Connexion...</span>
</div>
<button class="logger-toggle" onclick="openLogsInterface()" title="Ouvrir interface de logs">📋</button>
</div>
<!-- Navigation Breadcrumb -->
<nav class="breadcrumb" id="breadcrumb">
<button class="breadcrumb-item active" data-page="home">🏠 Accueil</button>
</nav>
<!-- Main Container -->
<main class="container" id="main-container">
<!-- Page d'Accueil -->
<div class="page active" id="home-page">
<div class="hero">
<h1>🎓 Cours d'Anglais Interactif</h1>
<p>Apprends l'anglais en t'amusant !</p>
</div>
<div class="main-options">
<button class="option-card primary" onclick="navigateTo('games')">
🎮 <span>Créer une leçon personnalisée</span>
</button>
<button class="option-card secondary" onclick="showComingSoon()">
📊 <span>Statistiques</span>
<small>Bientôt disponible</small>
</button>
<button class="option-card secondary" onclick="showComingSoon()">
⚙️ <span>Paramètres</span>
<small>Bientôt disponible</small>
</button>
<button class="option-card primary" onclick="showContentCreator()">
🏭 <span>Créateur de Contenu</span>
<small>Créez vos propres exercices</small>
</button>
</div>
</div>
<!-- Sélection Type de Jeu -->
<div class="page" id="games-page">
<div class="page-header">
<h2>🎮 Choisis ton jeu</h2>
<p>Sélectionne le type d'activité que tu veux faire</p>
</div>
<div class="cards-grid" id="games-grid">
<!-- Les cartes seront générées dynamiquement -->
</div>
</div>
<!-- Sélection Contenu/Niveau -->
<div class="page" id="levels-page">
<div class="page-header">
<h2>📚 Choisis ton niveau</h2>
<p id="level-description">Sélectionne le contenu à apprendre</p>
</div>
<div class="cards-grid" id="levels-grid">
<!-- Les cartes seront générées dynamiquement -->
</div>
</div>
<!-- Page de Jeu -->
<div class="page" id="game-page">
<div class="game-header">
<button class="back-btn" onclick="goBack()">← Retour</button>
<h3 id="game-title">Jeu en cours...</h3>
<div class="score-display">
Score: <span id="current-score">0</span>
</div>
</div>
<div class="game-container" id="game-container">
<!-- Le jeu sera chargé ici dynamiquement -->
</div>
</div>
</main>
<!-- Modal Coming Soon -->
<div class="modal" id="coming-soon-modal">
<div class="modal-content">
<h3>🚧 Bientôt disponible !</h3>
<p>Cette fonctionnalité sera disponible dans une prochaine version.</p>
<button onclick="closeModal()">OK</button>
</div>
</div>
<!-- Loading Indicator -->
<div class="loading" id="loading">
<div class="spinner"></div>
<p>Chargement...</p>
</div>
<!-- Scripts -->
<script src="js/core/websocket-logger.js"></script>
<script src="js/core/env-config.js"></script>
<script src="js/core/utils.js"></script>
<script src="js/core/content-engine.js"></script>
<script src="js/core/content-factory.js"></script>
<script src="js/core/content-parsers.js"></script>
<script src="js/core/content-generators.js"></script>
<script src="js/core/content-scanner.js"></script>
<script src="js/core/json-content-loader.js"></script>
<script src="js/tools/content-creator.js"></script>
<script src="js/core/navigation.js"></script>
<script src="js/core/game-loader.js"></script>
<script>
// Fonction de debug pour le logger
function toggleLoggerDebug() {
console.log('🔧 Bouton toggle cliqué!');
if (typeof window.logger === 'undefined') {
console.error('❌ window.logger n\'existe pas!');
alert('Erreur: Logger non initialisé!');
return;
}
console.log('✅ Logger existe, toggle...');
try {
window.logger.toggle();
console.log('✅ Toggle réussi');
} catch (error) {
console.error('❌ Erreur toggle:', error);
alert('Erreur toggle: ' + error.message);
}
}
// Initialize app when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
console.log('🔧 DOM loaded, initializing...');
logSh('🎯 DOM chargé, initialisation de l\'application...', 'INFO');
// Vérifier que le logger existe
if (typeof window.logger === 'undefined') {
console.error('❌ Logger non trouvé au chargement!');
} else {
console.log('✅ Logger trouvé:', window.logger);
}
// Test du logger
if (typeof logSh !== 'undefined') {
logSh('🚀 Application démarrée', 'INFO');
logSh('Logger système intégré avec succès', 'DEBUG');
} else {
console.log('🚀 Application démarrée (pas de logger)');
}
// Initialize connection status listener
initConnectionStatus();
// Initialize navigation system
AppNavigation.init();
// Test initial network connection
setTimeout(testNetworkConnection, 1000);
});
// Network Status Manager
function initConnectionStatus() {
// Listen for content connection status events
window.addEventListener('contentConnectionStatus', function(event) {
updateNetworkStatus(event.detail);
});
// Test connection périodiquement
setInterval(testNetworkConnection, 30000); // Test toutes les 30 secondes
}
function updateNetworkStatus(details) {
const indicator = document.getElementById('network-indicator');
const text = document.getElementById('network-status-text');
// Remove all status classes
indicator.classList.remove('connecting', 'online', 'offline');
// Update based on status
switch(details.status) {
case 'loading':
indicator.classList.add('connecting');
text.textContent = 'Connexion...';
break;
case 'online':
indicator.classList.add('online');
text.textContent = 'En ligne';
break;
case 'offline':
indicator.classList.add('offline');
text.textContent = 'Local';
break;
case 'error':
indicator.classList.add('offline');
text.textContent = 'Hors ligne';
break;
}
}
async function testNetworkConnection() {
const indicator = document.getElementById('network-indicator');
const text = document.getElementById('network-status-text');
logSh('🔍 Test de connexion réseau démarré...', 'INFO');
try {
// Test avec l'endpoint DigitalOcean avec timeout approprié
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);
const testUrl = envConfig.getRemoteContentUrl() + 'test.json';
logSh(`🌐 Test URL: ${testUrl}`, 'DEBUG');
const authHeaders = await envConfig.getAuthHeaders('HEAD', testUrl);
logSh(`🔐 Headers d'auth générés: ${Object.keys(authHeaders).join(', ')}`, 'DEBUG');
const response = await fetch(testUrl, {
method: 'HEAD',
signal: controller.signal,
headers: authHeaders
});
clearTimeout(timeoutId);
logSh(`📡 Réponse reçue: ${response.status} ${response.statusText}`, 'INFO');
if (response.ok) {
indicator.classList.remove('connecting', 'offline');
indicator.classList.add('online');
text.textContent = 'En ligne';
logSh('✅ Connexion réussie !', 'INFO');
} else {
// Pour les buckets privés, on considère 403 comme "connexion OK mais accès privé"
if (response.status === 403) {
indicator.classList.remove('connecting', 'offline');
indicator.classList.add('online');
text.textContent = 'Privé';
logSh('🔒 Connexion OK mais accès privé (403)', 'WARN');
} else {
logSh(`❌ Erreur HTTP: ${response.status}`, 'ERROR');
throw new Error(`HTTP ${response.status}`);
}
}
} catch (error) {
logSh(`💥 Erreur de connexion: ${error.name} - ${error.message}`, 'ERROR');
indicator.classList.remove('connecting', 'online');
indicator.classList.add('offline');
if (error.name === 'AbortError') {
text.textContent = 'Timeout';
logSh('⏰ Timeout de connexion', 'WARN');
} else {
text.textContent = 'Hors ligne';
logSh(`🚫 Hors ligne: ${error.message}`, 'ERROR');
}
}
}
// Coming soon functionality
function showComingSoon() {
logSh('🚧 Ouverture modal "Bientôt disponible"', 'INFO');
document.getElementById('coming-soon-modal').classList.add('show');
}
function closeModal() {
logSh('❌ Fermeture modal', 'DEBUG');
document.getElementById('coming-soon-modal').classList.remove('show');
}
function showContentCreator() {
logSh('🏭 Ouverture du créateur de contenu', 'INFO');
// Masquer la page d'accueil
document.getElementById('home-page').classList.remove('active');
// Créer et afficher le créateur de contenu
const creator = new ContentCreator();
creator.init();
}
// Keyboard navigation
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
logSh('⌨️ Touche Escape pressée', 'DEBUG');
closeModal();
AppNavigation.goBack();
}
});
</script>
</body>
</html>