BitDown commited on
Commit
b59ef08
·
verified ·
1 Parent(s): 840f62b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +100 -178
index.html CHANGED
@@ -7,7 +7,7 @@
7
  <!-- Ajout de la librairie pour les confettis -->
8
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
9
  <style>
10
- /* --- Styles CSS (avec ajouts/modifications) --- */
11
  :root {
12
  --bg-dark: #121212;
13
  --bg-card: #1e1e1e;
@@ -15,7 +15,7 @@
15
  --accent: #4CAF50;
16
  --accent-dark: #3a8a3d;
17
  --danger: #f44336;
18
- --superset-border: #4a90e2; /* Couleur pour indiquer superset */
19
  }
20
  * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
21
  body { background-color: var(--bg-dark); color: var(--text-light); min-height: 100vh; padding-bottom: 80px; }
@@ -45,10 +45,6 @@
45
  display: block; /* Afficher l'exercice actif */
46
  animation: fadeIn 0.3s ease-in-out;
47
  }
48
- /* Style pour exercice débutant un superset (dans le formulaire) */
49
- .exercise.is-superset-start {
50
- border-left-color: var(--superset-border);
51
- }
52
  .exercise-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; gap: 0.5rem;}
53
  .exercise-header input {margin-bottom: 0;}
54
  .series-container { margin-left: 0.5rem; margin-top: 0.5rem; }
@@ -69,7 +65,7 @@
69
  #app-container > div:not(.active) { display: none !important; }
70
  .flex-between { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;}
71
  .badge { background-color: var(--accent); color: white; padding: 0.2rem 0.5rem; border-radius: 10px; font-size: 0.8rem; white-space: nowrap; }
72
- .badge-superset { background-color: var(--superset-border); }
73
  .spinner { border: 4px solid rgba(0, 0, 0, 0.1); width: 36px; height: 36px; border-radius: 50%; border-left-color: var(--accent); animation: spin 1s linear infinite; margin: 2rem auto; display: none; }
74
  @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
75
  .exercise-summary { margin: 0.3rem 0; padding: 0.3rem 0; border-bottom: 1px solid #333; font-size: 0.9rem;}
@@ -77,18 +73,7 @@
77
  .satisfaction { display: flex; align-items: center; justify-content: center; flex-direction: column; margin-top: 1rem; }
78
  .satisfaction-value { font-size: 2rem; color: var(--accent); margin-top: 0.5rem; }
79
  .exercise-navigation { display: flex; justify-content: space-between; margin-top: 1rem; margin-bottom: 1rem; }
80
- .detail-exercise-card.is-superset-start {
81
- border-left: 3px solid var(--superset-border);
82
- margin-bottom: 0.2rem; /* Réduire l'espace avant le suivant */
83
- }
84
- .detail-exercise-card.is-superset-continuation {
85
- border-left: 3px solid var(--superset-border);
86
- padding-top: 0.5rem;
87
- margin-top: -0.8rem; /* Rapprocher visuellement */
88
- border-top-left-radius: 0; /* Pour lier visuellement */
89
- border-bottom-left-radius: 8px;
90
- }
91
-
92
 
93
  /* Animation d'apparition/zoom pour nouvelle séance */
94
  @keyframes fadeInZoom {
@@ -115,7 +100,7 @@
115
  .flex-between > div { width: 100%; display: flex; justify-content: flex-end; margin-top: 0.5rem;}
116
  .user-info { text-align: center; margin-bottom: 0.5rem;}
117
  .user-info button { display: block; margin: 0.5rem auto 0;}
118
- .exercise-navigation button { padding: 0.5rem; font-size: 0.9rem;} /* Ajuster boutons nav exercice */
119
  }
120
  /* Animation fade in standard */
121
  @keyframes fadeIn {
@@ -133,7 +118,6 @@
133
 
134
  <!-- Écran de Connexion -->
135
  <div id="login-page">
136
- <!-- Contenu page connexion -->
137
  <div class="card">
138
  <h2>Accès Utilisateur</h2>
139
  <div class="form-group">
@@ -233,8 +217,8 @@
233
  let workouts = [];
234
  let currentUser = null;
235
  let currentWorkoutId = null;
236
- let currentExerciseIndex = 0; // Index de l'exercice affiché dans le formulaire Nouvelle Séance
237
- let workoutExercisesForm = []; // Tableau temporaire pour les divs d'exercice dans le form
238
 
239
  // --- Éléments DOM ---
240
  const loginPage = document.getElementById('login-page');
@@ -251,8 +235,8 @@
251
  const saveWorkoutBtn = document.getElementById('save-workout-btn');
252
  const cancelNewWorkoutBtn = document.getElementById('cancel-new-workout-btn');
253
  const addExerciseBtn = document.getElementById('add-exercise-btn');
254
- const exercisesContainer = document.getElementById('exercises-container');
255
- const workoutsList = document.getElementById('workouts-list');
256
  const backToHomeBtn = document.getElementById('back-to-home');
257
  const deleteWorkoutBtn = document.getElementById('delete-workout-btn');
258
  const satisfactionRange = document.getElementById('satisfaction');
@@ -263,7 +247,6 @@
263
  const nextExerciseBtn = document.getElementById('next-exercise-btn');
264
  const currentExerciseIndicator = document.getElementById('current-exercise-indicator');
265
 
266
-
267
  // --- Initialisation ---
268
  document.addEventListener('DOMContentLoaded', () => {
269
  const rememberedUser = sessionStorage.getItem('liftTrackCurrentUser');
@@ -272,18 +255,18 @@
272
  });
273
 
274
  // --- Authentification & Persistance (inchangées) ---
275
- function showLoginPage() { /* ... */ loginPage.style.display = 'block'; mainAppContent.style.display = 'none'; loginError.style.display = 'none'; usernameInput.value = ''; currentUser = null; }
276
- function showApp() { /* ... */ if (!currentUser) return; loginPage.style.display = 'none'; mainAppContent.style.display = 'block'; currentUserDisplay.textContent = currentUser; setTodayDate(); loadWorkouts(); showPage('home-page'); }
277
- function handleLogin() { /* ... */ const username = usernameInput.value.trim(); if (username && username.length > 0) { loginUser(username); } else { loginError.textContent = "Veuillez entrer un nom d'utilisateur."; loginError.style.display = 'block'; }}
278
- function loginUser(username) { /* ... */ currentUser = username; sessionStorage.setItem('liftTrackCurrentUser', currentUser); showApp(); }
279
- function handleLogout() { /* ... */ currentUser = null; sessionStorage.removeItem('liftTrackCurrentUser'); workouts = []; showLoginPage(); }
280
- function getStorageKey() { /* ... */ if (!currentUser) return null; const safeUsername = currentUser.replace(/[^a-zA-Z0-9_-]/g, '_'); return `liftTrackData_${safeUsername}`; }
281
- function loadWorkouts() { /* ... (avec spinner) */
282
  const storageKey = getStorageKey(); if (!storageKey) { workouts = []; return; }
283
  if (spinner) spinner.classList.remove('hidden'); emptyWorkoutMessage.classList.add('hidden'); workoutsList.innerHTML = '';
284
  setTimeout(() => { try { const savedData = localStorage.getItem(storageKey); workouts = savedData ? JSON.parse(savedData) : []; console.log(`Chargé ${workouts.length} séances pour ${currentUser}`); } catch (e) { console.error("Erreur parsing localStorage:", e); workouts = []; alert("Erreur chargement données."); } finally { if (spinner) spinner.classList.add('hidden'); renderWorkoutsList(); } }, 150);
285
  }
286
- function saveWorkouts() { /* ... (avec try/catch) */
287
  const storageKey = getStorageKey(); if (!storageKey) { console.error("Sauvegarde impossible: non connecté."); return; } try { localStorage.setItem(storageKey, JSON.stringify(workouts)); console.log(`Sauvegardé ${workouts.length} séances pour ${currentUser}`); } catch (e) { console.error("Erreur sauvegarde localStorage:", e); alert("Erreur sauvegarde données."); }
288
  }
289
 
@@ -293,61 +276,36 @@
293
  logoutBtn.addEventListener('click', handleLogout);
294
  usernameInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); handleLogin(); } });
