diff --git a/assets/js/theme/blocks/timeline.js b/assets/js/theme/blocks/timeline.js index 4a3c3fd58ecde91dade40422d939dce40210c00d..8a13e87dd434ccad76bf94634503900b86120aec 100644 --- a/assets/js/theme/blocks/timeline.js +++ b/assets/js/theme/blocks/timeline.js @@ -125,7 +125,6 @@ class BlockTimeline { this.next.disabled = this.index === this.items.length - 1; } } - } timelines.forEach((timeline) => { diff --git a/assets/js/theme/index.js b/assets/js/theme/index.js index 74d3e44244d0b302c8f0a066314eff33cd0ae2f8..8aa2514e8224c085cf1593ddc901cc5272b42dd7 100644 --- a/assets/js/theme/index.js +++ b/assets/js/theme/index.js @@ -2,4 +2,5 @@ import './body.js'; import './blocks/keyFigures'; import './blocks/timeline'; import './nav/stickyNav'; - +// import './nav/responsive'; +import './nav/mainMenu'; diff --git a/assets/js/theme/nav/mainMenu.js b/assets/js/theme/nav/mainMenu.js new file mode 100644 index 0000000000000000000000000000000000000000..3fa3cace2a5cf55ac582e18e0c2c91c4b0cc1665 --- /dev/null +++ b/assets/js/theme/nav/mainMenu.js @@ -0,0 +1,132 @@ +import breakpoints from '../utils/breakpoints'; + +const CLASSES = { + mainMenuOpened: 'is-opened', + scrollingDown: 'is-scrolling-down', + menusOpened: 'has-menu-opened', + sticky: 'is-sticky' +}; +class MainMenu { + constructor (selector) { + this.element = document.querySelector(selector); + this.menu = this.element.querySelector('.menu'); + this.mainButton = this.element.querySelector('button'); + this.dropdownsButtons = this.element.querySelectorAll('.has-children a[role="button"]'); + + this.state = { + isOpened: false, + isMobile: false, + hasDropdownOpened: false, + previousScrollY: window.scrollY + }; + + this.listen(); + } + + listen () { + window.addEventListener('resize', this.resize.bind(this)); + + this.mainButton.addEventListener('click', () => { + this.toggleMainMenu(); + }); + + this.dropdownsButtons.forEach((button) => { + button.addEventListener('click', (event) => { + event.preventDefault(); + this.toggleDropdown(button); + }); + }); + + ['scroll', 'touchmove'].forEach(event => { + window.addEventListener(event, this.onScroll.bind(this)); + }); + + window.addEventListener('click', (event) => { + if (event.target === document.body) { + this.closeEverything(); + } + }); + } + + resize () { + const isMobile = window.innerWidth <= breakpoints.md; + + // is state changed ? + if (this.state.isMobile === isMobile) { + return null; + } + + this.state.isMobile = isMobile; + + this.closeEverything(); + } + + toggleMainMenu (open = !this.state.isOpened) { + let classAction; + this.state.isOpened = open; + classAction = this.state.isOpened ? 'add' : 'remove'; + this.mainButton.setAttribute('aria-expanded', this.state.isOpened); + this.menu.classList[classAction](CLASSES.mainMenuOpened); + document.documentElement.classList[classAction](CLASSES.menusOpened); + + // Update global overlay + this.updateOverlay(); + } + + toggleDropdown (clickedButton) { + let isExpanded = true; + + if (clickedButton) { + isExpanded = clickedButton.getAttribute('aria-expanded') === 'true'; + } + + // Close all dropdowns except selected + this.dropdownsButtons.forEach(button => { + if (clickedButton === button) { + clickedButton.setAttribute('aria-expanded', !isExpanded); + } else { + button.setAttribute('aria-expanded', 'false'); + } + }); + + // Now menu is expanded or closed + isExpanded = !isExpanded; + this.state.hasDropdownOpened = isExpanded; + + // Update global overlay + this.updateOverlay(); + } + + updateOverlay () { + const classAction = this.state.hasDropdownOpened || this.state.isOpened ? 'add' : 'remove'; + document.documentElement.classList[classAction](CLASSES.menusOpened); + } + + closeEverything () { + this.state.isOpened = false; + this.toggleDropdown(false); + this.toggleMainMenu(false); + } + + onScroll () { + const offset = this.element.offsetHeight, + y = window.scrollY, + isNearTop = y < offset; + + if (isNearTop) { + this.element.classList.remove(CLASSES.sticky); + } else { + this.element.classList.add(CLASSES.sticky); + } + + if (y > this.state.previousScrollY && !isNearTop) { + document.documentElement.classList.add(CLASSES.scrollingDown); + } else { + document.documentElement.classList.remove(CLASSES.scrollingDown); + } + + this.state.previousScrollY = y; + } +} + +export default new MainMenu('header[role="banner"]'); diff --git a/assets/js/theme/nav/responsive.js b/assets/js/theme/nav/responsive.js new file mode 100644 index 0000000000000000000000000000000000000000..6e287c1a56fad0013221ac4979ebed32d196b8cf --- /dev/null +++ b/assets/js/theme/nav/responsive.js @@ -0,0 +1,43 @@ +const events = ['load', 'resize']; +let navBtn = document.querySelector('nav[role="navigation"] button'), + menuHeader = document.querySelector('.menu'), + bodyOverlay = document.querySelector('body'), // document.body + dropdownBtns = document.querySelectorAll('.has-children a[role="button"]'), + breckpointMd = 768, + classMobile = 'show'; + +events.forEach((event) => { + window.addEventListener(event, () => { + windowWidth = window.innerWidth; + + if (windowWidth <= breckpointMd) { + navBtn.addEventListener("click", function(){ + if(menuHeader.className.includes(classMobile)) { + navBtn.setAttribute('aria-expanded', 'false') + } + else { + navBtn.setAttribute('aria-expanded', 'true') + } + menuHeader.classList.toggle(classMobile) + bodyOverlay.classList.toggle('has-overlay') + }); + + dropdownBtns.forEach((dropdownBtn) => { + dropdownBtn.addEventListener("click", (e) => { + e.preventDefault() + + if(dropdownBtn.getAttribute('aria-expanded') == "true") { + dropdownBtn.setAttribute('aria-expanded', 'false') + } + else { + dropdownBtn.setAttribute('aria-expanded', 'true') + } + }) + }) + } + }) +}); + + + + diff --git a/assets/js/theme/nav/stickyNav.js b/assets/js/theme/nav/stickyNav.js index 0598fc822651332964625a3487584ae8cb40c033..4f533aa4451f41f69406000613b72d0ef001d6fd 100644 --- a/assets/js/theme/nav/stickyNav.js +++ b/assets/js/theme/nav/stickyNav.js @@ -1,51 +1,51 @@ -const events = ['scroll', 'touchmove']; -let previousY = 0, - y = 0, - classSticky = 'is-sticky', - classScrollingDown = 'is-scrolling-down', - classMenuOpen = 'is-menu-open', - header = document.querySelector('header[role="banner"]'), - offset = header.offsetHeight, - dropdowns = header.querySelectorAll('[data-bs-toggle="dropdown"]'), - menu = header.querySelector('.menu'); +// const events = ['scroll', 'touchmove']; +// let previousY = 0, +// y = 0, +// classSticky = 'is-sticky', +// classScrollingDown = 'is-scrolling-down', +// classMenuOpen = 'is-menu-open', +// header = document.querySelector('header[role="banner"]'), +// offset = header.offsetHeight, +// dropdowns = header.querySelectorAll('[data-bs-toggle="dropdown"]'), +// menu = header.querySelector('.menu'); -dropdowns.forEach((dropdown) => { - dropdown.addEventListener('hidden.bs.dropdown', () => { - if (!header.querySelector('[aria-expanded="true"]')) { - document.documentElement.classList.remove(classMenuOpen); - } - }); - dropdown.addEventListener('show.bs.dropdown', () => { - document.documentElement.classList.add(classMenuOpen); - }); -}); +// // dropdowns.forEach((dropdown) => { +// // dropdown.addEventListener('hidden.bs.dropdown', () => { +// // if (!header.querySelector('[aria-expanded="true"]')) { +// // document.documentElement.classList.remove(classMenuOpen); +// // } +// // }); +// // dropdown.addEventListener('show.bs.dropdown', () => { +// // document.documentElement.classList.add(classMenuOpen); +// // }); +// // }); -menu.addEventListener('show.bs.collapse', () => { - document.documentElement.classList.add(classMenuOpen); -}); +// // menu.addEventListener('show.bs.collapse', () => { +// // document.documentElement.classList.add(classMenuOpen); +// // }); -menu.addEventListener('hide.bs.collapse', () => { - document.documentElement.classList.remove(classMenuOpen); -}); +// // menu.addEventListener('hide.bs.collapse', () => { +// // document.documentElement.classList.remove(classMenuOpen); +// // }); -events.forEach((event) => { - window.addEventListener(event, () => { - y = window.scrollY; +// events.forEach((event) => { +// window.addEventListener(event, () => { +// y = window.scrollY; - if (y > offset) { - header.classList.add(classSticky); - } else { - header.classList.remove(classSticky); - } +// if (y > offset) { +// header.classList.add(classSticky); +// } else { +// header.classList.remove(classSticky); +// } - if (y > previousY && y > offset) { - document.documentElement.classList.add(classScrollingDown); - // document.documentElement.style.setProperty(scrollMarginTop, '100px'); - } else { - document.documentElement.classList.remove(classScrollingDown); - // document.documentElement.style.setProperty(scrollMarginTop, '200px'); - } +// if (y > previousY && y > offset) { +// document.documentElement.classList.add(classScrollingDown); +// // document.documentElement.style.setProperty(scrollMarginTop, '100px'); +// } else { +// document.documentElement.classList.remove(classScrollingDown); +// // document.documentElement.style.setProperty(scrollMarginTop, '200px'); +// } - previousY = y; - }); -}); +// previousY = y; +// }); +// }); diff --git a/assets/js/theme/utils/breakpoints.js b/assets/js/theme/utils/breakpoints.js new file mode 100644 index 0000000000000000000000000000000000000000..5779a036e01969faa66d1ddf24024c5247edbec9 --- /dev/null +++ b/assets/js/theme/utils/breakpoints.js @@ -0,0 +1,8 @@ +export default { + xs: 0, + sm: 576, + md: 768, + lg: 992, + xl: 1200, + xxl: 1400 +}; diff --git a/assets/sass/_theme/_configuration.sass b/assets/sass/_theme/_configuration.sass index 6d12f934277a427f4375827f6e24f0ce8fcb1064..891fe7330d3200c0e6f2ddf9ae557b2c785370ea 100644 --- a/assets/sass/_theme/_configuration.sass +++ b/assets/sass/_theme/_configuration.sass @@ -66,6 +66,8 @@ $grid-gutter-sm: $spacing1 !default // Z-index $zindex-nav-accessibility: 1010 !default $zindex-stretched-link: 2 !default +$zindex-header: 52 !default +$zindex-body-overlay: 51 !default $zindex-toc: 50 !default // Header @@ -74,9 +76,13 @@ $header-hover-color: rgba($header-color, 0.7) !default // TODO : Réflechir à p $header-background-color: $main-background-color !default $header-sticky-enabled: true !default $header-sticky-transition: 0.3s !default -$header-height: 74px !default +$header-dropdown-transition: 0.3s !default +$header-height: 61px !default $header-height-md: 74px !default +// Navs +$body-overlay-color: rgba(0, 0, 0, 0.3) !default + // Footer $footer-color: $main-color !default $footer-background-color: darken($main-background-color, 2.5) !default diff --git a/assets/sass/_theme/design-system/a11y.sass b/assets/sass/_theme/design-system/a11y.sass index 24b7c0d39502485c2643f80b9f5c3a82b9a43c90..0ce6576526745401209d2d0b15eed8eecfe5e7f9 100644 --- a/assets/sass/_theme/design-system/a11y.sass +++ b/assets/sass/_theme/design-system/a11y.sass @@ -2,7 +2,7 @@ @include list-reset padding: $spacing1 position: absolute - transform: translateY(-100%) + transform: translateY(calc(-100% - 24px)) z-index: $zindex-nav-accessibility li display: inline-block diff --git a/assets/sass/_theme/design-system/header.sass b/assets/sass/_theme/design-system/header.sass index e44d1c93a90f4fa05ad680b5936dd8088e6c4e55..74e57d15a69a5591437c38ecdfb86af0f14a452f 100644 --- a/assets/sass/_theme/design-system/header.sass +++ b/assets/sass/_theme/design-system/header.sass @@ -1,27 +1,38 @@ header[role="banner"] + z-index: $zindex-header + @include media-breakpoint-down(md) + position: fixed + padding: 1rem 0 + width: 100% + @if $header-sticky-enabled background-color: $header-background-color - position: sticky top: 0 transition: transform $header-sticky-transition - z-index: 10 - html.is-scrolling-down:not(.is-menu-open) & - &:not(:hover) - transform: translateY(-100%) - - &.is-sticky + @include media-breakpoint-up(md) position: sticky + html.is-scrolling-down:not(.has-menu-opened) & + @include media-breakpoint-down(md) + transform: translateY(-100%) + @include media-breakpoint-up(md) + &:not(:hover) + transform: translateY(-100%) nav[role="navigation"] .container align-items: center display: flex + flex-wrap: wrap justify-content: space-between button[type="button"] + @include button-reset display: none border: 0 color: $body-color position: relative + @include media-breakpoint-down(md) + display: flex + align-items: center &:focus box-shadow: none &:focus-visible @@ -33,6 +44,7 @@ header[role="banner"] font-size: px2rem(14) text-transform: uppercase span:last-of-type + @include icon("burger", before) background: none height: calc(1.063rem + .3125rem * 2) padding: px2rem(5) 0 px2rem(5) px2rem(5) diff --git a/assets/sass/_theme/design-system/layout.sass b/assets/sass/_theme/design-system/layout.sass index 18b4f3da850fcdaa3f3fcf4b4e430db5db8835c2..4f8dbce3401dbfe22d9039fe90227c7da233c4d5 100644 --- a/assets/sass/_theme/design-system/layout.sass +++ b/assets/sass/_theme/design-system/layout.sass @@ -13,6 +13,12 @@ body * transition-duration: 0s !important + +main + // Create padding-top for fixed header under md + @include media-breakpoint-down(md) + padding-top: $header-height + figure margin: 0 img diff --git a/assets/sass/_theme/design-system/nav.sass b/assets/sass/_theme/design-system/nav.sass index 896077d2c53de4b664d03ef48d8bcaf58d5addf2..c062254a0b2bf923237f65e0856b99aac0e31ca9 100644 --- a/assets/sass/_theme/design-system/nav.sass +++ b/assets/sass/_theme/design-system/nav.sass @@ -1,4 +1,20 @@ +@keyframes showIn + 0% + opacity: 0 + 100% + opacity: 1 + 0% + opacity: 0 + .menu + @include media-breakpoint-down(md) + -webkit-flex-basis: 100vw + display: none + flex-basis: 100vw + margin-top: 1.875rem + max-height: 70vh + overflow: auto + a, a:hover, a:focus, @@ -14,31 +30,39 @@ font-size: px2rem(18) line-height: px2rem(26) color: $header-color - a:hover, - a:focus - color: $header-hover-color + @include media-breakpoint-up(md) + a:hover, + a:focus + color: $header-hover-color .dropdown-menu display: none background: $header-background-color padding-bottom: $spacing1 padding-top: $spacing1 - inset: 100% 0 auto 0 - position: absolute + @include media-breakpoint-up(md) + inset: 100% 0 auto 0 + position: absolute .nav-level-1 display: flex + @include media-breakpoint-down(md) + @include grid(1) > li - > a + > a, span padding: $spacing1 display: block &:last-child a padding-right: 0 - li.has-children:hover - .dropdown-menu + li.has-children + a[aria-expanded="true"] + .dropdown-menu display: block + animation-duration: $header-dropdown-transition + animation-fill-mode: both + animation-name: showIn .nav-level-2 + @include grid(1) @include media-breakpoint-up(md) @include container @include grid(4, md) @@ -56,6 +80,51 @@ span font-size: px2rem(14) + @include media-breakpoint-down(md) + &.is-opened + flex-grow: 1 + display: block + a + text-decoration: none + .nav-level-1 + li + a + padding: 1rem 0 + > li:not(:last-child) + border-bottom: 1px solid #adb5bd + li.has-children + a[role="button"] + align-items: center + display: flex + justify-content: space-between + @include icon("caret-bottom", after) + &::after + font-size: .375rem + line-height: 1 + .dropdown-menu + display: none + padding-top: 0 + + a[aria-expanded=true] + @include icon("caret-top", after) + + + .dropdown-menu + display: block + +body + &::after + background-color: $body-overlay-color + content: "" + display: none + inset: 82px 0 0 0 + position: fixed + z-index: $zindex-body-overlay + html.has-menu-opened & + &::after + display: block + animation-duration: $header-dropdown-transition + animation-fill-mode: both + animation-name: showIn .share display: flex diff --git a/assets/sass/_theme/sections/programs.sass b/assets/sass/_theme/sections/programs.sass index 343b0a1d155e09b1f34d41ad7e4829c35e6eba8e..3b4b6a995b0dacfa9b6b482d7584ff9476cd009a 100644 --- a/assets/sass/_theme/sections/programs.sass +++ b/assets/sass/_theme/sections/programs.sass @@ -80,7 +80,7 @@ ol.programs padding-top: $spacing4 aside @include container - @include sticky($header-height) + @include sticky overflow: auto background: darken($main-background-color, 3) z-index: $program-zindex-toc diff --git a/assets/sass/_theme/sections/sitemap.sass b/assets/sass/_theme/sections/sitemap.sass index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b52730394e6b1466077b16467600dca7c594c6a0 100644 --- a/assets/sass/_theme/sections/sitemap.sass +++ b/assets/sass/_theme/sections/sitemap.sass @@ -0,0 +1,9 @@ +.sitemap__section + .content + > div + @include media-breakpoint-up(md) + padding-left: col(5) + ul + list-style: none + margin-bottom: 7.5rem + padding: 0 \ No newline at end of file