/** * ==================================================================== * RYM HORIZON — ENGINE APPLICATION (v3.1.3) * ==================================================================== * Philosophie : Code découplé, souveraineté et performance pure. * Architecture : Gestionnaire de vues + Moteur Drag & Drop + Usine à badges. * Conformité : Sans dépendances tierces intrusives. */ document.addEventListener('DOMContentLoaded', () => { // --- INTÉGRATION DE LA CHRONOLOGIE (SESSION LOG) --- console.log("RYM Horizon Engine v3.1.3 : Initialisation du système..."); // ========================================== // MODULE 1 : MANAGER DE NAVIGATION SOUVERAIN // ========================================== const tabButtons = document.querySelectorAll('.nav-view-switcher .nav-link'); const tabPanes = document.querySelectorAll('.tab-content .tab-pane'); tabButtons.forEach(button => { button.addEventListener('click', (e) => { const targetTabId = button.getAttribute('data-tab'); // 1. Mise à jour de l'état actif sur les boutons du menu tabButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); // 2. Commutation stricte des conteneurs de vues (Géré via CSS display !important) tabPanes.forEach(pane => { if (pane.id === targetTabId) { pane.classList.add('active'); } else { pane.classList.remove('active'); } }); console.log(`[Navigation] Passage sur la vue : ${targetTabId}`); }); }); // ========================================== // MODULE 2 : USINE DE CRÉATION DE BADGES (À LA VOLÉE) // ========================================== const generatorForm = document.getElementById('rym-coach-generator'); const productionZone = document.getElementById('badge-production-zone'); // Dictionnaire de configuration des composants (Couleurs CSS natifs et Icônes) const typeDictionary = { run: { cssClass: 'run', icon: 'bi-lightning-fill' }, bike: { cssClass: 'bike', icon: 'bi-bicycle' }, swim: { cssClass: 'swim', icon: 'bi-water' }, matos: { cssClass: 'run', icon: 'bi-gear-wide-connected', customStyle: 'background: #fef2f2; color: #991b1b; border: 1px dashed #f87171;' }, soins: { cssClass: 'swim', icon: 'bi-heart-pulse-fill', customStyle: 'background: #faf5ff; color: #6b21a8; border: 1px dashed #c084fc;' } }; generatorForm.addEventListener('submit', (e) => { e.preventDefault(); // Bloque le rechargement de la page pour préserver le cache local const type = document.getElementById('gen-type').value; const title = document.getElementById('gen-title').value; const config = typeDictionary[type]; const uniqueId = `w-generated-${Date.now()}`; // Identifiant unique basé sur le timestamp // Nettoyage de la zone de production productionZone.innerHTML = ''; // Création du nœud DOM du badge const badge = document.createElement('div'); badge.id = uniqueId; badge.className = `workout ${config.cssClass} rym-draggable-workout`; badge.setAttribute('draggable', 'true'); if (config.customStyle) { badge.setAttribute('style', config.customStyle); } // Injection du contenu structuré badge.innerHTML = ` ${title}`; // Activation immédiate de la mécanique Drag sur le nouveau composant attachDragEventsToElement(badge); // Rendu final dans l'interface productionZone.appendChild(badge); generatorForm.reset(); console.log(`[Engine] Nouveau badge instancié avec succès ID: ${uniqueId}`); }); // ========================================== // MODULE 3 : MOTEUR DRAG & DROP MULTI-CIBLES // ========================================== let draggedElement = null; /** * Attache les écouteurs d'événements Drag à un élément unique * @param {HTMLElement} element */ function attachDragEventsToElement(element) { element.addEventListener('dragstart', (e) => { draggedElement = element; e.dataTransfer.setData('text/plain', element.id); element.style.opacity = '0.4'; console.log(`[Drag] Début du déplacement de l'élément : ${element.id}`); }); element.addEventListener('dragend', () => { element.style.opacity = '1'; draggedElement = null; }); } // Initialisation du moteur Drag sur les cartes pré-existantes au boot document.querySelectorAll('.rym-draggable-workout').forEach(attachDragEventsToElement); // Configuration des zones de réception (Les jours de la semaine) const dropZones = document.querySelectorAll('.drop-zone'); dropZones.forEach(zone => { zone.addEventListener('dragover', (e) => { e.preventDefault(); // Indispensable pour autoriser le drop dans le navigateur zone.classList.add('drag-over'); }); zone.addEventListener('dragleave', () => { zone.classList.remove('drag-over'); }); zone.addEventListener('drop', (e) => { e.preventDefault(); zone.classList.remove('drag-over'); if (draggedElement) { // Déplacement physique du nœud dans le conteneur du jour ciblé zone.appendChild(draggedElement); // Si le badge provient de la zone de production, on remet le texte d'attente if (productionZone.children.length === 0) { productionZone.innerHTML = 'Aucun badge généré'; } console.log(`[Drop] Élément réassigné au jour : ${zone.getAttribute('data-day')}`); } }); }); });