295
 
296
- navItems.forEach(item => { /* ... navigation menu bas ... */
297
  item.addEventListener('click', (e) => { e.preventDefault(); if (!currentUser) return; const targetPageId = item.getAttribute('data-page'); showPage(targetPageId); navItems.forEach(nav => nav.classList.remove('active')); item.classList.add('active'); if (targetPageId === 'stats-page') { updateStats(); } });
298
  });
299
 
300
- // Bouton Nouvelle Séance
301
  newWorkoutBtn.addEventListener('click', () => {
302
- if (!currentUser) return;
303
- currentWorkoutId = null; // C'est une nouvelle séance
304
- clearNewWorkoutForm(); // Réinitialise le formulaire et ajoute le premier exercice vide
305
- showPage('new-workout-page');
306
- // Déclencher l'animation d'entrée (la classe 'active' est déjà ajoutée par showPage)
307
- // L'animation CSS sur #new-workout-page.active s'en charge
308
  });
309
 
310
  cancelNewWorkoutBtn.addEventListener('click', () => showPage('home-page'));
311
- saveWorkoutBtn.addEventListener('click', saveWorkout); // Sauvegarde tous les exercices ajoutés
312
- addExerciseBtn.addEventListener('click', handleAddNewExercise); // Ajoute un exo et navigue vers lui
313
-
314
- // Navigation formulaire exercices
315
  prevExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, -1));
316
  nextExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, 1));
317
-
318
  backToHomeBtn.addEventListener('click', () => showPage('home-page'));
319
  deleteWorkoutBtn.addEventListener('click', deleteWorkout);
320
  satisfactionRange.addEventListener('input', () => { satisfactionValue.textContent = `${satisfactionRange.value}%`; });
321
  }
322
 
323
  // --- Logique Principale ---
324
- function setTodayDate() { /* ... */ if(workoutDateInput) { try { const today = new Date().toISOString().split('T')[0]; workoutDateInput.value = today; } catch (e) { console.error("Impossible définir date:", e); workoutDateInput.value = ''; } } }
325
 
326
  function showPage(pageId) {
327
  if (!currentUser) { showLoginPage(); return; }
328
-
329
- document.querySelectorAll('#app-container > div').forEach(page => {
330
- page.classList.remove('active');
331
- });
332
-
333
  const pageToShow = document.getElementById(pageId);
334
- if (pageToShow) {
335
- pageToShow.classList.add('active');
336
- } else {
337
- console.error(`Page ID "${pageId}" non trouvée. Affichage home-page.`);
338
- document.getElementById('home-page').classList.add('active');
339
- pageId = 'home-page';
340
- }
341
-
342
- // Gérer la nav active
343
- navItems.forEach(item => { item.classList.remove('active'); });
344
- const activeNavItem = document.querySelector(`.nav-item[data-page="${pageId === 'stats-page' ? 'stats-page' : 'home-page'}"]`);
345
- if(activeNavItem) activeNavItem.classList.add('active');
346
-
347
- // Si on affiche la page nouvelle séance, s'assurer que le premier exercice est visible
348
- if (pageId === 'new-workout-page') {
349
- renderActiveExerciseForm(); // Affichera l'exercice à currentExerciseIndex
350
- }
351
  }
352
 
353
  // --- Logique Formulaire Nouvelle Séance ---
@@ -360,73 +318,65 @@
360
  if (!currentUser) return;
361
  const exerciseId = `exercise-${Date.now()}`;
362
  const exerciseDiv = document.createElement('div');
363
- exerciseDiv.className = 'card exercise'; // Pas 'active-exercise' ici
364
  exerciseDiv.setAttribute('data-exercise-id', exerciseId);
365
 
 
366
  exerciseDiv.innerHTML = `
367
  <div class="exercise-header">
368
  <input type="text" placeholder="Nom Exercice" class="exercise-name">
369
  <button class="btn btn-danger remove-exercise" style="padding: 0.3rem 0.6rem; flex-shrink: 0;">×</button>
370
  </div>
371
- <div class="form-row" style="margin-top: 0.5rem; margin-bottom: 0.5rem; gap: 1rem;">
372
  <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.9rem;">
373
  <input type="checkbox" class="unilateral-checkbox"> Unilatéral
374
  </label>
375
- <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.9rem;">
376
- <input type="checkbox" class="superset-checkbox"> Début de Superset
377
- </label>
378
  </div>
379
  <div class="series-container"></div>
380
  <button class="btn btn-outline add-series" style="width: 100%; margin-top: 0.5rem; padding: 0.4rem;">+ Ajouter Série</button>
381
  `;
382
- exercisesContainer.appendChild(exerciseDiv); // Ajouter au DOM
383
 
384
- // Garder une référence (important pour la navigation)
385
- workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise'));
386
 
387
  // Écouteurs pour cet exercice
388
  const removeBtn = exerciseDiv.querySelector('.remove-exercise');
