diff --git a/src/assets/header/header.css b/src/assets/header/header.css new file mode 100644 index 0000000..6fb79d4 --- /dev/null +++ b/src/assets/header/header.css @@ -0,0 +1,277 @@ +/* +M M AAAAA X X L W W AAAAA RRRR EEEEE +MM MM A A X X L W W A A R R E +M M M AAAAA X L W W W AAAAA RRRR EEE +M M A A X X L WW WW A A R R E +M M A A X X LLLLL W W A A R R EEEEE +*/ + +.site-header { + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 2000; + background: rgba(11, 11, 14, 0.82); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); + border-bottom: 1px solid #1a1a22; + transform: translateY(-100%); + opacity: 0; + pointer-events: none; + transition: transform 0.35s ease, opacity 0.3s ease; + font-family: var(--police-big), var(--police); +} + +.site-header.visible { + transform: translateY(0); + opacity: 1; + pointer-events: auto; +} + +.site-header-inner { + max-width: 1100px; + margin: 0 auto; + padding: 0.7rem 2rem; + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; + position: relative; +} + +.site-header-brand { + display: flex; + align-items: center; + gap: 0.6rem; + text-decoration: none; + flex-shrink: 0; +} + +.site-header-brand:hover { + text-decoration: none; +} + +.site-header-logo { + width: 28px; + height: 28px; + object-fit: contain; +} + +.site-header-name { + font-family: 'Syne', sans-serif; + font-weight: 700; + font-size: 1.1rem; + letter-spacing: 0.5px; + color: var(--light); +} + +.site-header-nav { + display: flex; + align-items: center; + gap: 0.4rem; +} + +.site-header-item { + position: relative; +} + +.site-header-link { + display: inline-flex; + align-items: center; + gap: 0.35rem; + background: none; + border: none; + color: #ccc; + font-family: var(--police-big), var(--police); + font-size: 0.92rem; + padding: 0.5rem 0.7rem; + cursor: pointer; + border-radius: 4px; + transition: color 0.2s ease, background 0.2s ease; + text-decoration: none; +} + +.site-header-link:hover, +.site-header-item.open > .site-header-link { + color: var(--light); + background: rgba(255, 255, 255, 0.05); + text-decoration: none; +} + +.site-header-caret { + display: inline-block; + font-size: 0.65rem; + transition: transform 0.2s ease; + opacity: 0.6; +} + +.site-header-item.open .site-header-caret { + transform: rotate(180deg); +} + +.site-header-dropdown { + position: absolute; + top: calc(100% + 10px); + left: 0; + min-width: 230px; + background: #0e0e13; + border: 1px solid #222; + border-radius: 8px; + padding: 0.6rem; + display: flex; + flex-direction: column; + gap: 0.15rem; + opacity: 0; + visibility: hidden; + transform: translateY(-6px); + transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s; + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35); +} + +.site-header-item.open > .site-header-dropdown { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.site-header-dropdown a, +.site-header-dropdown .site-header-sublink { + display: flex; + align-items: center; + gap: 0.6rem; + color: #bbb; + font-size: 0.88rem; + padding: 0.5rem 0.6rem; + border-radius: 5px; + text-decoration: none; + transition: background 0.15s ease, color 0.15s ease; +} + +.site-header-dropdown a:hover, +.site-header-dropdown .site-header-sublink:hover { + background: rgba(255, 255, 255, 0.06); + color: var(--light); + text-decoration: none; +} + +.site-header-net-icon { + width: 18px; + height: 18px; + flex-shrink: 0; + color: var(--secondary); +} + +.site-header-dropdown-full { + position: fixed; + top: var(--site-header-h, 64px); + left: 0; + right: 0; + width: 100%; + min-width: 0; + border-radius: 0; + border-left: none; + border-right: none; + background: #0b0b0f; + padding: 1.4rem 2rem; + flex-direction: row; + flex-wrap: wrap; + gap: 0.4rem 1rem; + max-width: none; +} + +.site-header-dropdown-full-inner { + max-width: 1100px; + margin: 0 auto; + display: flex; + flex-wrap: wrap; + gap: 0.4rem 1.2rem; + width: 100%; +} + +.site-header-dropdown-full a { + flex: 0 0 auto; +} + +.site-header-subgroup { + display: flex; + flex-direction: column; +} + +.site-header-sublink[aria-expanded="true"] .site-header-caret-sm { + transform: rotate(180deg); +} + +.site-header-caret-sm { + margin-left: auto; + font-size: 0.6rem; + opacity: 0.6; + transition: transform 0.2s ease; +} + +.site-header-subpanel { + display: none; + flex-direction: column; + padding-left: 1.1rem; + border-left: 1px solid #222; + margin: 0.1rem 0 0.3rem 1rem; +} + +.site-header-subpanel.open { + display: flex; +} + +body.scrolled-past-hero .diapo-container { + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; +} + +body.scrolled-past-hero .notification-banner { + top: calc(var(--site-header-h, 64px) + 15px); + transition: top 0.3s ease; +} + +@media (max-width: 860px) { + .site-header-inner { + flex-direction: column; + gap: 0.6rem; + padding: 0.8rem 1rem 1rem; + } + + .site-header-brand { + order: 1; + } + + .site-header-nav { + order: 2; + width: 100%; + justify-content: center; + flex-wrap: wrap; + gap: 0.2rem; + } + + .site-header-item { + position: static; + } + + .site-header-dropdown { + position: fixed; + left: 1rem; + right: 1rem; + top: calc(var(--site-header-h, 96px) + 10px); + width: auto; + min-width: 0; + } + + .site-header-dropdown-full { + top: auto; + position: fixed; + left: 0; + right: 0; + bottom: 0; + max-height: 70vh; + overflow-y: auto; + border-top: 1px solid #222; + } +} diff --git a/src/assets/header/header.js b/src/assets/header/header.js new file mode 100644 index 0000000..a2461bd --- /dev/null +++ b/src/assets/header/header.js @@ -0,0 +1,175 @@ +// M M AAAAA X X L W W AAAAA RRRR EEEEE +// MM MM A A X X L W W A A R R E +// M M M AAAAA X L W W W AAAAA RRRR EEE +// M M A A X X L WW WW A A R R E +// M M A A X X LLLLL W W A A R R EEEEE + +(function () { + + const lang = (document.documentElement.lang || 'fr').toLowerCase().startsWith('fr') ? 'fr' : 'en'; + const HOME_PATH = lang === 'fr' ? '/fr_fr.html' : '/en_en.html'; + + const PORTFOLIO_LINKS = [ + { id: 'apropos', label: lang === 'fr' ? 'À propos' : 'About' }, + { id: 'projets', label: lang === 'fr' ? 'Projets' : 'Projects' }, + { id: 'stack', label: 'Stack' }, + { id: 'activite', label: lang === 'fr' ? 'Activité' : 'Activity' }, + ]; + + const NET_ICON = (label) => ``; + + function portfolioLinksHTML() { + return PORTFOLIO_LINKS.map(l => + `${l.label}` + ).join(''); + } + + const HEADER_HTML = ` +
+ Maxlware_
+
+
+
+