diff --git a/src/base/component/menu/group.rs b/src/base/component/menu/group.rs index 41279b4..ba18893 100644 --- a/src/base/component/menu/group.rs +++ b/src/base/component/menu/group.rs @@ -18,7 +18,7 @@ impl Component for Group { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { - div id=[self.id()] class="menu-group" { + div id=[self.id()] class="menu__group" { (self.elements().render(cx)) } }) diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs index 07d629a..7a36fbb 100644 --- a/src/base/component/menu/item.rs +++ b/src/base/component/menu/item.rs @@ -1,11 +1,9 @@ use crate::prelude::*; -//use super::{Megamenu, Submenu}; - type Label = L10n; type Content = Typed; type SubmenuItems = Typed; -//type MegamenuGroups = Typed; +type MegamenuGroups = Typed; #[derive(AutoDefault)] pub enum ItemKind { @@ -16,7 +14,7 @@ pub enum ItemKind { LinkBlank(Label, FnPathByContext), Html(Content), Submenu(Label, SubmenuItems), - // Megamenu(Label, MegamenuGroups), + Megamenu(Label, MegamenuGroups), } #[rustfmt::skip] @@ -41,61 +39,65 @@ impl Component for Item { match self.item_kind() { ItemKind::Void => PrepareMarkup::None, ItemKind::Label(label) => PrepareMarkup::With(html! { - li class="menu__label" { + li class="menu__item menu__item--label" { span title=[description] { (left_icon) - (label.using(cx)) + span class="menu__label" { (label.using(cx)) } (right_icon) } } }), ItemKind::Link(label, path) => PrepareMarkup::With(html! { - li class="menu__link" { + li class="menu__item menu__item--link" { a href=(path(cx)) title=[description] { (left_icon) - (label.using(cx)) + span class="menu__label" { (label.using(cx)) } (right_icon) } } }), ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! { - li class="menu__link" { + li class="menu__item menu__item--link" { a href=(path(cx)) title=[description] target="_blank" { (left_icon) - (label.using(cx)) + span class="menu__label" { (label.using(cx)) } (right_icon) } } }), ItemKind::Html(content) => PrepareMarkup::With(html! { - li class="menu__html" { + li class="menu__item menu__item--html" { (content.render(cx)) } }), ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! { - li class="menu__children" { + li class="menu__item menu__item--children" { a href="#" title=[description] { (left_icon) - (label.using(cx)) i class="menu__icon bi-chevron-down" {} + span class="menu__label" { (label.using(cx)) } + (Icon::svg(html! { + path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {} + }).render(cx)) } - div class="menu__subs" { + div class="menu__children menu__children--submenu" { (submenu.render(cx)) } } }), - /* ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! { - li class="menu__children" { + li class="menu__item menu__item--children" { a href="#" title=[description] { (left_icon) - (label.escaped(cx.langid())) i class="menu__icon bi-chevron-down" {} + span class="menu__label" { (label.using(cx)) } + (Icon::svg(html! { + path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {} + }).render(cx)) } - div class="menu__subs menu__mega" { + div class="menu__children menu__children--mega" { (megamenu.render(cx)) } } }), - */ } } } diff --git a/src/base/component/menu/megamenu.rs b/src/base/component/menu/megamenu.rs index f22b184..e435e75 100644 --- a/src/base/component/menu/megamenu.rs +++ b/src/base/component/menu/megamenu.rs @@ -18,7 +18,7 @@ impl Component for Megamenu { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { - div id=[self.id()] class="menu__groups" { + div id=[self.id()] class="menu__mega" { (self.groups().render(cx)) } }) diff --git a/src/base/component/menu/menu_menu.rs b/src/base/component/menu/menu_menu.rs index a7f91be..58a4c21 100644 --- a/src/base/component/menu/menu_menu.rs +++ b/src/base/component/menu/menu_menu.rs @@ -54,7 +54,9 @@ impl Component for Menu { class="menu__trigger" title=[L10n::l("menu_toggle").lookup(cx)] { - span {} span {} span {} + (Icon::svg(html! { + path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5" {} + }).render(cx)) } } } diff --git a/src/base/component/menu/submenu.rs b/src/base/component/menu/submenu.rs index 5877052..a5957ef 100644 --- a/src/base/component/menu/submenu.rs +++ b/src/base/component/menu/submenu.rs @@ -19,9 +19,9 @@ impl Component for Submenu { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { - div id=[self.id()] class="menu__items" { + div id=[self.id()] class="menu__submenu" { @if let Some(title) = self.title().lookup(cx) { - h4 class="menu__title" { (title) } + h4 class="menu__submenu-title" { (title) } } ul { (self.items().render(cx)) diff --git a/static/css/menu.css b/static/css/menu.css index a8b2854..5520e39 100644 --- a/static/css/menu.css +++ b/static/css/menu.css @@ -27,13 +27,13 @@ .menu__nav li { display: inline-block; margin: 0 0 0 1.5rem; - padding: var(--val-menu--line-padding) 0; - line-height: var(--val-menu--line-height); + padding: 0; + line-height: var(--val-menu--item-height); list-style: none; list-style-type: none; } -.menu__nav li.menu__label, +.menu__item--label, .menu__nav li > a { position: relative; font-weight: 500; @@ -48,19 +48,18 @@ .menu__nav li > a:focus { color: var(--val-menu--color-highlight); } -.menu__nav li > a > i.menu__icon { +.menu__nav li > a > svg.icon { margin-left: 0.25rem; } -.menu__nav li .menu__subs { +.menu__children { position: absolute; max-width: 100%; height: auto; - padding: 1rem 2rem; + padding: var(--val-gap-0-5) var(--val-gap-1-5); border: none; outline: none; background: var(--val-menu--color-bg); - border-radius: var(--val-menu--border-radius); border-top: 3px solid var(--val-menu--color-highlight); z-index: 500; opacity: 0; @@ -69,19 +68,19 @@ transition: all 0.5s ease-in-out; } -.menu__nav li.menu__children:hover > .menu__subs, -.menu__nav li.menu__children > a:focus + .menu__subs, -.menu__nav li.menu__children .menu__subs:focus-within { +.menu__item--children:hover > .menu__children, +.menu__item--children > a:focus + .menu__children, +.menu__item--children .menu__children:focus-within { margin-top: 0.4rem; opacity: 1; visibility: visible; } -.menu__nav li .menu__items { +.menu__submenu { min-width: var(--val-menu--item-width-min); max-width: var(--val-menu--item-width-max); } -.menu__nav li .menu__items .menu__title { +.menu__submenu-title { font-family: inherit; font-size: 1rem; font-weight: 500; @@ -94,17 +93,17 @@ text-transform: uppercase; text-rendering: optimizeLegibility; } -.menu__nav li .menu__items li { +.menu__submenu li { display: block; - margin-left: 0; + margin: 0; } -.menu__nav li .menu__mega { +.menu__children--mega { left: 50%; transform: translateX(-50%); } -.menu__nav li .menu__groups { +.menu__mega { display: flex; flex-wrap: nowrap; } @@ -116,15 +115,9 @@ /* Applies <= 992px */ @media only screen and (max-width: 62rem) { - .menu { - border-radius: var(--val-border-radius); - } .menu__wrapper { padding-right: var(--val-gap-0-5); } - .menu__wrapper button { - margin: var(--val-gap-0-5) 0 var(--val-gap-0-5) var(--val-gap-0-5); - } .menu__trigger { cursor: pointer; width: var(--val-menu--trigger-width); @@ -136,14 +129,10 @@ flex-direction: column; justify-content: center; } - .menu__trigger span { - width: 100%; - height: 2px; - margin: 12.675% 0; - border-radius: var(--val-border-radius); - background: var(--val-color--text); + .menu__trigger svg.icon { + width: 2rem; + height: 2rem; } - .menu__nav { position: fixed; top: 0; @@ -156,34 +145,36 @@ transform: translate(-100%); transition: all 0.5s ease-in-out; } - .menu__panel .menu__nav.active { + .menu__nav.active { transform: translate(0%); } .menu__nav li { display: block; margin: 0; - padding: 0; + line-height: var(--val-menu--line-height); } - .menu__nav li.menu__label, + + .menu__item--label, .menu__nav li > a { display: block; padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); border-bottom: 1px solid var(--val-menu--color-border); } - .menu__nav li ul li.menu__label, + .menu__nav li ul li.menu__item--label, .menu__nav li ul li > a { border-bottom: 0; } - .menu__nav li > a > i.menu__icon { + .menu__nav li > a > svg.icon { position: absolute; top: var(--val-menu--line-padding); right: var(--val-menu--line-padding); + height: var(--val-menu--line-height); font-size: 1.25rem; transform: rotate(-90deg); } - .menu__nav li .menu__subs { + .menu__children { position: absolute; display: none; top: 0; @@ -201,22 +192,22 @@ transform: translateX(0%); box-shadow: none; } - .menu__nav li .menu__subs.active { + .menu__children.active { display: block; } - .menu__nav li .menu__subs > :first-child { - margin-top: 4rem; + .menu__children > :first-child { + margin-top: 2.675rem; } - .menu__nav li .menu__items .menu__title { + .menu__submenu-title { padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); } - .menu__nav li .menu__groups { + .menu__mega { display: block; } - .menu__nav .menu__header { + .menu__header { position: sticky; display: flex; align-items: center; @@ -227,14 +218,14 @@ background: var(--val-menu--color-bg); z-index: 501; } - .menu__nav .menu__header .menu__title { + .menu__title { padding: var(--val-menu--line-padding); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } - .menu__nav .menu__header .menu__close, - .menu__nav .menu__header .menu__back { + .menu__close, + .menu__back { width: var(--val-menu--item-height); min-width: var(--val-menu--item-height); height: var(--val-menu--item-height); @@ -245,20 +236,20 @@ align-items: center; justify-content: center; } - .menu__nav .menu__header .menu__close { + .menu__close { font-size: 2.25rem; - border-left: 1px solid var(--val-menu--color-border); + border-left: 1px solid var(--val-menu--color-border) !important; } - .menu__nav .menu__header .menu__back { + .menu__back { font-size: 1.25rem; - border-right: 1px solid var(--val-menu--color-border); + border-right: 1px solid var(--val-menu--color-border) !important; display: none; } - .menu__nav .menu__header.active .menu__back { + .menu__header.active .menu__back { display: flex; } - .menu__nav .menu__list { + .menu__list { height: 100%; overflow-y: auto; overflow-x: hidden; diff --git a/static/css/root.css b/static/css/root.css index bc55a44..aeab1c6 100644 --- a/static/css/root.css +++ b/static/css/root.css @@ -191,6 +191,8 @@ --color--green: #3fa21c; --header-height-wide-when-fixed: calc(6 * var(--val-gap)); --mobile-nav-width: 31.25rem; + + --val-menu--border-radius: 0.625rem; */ --val-border-radius: 0.375rem; @@ -205,7 +207,6 @@ --val-menu--item-width-min: 14rem; --val-menu--item-width-max: 20rem; --val-menu--item-gap: 1rem; - --val-menu--border-radius: 0.625rem; - --val-menu--trigger-width: var(--val-menu--item-height); + --val-menu--trigger-width: 2.675rem; --val-menu--side-width: 20rem; } diff --git a/static/js/menu.js b/static/js/menu.js index 2f3b332..6b5ae1b 100644 --- a/static/js/menu.js +++ b/static/js/menu.js @@ -1,15 +1,17 @@ function menu__showChildren(nav, children) { - let submenu = children[0].querySelector('.menu__subs'); + const li = children[0]; + const submenu = li.querySelector('.menu__children'); submenu.classList.add('active'); submenu.style.animation = 'slideLeft 0.5s ease forwards'; - let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; + const labelEl = li.querySelector('.menu__label'); + const title = labelEl ? labelEl.textContent.trim() : (li.querySelector('a')?.textContent?.trim() ?? ''); nav.querySelector('.menu__title').innerHTML = title; nav.querySelector('.menu__header').classList.add('active'); } function menu__hideChildren(nav, children) { - let submenu = children[0].querySelector('.menu__subs'); + const submenu = children[0].querySelector('.menu__children'); submenu.style.animation = 'slideRight 0.5s ease forwards'; setTimeout(() => { submenu.classList.remove('active'); @@ -18,11 +20,12 @@ function menu__hideChildren(nav, children) { children.shift(); if (children.length > 0) { - let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; - nav.querySelector('.menu__title').innerHTML = title; + const a = children[0].querySelector('a'); + const title = (a && a.textContent ? a.textContent.trim() : ''); + nav.querySelector('.menu__title').textContent = title; } else { nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').innerHTML = ''; + nav.querySelector('.menu__title').textContent = ''; } } @@ -36,7 +39,7 @@ function menu__reset(menu, nav, overlay) { setTimeout(() => { nav.querySelector('.menu__header').classList.remove('active'); nav.querySelector('.menu__title').innerHTML = ''; - menu.querySelectorAll('.menu__subs').forEach(submenu => { + menu.querySelectorAll('.menu__children').forEach(submenu => { submenu.classList.remove('active'); submenu.style.removeProperty('animation'); }); @@ -52,7 +55,7 @@ document.querySelectorAll('.menu').forEach(menu => { menu.querySelector('.menu__list').addEventListener('click', (e) => { if (menuNav.classList.contains('active')) { - let target = e.target.closest('.menu__children'); + let target = e.target.closest('.menu__item--children'); if (target && target != menuChildren[0]) { menuChildren.unshift(target); menu__showChildren(menuNav, menuChildren); @@ -68,7 +71,7 @@ document.querySelectorAll('.menu').forEach(menu => { menuChildren = menu__reset(menu, menuNav, menuOverlay); }); - menu.querySelectorAll('.menu__link > a[target="_blank"]').forEach(link => { + menu.querySelectorAll('.menu__item--link > a[target="_blank"]').forEach(link => { link.addEventListener('click', (e) => { menuChildren = menu__reset(menu, menuNav, menuOverlay); e.target.blur();