389
- // Gérer la suppression d'exercice dans le formulaire
390
  removeBtn.addEventListener('click', () => {
391
  const indexToRemove = workoutExercisesForm.indexOf(exerciseDiv);
392
  if (indexToRemove > -1) {
393
- exerciseDiv.remove(); // Supprimer du DOM
394
- workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); // Mettre à jour la liste
395
- // Ajuster l'index courant si on supprime l'actuel ou un précédent
396
- if (currentExerciseIndex >= indexToRemove) {
397
- currentExerciseIndex = Math.max(0, currentExerciseIndex - 1);
398
- }
399
- // Si on supprime le dernier, l'index doit pointer sur le nouveau dernier (ou 0 si vide)
400
- if (currentExerciseIndex >= workoutExercisesForm.length) {
401
- currentExerciseIndex = Math.max(0, workoutExercisesForm.length - 1);
402
- }
403
- renderActiveExerciseForm(); // Afficher le bon exercice après suppression
404
  }
405
  });
406
 
407
-
408
  const addSeriesBtn = exerciseDiv.querySelector('.add-series');
409
  const seriesContainer = exerciseDiv.querySelector('.series-container');
410
  addSeriesBtn.addEventListener('click', () => addSeries(seriesContainer));
411
 
412
- addSeries(seriesContainer); // Ajouter la première série
413
 
414
  if (navigateToNew) {
415
- currentExerciseIndex = workoutExercisesForm.length - 1; // Aller au nouvel exercice ajouté
416
  renderActiveExerciseForm();
417
  } else {
418
- updateExerciseNavButtons(); // Juste mettre à jour les boutons si on n'y navigue pas
419
  }
420
-
421
  }
422
 
423
- function addSeries(container) { /* ... (inchangé) ... */
424
  if (!currentUser || !container) return; const seriesId = `series-${Date.now()}`; const seriesDiv = document.createElement('div'); seriesDiv.className = 'series'; seriesDiv.setAttribute('data-series-id', seriesId);
425
  seriesDiv.innerHTML = `<div class="form-row" style="align-items: flex-end; gap: 0.8rem;"> <div class="form-group" style="flex: 1.2;"> <label>Reps</label> <input type="number" class="reps" min="1" placeholder="10" style="padding: 0.4rem;"> </div> <div class="form-group" style="flex: 1.2;"> <label>Charge (kg)</label> <input type="number" class="weight" min="0" step="0.1" placeholder="20" style="padding: 0.4rem;"> </div> <div class="form-group" style="flex: 1; display: flex; align-items: center; padding-bottom: 0.6rem; min-width: 100px;"> <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.8rem; margin-bottom: 0; white-space: nowrap;"> <input type="checkbox" class="degressive-checkbox" style="margin-right: 0.3rem;"> Dégressive </label> </div> <button class="btn btn-danger remove-series" style="padding: 0.3rem 0.6rem; margin-bottom: 0.6rem; flex-basis: 30px; flex-grow: 0; align-self: center;">×</button> </div>`;
426
  container.appendChild(seriesDiv); const removeBtn = seriesDiv.querySelector('.remove-series'); removeBtn.addEventListener('click', () => seriesDiv.remove());
427
  }
428
 
429
  function navigateExerciseForm(direction) {
 
 
430
  const newIndex = currentExerciseIndex + direction;
431
  if (newIndex >= 0 && newIndex < workoutExercisesForm.length) {
432
  currentExerciseIndex = newIndex;
@@ -435,25 +385,14 @@
435
  }
436
 
437
  function renderActiveExerciseForm() {
438
- workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); // MAJ référence
439
- // Cacher tous les exercices du formulaire
440
- workoutExercisesForm.forEach(ex => ex.classList.remove('active-exercise'));
441
 
442
- // Afficher l'exercice courant s'il existe
443
  if (currentExerciseIndex >= 0 && currentExerciseIndex < workoutExercisesForm.length) {
444
  const currentExDiv = workoutExercisesForm[currentExerciseIndex];
445
  currentExDiv.classList.add('active-exercise');
446
- // Appliquer style superset si coché
447
- const isSuperset = currentExDiv.querySelector('.superset-checkbox').checked;
448
- if (isSuperset) {
449
- currentExDiv.classList.add('is-superset-start');
450
- } else {
451
- currentExDiv.classList.remove('is-superset-start');
452
- }
453
-
454
  }
455
-
456
- // Mettre à jour l'indicateur et les boutons
457
  updateExerciseNavButtons();
458
  }
459
 
@@ -470,65 +409,71 @@
470
  }
471
  }
472
 
473
-
474
  function clearNewWorkoutForm() {
475
  if (!currentUser) return;
476
- document.getElementById('workout-name').value = '';
477
- document.getElementById('workout-duration').value = '';
478
- setTodayDate();
479
- exercisesContainer.innerHTML = ''; // Vider le conteneur
480
- workoutExercisesForm = []; // Vider la référence
481
- satisfactionRange.value = 75;
482
- satisfactionValue.textContent = '75%';
483
- currentWorkoutId = null;
484
- currentExerciseIndex = 0; // Revenir au premier potentiel exercice
485
- addExercise(false); // Ajouter le premier bloc d'exercice vide mais ne pas naviguer (render s'en charge)
486
- renderActiveExerciseForm(); // Afficher le premier exercice et MAJ boutons
487
  }
488
 
489
  function saveWorkout() {
490
  if (!currentUser) return;
491
 
 
 
 
492
  const workoutName = document.getElementById('workout-name').value.trim();
493
  const workoutDate = document.getElementById('workout-date').value;
494
  const workoutDuration = parseInt(document.getElementById('workout-duration').value) || 0;
495
  const satisfaction = parseInt(document.getElementById('satisfaction').value);
496
 
497
- if (!workoutName) { alert("Nom séance requis."); return; }
498
- if (!workoutDate) { alert("Date requise."); return; }
499
- if (workoutDuration <= 0) { alert("Durée invalide."); return; }
500
 
501
- // Lire depuis les divs d'exercices présents dans le conteneur du formulaire
502
- const exerciseElements = workoutExercisesForm; // Utiliser notre référence à jour
503
  const exercises = [];
504
- if (exerciseElements.length === 0) { alert("Ajoutez au moins un exercice."); return; }
505
 
506
  let validationError = null;
507
- exerciseElements.forEach(exerciseEl => {
508
  if (validationError) return;
509
- const exerciseName = exerciseEl.querySelector('.exercise-name').value.trim();
510
- const isUnilateral = exerciseEl.querySelector('.unilateral-checkbox').checked;
511
- const isSupersetStart = exerciseEl.querySelector('.superset-checkbox').checked; // Récupérer état superset
512
 
513
- if (!exerciseName) { validationError = "Nommez tous les exercices."; return; }
 
 
 
 
 
 
 
 
 
 
 
 
514
 
515
  const series = [];
516
  const seriesElements = exerciseEl.querySelectorAll('.series');
517
- if (seriesElements.length === 0) { validationError = `Exercice "${exerciseName}" sans série.`; return; }
518
 
519
  seriesElements.forEach(seriesEl => {
520
  if (validationError) return;
521
  const repsInput = seriesEl.querySelector('.reps'); const weightInput = seriesEl.querySelector('.weight');
522
  const reps = parseInt(repsInput.value) || 0; const weight = parseFloat(weightInput.value) || 0;
523
  const isDegressive = seriesEl.querySelector('.degressive-checkbox').checked;
524
- if (reps <= 0) { validationError = `Reps invalides pour "${exerciseName}".`; repsInput.focus(); return; }
525
- if (weight < 0) { validationError = `Charge invalide pour "${exerciseName}".`; weightInput.focus(); return; }
526
  series.push({ reps, weight, isDegressive });
527
  });
528
 
529
  if (!validationError) {
530
- // Ajouter isSupersetStart à l'objet exercice
531
- exercises.push({ name: exerciseName, isUnilateral, isSupersetStart, series });
532
  }
533
  });
534
 
@@ -543,26 +488,23 @@
543
  });
