You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
17 KiB

function createNavigation(activePage = 'home') {
const nav = document.getElementById('navbar');
if (!nav) return;
const currentPath = window.location.pathname;
const isInSubdir = currentPath.includes('/projets/') || currentPath.includes('/projects/');
const prefix = isInSubdir ? '../' : '';
nav.innerHTML = `
<div class="bg-white shadow-sm border-b border-gray-100">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-20">
<div class="md:hidden">
<button
id="mobile-menu-button"
class="text-gray-600 hover:text-gray-900 focus:outline-none focus:text-gray-900 transition-colors duration-200"
aria-label="Toggle menu"
>
<svg id="menu-icon" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="close-icon" class="h-6 w-6 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="flex-shrink-0">
<a href="${prefix}index.html">
<div class="text-gray-900 font-semibold text-lg">Jules Merienne</div>
</a>
</div>
<div class="hidden md:block">
<ul class="flex gap-8 items-center">
<li>
<a
href="${prefix}index.html"
class="nav-link ${activePage === 'home' ? 'nav-link-active' : ''}"
>
<span class="nav-link-text">Accueil</span>
</a>
</li>
<li>
<a
href="${prefix}projets.html"
class="nav-link ${activePage === 'projects' ? 'nav-link-active' : ''}"
>
<span class="nav-link-text">Projets</span>
</a>
</li>
<li>
<a
href="${prefix}apropos.html"
class="nav-link ${activePage === 'about' ? 'nav-link-active' : ''}"
>
<span class="nav-link-text">À propos</span>
</a>
</li>
<li>
<a
href="${prefix}interets.html"
class="nav-link ${activePage === 'interests' ? 'nav-link-active' : ''}"
>
<span class="nav-link-text">Centres d'intérêt</span>
</a>
</li>
<li>
<a
href="${prefix}contact.html"
class="nav-link ${activePage === 'contact' ? 'nav-link-active' : ''}"
>
<span class="nav-link-text">Contact</span>
</a>
</li>
</ul>
</div>
<a class="flex items-center" href="${prefix}contact.html">
<button class="btn-primary-nav">Discutons ensemble</button>
</a>
</div>
</div>
<!-- Mobile Navigation -->
<div id="mobile-menu" class="md:hidden overflow-hidden transition-all duration-300 ease-in-out max-h-0 opacity-0">
<div class="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-white border-t border-gray-100">
<ul class="space-y-1">
<li>
<a
href="${prefix}index.html"
class="mobile-nav-link ${activePage === 'home' ? 'text-blue-600 bg-blue-50' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'}"
>
<span class="mobile-nav-text">Accueil</span>
</a>
</li>
<li>
<a
href="${prefix}projets.html"
class="mobile-nav-link ${activePage === 'projects' ? 'text-blue-600 bg-blue-50' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'}"
>
<span class="mobile-nav-text">Projets</span>
</a>
</li>
<li>
<a
href="${prefix}apropos.html"
class="mobile-nav-link ${activePage === 'about' ? 'text-blue-600 bg-blue-50' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'}"
>
<span class="mobile-nav-text">À propos</span>
</a>
</li>
<li>
<a
href="${prefix}interets.html"
class="mobile-nav-link ${activePage === 'interests' ? 'text-blue-600 bg-blue-50' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'}"
>
<span class="mobile-nav-text">Intérêts</span>
</a>
</li>
<li>
<a
href="${prefix}contact.html"
class="mobile-nav-link ${activePage === 'contact' ? 'text-blue-600 bg-blue-50' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'}"
>
<span class="mobile-nav-text">Contact</span>
</a>
</li>
</ul>
</div>
</div>
</div>
`;
if (!document.getElementById('nav-styles')) {
const styles = document.createElement('style');
styles.id = 'nav-styles';
styles.textContent = `
.nav-link {
position: relative;
font-weight: 500;
padding: 12px 20px;
border-radius: 8px;
color: rgb(75 85 99);
text-decoration: none;
transition: all 0.3s ease;
}
.nav-link-text {
display: inline-block;
}
.nav-link-text .letter {
display: inline-block;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: center bottom;
}
.nav-link:hover .nav-link-text .letter {
color: #3b82f6;
transform: translateY(-2px) scale(1.05);
}
.nav-link:hover .nav-link-text .letter:nth-child(1) { transition-delay: 0ms; }
.nav-link:hover .nav-link-text .letter:nth-child(2) { transition-delay: 50ms; }
.nav-link:hover .nav-link-text .letter:nth-child(3) { transition-delay: 100ms; }
.nav-link:hover .nav-link-text .letter:nth-child(4) { transition-delay: 150ms; }
.nav-link:hover .nav-link-text .letter:nth-child(5) { transition-delay: 200ms; }
.nav-link:hover .nav-link-text .letter:nth-child(6) { transition-delay: 250ms; }
.nav-link:hover .nav-link-text .letter:nth-child(7) { transition-delay: 300ms; }
.nav-link:hover .nav-link-text .letter:nth-child(8) { transition-delay: 350ms; }
.nav-link:hover .nav-link-text .letter:nth-child(9) { transition-delay: 400ms; }
.nav-link:hover .nav-link-text .letter:nth-child(10) { transition-delay: 450ms; }
.nav-link:hover .nav-link-text .letter:nth-child(11) { transition-delay: 500ms; }
.nav-link:hover .nav-link-text .letter:nth-child(12) { transition-delay: 550ms; }
.nav-link:hover .nav-link-text .letter:nth-child(13) { transition-delay: 600ms; }
.nav-link:hover .nav-link-text .letter:nth-child(14) { transition-delay: 650ms; }
.nav-link:hover .nav-link-text .letter:nth-child(15) { transition-delay: 700ms; }
.nav-link:hover .nav-link-text .letter:nth-child(16) { transition-delay: 750ms; }
.nav-link:hover .nav-link-text .letter:nth-child(17) { transition-delay: 800ms; }
.nav-link:hover .nav-link-text .letter:nth-child(18) { transition-delay: 850ms; }
.nav-link::after {
content: '';
position: absolute;
bottom: 8px;
left: 50%;
width: 0;
height: 1px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
transform: translateX(-50%);
}
.nav-link:hover::after {
width: 80%;
}
.nav-link-active {
color: rgb(37 99 235);
font-weight: 600;
}
.nav-link-active::after {
width: 80%;
}
.nav-link-active .nav-link-text .letter {
color: #3b82f6;
}
.mobile-nav-link {
display: block;
padding: 8px 12px;
font-weight: 500;
border-radius: 6px;
transition: all 0.2s;
overflow: hidden;
position: relative;
}
.mobile-nav-text {
display: inline-block;
}
.mobile-nav-text .letter {
display: inline-block;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: center bottom;
}
.mobile-nav-link:hover .mobile-nav-text .letter {
color: #3b82f6;
transform: translateY(-2px) scale(1.05);
}
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(1) { transition-delay: 0ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(2) { transition-delay: 50ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(3) { transition-delay: 100ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(4) { transition-delay: 150ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(5) { transition-delay: 200ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(6) { transition-delay: 250ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(7) { transition-delay: 300ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(8) { transition-delay: 350ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(9) { transition-delay: 400ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(10) { transition-delay: 450ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(11) { transition-delay: 500ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(12) { transition-delay: 550ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(13) { transition-delay: 600ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(14) { transition-delay: 650ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(15) { transition-delay: 700ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(16) { transition-delay: 750ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(17) { transition-delay: 800ms; }
.mobile-nav-link:hover .mobile-nav-text .letter:nth-child(18) { transition-delay: 850ms; }
.mobile-nav-link::after {
content: '';
position: absolute;
bottom: 4px;
left: 50%;
width: 0;
height: 1px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
transform: translateX(-50%);
}
.mobile-nav-link:hover::after {
width: 80%;
}
.btn-primary-nav {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 24px;
font-size: 14px;
font-weight: 600;
color: white;
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
border-radius: 12px;
border: none;
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
overflow: hidden;
cursor: pointer;
}
.btn-primary-nav:hover {
transform: translateY(-3px) scale(1.02);
box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4);
background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
}
.btn-primary-nav::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
transition: left 0.6s ease;
}
.btn-primary-nav:hover::before {
left: 100%;
}
.btn-primary-nav:active {
transform: translateY(-1px) scale(0.98);
transition: all 0.1s ease;
}
`;
document.head.appendChild(styles);
}
if (!document.getElementById('cv-download-btn')) {
const cvButton = document.createElement('a');
cvButton.id = 'cv-download-btn';
cvButton.href = 'images/cv.pdf';
cvButton.className = 'cv-download-btn';
cvButton.setAttribute('download', 'cv-jules-merienne.pdf');
cvButton.title = 'Télécharger mon CV';
cvButton.innerHTML = `Télécharger CV <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>`;
document.body.appendChild(cvButton);
}
function splitTextIntoLetters() {
const navLinks = document.querySelectorAll('.nav-link-text, .mobile-nav-text');
navLinks.forEach(link => {
const text = link.textContent;
link.innerHTML = text.split('').map(letter =>
letter === ' ' ? '<span class="letter">&nbsp;</span>' : `<span class="letter">${letter}</span>`
).join('');
});
}
const mobileMenuButton = document.getElementById('mobile-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
const menuIcon = document.getElementById('menu-icon');
const closeIcon = document.getElementById('close-icon');
let isMobileMenuOpen = false;
mobileMenuButton.addEventListener('click', () => {
isMobileMenuOpen = !isMobileMenuOpen;
if (isMobileMenuOpen) {
mobileMenu.style.maxHeight = '384px';
mobileMenu.style.opacity = '1';
menuIcon.classList.add('hidden');
closeIcon.classList.remove('hidden');
} else {
mobileMenu.style.maxHeight = '0';
mobileMenu.style.opacity = '0';
menuIcon.classList.remove('hidden');
closeIcon.classList.add('hidden');
}
});
splitTextIntoLetters();
}
function initNavigation(activePage) {
createNavigation(activePage);
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = { initNavigation };
}