diff --git a/src/main/resources/static/css/app.css b/src/main/resources/static/css/app.css index 19504f9..339844c 100644 --- a/src/main/resources/static/css/app.css +++ b/src/main/resources/static/css/app.css @@ -129,7 +129,8 @@ body { } .rw-menu-trigger:hover, -.rw-menu-trigger:focus { +.rw-menu-trigger:focus, +.rw-menu-group.open .rw-menu-trigger { background: var(--rw-surface-muted); border-color: var(--rw-border); color: var(--rw-text); @@ -149,8 +150,7 @@ body { z-index: 30; } -.rw-menu-group:hover .rw-menu-panel, -.rw-menu-group:focus-within .rw-menu-panel { +.rw-menu-group.open .rw-menu-panel { display: grid; gap: .15rem; } @@ -181,7 +181,7 @@ body { position: static; } - .rw-menu-group:focus-within .rw-menu-panel { + .rw-menu-group.open .rw-menu-panel { display: grid; } diff --git a/src/main/resources/static/js/app.js b/src/main/resources/static/js/app.js index 3c729c4..1dcddce 100644 --- a/src/main/resources/static/js/app.js +++ b/src/main/resources/static/js/app.js @@ -59,6 +59,48 @@ function syncPolicyTemplate(select) { }); } +function closeMenuGroup(group) { + if (!group) { + return; + } + group.classList.remove('open'); + group.querySelector('.rw-menu-trigger')?.setAttribute('aria-expanded', 'false'); +} + +function closeAllMenuGroups(exceptGroup = null) { + document.querySelectorAll('.rw-menu-group.open').forEach((group) => { + if (group !== exceptGroup) { + closeMenuGroup(group); + } + }); +} + +function initPersistentMenus() { + document.querySelectorAll('.rw-menu-trigger').forEach((button) => { + button.addEventListener('click', (event) => { + event.stopPropagation(); + const group = button.closest('.rw-menu-group'); + if (!group) { + return; + } + const nextOpen = !group.classList.contains('open'); + closeAllMenuGroups(group); + group.classList.toggle('open', nextOpen); + button.setAttribute('aria-expanded', String(nextOpen)); + }); + }); + document.addEventListener('click', (event) => { + if (!event.target.closest('.rw-menu')) { + closeAllMenuGroups(); + } + }); + document.addEventListener('keydown', (event) => { + if (event.key === 'Escape') { + closeAllMenuGroups(); + } + }); +} + function escapeHtml(value) { return value .replaceAll('&', '&') @@ -428,6 +470,7 @@ function initPermissionWizard() { } document.addEventListener('DOMContentLoaded', () => { + initPersistentMenus(); renderMarkdownViews(); const master = document.getElementById('userRoleMaster'); if (master) { diff --git a/src/main/resources/templates/fragments/layout.html b/src/main/resources/templates/fragments/layout.html index bf7748f..491cc17 100644 --- a/src/main/resources/templates/fragments/layout.html +++ b/src/main/resources/templates/fragments/layout.html @@ -16,7 +16,7 @@ VPD Backoffice