544
  });
545
 
 
546
  const workout = {
547
  id: currentWorkoutId || `workout-${Date.now()}`, name: workoutName, date: workoutDate, duration: workoutDuration,
548
- exercises: exercises, // Tableau d'exercices avec potentiellement isSupersetStart
549
  totalTonnage: totalTonnage, satisfaction: satisfaction
550
  };
551
-
552
  const existingIndex = workouts.findIndex(w => w.id === workout.id);
553
  if (existingIndex > -1) { workouts[existingIndex] = workout; } else { workouts.push(workout); }
554
 
555
  saveWorkouts();
556
-
557
- // Animation Confettis !
558
- confetti({ particleCount: 150, spread: 90, origin: { y: 0.6 } });
559
-
560
  showPage('home-page');
561
  renderWorkoutsList();
562
  }
563
 
564
- // --- Affichage et Stats (avec gestion superset dans l'affichage détail) ---
565
- function renderWorkoutsList() { /* ... (inchangé sauf appel updateStats) ... */
566
  if (!currentUser) return; workoutsList.innerHTML = ''; if (workouts.length === 0) { emptyWorkoutMessage.classList.remove('hidden'); updateStats(); return; } emptyWorkoutMessage.classList.add('hidden');
567
  const sortedWorkouts = [...workouts].sort((a, b) => new Date(b.date) - new Date(a.date));
568
  sortedWorkouts.forEach(workout => { const workoutDate = new Date(workout.date).toLocaleDateString('fr-FR', { year: 'numeric', month: 'short', day: 'numeric' }); const workoutDiv = document.createElement('div'); workoutDiv.className = 'card workout-card'; workoutDiv.setAttribute('data-workout-id', workout.id); workoutDiv.innerHTML = `<div class="workout-header"><h3 style="margin-bottom: 0.5rem;">${workout.name}</h3><div class="badge">${workoutDate}</div></div><div class="workout-details" style="font-size: 0.9rem; color: #ccc; margin-top: 0.5rem;"><span>${workout.duration} min</span> | <span>${workout.exercises.length} exo${workout.exercises.length > 1 ? 's' : ''}</span> | <span>${workout.totalTonnage.toFixed(1)} kg</span> | <span>${workout.satisfaction}%</span></div>`; workoutDiv.addEventListener('click', () => displayWorkoutDetails(workout.id)); workoutsList.appendChild(workoutDiv); });
@@ -570,47 +512,27 @@
570
  }
571
 
572
  function displayWorkoutDetails(workoutId) {
573
- if (!currentUser) return;
574
- const workout = workouts.find(w => w.id === workoutId);
575
- if (!workout) { console.error("Séance non trouvée:", workoutId); showPage('home-page'); return; }
576
-
577
- // MAJ Infos générales (inchangé)
578
- document.getElementById('detail-workout-name').textContent = workout.name; document.getElementById('detail-date').textContent = new Date(workout.date).toLocaleDateString('fr-FR'); document.getElementById('detail-duration').textContent = workout.duration; document.getElementById('detail-tonnage').textContent = workout.totalTonnage.toFixed(1); document.getElementById('detail-satisfaction').textContent = `${workout.satisfaction}%`; document.getElementById('detail-exercises-count').textContent = workout.exercises.length;
579
 
580
- const detailExercisesContainer = document.getElementById('detail-exercises-container');
581
- detailExercisesContainer.innerHTML = '';
582
-
583
- // MAJ Exercices avec indicateur Superset
584
- workout.exercises.forEach((exercise, index) => {
585
  const exerciseDiv = document.createElement('div');
586
- // Ajouter des classes pour le style Superset
587
- exerciseDiv.classList.add('card', 'detail-exercise-card'); // Classe de base
588
- let isContinuation = false;
589
- if (exercise.isSupersetStart) {
590
- exerciseDiv.classList.add('is-superset-start');
591
- }
592
- // Vérifier si l'exercice *précédent* était un début de superset
593
- if (index > 0 && workout.exercises[index - 1].isSupersetStart) {
594
- exerciseDiv.classList.add('is-superset-continuation');
595
- isContinuation = true;
596
- }
597
-
598
 
599
  let seriesHtml = '';
600
- exercise.series.forEach((serie, sIndex) => { /* ... (inchangé) ... */
601
  const degressiveLabel = serie.isDegressive ? ' <span class="badge" style="font-size: 0.7rem; background-color: var(--accent-dark);">Dégr.</span>' : ''; const weightFactor = exercise.isUnilateral ? 2 : 1; const seriesTonnage = serie.reps * serie.weight * weightFactor;
602
  seriesHtml += `<div class="exercise-summary"><div class="flex-between"><span>Série ${sIndex + 1}: ${serie.reps} reps × ${serie.weight} kg${degressiveLabel}</span><span style="color: #aaa;">(${seriesTonnage.toFixed(1)} kg)</span></div></div>`;
603
  });
604
 
605
  const unilateralLabel = exercise.isUnilateral ? ' <span class="badge" style="font-size: 0.7rem;">Unilat.</span>' : '';
606
- // Ajout badge Superset si c'est le début
607
- const supersetLabel = exercise.isSupersetStart ? ` <span class="badge badge-superset" style="font-size: 0.7rem;">Superset 🔽</span>` : '';
608
 
609
  exerciseDiv.innerHTML = `
610
- <h3 style="font-size: 1.1rem; margin-bottom: 0.5rem;">${exercise.name}${unilateralLabel}${supersetLabel}</h3>
611
- <div class="series-summary-container">
612
- ${seriesHtml}
613
- </div>`;
614
  detailExercisesContainer.appendChild(exerciseDiv);
615
  });
616
 
@@ -618,11 +540,11 @@
618
  showPage('workout-details-page');
619
  }
