diff --git a/ecosystem.html b/ecosystem.html index d147639..1b09b5c 100644 --- a/ecosystem.html +++ b/ecosystem.html @@ -702,8 +702,13 @@ diff --git a/index.html b/index.html index f60cff5..6b456b5 100644 --- a/index.html +++ b/index.html @@ -3485,107 +3485,287 @@ // Sélection du fichier JSON selon le paramètre ?cv= const cvParam = new URLSearchParams(window.location.search).get('cv'); - const cvAllowed = ['ux', 'dsi']; - const cvFile = cvAllowed.includes(cvParam) ? `cv-data-${cvParam}.json` : 'cv-data.json'; + + // Mapping des codes de 24 caractères vers les fichiers de CV correspondants + const cvMap = { + 'f3b9c7a8d5e4b2d1c0a9b8d7': 'cv-data.json', // Version Générale (Directeur Conseil Service) + 'e2d1c0b9a8f7e6d5c4b3a2f1': 'cv-data-ux.json', // Version UX & Digital Manager + 'a1b2c3d4e5f6a7b8c9d0e1f2': 'cv-data-dsi.json' // Version Directeur SI & Transformation + }; - fetch(cvFile) - .then(r => { - if (!r.ok) throw new Error('Impossible de charger ' + cvFile + ' (code ' + r.status + ')'); - return r.json(); - }) - .then(data => { - render(data); - injectSEO(data); + if (!cvParam || !cvMap[cvParam]) { + // Masquer l'écran de chargement + const ld = document.getElementById('loading'); + if (ld) ld.remove(); - // Mettre à jour le lien infra APRÈS render (l'élément existe maintenant dans le DOM) - const infraBtn = document.getElementById('infraBtn'); - if (infraBtn && cvParam) infraBtn.href = `infrastructure.html?cv=${cvParam}`; - const ecosystemBtn = document.getElementById('ecosystemBtn'); - if (ecosystemBtn && cvParam) ecosystemBtn.href = `ecosystem.html?cv=${cvParam}`; + // Masquer les contrôles globaux non pertinents pour l'écran de verrouillage + const burger = document.getElementById('burgerBtn'); + if (burger) burger.style.display = 'none'; + const readProgress = document.getElementById('read-progress'); + if (readProgress) readProgress.style.display = 'none'; - // Lang dynamique depuis le JSON (défaut : fr) - document.documentElement.lang = data.identity.lang || 'fr'; - - // Tracking version CV - if (typeof umami !== 'undefined') umami.track('cv-view', { version: cvParam || 'master' }); - - // Restaurer le thème sauvegardé - const saved = localStorage.getItem('cv-theme'); - if (saved && ['cyberpunk', 'bd', 'itpro', 'cgi'].includes(saved)) setTheme(saved); - - // Scroll reveal — fix: sections already in viewport au chargement - document.querySelectorAll('section').forEach(s => { - const rect = s.getBoundingClientRect(); - if (rect.top < window.innerHeight) s.classList.add('visible'); - }); - - // Scroll reveal - const obs = new IntersectionObserver(entries => { - entries.forEach(entry => { - if (entry.isIntersecting) { - entry.target.classList.add('visible'); - if (entry.target.id === 'competences') { - setTimeout(() => { - document.querySelectorAll('.skill-row').forEach(r => { - r.querySelector('.skill-fill').style.width = r.dataset.level + '%'; - }); - }, 300); - } - } - }); - }, { threshold: 0.08 }); - document.querySelectorAll('section').forEach(s => obs.observe(s)); - - // Typing effect hero badge - const badge = document.getElementById('heroBadge'); - if (badge) { - const txt = badge.textContent; - badge.textContent = ''; - let i = 0; - setTimeout(() => { - const t = setInterval(() => { - badge.textContent = txt.slice(0, i++); - if (i > txt.length) clearInterval(t); - }, 40); - }, 500); + // Injecter le CSS pour la page privée + const style = document.createElement('style'); + style.textContent = ` + .private-container { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + background: #02050a; + color: #f4f7fb; + font-family: 'Inter', system-ui, -apple-system, sans-serif; + padding: 20px; + box-sizing: border-box; + position: fixed; + inset: 0; + z-index: 9999; } + .private-card { + background: rgba(7, 18, 29, 0.75); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid rgba(0, 215, 255, 0.2); + border-radius: 16px; + padding: 40px 30px; + max-width: 440px; + width: 100%; + text-align: center; + box-shadow: 0 0 40px rgba(0, 215, 255, 0.08); + } + .lock-icon { + color: #00d8ff; + margin-bottom: 24px; + animation: pulse-glow 3s infinite ease-in-out; + display: inline-flex; + justify-content: center; + align-items: center; + } + @keyframes pulse-glow { + 0%, 100% { + transform: scale(1); + filter: drop-shadow(0 0 8px rgba(0, 216, 255, 0.4)); + } + 50% { + transform: scale(1.05); + filter: drop-shadow(0 0 20px rgba(0, 216, 255, 0.8)); + } + } + .private-card h1 { + font-family: 'Orbitron', 'Arial Black', sans-serif; + font-size: 22px; + letter-spacing: 0.15em; + margin-bottom: 16px; + color: #00d8ff; + text-shadow: 0 0 10px rgba(0, 216, 255, 0.3); + } + .private-card p { + color: #9aa8b8; + font-size: 14px; + line-height: 1.6; + margin-bottom: 30px; + } + .input-group { + position: relative; + margin-bottom: 20px; + } + .private-card input { + width: 100%; + padding: 14px 16px; + background: rgba(2, 5, 10, 0.8); + border: 1px solid rgba(0, 215, 255, 0.15); + border-radius: 8px; + color: #fff; + font-family: 'Share Tech Mono', 'Courier New', monospace; + font-size: 15px; + letter-spacing: 0.05em; + text-align: center; + transition: all 0.3s ease; + box-sizing: border-box; + } + .private-card input:focus { + outline: none; + border-color: #00d8ff; + box-shadow: 0 0 15px rgba(0, 216, 255, 0.25); + } + .private-card button { + width: 100%; + padding: 14px; + background: linear-gradient(135deg, #00d8ff 0%, #228cff 100%); + border: none; + border-radius: 8px; + color: #02050a; + font-family: 'Orbitron', sans-serif; + font-size: 14px; + font-weight: 700; + letter-spacing: 0.1em; + cursor: pointer; + transition: all 0.3s ease; + } + .private-card button:hover { + transform: translateY(-2px); + box-shadow: 0 5px 20px rgba(0, 216, 255, 0.4); + } + .private-card button:active { + transform: translateY(0); + } + .error-message { + color: #ff3c74; + font-size: 12px; + margin-top: 15px; + font-family: 'Share Tech Mono', monospace; + min-height: 18px; + } + `; + document.head.appendChild(style); - // ── Progress bar ── - const progressBar = document.getElementById('read-progress'); - window.addEventListener('scroll', () => { - const scrolled = window.scrollY; - const total = document.documentElement.scrollHeight - window.innerHeight; - progressBar.style.width = (total > 0 ? (scrolled / total) * 100 : 0) + '%'; - }, { passive: true }); + // Injecter le HTML de la page privée dans #app + const app = document.getElementById('app'); + app.innerHTML = ` +
+
+
+ + + + +
+

