Portfolio avec Docker

This commit is contained in:
2025-12-08 00:06:03 +01:00
commit 52f3de74b7
12 changed files with 1161 additions and 0 deletions

130
script.js Normal file
View File

@@ -0,0 +1,130 @@
document.addEventListener('DOMContentLoaded', () => {
// ===============================================
// 0. GESTION DU PRÉCHARGEUR (SPLASH SCREEN)
// ===============================================
const preloader = document.getElementById('preloader');
// const introSound = document.getElementById('soundToggle'); <-- Supprimé, car cette variable est trompeuse ici
if (preloader) {
// 1. Jouer le son de l'animation d'introduction
// LIGNE(S) RETIRÉE(S) :
/*
if (introSound) {
// Tenter de jouer le son immédiatement (les navigateurs peuvent le bloquer)
introSound.play().catch(e => console.log("Intro sound blocked by browser:", e));
}
*/
// Le son ne se jouera plus ici, mais seulement au clic sur le bouton de thème.
// 2. Définir le délai de 2000 ms (2 secondes) avant la disparition
setTimeout(() => {
// Retirer la classe active pour déclencher la transition CSS de disparition (opacité: 1 -> 0)
preloader.classList.remove('preloader-active');
// 3. Suppression totale du DOM après la transition de 0.5 seconde
setTimeout(() => {
preloader.style.display = 'none';
}, 500);
}, 2000); // Durée de l'animation principale avant le fade out
}
// ===============================================
// 1. GESTION DU MODE SOMBRE (DARK MODE)
// ===============================================
const themeToggle = document.getElementById('themeToggle');
const body = document.body;
const localStorageKey = 'themePreference';
/**
* Applique la classe .dark-mode au corps et met à jour le texte du bouton.
* @param {boolean} isDarkMode - Vrai si le mode sombre doit être activé.
*/
function applyTheme(isDarkMode) {
if (isDarkMode) {
body.classList.add('dark-mode');
themeToggle.textContent = 'Light mode';
themeToggle.classList.remove('btn-outline-light');
themeToggle.classList.add('btn-outline-warning');
} else {
body.classList.remove('dark-mode');
themeToggle.textContent = 'Dark mode';
themeToggle.classList.remove('btn-outline-warning');
themeToggle.classList.add('btn-outline-light');
}
}
/**
* Charge le thème préféré depuis le localStorage ou détecte la préférence système.
*/
function loadTheme() {
const storedTheme = localStorage.getItem(localStorageKey);
let isDarkMode = false;
if (storedTheme !== null) {
isDarkMode = storedTheme === 'dark';
} else {
isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
applyTheme(isDarkMode);
}
// Charger le thème au chargement initial de la page
if (themeToggle) {
loadTheme();
}
// Événement au clic du bouton
if (themeToggle) {
themeToggle.addEventListener('click', () => {
const isCurrentlyDark = body.classList.contains('dark-mode');
const newTheme = isCurrentlyDark ? 'light' : 'dark';
// 1. Basculer le thème
applyTheme(!isCurrentlyDark);
// 2. Stocker le nouveau choix
localStorage.setItem(localStorageKey, newTheme);
// 3. (Optionnel) Jouer le son si l'élément audio existe
const soundToggle = document.getElementById('soundToggle');
if (soundToggle) {
// C'est l'endroit CORRECT pour jouer le son (uniquement au clic)
soundToggle.currentTime = 0;
soundToggle.play().catch(e => console.log("Audio play failed:", e));
}
});
}
// ===============================================
// 2. VALIDATION DES FORMULAIRES BOOTSTRAP
// ===============================================
// Fonction d'auto-exécution pour la validation des formulaires
(function () {
'use strict'
var forms = document.querySelectorAll('.needs-validation')
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
});