620
 
621
- function deleteWorkout() { /* ... (inchangé) ... */
622
  if (!currentUser || !currentWorkoutId) return; const workoutToDelete = workouts.find(w => w.id === currentWorkoutId); if (!workoutToDelete) return; const confirmDelete = confirm(`Supprimer séance "${workoutToDelete.name}" du ${new Date(workoutToDelete.date).toLocaleDateString('fr-FR')} ?`); if (!confirmDelete) return; workouts = workouts.filter(w => w.id !== currentWorkoutId); saveWorkouts(); currentWorkoutId = null; showPage('home-page'); renderWorkoutsList();
623
  }
624
 
625
- function updateStats() { /* ... (inchangé) ... */
626
  if (!currentUser) return; const workoutCount = workouts.length; document.getElementById('stats-workout-count').textContent = workoutCount; if (workoutCount === 0) { document.getElementById('stats-avg-tonnage').textContent = '0'; document.getElementById('stats-avg-satisfaction').textContent = '0%'; return; } const totalTonnageAll = workouts.reduce((sum, workout) => sum + (workout.totalTonnage || 0), 0); const avgTonnage = totalTonnageAll / workoutCount; document.getElementById('stats-avg-tonnage').textContent = avgTonnage.toFixed(1); const totalSatisfaction = workouts.reduce((sum, workout) => sum + (workout.satisfaction || 0), 0); const avgSatisfaction = totalSatisfaction / workoutCount; document.getElementById('stats-avg-satisfaction').textContent = `${Math.round(avgSatisfaction)}%`;
627
  }
628
 
 
7
  <!-- Ajout de la librairie pour les confettis -->
8
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
9
  <style>
10
+ /* --- Styles CSS (Superset enlevé) --- */
11
  :root {
12
  --bg-dark: #121212;
13
  --bg-card: #1e1e1e;
 
15
  --accent: #4CAF50;
16
  --accent-dark: #3a8a3d;
17
  --danger: #f44336;
18
+ /* --superset-border: #4a90e2; enlevé */
19
  }
20
  * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
21
  body { background-color: var(--bg-dark); color: var(--text-light); min-height: 100vh; padding-bottom: 80px; }
 
45
  display: block; /* Afficher l'exercice actif */
46
  animation: fadeIn 0.3s ease-in-out;
47
  }
 
 
 
 
48
  .exercise-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; gap: 0.5rem;}
49
  .exercise-header input {margin-bottom: 0;}
50
  .series-container { margin-left: 0.5rem; margin-top: 0.5rem; }
 
65
  #app-container > div:not(.active) { display: none !important; }
66
  .flex-between { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;}
67
  .badge { background-color: var(--accent); color: white; padding: 0.2rem 0.5rem; border-radius: 10px; font-size: 0.8rem; white-space: nowrap; }
68
+ /* .badge-superset enlevé */
69
  .spinner { border: 4px solid rgba(0, 0, 0, 0.1); width: 36px; height: 36px; border-radius: 50%; border-left-color: var(--accent); animation: spin 1s linear infinite; margin: 2rem auto; display: none; }
70
  @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
71
  .exercise-summary { margin: 0.3rem 0; padding: 0.3rem 0; border-bottom: 1px solid #333; font-size: 0.9rem;}
 
73
  .satisfaction { display: flex; align-items: center; justify-content: center; flex-direction: column; margin-top: 1rem; }
74
  .satisfaction-value { font-size: 2rem; color: var(--accent); margin-top: 0.5rem; }
75
  .exercise-navigation { display: flex; justify-content: space-between; margin-top: 1rem; margin-bottom: 1rem; }
76
+ /* Styles détail superset enlevés */
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  /* Animation d'apparition/zoom pour nouvelle séance */
79
  @keyframes fadeInZoom {
 
100
  .flex-between > div { width: 100%; display: flex; justify-content: flex-end; margin-top: 0.5rem;}
101
  .user-info { text-align: center; margin-bottom: 0.5rem;}
102
  .user-info button { display: block; margin: 0.5rem auto 0;}
103
+ .exercise-navigation button { padding: 0.5rem; font-size: 0.9rem;}
104
  }
105
  /* Animation fade in standard */
106
  @keyframes fadeIn {
 
118
 
119
  <!-- Écran de Connexion -->
120
  <div id="login-page">
 
121
  <div class="card">
122
  <h2>Accès Utilisateur</h2>
123
  <div class="form-group">
 
217
  let workouts = [];
218
  let currentUser = null;
219
  let currentWorkoutId = null;
220
+ let currentExerciseIndex = 0;
221
+ let workoutExercisesForm = []; // Référence aux divs .exercise dans le formulaire
222
 
223
  // --- Éléments DOM ---
224
  const loginPage = document.getElementById('login-page');
 
235
  const saveWorkoutBtn = document.getElementById('save-workout-btn');
236
  const cancelNewWorkoutBtn = document.getElementById('cancel-new-workout-btn');
237
  const addExerciseBtn = document.getElementById('add-exercise-btn');
238
+ const exercisesContainer = document.getElementById('exercises-container'); // Conteneur formulaire
239
+ const workoutsList = document.getElementById('workouts-list'); // Conteneur affichage liste
240
  const backToHomeBtn = document.getElementById('back-to-home');
241
  const deleteWorkoutBtn = document.getElementById('delete-workout-btn');
242
  const satisfactionRange = document.getElementById('satisfaction');
 
247
  const nextExerciseBtn = document.getElementById('next-exercise-btn');
248
  const currentExerciseIndicator = document.getElementById('current-exercise-indicator');
249
 
 
250
  // --- Initialisation ---
251
  document.addEventListener('DOMContentLoaded', () => {
252
  const rememberedUser = sessionStorage.getItem('liftTrackCurrentUser');
 
255
  });
256
 
257
  // --- Authentification & Persistance (inchangées) ---
258
+ function showLoginPage() { loginPage.style.display = 'block'; mainAppContent.style.display = 'none'; loginError.style.display = 'none'; usernameInput.value = ''; currentUser = null; }
259
+ function showApp() { if (!currentUser) return; loginPage.style.display = 'none'; mainAppContent.style.display = 'block'; currentUserDisplay.textContent = currentUser; setTodayDate(); loadWorkouts(); showPage('home-page'); }
260
+ function handleLogin() { const username = usernameInput.value.trim(); if (username && username.length > 0) { loginUser(username); } else { loginError.textContent = "Veuillez entrer un nom d'utilisateur."; loginError.style.display = 'block'; }}
261
+ function loginUser(username) { currentUser = username; sessionStorage.setItem('liftTrackCurrentUser', currentUser); showApp(); }
262
+ function handleLogout() { currentUser = null; sessionStorage.removeItem('liftTrackCurrentUser'); workouts = []; showLoginPage(); }
263
+ function getStorageKey() { if (!currentUser) return null; const safeUsername = currentUser.replace(/[^a-zA-Z0-9_-]/g, '_'); return `liftTrackData_${safeUsername}`; }
264
+ function loadWorkouts() {
265
  const storageKey = getStorageKey(); if (!storageKey) { workouts = []; return; }
266
  if (spinner) spinner.classList.remove('hidden'); emptyWorkoutMessage.classList.add('hidden'); workoutsList.innerHTML = '';
267
  setTimeout(() => { try { const savedData = localStorage.getItem(storageKey); workouts = savedData ? JSON.parse(savedData) : []; console.log(`Chargé ${workouts.length} séances pour ${currentUser}`); } catch (e) { console.error("Erreur parsing localStorage:", e); workouts = []; alert("Erreur chargement données."); } finally { if (spinner) spinner.classList.add('hidden'); renderWorkoutsList(); } }, 150);
268
  }
269
+ function saveWorkouts() {
270
  const storageKey = getStorageKey(); if (!storageKey) { console.error("Sauvegarde impossible: non connecté."); return; } try { localStorage.setItem(storageKey, JSON.stringify(workouts)); console.log(`Sauvegardé ${workouts.length} séances pour ${currentUser}`); } catch (e) { console.error("Erreur sauvegarde localStorage:", e); alert("Erreur sauvegarde données."); }
271
  }
272
 
 
276
  logoutBtn.addEventListener('click', handleLogout);
277
  usernameInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); handleLogin(); } });