PAGE PRIVÉE

+

Ce curriculum vitæ est confidentiel. Veuillez saisir votre code d'accès de 24 caractères pour y accéder.

+
+
+ +
+ +
+
+
+
+ `; - // ── Nav active (Intersection Observer) ── - const navObs = new IntersectionObserver(entries => { - entries.forEach(entry => { - const link = document.querySelector(`nav a[data-section="${entry.target.id}"]`); - if (link) link.classList.toggle('nav-active', entry.isIntersecting); - }); - }, { threshold: 0.3 }); - ['experience', 'competences', 'secteurs', 'formation'].forEach(id => { - const el = document.getElementById(id); - if (el) navObs.observe(el); - }); + // Se focaliser sur le champ de saisie + const accessCodeInput = document.getElementById('accessCode'); + if (accessCodeInput) accessCodeInput.focus(); - // Cacher le loading - const ld = document.getElementById('loading'); - ld.style.opacity = '0'; - setTimeout(() => ld.remove(), 400); - }) - .catch(err => { - document.getElementById('loading').innerHTML = ` -
- ⚠️ ERREUR DE CHARGEMENT

- ${err.message}

- - Assurez-vous que cv-data.json est dans le même dossier
- et que la page est servie via un serveur web (pas file://). -
-
`; + // Écouter la soumission du formulaire + document.getElementById('accessForm').addEventListener('submit', (e) => { + e.preventDefault(); + const code = accessCodeInput.value.trim(); + if (cvMap[code]) { + // Rediriger avec le bon paramètre d'URL + window.location.search = `?cv=${code}`; + } else { + // Afficher le message d'erreur + const errEl = document.getElementById('errorMessage'); + if (errEl) { + errEl.textContent = '❌ Code d\'accès invalide'; + accessCodeInput.style.borderColor = '#ff3c74'; + accessCodeInput.style.boxShadow = '0 0 15px rgba(255, 60, 116, 0.25)'; + } + } }); + } else { + const cvFile = cvMap[cvParam]; + + fetch(cvFile) + .then(r => { + if (!r.ok) throw new Error('Impossible de charger ' + cvFile + ' (code ' + r.status + ')'); + return r.json(); + }) + .then(data => { + render(data); + injectSEO(data); + + // Mettre à jour le lien infra APRÈS render (l'élément existe maintenant dans le DOM) + const infraBtn = document.getElementById('infraBtn'); + if (infraBtn && cvParam) infraBtn.href = `infrastructure.html?cv=${cvParam}`; + const ecosystemBtn = document.getElementById('ecosystemBtn'); + if (ecosystemBtn && cvParam) ecosystemBtn.href = `ecosystem.html?cv=${cvParam}`; + + // Lang dynamique depuis le JSON (défaut : fr) + document.documentElement.lang = data.identity.lang || 'fr'; + + // Tracking version CV + if (typeof umami !== 'undefined') umami.track('cv-view', { version: cvParam || 'master' }); + + // Restaurer le thème sauvegardé + const saved = localStorage.getItem('cv-theme'); + if (saved && ['cyberpunk', 'bd', 'itpro', 'cgi'].includes(saved)) setTheme(saved); + + // Scroll reveal — fix: sections already in viewport au chargement + document.querySelectorAll('section').forEach(s => { + const rect = s.getBoundingClientRect(); + if (rect.top < window.innerHeight) s.classList.add('visible'); + }); + + // Scroll reveal + const obs = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + if (entry.target.id === 'competences') { + setTimeout(() => { + document.querySelectorAll('.skill-row').forEach(r => { + r.querySelector('.skill-fill').style.width = r.dataset.level + '%'; + }); + }, 300); + } + } + }); + }, { threshold: 0.08 }); + document.querySelectorAll('section').forEach(s => obs.observe(s)); + + // Typing effect hero badge + const badge = document.getElementById('heroBadge'); + if (badge) { + const txt = badge.textContent; + badge.textContent = ''; + let i = 0; + setTimeout(() => { + const t = setInterval(() => { + badge.textContent = txt.slice(0, i++); + if (i > txt.length) clearInterval(t); + }, 40); + }, 500); + } + + // ── Progress bar ── + const progressBar = document.getElementById('read-progress'); + window.addEventListener('scroll', () => { + const scrolled = window.scrollY; + const total = document.documentElement.scrollHeight - window.innerHeight; + progressBar.style.width = (total > 0 ? (scrolled / total) * 100 : 0) + '%'; + }, { passive: true }); + + // ── Nav active (Intersection Observer) ── + const navObs = new IntersectionObserver(entries => { + entries.forEach(entry => { + const link = document.querySelector(`nav a[data-section="${entry.target.id}"]`); + if (link) link.classList.toggle('nav-active', entry.isIntersecting); + }); + }, { threshold: 0.3 }); + ['experience', 'competences', 'secteurs', 'formation'].forEach(id => { + const el = document.getElementById(id); + if (el) navObs.observe(el); + }); + + // Cacher le loading + const ld = document.getElementById('loading'); + ld.style.opacity = '0'; + setTimeout(() => ld.remove(), 400); + }) + .catch(err => { + document.getElementById('loading').innerHTML = ` +
+ ⚠️ ERREUR DE CHARGEMENT

+ ${err.message}

+ + Assurez-vous que cv-data.json est dans le même dossier
+ et que la page est servie via un serveur web (pas file://). +
+
`; + }); + } // ══════════════════════════════════════════════ // TÉLÉCHARGEMENT PDF diff --git a/infrastructure.html b/infrastructure.html index 264d4ce..db2950f 100644 --- a/infrastructure.html +++ b/infrastructure.html @@ -980,7 +980,12 @@