From 7b5c545f3709b64a5c244a579239fc265324be2b Mon Sep 17 00:00:00 2001 From: Peter French Date: Thu, 19 Oct 2023 09:53:52 +0200 Subject: [PATCH] Nojs meganav (#13141) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add global nav * add tabbed content js to main js * fix global nav chevron position on reduced view * Add second view for mobile * Refactor to work with new sliding nav * Fix css issues from refactoring html structure * lint-scss * Update with design usggestions from initial ux review * Further ux review changes * Make user dropdown work wit sliding nav * Fix bug in account dropdown where clicking outside the made navigation would cause it to open * Format prettier * revert use-cases changes for demo * Increase default grid width * Implemened redesigned use-cases * Lint-scss * Further ux changes for demo purpose - global nav not working on mobile * Implement new global nav for desktop * Implement new global nav for mobile view * Changes based on code and QA * Content QA Shorten line on Products > Featured Fix capitalisation Fix consistency issues * Reposition search icon * Add content fixes Hyphenation for "enterprise-grade" Replace Cloud Native Operations Survey link Sort and tweak quick links under K8s, Juju and snaps * Some final ux improvement and a small bug fix * Fix spacing issue and highlight not appearing on account dropdown * Fix global nav item alignment * Implement global-nav 3.5.0 changes * Changes based on Hans feedback * Tweak bubble labels Fix "Sign in" hyphenation typo * Remove redundant headings ("Products") * Visual design review changes * Fix navigation padding bug * Remove second 'skip to main content' * Update with UX suggestions * Bump grid-max-width to 90rem * Fix logo alignment in primary navigation * Refactor to use event delegation * Update alignment in reduced nav * Add failsafe to prevent dropdowns being fetched multiple times * Bump global-nav version to 3.6.1 * Align logos far left * Make reduced nav not sticky * Allow dropdowns to be scrollable if viewport height is smaller than the dropdown height * Add missing links to mobile dropdowns * Align top level mobile items with logo * Add fallback for hover loading on touchscreen devices * Use variables for repeated values * Handle resize events * Close meganav on any resize event * Use grid-max-width variable * Handle resize event on secondary nav * Fix highlighted page alignment * Delete unused 'navigation-meganav-base.html file * Only closeAll on resize event if mobile-breakpoint threshold is crossed * Create basic static nojs-meganav * Apply style changes from UX mockup * Enable nojs-meganav when JS is not enabled * Apply changes from U review and make a basic mobile view mockup * Format prettier * Hide chevrons and implement fallbacks for 'menu' and 'search' * Fix search not working on nojs mobile view * Ux updates * Fix prettier errors * Lint JS * Format prettier --------- Co-authored-by: Scott Mason Nash Co-authored-by: Juan RuitiƱa --- static/js/src/navigation.js | 63 ++-- static/sass/_pattern_navigation-dropdown.scss | 40 +-- static/sass/_pattern_navigation.scss | 319 ++++++++++-------- static/sass/styles.scss | 1 + templates/templates/_navigation.html | 20 +- .../templates/meganav/_section-heading.html | 11 + templates/templates/meganav/base.html | 2 +- .../templates/meganav/navigation-nojs.html | 222 ++++++++++++ webapp/app.py | 3 + webapp/context.py | 3 + webapp/views.py | 4 + 11 files changed, 489 insertions(+), 199 deletions(-) create mode 100644 templates/templates/meganav/_section-heading.html create mode 100644 templates/templates/meganav/navigation-nojs.html diff --git a/static/js/src/navigation.js b/static/js/src/navigation.js index 58eba27175d..c2698b892b8 100644 --- a/static/js/src/navigation.js +++ b/static/js/src/navigation.js @@ -14,15 +14,12 @@ const topLevelNavDropdowns = Array.from( ); const nav = navigation.querySelector(".js-show-nav"); const menuButtons = document.querySelectorAll(".js-menu-button"); -const skipLink = document.querySelector(".p-link--skip"); -const jsBackbuttons = document.querySelectorAll(".js-back"); -const reducedNav = document.querySelector(".p-navigation--sliding.is-reduced "); let dropdowns = []; const mainList = document.querySelector( "nav.p-navigation__nav > .p-navigation__items" ); -const currentBubble = window.location.pathname.split("/")[1]; +navigation.classList.add("js-enabled"); nav.classList.remove("u-hide"); //Helper functions @@ -52,7 +49,8 @@ function getAllElements(queryString) { } // Attach initial event listeners -mainList.addEventListener("click", function(e) { +mainList.addEventListener("click", function (e) { + e.preventDefault(); let target = e.target; if (target.classList.contains("p-navigation__link")) { if (target.classList.contains("js-back")) { @@ -61,11 +59,11 @@ mainList.addEventListener("click", function(e) { handleDropdownClick(e.target.parentNode); } } -}) +}); window.addEventListener("load", closeAll); let wasBelowSpecificWidth = window.innerWidth < MOBILE_VIEW_BREAKPOINT; -window.addEventListener("resize", function() { +window.addEventListener("resize", function () { // Only closeAll if the resize event crosses the MOBILE_VIEW_BREAKPOINT threshold const currentViewportWidth = window.innerWidth; const isBelowSpecificWidth = currentViewportWidth < MOBILE_VIEW_BREAKPOINT; @@ -75,7 +73,6 @@ window.addEventListener("resize", function() { wasBelowSpecificWidth = isBelowSpecificWidth; }); - dropdownWindowOverlay?.addEventListener("click", () => { if (dropdownWindow.classList.contains("is-active")) { closeAll(); @@ -98,7 +95,9 @@ document.addEventListener("global-nav-opened", () => { function toggleSecondaryMobileNavDropdown(e) { const mobileNavDropdown = secondaryNav.querySelector(".p-navigation__nav"); - const mobileNavDropdownToggle = secondaryNav.querySelector(".p-navigation__toggle--open"); + const mobileNavDropdownToggle = secondaryNav.querySelector( + ".p-navigation__toggle--open" + ); let isDropdownOpen; if (e && e.type == "click") { e.preventDefault(); @@ -161,7 +160,16 @@ function updateNavMenu(dropdown, show) { dropdown.id + "-content-mobile" ); let isAccountDropdown = dropdown.classList.contains("js-account"); - + + function handleMutation(mutationsList, observer) { + mutationsList.forEach((mutation) => { + if (mutation.type === "childList") { + handleDropdownClick(mutation.target); + observer.disconnect(); + } + }); + } + if ((dropdownContent && dropdownContentMobile) || isAccountDropdown) { if (!show) updateDropdownStates(dropdown, show, ANIMATION_DELAY); else updateDropdownStates(dropdown, show); @@ -169,14 +177,6 @@ function updateNavMenu(dropdown, show) { } else if (dropdownContentMobile) { updateMobileDropdownState(dropdown, show); } else { - function handleMutation(mutationsList, observer) { - mutationsList.forEach(mutation => { - if (mutation.type === 'childList') { - handleDropdownClick(mutation.target); - observer.disconnect(); - } - }); - } const observer = new MutationObserver(handleMutation); const observerConfig = { childList: true, subtree: true }; observer.observe(dropdown, observerConfig); @@ -200,9 +200,7 @@ function updateDropdownStates(dropdown, show, delay) { } function updateDesktopDropdownStates(dropdown, show, delay) { - let dropdownContent = document.getElementById( - dropdown.id + "-content" - ); + let dropdownContent = document.getElementById(dropdown.id + "-content"); toggleIsActiveState(dropdown, show); if (dropdownContent) { toggleDropdownContentVisibility(dropdownContent, show, delay); @@ -286,7 +284,7 @@ function fetchDropdown(url, id) { const key = `${url}-${id}`; if (fetchedMap[key] === true) return; fetchedMap[key] = true; - + const desktopContainer = document.getElementById(id + "-content"); const mobileContainer = document.getElementById(id); @@ -312,10 +310,7 @@ function fetchDropdown(url, id) { const activeCTAs = mobileContainer.querySelectorAll("a.is-active"); activeCTAs.forEach(deactivateActiveCTA); }); - } else { - resolve(); } - isFetching = false; } /** @@ -373,7 +368,10 @@ function closeMobileDropdown() { const dropdownElements = getAllElements( ".p-navigation__item--dropdown-toggle" ); - removeClassesFromElements([navigation, mainList], ["has-menu-open", "is-active"]); + removeClassesFromElements( + [navigation, mainList], + ["has-menu-open", "is-active"] + ); if (secondaryNav) { toggleSecondaryMobileNavDropdown(); } @@ -407,7 +405,9 @@ function openMenu(e) { // Setup and functions for navigaiton search function initNavigationSearch() { - searchButtons.forEach((searchButton) => searchButton.addEventListener("click", toggleSearch)); + searchButtons.forEach((searchButton) => + searchButton.addEventListener("click", toggleSearch) + ); searchOverlay.addEventListener("click", toggleSearch); @@ -467,8 +467,11 @@ function setUpGlobalNav() { const globalNavMainTab = globalNavTab.querySelector("ul.p-navigation__items"); globalNavMainTab.classList.replace("u-hide", "dropdown-content-mobile"); - globalNavMainTab.classList.replace("p-navigation__items", "p-navigation__dropdown",); - + globalNavMainTab.classList.replace( + "p-navigation__items", + "p-navigation__dropdown" + ); + globalNavMainTab.setAttribute("id", "all-canonical-content-mobile"); globalNavTab @@ -485,7 +488,6 @@ function setUpGlobalNav() { dropdownToggle .querySelector("button.p-navigation__link") .setAttribute("href", `#${newDropdownId}-content-mobile`); - } const tempHTMLContainer = document.createElement("div"); tempHTMLContainer.innerHTML = `
  • @@ -534,7 +536,6 @@ if (accountContainer) { Logout
  • `; - } }); } diff --git a/static/sass/_pattern_navigation-dropdown.scss b/static/sass/_pattern_navigation-dropdown.scss index cee3ac4d532..7e5c799ecd2 100644 --- a/static/sass/_pattern_navigation-dropdown.scss +++ b/static/sass/_pattern_navigation-dropdown.scss @@ -34,10 +34,10 @@ box-shadow: 0 1px 32px 1px transparentize($color-dark, 0.8); flex-direction: column; height: auto; + max-height: calc(100vh - 3rem); + overflow-y: auto; position: fixed; width: 100%; - overflow-y: auto; - max-height: calc(100vh - 3rem); z-index: 11; } @@ -112,23 +112,6 @@ } } - .dropdown-window__side-panel { - margin: 2.5rem 0; - padding: 0; - - .p-list__item { - padding-left: 0.5rem; - - a { - color: #69c; - - &:visited { - color: #a679d2; - } - } - } - } - .dropdown-window__main-panel, .dropdown-window__side-panel { margin: 2.5rem 0; @@ -184,6 +167,25 @@ } } + .dropdown-window__side-panel { + margin: 2.5rem 0; + padding: 0; + + .p-list { + .p-list__item { + padding-left: 0.5rem; + + a.dropdown-window__side-panel-link { + color: #69c; + + &:visited { + color: #a679d2; + } + } + } + } + } + .dropdown-window__sidenav-back { color: $color-light; display: block; diff --git a/static/sass/_pattern_navigation.scss b/static/sass/_pattern_navigation.scss index df912d94afd..5ef383fc86e 100644 --- a/static/sass/_pattern_navigation.scss +++ b/static/sass/_pattern_navigation.scss @@ -2,9 +2,7 @@ $row-margin-medium: 1.5rem; $row-margin-small: 1rem; $meganav-height: 3rem; - @mixin ubuntu-p-navigation { - #all-canonical-mobile .global-nav__header-link-anchor::after { @media (max-width: $breakpoint-small) { right: 1rem !important; @@ -23,38 +21,50 @@ $meganav-height: 3rem; } .global-nav-desktop .global-nav-dropdown { - top: 0; position: relative; + top: 0; .global-nav-dropdown__content { max-width: $grid-max-width; } .global-nav__link { - color: 69c; + color: 69; } } .p-navigation--sliding { - z-index: 40; position: sticky; - top: 0px; - + top: 0; + z-index: 40; + .p-link--inverted { font-weight: 400; } .p-navigation__nav { margin-left: -2rem; - margin-right: 0rem; - width: auto; + margin-right: 0; max-height: calc(100vh - 3rem); + width: auto; .p-navigation__items { width: 100%; @media (max-width: $breakpoint-navigation-threshold) { - &>.p-navigation__item--dropdown-toggle > .p-navigation__link { + .p-navigation__link { + padding-left: calc(1.5rem + $row-margin-medium); + + &::before { + left: calc(1.5rem + $row-margin-medium); + } + + &.js-back::after { + left: $row-margin-medium; + } + } + + & > .p-navigation__item--dropdown-toggle > .p-navigation__link { padding-left: $row-margin-medium; &::before { @@ -66,33 +76,21 @@ $meganav-height: 3rem; &:first-child .p-navigation__link::before { content: ""; } - + &.is-selected > .p-navigation__link::before { content: none; } } - .p-navigation__item--dropdown-toggle:first-of-type, + .p-navigation__item--dropdown-toggle:first-of-type, .p-navigation__item--dropdown-close:first-of-type { > .p-navigation__link::before { content: none; } } - .p-navigation__link { - padding-left: calc(1.5rem + $row-margin-medium); - - &::before { - left: calc(1.5rem + $row-margin-medium); - } - - &.js-back::after { - left: $row-margin-medium; - } - } - .p-navigation__dropdown-item { padding-left: calc(1.5rem + $row-margin-medium); - + &::before { left: calc(1.5rem + $row-margin-medium); } @@ -104,29 +102,29 @@ $meganav-height: 3rem; } @media (max-width: $breakpoint-medium) { - &>.p-navigation__item--dropdown-toggle > .p-navigation__link { - padding-left: $row-margin-small; + .p-navigation__link { + padding-left: calc(1.5rem + $row-margin-small); &::before { + left: calc(1.5rem + $row-margin-small); + } + + &.js-back::after { left: $row-margin-small; } } - .p-navigation__link { - padding-left: calc(1.5rem + $row-margin-small); - + & > .p-navigation__item--dropdown-toggle > .p-navigation__link { + padding-left: $row-margin-small; + &::before { - left: calc(1.5rem + $row-margin-small); - } - - &.js-back::after { left: $row-margin-small; } } - + .p-navigation__dropdown-item { padding-left: calc(1.5rem + $row-margin-small); - + &::before { left: calc(1.5rem + $row-margin-small); } @@ -146,16 +144,16 @@ $meganav-height: 3rem; .p-navigation__banner { padding-left: 0; } - + @media (max-width: $breakpoint-navigation-threshold) { .p-navigation__nav { - overflow-y: auto; margin-left: 0; + overflow-y: auto; } .p-navigation__banner { - padding-left: $row-margin-medium; height: $meganav-height; + padding-left: $row-margin-medium; } } @@ -165,11 +163,10 @@ $meganav-height: 3rem; } } - .row { @media (max-width: $breakpoint-navigation-threshold) { - padding-right: 0; padding-left: 0; + padding-right: 0; } .p-navigation__dropdown { @@ -195,31 +192,28 @@ $meganav-height: 3rem; } } - li.p-navigation__dropdown-item { - line-height: 1.5rem; - margin: 0; - padding-bottom: 0.25rem; - padding-top: 0.25rem; - position: relative; + ul.p-navigation__dropdown { + li.p-navigation__dropdown-item { + line-height: 1.5rem; + margin: 0; + padding-bottom: 0.25rem; + padding-top: 0.25rem; + position: relative; - a { - &:not(.p-button--positive) { - display: block; - padding: 0.25rem 0; - white-space: normal; - } + a { + &:not(.p-button--positive) { + display: block; + padding: 0.25rem 0; + white-space: normal; + } - &:hover { - text-decoration: none; + &:hover { + text-decoration: none; + } } } } - a.p-navigation__dropdown-item { - padding-bottom: 0.75rem; - padding-top: 0.75rem; - } - .p-navigation__item--dropdown-toggle { .p-navigation__account-name { @extend .p-navigation__dropdown-item; @@ -244,11 +238,11 @@ $meganav-height: 3rem; } } } - + &.is-active[role="menuitem"] { @extend .is-selected; - - > .p-navigation__link { + + > a.p-navigation__link { background-color: #2d2d2d; } } @@ -267,7 +261,7 @@ $meganav-height: 3rem; } } - a { + a.p-link--inverted { &::after { @media (min-width: $breakpoint-navigation-threshold) { content: none; @@ -275,7 +269,7 @@ $meganav-height: 3rem; } } - a:not(.is-signed-in) { + a.p-link--inverted:not(.is-signed-in) { &::after { content: none; } @@ -288,11 +282,16 @@ $meganav-height: 3rem; .p-navigation__link::before { &:first-of-type { - content: ""; + content: ""; } } } + a.p-navigation__dropdown-item { + padding-bottom: 0.75rem; + padding-top: 0.75rem; + } + .p-navigation__link::after { top: 1.25rem; @media (max-width: $breakpoint-navigation-threshold) { @@ -303,9 +302,9 @@ $meganav-height: 3rem; .p-navigation__secondary-links { @extend .dropdown-window__side-panel; - - padding-left: calc(1rem + $row-margin-medium) !important; + margin-top: 1.5rem; + padding-left: calc(1rem + $row-margin-medium) !important; @media (max-width: $breakpoint-medium) { padding-left: calc(1rem + $row-margin-small) !important; @@ -314,6 +313,16 @@ $meganav-height: 3rem; } } + .p-navigation--sliding:not(.js-enabled) { + .p-navigation__item--dropdown-toggle > .p-navigation__link { + padding-right: 1rem; + + &::after { + content: none; + } + } + } + .p-navigation--sliding.has-menu-open { height: fit-content; @@ -351,76 +360,9 @@ $meganav-height: 3rem; } } - .p-navigation.is-secondary { - top: 0; - position: sticky; - z-index: 10; - - .p-navigation__nav { - margin-left: -2rem; - } - - .p-navigation__nav.is-open { - display: flex; - - .p-navigation__items { - display: block; - } - - .p-navigation__link { - padding-left: calc(1rem + $row-margin-medium); - - @media (max-width: $breakpoint-medium) { - padding-left: calc(1rem + $row-margin-small); - } - - &::before { - left: $row-margin-small; - } - } - } - - .p-navigation__banner { - padding-left: 0; - } - - @media (max-width: $breakpoint-navigation-threshold) { - .p-navigation__banner { - padding-left: $row-margin-medium; - } - - .row { - padding-right: 0; - padding-left: 0; - } - - .p-navigation__nav { - margin-left: -1rem; - } - } - - @media (max-width: $breakpoint-medium) { - .p-navigation__banner { - padding-left: $row-margin-small; - } - } - - .p-navigation__toggle--open.is-open { - transform: rotate(-180deg); - } - - .p-navigation__tagged-logo { - width: 17.5rem; - - @media (min-width: $breakpoint-x-large) { - width: 19.5rem; - } - } - } - .p-navigation--sliding.is-reduced { - position: relative; margin-bottom: 0; + position: relative; .p-navigation__banner { height: auto; @@ -441,8 +383,8 @@ $meganav-height: 3rem; .p-navigation__tagged-logo { .p-navigation__link { - padding-top: 0.5rem; padding-left: 0; + padding-top: 0.5rem; } } @@ -471,13 +413,14 @@ $meganav-height: 3rem; .p-navigation__item { .p-navigation__link { color: $color-mid-light; - padding: .5rem 2rem .5rem 0; + padding: 0.5rem 2rem 0.5rem 0; } } .p-navigation__link--search-toggle { padding-bottom: 0.5rem; padding-top: 0.5rem; + &::after { color: $color-mid-light; top: 0.75rem; @@ -596,4 +539,104 @@ $meganav-height: 3rem; top: 2.1rem !important; } } + + .p-navigation.is-secondary { + position: sticky; + top: 0; + z-index: 10; + + .p-navigation__nav { + margin-left: -2rem; + } + + .p-navigation__nav.is-open { + display: flex; + + .p-navigation__items { + display: block; + } + + .p-navigation__link { + padding-left: calc(1rem + $row-margin-medium); + + @media (max-width: $breakpoint-medium) { + padding-left: calc(1rem + $row-margin-small); + } + + &::before { + left: $row-margin-small; + } + } + } + + .p-navigation__banner { + padding-left: 0; + } + + @media (max-width: $breakpoint-navigation-threshold) { + .p-navigation__banner { + padding-left: $row-margin-medium; + } + + .row { + padding-left: 0; + padding-right: 0; + } + + .p-navigation__nav { + margin-left: -1rem; + } + } + + @media (max-width: $breakpoint-medium) { + .p-navigation__banner { + padding-left: $row-margin-small; + } + } + + .p-navigation__toggle--open.is-open { + transform: rotate(-180deg); + } + + .p-navigation__tagged-logo { + width: 17.5rem; + + @media (min-width: $breakpoint-x-large) { + width: 19.5rem; + } + } + } +} + +@mixin ubuntu-p-nojs-navigation { + .nojs-meganav { + background: #262626; + overflow-x: unset !important; + + h2 { + color: #f7f7f7; + padding-left: 1.5rem; + } + + .p-side-navigation { + padding-top: 1rem; + } + + .dropdown-window__tab-panel { + height: fit-content; + padding-bottom: 3rem; + position: sticky; + top: 3rem; + } + + .dropdown-window__footer { + padding-bottom: 3rem; + } + + @media (max-width: $breakpoint-navigation-threshold - 1) { + .dropdown-window__tab-panel { + display: none; + } + } + } } diff --git a/static/sass/styles.scss b/static/sass/styles.scss index 766ac418d28..a836d4585ed 100644 --- a/static/sass/styles.scss +++ b/static/sass/styles.scss @@ -121,6 +121,7 @@ $color-shadow: rgba(0, 0, 0, 0.5) !default; @include ubuntu-p-navigation; @include ubuntu-p-navigation-dropdown; @include ubuntu-p-navigation-reduced; +@include ubuntu-p-nojs-navigation; @include ubuntu-p-strip; @include ubuntu-p-ua-payment-modal; @include ubuntu-p-pie-chart; diff --git a/templates/templates/_navigation.html b/templates/templates/_navigation.html index d5e85e16022..aaffc927ab5 100644 --- a/templates/templates/_navigation.html +++ b/templates/templates/_navigation.html @@ -19,35 +19,35 @@ -