278
 
279
+ navItems.forEach(item => {
280
  item.addEventListener('click', (e) => { e.preventDefault(); if (!currentUser) return; const targetPageId = item.getAttribute('data-page'); showPage(targetPageId); navItems.forEach(nav => nav.classList.remove('active')); item.classList.add('active'); if (targetPageId === 'stats-page') { updateStats(); } });
281
  });
282
 
 
283
  newWorkoutBtn.addEventListener('click', () => {
284
+ if (!currentUser) return; currentWorkoutId = null; clearNewWorkoutForm(); showPage('new-workout-page');
 
 
 
 
 
285
  });
286
 
287
  cancelNewWorkoutBtn.addEventListener('click', () => showPage('home-page'));
288
+ saveWorkoutBtn.addEventListener('click', saveWorkout);
289
+ addExerciseBtn.addEventListener('click', handleAddNewExercise);
 
 
290
  prevExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, -1));
291
  nextExerciseBtn.addEventListener('click', navigateExerciseForm.bind(null, 1));
 
292
  backToHomeBtn.addEventListener('click', () => showPage('home-page'));
293
  deleteWorkoutBtn.addEventListener('click', deleteWorkout);
294
  satisfactionRange.addEventListener('input', () => { satisfactionValue.textContent = `${satisfactionRange.value}%`; });
295
  }
296
 
297
  // --- Logique Principale ---
298
+ function setTodayDate() { if(workoutDateInput) { try { const today = new Date().toISOString().split('T')[0]; workoutDateInput.value = today; } catch (e) { console.error("Impossible définir date:", e); workoutDateInput.value = ''; } } }
299
 
300
  function showPage(pageId) {
301
  if (!currentUser) { showLoginPage(); return; }
302
+ document.querySelectorAll('#app-container > div').forEach(page => page.classList.remove('active'));
 
 
 
 
303
  const pageToShow = document.getElementById(pageId);
304
+ if (pageToShow) { pageToShow.classList.add('active'); } else { console.error(`Page ID "${pageId}" non trouvée. Affichage home-page.`); document.getElementById('home-page').classList.add('active'); pageId = 'home-page'; }
305
+ navItems.forEach(item => { item.classList.remove('active'); });
306
+ const activeNavItem = document.querySelector(`.nav-item[data-page="${pageId === 'stats-page' ? 'stats-page' : 'home-page'}"]`);
307
+ if(activeNavItem) activeNavItem.classList.add('active');
308
+ if (pageId === 'new-workout-page') { renderActiveExerciseForm(); }
 
 
 
 
 
 
 
 
 
 
 
 
309
  }
310
 
311
  // --- Logique Formulaire Nouvelle Séance ---
 
318
  if (!currentUser) return;
319
  const exerciseId = `exercise-${Date.now()}`;
320
  const exerciseDiv = document.createElement('div');
321
+ exerciseDiv.className = 'card exercise';
322
  exerciseDiv.setAttribute('data-exercise-id', exerciseId);
323
 
324
+ // **HTML SANS SUPERSET**
325
  exerciseDiv.innerHTML = `
326
  <div class="exercise-header">
327
  <input type="text" placeholder="Nom Exercice" class="exercise-name">
328
  <button class="btn btn-danger remove-exercise" style="padding: 0.3rem 0.6rem; flex-shrink: 0;">×</button>
329
  </div>
330
+ <div class="form-group" style="margin-top: 0.5rem; margin-bottom: 0.5rem;">
331
  <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.9rem;">
332
  <input type="checkbox" class="unilateral-checkbox"> Unilatéral
333
  </label>
334
+ <!-- Checkbox Superset enlevée -->
 
 
335
  </div>
336
  <div class="series-container"></div>
337
  <button class="btn btn-outline add-series" style="width: 100%; margin-top: 0.5rem; padding: 0.4rem;">+ Ajouter Série</button>
338
  `;
339
+ exercisesContainer.appendChild(exerciseDiv);
340
 
341
+ // Mettre à jour la référence immédiatement
342
+ workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise'));
343
 
344
  // Écouteurs pour cet exercice
345
  const removeBtn = exerciseDiv.querySelector('.remove-exercise');
 
346
  removeBtn.addEventListener('click', () => {
347
  const indexToRemove = workoutExercisesForm.indexOf(exerciseDiv);
348
  if (indexToRemove > -1) {
349
+ exerciseDiv.remove();
350
+ workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise')); // MAJ après suppression DOM
351
+ if (currentExerciseIndex >= indexToRemove) { currentExerciseIndex = Math.max(0, currentExerciseIndex - 1); }
352
+ if (currentExerciseIndex >= workoutExercisesForm.length) { currentExerciseIndex = Math.max(0, workoutExercisesForm.length - 1); }
353
+ renderActiveExerciseForm();
 
 
 
 
 
 
354
  }
355
  });
356
 
 
357
  const addSeriesBtn = exerciseDiv.querySelector('.add-series');
