diff --git a/assets/css/futuristic.css b/assets/css/futuristic.css index 297c59c..14212f6 100644 --- a/assets/css/futuristic.css +++ b/assets/css/futuristic.css @@ -72,16 +72,17 @@ /* Shadows */ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), - 0 4px 6px -4px rgb(0 0 0 / 0.1); - --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), - 0 8px 10px -6px rgb(0 0 0 / 0.1); + --shadow-lg: + 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --shadow-xl: + 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); --shadow-glow: 0 0 40px rgba(59, 130, 246, 0.3); --shadow-card: 0 0 0 1px var(--border-color), var(--shadow-md); /* Typography */ - --font-sans: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", - Roboto, sans-serif; + --font-sans: + "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + sans-serif; --font-mono: "JetBrains Mono", "Fira Code", "Consolas", monospace; --text-xs: 0.75rem; @@ -134,6 +135,7 @@ /* Z-Index Scale */ --z-dropdown: 100; --z-sticky: 200; + --z-nav-mobile: 250; --z-fixed: 300; --z-modal-backdrop: 400; --z-modal: 500; @@ -201,8 +203,8 @@ #0f172a 50%, #1e293b 100% ); - --shadow-card: 0 0 0 1px var(--border-color), - 0 4px 6px -1px rgb(0 0 0 / 0.3); + --shadow-card: + 0 0 0 1px var(--border-color), 0 4px 6px -1px rgb(0 0 0 / 0.3); } } @@ -407,12 +409,13 @@ pre code { .site-header { position: sticky; top: 0; - z-index: var(--z-sticky); + z-index: var(--z-fixed); background: var(--bg-primary); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--border-color); - transition: background-color var(--transition-normal), + transition: + background-color var(--transition-normal), box-shadow var(--transition-normal); } @@ -571,49 +574,251 @@ pre code { color: var(--text-primary); } +/* Mobile Navigation */ +.mobile-menu { + display: none; +} + @media (max-width: 768px) { .main-nav { + display: none; + } + + .menu-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: var(--radius-md); + color: var(--text-primary); + } + + .menu-toggle:active, + .menu-toggle:hover { + background: var(--bg-tertiary); + } + + .search-toggle { + min-width: 40px; + height: 40px; + justify-content: center; + padding: 0; + border-radius: var(--radius-md); + } + + .search-toggle span, + .search-toggle kbd, + .header-actions > .theme-toggle { + display: none; + } + + .mobile-menu { + display: block; position: fixed; - top: var(--header-height); - left: 0; + inset: 0; + z-index: var(--z-modal); + opacity: 0; + pointer-events: none; + transition: opacity var(--transition-normal); + } + + .mobile-menu.open { + opacity: 1; + pointer-events: auto; + } + + .mobile-menu-backdrop { + position: absolute; + inset: 0; + background: rgba(15, 23, 42, 0.62); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + } + + .mobile-menu-panel { + position: absolute; + top: 0; right: 0; bottom: 0; - flex-direction: column; - align-items: stretch; - padding: var(--space-4); + display: grid; + grid-template-rows: auto 1fr auto; + width: min(92vw, 390px); background: var(--bg-primary); - border-top: 1px solid var(--border-color); - transform: translateX(-100%); - transition: transform var(--transition-normal); - overflow-y: auto; + border-left: 1px solid var(--border-color); + box-shadow: -24px 0 80px rgba(0, 0, 0, 0.28); + transform: translateX(100%); + transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1); } - .main-nav.open { + .mobile-menu.open .mobile-menu-panel { transform: translateX(0); } - .nav-list { - flex-direction: column; - align-items: stretch; + .mobile-menu-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-4); + padding: var(--space-5) var(--space-5) var(--space-4); + border-bottom: 1px solid var(--border-color); } - .dropdown-menu { - position: static; - opacity: 1; - visibility: visible; - transform: none; - box-shadow: none; - border: none; + .mobile-menu-eyebrow { + display: block; + margin-bottom: var(--space-1); + font-size: var(--text-xs); + font-weight: 700; + color: var(--color-primary); + text-transform: uppercase; + } + + .mobile-menu-title { + margin: 0; + font-size: var(--text-2xl); + line-height: 1.1; + color: var(--text-primary); + } + + .mobile-menu-close { + display: inline-flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + background: var(--bg-tertiary); + color: var(--text-primary); + cursor: pointer; + } + + .mobile-menu-close i { + font-size: 22px; + line-height: 1; + } + + .mobile-menu-body { + min-height: 0; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + padding: var(--space-4) var(--space-4) var(--space-6); + } + + .mobile-menu-list { + display: grid; + gap: var(--space-3); + list-style: none; + margin: 0; + padding: 0; + } + + .mobile-menu-link, + .mobile-menu-heading, + .mobile-submenu-link { + display: flex; + align-items: center; + gap: var(--space-3); + width: 100%; + min-height: 48px; + color: var(--text-primary); + text-decoration: none; + } + + .mobile-menu-link, + .mobile-menu-heading { + padding: var(--space-3); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + background: var(--bg-secondary); + font-size: var(--text-base); + font-weight: 700; + } + + .mobile-menu-link.active, + .mobile-menu-link:active, + .mobile-menu-link:hover { + border-color: var(--color-primary); + color: var(--color-primary); + text-decoration: none; + } + + .mobile-menu-icon, + .mobile-submenu-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: var(--radius-md); + background: var(--gradient-accent); + color: #fff; + flex: 0 0 auto; + } + + .mobile-menu-group { + display: grid; + gap: var(--space-2); + } + + .mobile-submenu { + display: grid; + gap: var(--space-2); padding-left: var(--space-4); - display: none; } - .nav-item.open .dropdown-menu { - display: block; + .mobile-submenu-link { + min-height: 44px; + padding: var(--space-2) var(--space-3); + border-radius: var(--radius-md); + color: var(--text-secondary); + font-size: var(--text-sm); + font-weight: 600; } - .menu-toggle { - display: block; + .mobile-submenu-link:active, + .mobile-submenu-link:hover { + background: var(--bg-tertiary); + color: var(--text-primary); + text-decoration: none; + } + + .mobile-submenu-icon { + width: 28px; + height: 28px; + border-radius: var(--radius-sm); + } + + .mobile-menu-footer { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-3); + padding: var(--space-4); + border-top: 1px solid var(--border-color); + background: var(--bg-primary); + } + + .mobile-menu-action { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + min-height: 44px; + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + background: var(--bg-secondary); + color: var(--text-primary); + font-size: var(--text-sm); + font-weight: 700; + text-decoration: none; + cursor: pointer; + } + + .mobile-menu-action:hover, + .mobile-menu-action:active { + border-color: var(--color-primary); + color: var(--color-primary); + text-decoration: none; } } @@ -832,10 +1037,8 @@ pre code { .hero-grid { position: absolute; inset: 0; - background-image: linear-gradient( - rgba(255, 255, 255, 0.03) 1px, - transparent 1px - ), + background-image: + linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px); background-size: 60px 60px; mask-image: radial-gradient(ellipse at center, black 30%, transparent 70%); @@ -1006,7 +1209,9 @@ pre code { .card:hover { border-color: var(--color-primary); - box-shadow: var(--shadow-lg), 0 0 0 1px var(--color-primary); + box-shadow: + var(--shadow-lg), + 0 0 0 1px var(--color-primary); transform: translateY(-4px); } @@ -1199,7 +1404,10 @@ pre code { margin-bottom: var(--space-4); } -[data-theme="dark"] .timeline-year-header, +[data-theme="dark"] .timeline-year-header { + background: var(--bg-primary); +} + @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .timeline-year-header { background: var(--bg-primary); diff --git a/assets/js/main.js b/assets/js/main.js index bbe7497..d80be02 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -55,18 +55,12 @@ function setTheme(theme) { } function updateThemeToggle(theme) { - const sunIcon = document.querySelector(".sun-icon"); - const moonIcon = document.querySelector(".moon-icon"); - - if (sunIcon && moonIcon) { - if (theme === "dark") { - sunIcon.style.display = "none"; - moonIcon.style.display = "block"; - } else { - sunIcon.style.display = "block"; - moonIcon.style.display = "none"; - } - } + document.querySelectorAll(".sun-icon, .sun-icon-panel").forEach((el) => { + el.style.display = theme === "dark" ? "none" : "block"; + }); + document.querySelectorAll(".moon-icon, .moon-icon-panel").forEach((el) => { + el.style.display = theme === "dark" ? "block" : "none"; + }); } function toggleTheme() { @@ -101,7 +95,7 @@ function initHeader() { lastScroll = currentScroll; }, - { passive: true } + { passive: true }, ); } @@ -109,16 +103,39 @@ function initHeader() { * Mobile Menu */ function toggleMobileMenu() { - const nav = document.getElementById("mainNav"); + const menu = document.getElementById("mobileMenu"); const toggle = document.getElementById("menuToggle"); + if (!menu || !toggle) return; - if (nav && toggle) { - nav.classList.toggle("open"); - toggle.setAttribute("aria-expanded", nav.classList.contains("open")); - } + const isOpen = menu.classList.toggle("open"); + toggle.setAttribute("aria-expanded", String(isOpen)); + menu.setAttribute("aria-hidden", String(!isOpen)); + document.body.style.overflow = isOpen ? "hidden" : ""; } +function closeMobileMenu() { + const menu = document.getElementById("mobileMenu"); + const toggle = document.getElementById("menuToggle"); + if (!menu || !menu.classList.contains("open")) return; + + menu.classList.remove("open"); + menu.setAttribute("aria-hidden", "true"); + toggle && toggle.setAttribute("aria-expanded", "false"); + document.body.style.overflow = ""; +} + +document.addEventListener("click", (e) => { + const mobileLink = e.target.closest(".mobile-menu a[href]"); + if (mobileLink) closeMobileMenu(); +}); + +// Close on Escape +document.addEventListener("keydown", (e) => { + if (e.key === "Escape") closeMobileMenu(); +}); + window.toggleMobileMenu = toggleMobileMenu; +window.closeMobileMenu = closeMobileMenu; /** * Search Modal @@ -257,20 +274,20 @@ function handleSearch(e) { .map( (item, index) => ` + index === 0 ? " focused" : "" + }" data-index="${index}">
${highlightMatch( item.title, - query + query, )}
${item.section}
- ` + `, ) .join(""); } @@ -279,7 +296,7 @@ function highlightMatch(text, query) { const regex = new RegExp(`(${escapeRegex(query)})`, "gi"); return text.replace( regex, - '$1' + '$1', ); } @@ -369,7 +386,7 @@ function initAnimations() { { threshold: 0.1, rootMargin: "0px 0px -50px 0px", - } + }, ); document diff --git a/i18n/en.toml b/i18n/en.toml new file mode 100644 index 0000000..582ad57 --- /dev/null +++ b/i18n/en.toml @@ -0,0 +1,20 @@ +[mobileMenuOpenAriaLabel] +other = "Open menu" + +[mobileNavigationAriaLabel] +other = "Mobile navigation" + +[mobileMenuTitle] +other = "Menu" + +[mobileMenuCloseAriaLabel] +other = "Close menu" + +[themeToggleAriaLabel] +other = "Toggle dark mode" + +[theme] +other = "Theme" + +[github] +other = "GitHub" diff --git a/i18n/fr.toml b/i18n/fr.toml new file mode 100644 index 0000000..7417d00 --- /dev/null +++ b/i18n/fr.toml @@ -0,0 +1,20 @@ +[mobileMenuOpenAriaLabel] +other = "Ouvrir le menu" + +[mobileNavigationAriaLabel] +other = "Navigation mobile" + +[mobileMenuTitle] +other = "Menu" + +[mobileMenuCloseAriaLabel] +other = "Fermer le menu" + +[themeToggleAriaLabel] +other = "Activer ou désactiver le mode sombre" + +[theme] +other = "Thème" + +[github] +other = "GitHub" diff --git a/layouts/partials/header-new.html b/layouts/partials/header-new.html index ca61de5..bc82467 100644 --- a/layouts/partials/header-new.html +++ b/layouts/partials/header-new.html @@ -117,7 +117,7 @@ + + +
+ +
+ + + +