{# Styles du menu #} <style> /** * Menu Formsemestre * * @author Matthias HARTMANN (Iziram) * Approche Mobile-first */ /* CSS défaut */ :root{ --sco-formsemestre-color-primary: rgb(214, 233, 248); --sco-formsemestre-color-accent: rgb(103, 167, 227); } .menu-wrapper *{ margin: 0; padding: 0; box-sizing: border-box; } /* CSS menu */ .sco-formsemestre-menu { background-color: var(--sco-formsemestre-color-primary); border-top: var(--sco-formsemestre-color-accent) solid 3px; padding: 0 1rem; border-radius: 4px; margin: 0 0px; } .sco-formsemestre-menu-container { display: flex; justify-content: space-between; align-items: center; position: relative; } .sco-formsemestre-menu-toggle { display: block; background: none; border: none; cursor: pointer; z-index: 1000; } .sco-formsemestre-menu-toggle-icon { display: block; width: 25px; height: 3px; background-color: #333; position: relative; transition: background-color 0.3s ease; margin: 10px 5px; } .sco-formsemestre-menu-toggle-icon::before, .sco-formsemestre-menu-toggle-icon::after { content: ''; position: absolute; width: 100%; height: 100%; background-color: #333; transition: all 0.3s ease; left: 0; } .sco-formsemestre-menu-toggle-icon::before { top: -8px; } .sco-formsemestre-menu-toggle-icon::after { bottom: -8px; } .sco-formsemestre-menu-menu { position: fixed; top: 0; right: -100%; width: 100%; height: 100vh; background-color: #fff; box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1); transition: right 0.3s ease; z-index: 999; overflow-y: auto; padding-top: 5vh; margin: 0; transition: all 0.3s ease; } .sco-formsemestre-menu-menu.active { right: 0; } .sco-formsemestre-menu-item { list-style: none; width: 100%; user-select: none; display: flex; justify-content: center; border: none; text-transform: none; font-weight: normal; font-size: 12px; padding: 4px 8px; border-radius: 4px; } .sco-formsemestre-menu-menu>.dropdown>summary { text-transform: uppercase; font-weight: bold; font-size: 12px !important; } .sco-formsemestre-menu-link { color: #333; text-decoration: none; transition: color 0.3s ease; } .sco-formsemestre-menu-link:hover { color: #007bff; } .sco-formsemestre-menu-link[disabled] { pointer-events: none; color: #b7b7b7; } /* Animation */ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /* Styles spécifiques PC */ @media screen and (min-width: 768px) { .sco-formsemestre-menu-toggle { display: none; } .sco-formsemestre-menu-menu { position: static; display: flex; width: auto; height: auto; background-color: transparent; box-shadow: none; overflow-y: visible; flex-direction: row; justify-content: center; padding: 0; } .sco-formsemestre-menu-item { width: auto; } .sco-formsemestre-menu-link { text-wrap: nowrap; } .sco-formsemestre-menu .dropdown { padding-right: 16px; position: relative; } .sco-formsemestre-menu .dropdown[open] .dropdown-content { position: absolute; top: 100%; left: 0; z-index: 1; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } .sco-formsemestre-menu{ margin-top: 4px; } } /* Styles spécifiques mobile */ @media screen and (max-width: 767px) { /* Menu toggle button styles for mobile */ .sco-formsemestre-menu-toggle { display: block; background-color: var(--sco-formsemestre-color-primary); padding: 10px; border-radius: 5px; } .sco-formsemestre-menu-toggle-icon { width: 30px; height: 4px; background-color: #fff; } /* Mobile menu styles */ .sco-formsemestre-menu-menu { position: fixed; top: 0; right: -100%; width: 100vw; height: 100vh; background-color: var(--sco-formsemestre-color-primary); box-shadow: -2px 0 5px rgba(0, 0, 0, 0.2); padding: 4rem 1rem; transition: right 0.3s ease-in-out; z-index: 999; overflow-y: scroll; } .sco-formsemestre-menu-menu.active { right: 0; } /* Menu item styles */ .sco-formsemestre-menu-item { width: 100%; padding: 10px; margin-bottom: 5px; border-bottom: 1px solid var(--sco-formsemestre-color-accent); font-size: small; } .sco-formsemestre-menu-menu>.dropdown>.sco-formsemestre-menu-item { font-size: 16px; } .sco-formsemestre-menu-link { color: #333; font-size: 16px; text-decoration: none; display: block; width: 100%; transition: color 0.3s ease; font-size: small !important; text-wrap: wrap; } .sco-formsemestre-menu-link:hover { color: var(--sco-formsemestre-color-accent); } /* Dropdown styles */ .sco-formsemestre-menu .dropdown>summary { padding: 10px; border-bottom: 1px solid var(--sco-formsemestre-color-accent); cursor: pointer; } .sco-formsemestre-menu .dropdown-content { display: none; padding-left: 10px; background-color: var(--sco-formsemestre-color-primary); } .sco-formsemestre-menu .dropdown[open]>.dropdown-content { display: block; } .sco-formsemestre-menu .dropdown-content>.sco-formsemestre-menu-item { padding: 8px; margin-bottom: 5px; } .sco-formsemestre-menu .dropdown>summary::after { border-top: 4px solid #333; } /* Toggling the dropdown arrow */ .sco-formsemestre-menu .dropdown[open]>summary::after { transform: rotate(180deg); } .sco-formsemestre-menu{ border: none; } } .sco-formsemestre-menu-toggle.active .sco-formsemestre-menu-toggle-icon { background-color: transparent; } .sco-formsemestre-menu-toggle.active .sco-formsemestre-menu-toggle-icon::before { transform: translateY(8px) rotate(45deg); } .sco-formsemestre-menu-toggle.active .sco-formsemestre-menu-toggle-icon::after { transform: translateY(-8px) rotate(-45deg); } /*<== DROPDOWNS ==>*/ .sco-formsemestre-menu .dropdown>summary { list-style: none; padding: 0.25rem 0.5rem; border-radius: 4px; font-size: small; } .sco-formsemestre-menu .dropdown>summary::marker { display: none; } .sco-formsemestre-menu .dropdown>summary::after { content: ""; display: inline-block; width: 0; height: 0; margin-left: 4px; vertical-align: middle; border-top: 4px dashed; border-right: 4px solid transparent; border-left: 4px solid transparent; } .sco-formsemestre-menu .dropdown>summary:hover { background-color: #92cbf6; cursor: pointer; } .sco-formsemestre-menu .dropdown-content { background-color: #fff; padding: 10px; border: 1px solid #ccc; border-top: none; } .sco-formsemestre-menu .dropdown-content .sco-formsemestre-menu-item { padding: 0.25rem 0.5rem; list-style: none; width: 100%; display: block; text-align: left; transition: all 0.3s ease; border-radius: 5px; } .sco-formsemestre-menu .dropdown-content .sco-formsemestre-menu-item:hover { background-color: #f0f0f0; } </style> {# Scripts #} <script> document.addEventListener("DOMContentLoaded", () => { const navbarToggle = document.querySelector(".sco-formsemestre-menu-toggle"); const navbarMenu = document.querySelector(".sco-formsemestre-menu-menu"); const dropdownItems = document.querySelectorAll(".dropdown"); document.getElementById('mobileNav').append(document.getElementById('titre-court-sem')); document.getElementById('mobileNav').append(navbarToggle); // Affichage du menu mobile au clic navbarToggle.addEventListener("click", () => { navbarMenu.classList.toggle("active"); navbarToggle.classList.toggle("active"); // Animation de l'icône navbarToggle.setAttribute( "aria-expanded", navbarToggle.getAttribute("aria-expanded") === "false" ? "true" : "false" ); // Fermeture des dropdowns dropdownItems.forEach((item) => item.removeAttribute("open")); // Blockage du scroll toggleScroll(); }); // Fermeture du menu mobile au clic en dehors du menu document.addEventListener("click", (e) => { if (!navbarMenu.contains(e.target) && !navbarToggle.contains(e.target)) { navbarMenu.classList.remove("active"); navbarToggle.classList.remove("active"); navbarToggle.setAttribute("aria-expanded", "false"); toggleScroll(); } }); // Gestion du menu au redimensionnement de la fenêtre window.addEventListener("resize", () => { if (window.innerWidth >= 768) { navbarMenu.classList.remove("active"); navbarToggle.classList.remove("active"); navbarToggle.setAttribute("aria-expanded", "false"); dropdownItems.forEach((item) => item.classList.remove("active")); } }); // Gestion des dropdowns dropdownItems.forEach((item) => { item.addEventListener("mouseover", () => { if (window.innerWidth >= 768) { item.setAttribute("open", ""); } }); item.addEventListener("mouseout", () => { if (window.innerWidth >= 768) { item.removeAttribute("open"); } }); }); }); </script> {# Macro génération dropdown #} {% macro dropdown(category, items) %} <details class="dropdown"> <summary class="">{{category}}</summary> <div class="dropdown-content"> {% for item in items %} {% if item.submenu is defined %} {{dropdown(item.title, item.submenu)}} {% else %} {% set args = item.args or dict() %} {% set url = url_for(item.endpoint, scodoc_dept=g.scodoc_dept,**args) if item.endpoint is defined else item.url %} <a href="{{url}}" {{'disabled aria-disabled="true"' if item.enabled is defined and not item.enabled}} class="sco-formsemestre-menu-item sco-formsemestre-menu-link" > {{item.title}} </a> {% endif %} {% endfor %} </div> </details> {% endmacro %} {# Menu HTML #} <div class="menu-wrapper"> <nav class="sco-formsemestre-menu"> <div class="sco-formsemestre-menu-container"> {# Titre semestre court sera déplacé dans #mobileNav #} <h2 id="titre-court-sem"> <a class="stdlink" title="{{formsemestre.session_id()}}" href="{{url_for('notes.formsemestre_status', scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id)}}">{{formsemestre.formation.acronyme}}</a> </h2> {# Icône menu hamburger sera déplacé dans #mobileNav #} <button class="sco-formsemestre-menu-toggle" aria-label="Toggle menu"> <span class="sco-formsemestre-menu-toggle-icon"></span> </button> {# Menu #} <ul class="sco-formsemestre-menu-menu"> {% for category, items in menu.items() %} {{dropdown(category, items)}} {% endfor %} </ul> </div> </nav> </div>