358
  const seriesContainer = exerciseDiv.querySelector('.series-container');
359
  addSeriesBtn.addEventListener('click', () => addSeries(seriesContainer));
360
 
361
+ addSeries(seriesContainer);
362
 
363
  if (navigateToNew) {
364
+ currentExerciseIndex = workoutExercisesForm.length - 1;
365
  renderActiveExerciseForm();
366
  } else {
367
+ updateExerciseNavButtons();
368
  }
 
369
  }
370
 
371
+ function addSeries(container) {
372
  if (!currentUser || !container) return; const seriesId = `series-${Date.now()}`; const seriesDiv = document.createElement('div'); seriesDiv.className = 'series'; seriesDiv.setAttribute('data-series-id', seriesId);
373
  seriesDiv.innerHTML = `<div class="form-row" style="align-items: flex-end; gap: 0.8rem;"> <div class="form-group" style="flex: 1.2;"> <label>Reps</label> <input type="number" class="reps" min="1" placeholder="10" style="padding: 0.4rem;"> </div> <div class="form-group" style="flex: 1.2;"> <label>Charge (kg)</label> <input type="number" class="weight" min="0" step="0.1" placeholder="20" style="padding: 0.4rem;"> </div> <div class="form-group" style="flex: 1; display: flex; align-items: center; padding-bottom: 0.6rem; min-width: 100px;"> <label style="display: inline-flex; align-items: center; color: #bbb; font-size: 0.8rem; margin-bottom: 0; white-space: nowrap;"> <input type="checkbox" class="degressive-checkbox" style="margin-right: 0.3rem;"> Dégressive </label> </div> <button class="btn btn-danger remove-series" style="padding: 0.3rem 0.6rem; margin-bottom: 0.6rem; flex-basis: 30px; flex-grow: 0; align-self: center;">×</button> </div>`;
374
  container.appendChild(seriesDiv); const removeBtn = seriesDiv.querySelector('.remove-series'); removeBtn.addEventListener('click', () => seriesDiv.remove());
375
  }
376
 
377
  function navigateExerciseForm(direction) {
378
+ // S'assurer que la référence est à jour avant de naviguer
379
+ workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise'));
380
  const newIndex = currentExerciseIndex + direction;
381
  if (newIndex >= 0 && newIndex < workoutExercisesForm.length) {
382
  currentExerciseIndex = newIndex;
 
385
  }
386
 
387
  function renderActiveExerciseForm() {
388
+ workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise'));
389
+ workoutExercisesForm.forEach(ex => ex.classList.remove('active-exercise'));
 
390
 
 
391
  if (currentExerciseIndex >= 0 && currentExerciseIndex < workoutExercisesForm.length) {
392
  const currentExDiv = workoutExercisesForm[currentExerciseIndex];
393
  currentExDiv.classList.add('active-exercise');
394
+ // Logique style superset enlevée ici
 
 
 
 
 
 
 
395
  }
 
 
396
  updateExerciseNavButtons();
397
  }
398
 
 
409
  }
410
  }
411
 
 
412
  function clearNewWorkoutForm() {
413
  if (!currentUser) return;
414
+ document.getElementById('workout-name').value = ''; document.getElementById('workout-duration').value = '';
415
+ setTodayDate(); exercisesContainer.innerHTML = ''; workoutExercisesForm = [];
416
+ satisfactionRange.value = 75; satisfactionValue.textContent = '75%';
417
+ currentWorkoutId = null; currentExerciseIndex = 0;
418
+ addExercise(false); // Ajoute le premier vide
419
+ renderActiveExerciseForm(); // Assure l'affichage correct
 
 
 
 
 
420
  }
421
 
422
  function saveWorkout() {
423
  if (!currentUser) return;
424
 
425
+ // **CORRECTION : Rafraîchir la référence juste avant la validation**
426
+ workoutExercisesForm = Array.from(exercisesContainer.querySelectorAll('.exercise'));
427
+
428
  const workoutName = document.getElementById('workout-name').value.trim();
429
  const workoutDate = document.getElementById('workout-date').value;
430
  const workoutDuration = parseInt(document.getElementById('workout-duration').value) || 0;
431
  const satisfaction = parseInt(document.getElementById('satisfaction').value);
432
 
433
+ if (!workoutName) { alert("Veuillez entrer un nom pour la séance."); return; }
434
+ if (!workoutDate) { alert("Veuillez choisir une date pour la séance."); return; }
435
+ if (workoutDuration <= 0) { alert("Veuillez entrer une durée valide (en minutes)."); return; }
436
 
437
+ // Utiliser la référence fraîchement mise à jour
438
+ const exerciseElements = workoutExercisesForm;
439
  const exercises = [];
440
+ if (exerciseElements.length === 0) { alert("Veuillez ajouter au moins un exercice à la séance."); return; }
441
 
442
  let validationError = null;
443
+ exerciseElements.forEach((exerciseEl, index) => { // Ajout index pour debug éventuel
444
  if (validationError) return;
 
 
 
445
 
446
+ const nameInput = exerciseEl.querySelector('.exercise-name');
447
+ const exerciseName = nameInput ? nameInput.value.trim() : ''; // Vérifier si l'input existe
448
+ const isUnilateral = exerciseEl.querySelector('.unilateral-checkbox').checked;
449
+ // isSupersetStart enlevé
450
+
451
+ // **Point crucial de la validation du nom**
452
+ if (!exerciseName) {
453
+ // Donner un indice (numéro de l'exercice basé sur l'ordre actuel)
454
+ validationError = `Veuillez nommer l'exercice #${index + 1}.`;
455
+ // Essayer de mettre le focus sur le champ vide si possible
456
+ if(nameInput) nameInput.focus();
457
+ return;
458
+ }
459
 
460
  const series = [];
461
  const seriesElements = exerciseEl.querySelectorAll('.series');
462
+ if (seriesElements.length === 0) { validationError = `L'exercice "${exerciseName}" doit contenir au moins une série.`; return; }
463
 
464
  seriesElements.forEach(seriesEl => {
465
  if (validationError) return;
466
  const repsInput = seriesEl.querySelector('.reps'); const weightInput = seriesEl.querySelector('.weight');
467
  const reps = parseInt(repsInput.value) || 0; const weight = parseFloat(weightInput.value) || 0;
468
  const isDegressive = seriesEl.querySelector('.degressive-checkbox').checked;
469
+ if (reps <= 0) { validationError = `Reps invalides pour une série de "${exerciseName}".`; if(repsInput) repsInput.focus(); return; }
470
+ if (weight < 0) { validationError = `Charge invalide pour une série de "${exerciseName}".`; if(weightInput) weightInput.focus(); return; }
471
  series.push({ reps, weight, isDegressive });
472
  });
473
 
474
  if (!validationError) {
475
+ // **Objet exercice SANS isSupersetStart**
476
+ exercises.push({ name: exerciseName, isUnilateral, series });
477
  }
478
  });
479
 
 
488
  });
489
  });
490
 
491
+ // --- Création/MAJ Objet Workout ---
492
  const workout = {
493
  id: currentWorkoutId || `workout-${Date.now()}`, name: workoutName, date: workoutDate, duration: workoutDuration,
494
+ exercises: exercises, // Utilise le tableau local `exercises`
495
  totalTonnage: totalTonnage, satisfaction: satisfaction
496
  };
 
497
  const existingIndex = workouts.findIndex(w => w.id === workout.id);
498
  if (existingIndex > -1) { workouts[existingIndex] = workout; } else { workouts.push(workout); }
499
 
500
  saveWorkouts();
501
+ confetti({ particleCount: 150, spread: 90, origin: { y: 0.6 } }); // Confettis!
 
 
 
502
  showPage('home-page');
503
  renderWorkoutsList();
504
  }
505
 
506
+ // --- Affichage et Stats ---
507
+ function renderWorkoutsList() {
508
  if (!currentUser) return; workoutsList.innerHTML = ''; if (workouts.length === 0) { emptyWorkoutMessage.classList.remove('hidden'); updateStats(); return; } emptyWorkoutMessage.classList.add('hidden');
509
  const sortedWorkouts = [...workouts].sort((a, b) => new Date(b.date) - new Date(a.date));
510
  sortedWorkouts.forEach(workout => { const workoutDate = new Date(workout.date).toLocaleDateString('fr-FR', { year: 'numeric', month: 'short', day: 'numeric' }); const workoutDiv = document.createElement('div'); workoutDiv.className = 'card workout-card'; workoutDiv.setAttribute('data-workout-id', workout.id); workoutDiv.innerHTML = `<div class="workout-header"><h3 style="margin-bottom: 0.5rem;">${workout.name}</h3><div class="badge">${workoutDate}</div></div><div class="workout-details" style="font-size: 0.9rem; color: #ccc; margin-top: 0.5rem;"><span>${workout.duration} min</span> | <span>${workout.exercises.length} exo${workout.exercises.length > 1 ? 's' : ''}</span> | <span>${workout.totalTonnage.toFixed(1)} kg</span> | <span>${workout.satisfaction}%</span></div>`; workoutDiv.addEventListener('click', () => displayWorkoutDetails(workout.id)); workoutsList.appendChild(workoutDiv); });
 
512
  }
513
 
514
  function displayWorkoutDetails(workoutId) {
515
+ if (!currentUser) return; const workout = workouts.find(w => w.id === workoutId); if (!workout) { console.error("Séance non trouvée:", workoutId); showPage('home-page'); return; }
516
+ document.getElementById('detail-workout-name').textContent = workout.name; document.getElementById('detail-date').textContent = new Date(workout.date).toLocaleDateString('fr-FR'); document.getElementById('detail-duration').textContent = workout.duration; document.getElementById('detail-tonnage').textContent = workout.totalTonnage.toFixed(1); document.getElementById('detail-satisfaction').textContent = `${workout.satisfaction}%`; document.getElementById('detail-exercises-count').textContent = workout.exercises.length;
517
+ const detailExercisesContainer = document.getElementById('detail-exercises-container'); detailExercisesContainer.innerHTML = '';
 
 
 
518
 
519
+ // **Affichage détail SANS logique Superset**
520
+ workout.exercises.forEach((exercise) => {
 
 
 
521
  const exerciseDiv = document.createElement('div');
522
+ exerciseDiv.className = 'card detail-exercise-card'; // Juste la classe de base
 
 
 
 
 
 
 
 
 
 
 
523
 
524
  let seriesHtml = '';
525
+ exercise.series.forEach((serie, sIndex) => {
526
  const degressiveLabel = serie.isDegressive ? ' <span class="badge" style="font-size: 0.7rem; background-color: var(--accent-dark);">Dégr.</span>' : ''; const weightFactor = exercise.isUnilateral ? 2 : 1; const seriesTonnage = serie.reps * serie.weight * weightFactor;
527
  seriesHtml += `<div class="exercise-summary"><div class="flex-between"><span>Série ${sIndex + 1}: ${serie.reps} reps × ${serie.weight} kg${degressiveLabel}</span><span style="color: #aaa;">(${seriesTonnage.toFixed(1)} kg)</span></div></div>`;
528
  });
529
 
530
  const unilateralLabel = exercise.isUnilateral ? ' <span class="badge" style="font-size: 0.7rem;">Unilat.</span>' : '';
531
+ // Pas de supersetLabel ici
 
532
 
533
  exerciseDiv.innerHTML = `
534
+ <h3 style="font-size: 1.1rem; margin-bottom: 0.5rem;">${exercise.name}${unilateralLabel}</h3>
535
+ <div class="series-summary-container"> ${seriesHtml} </div>`;
 
 
536
  detailExercisesContainer.appendChild(exerciseDiv);
537
  });
538
 
 
540
  showPage('workout-details-page');
541
  }
542
 
543
+ function deleteWorkout() {
544
  if (!currentUser || !currentWorkoutId) return; const workoutToDelete = workouts.find(w => w.id === currentWorkoutId); if (!workoutToDelete) return; const confirmDelete = confirm(`Supprimer séance "${workoutToDelete.name}" du ${new Date(workoutToDelete.date).toLocaleDateString('fr-FR')} ?`); if (!confirmDelete) return; workouts = workouts.filter(w => w.id !== currentWorkoutId); saveWorkouts(); currentWorkoutId = null; showPage('home-page'); renderWorkoutsList();
545
  }
546
 
547
+ function updateStats() {
548
  if (!currentUser) return; const workoutCount = workouts.length; document.getElementById('stats-workout-count').textContent = workoutCount; if (workoutCount === 0) { document.getElementById('stats-avg-tonnage').textContent = '0'; document.getElementById('stats-avg-satisfaction').textContent = '0%'; return; } const totalTonnageAll = workouts.reduce((sum, workout) => sum + (workout.totalTonnage || 0), 0); const avgTonnage = totalTonnageAll / workoutCount; document.getElementById('stats-avg-tonnage').textContent = avgTonnage.toFixed(1); const totalSatisfaction = workouts.reduce((sum, workout) => sum + (workout.satisfaction || 0), 0); const avgSatisfaction = totalSatisfaction / workoutCount; document.getElementById('stats-avg-satisfaction').textContent = `${Math.round(avgSatisfaction)}%`;
549
  }
550