From 9cd5899d01c76c7b26aa4546a8fc1e91c01adcca Mon Sep 17 00:00:00 2001 From: Brett Cooper Date: Wed, 12 Jul 2023 11:11:34 -0600 Subject: [PATCH 1/4] Updated site-header markup. --- parts/site-header.html | 50 ++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/parts/site-header.html b/parts/site-header.html index dfe55ed3..4de692b9 100644 --- a/parts/site-header.html +++ b/parts/site-header.html @@ -1,29 +1,21 @@ - -
-
- -
- -
- - - -
- -
- -
- -
- - - -
- - - -
- -
- \ No newline at end of file + +
+
+
+
+ + + +
+
+
+ + + +
+
+ + + +
+ \ No newline at end of file From 2badd37a1d025d1af14ae400c6ec1a7f696b6d8f Mon Sep 17 00:00:00 2001 From: Brett Cooper Date: Wed, 12 Jul 2023 11:12:39 -0600 Subject: [PATCH 2/4] Updated JS behavior. --- src/js/components/main-nav.js | 155 ++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 44 deletions(-) diff --git a/src/js/components/main-nav.js b/src/js/components/main-nav.js index b60d2675..6b96153d 100644 --- a/src/js/components/main-nav.js +++ b/src/js/components/main-nav.js @@ -8,23 +8,102 @@ import state from '../config/state'; import { NAVIGATION_BREAKPOINT } from '../config/options'; import * as bodyLock from '../utils/body-lock'; -// Cache some elements. +// Cache some elements and state. const cache = { desktopBreakpoint: NAVIGATION_BREAKPOINT, + trussHeader: null, + stickyHeader: null, + stickyHeaderObserver: null, nav: null, + navIsOpen: false, navToggle: null, menuItems: [], }; +/** + * Show the main-nav menu on mobile. + */ +const showMenu = () => { + // Stop observing the sticky header when we open the menu, because it's going + // to float to the top of the viewport and not reflect our actual scroll + // position. + cache.stickyHeaderObserver.unobserve( cache.stickyHeader ); + bodyLock.lock(); + + document.documentElement.classList.add( 'main-nav--is-open' ); + if ( ! cache.navIsOpen ) { + document.documentElement.classList.add( 'main-nav--is-opening' ); + } + + cache.nav.setAttribute( 'aria-hidden', false ); + cache.navToggle.setAttribute( 'aria-label', 'Hide main navigation menu' ); + cache.navIsOpen = true; +}; + +/** + * Hide the main-nav menu on mobile. + */ +const hideMenu = () => { + document.documentElement.classList.remove( 'main-nav--is-open' ); + if ( cache.navIsOpen ) { + document.documentElement.classList.add( 'main-nav--is-closing' ); + } + + cache.nav.setAttribute( 'aria-hidden', true ); + cache.navToggle.setAttribute( 'aria-label', 'Show main navigation menu' ); + + // Reset submenus when the main nav is hidden. + cache.menuItems.forEach( ( data ) => { + deactivateMenuItem( data ); + } ); + + // If we unlock the body before our closing animation completes, the scroll + // position will be off in some cases. For that reason, we unlock the body in + // our transitionended event handler. However, if the nav is already hidden, + // no transition will occur, so we handle that here. + if ( ! cache.navIsOpen && bodyLock.isLocked() ) { + bodyLock.unlock(); + } + + cache.stickyHeaderObserver.observe( cache.stickyHeader ); + cache.navIsOpen = false; +}; + +/** + * Toggle the main-nav menu on mobile. + */ +const toggleMenu = () => { + if ( cache.navIsOpen ) { + hideMenu(); + } else { + showMenu(); + } +}; + /** * Add JS behaviors to the main-nav menu. */ -function initMainNav() { +const initMainNav = () => { cache.nav = document.querySelector( '[data-js="main-nav"]' ); if ( ! cache.nav ) { return; } + // Observer when our sticky header becomes "stuck". + cache.stickyHeader = document.querySelector( '.header-region' ); + cache.stickyHeaderObserver = new window.IntersectionObserver( + ( entries ) => { + document.documentElement.classList.toggle( + 'header-region--stuck', + entries[ 0 ].intersectionRatio < 1 + ); + }, + { + threshold: 1, + rootMargin: '-1px 0px 0px 0px', + } + ); + // Get our mobile-to-desktop breakpoint. const breakpoint = window .getComputedStyle( cache.nav ) @@ -34,17 +113,24 @@ function initMainNav() { cache.desktopBreakpoint = parseInt( breakpoint ); } + // Update CSS classes for navigation animation states. + const navigation = document.querySelector( '.site-header__navigation' ); + navigation.addEventListener( 'transitionend', () => { + document.documentElement.classList.remove( + 'main-nav--is-opening', + 'main-nav--is-closing' + ); + // Unlock the body after the nav is closed. + if ( ! cache.navIsOpen && bodyLock.isLocked() ) { + bodyLock.unlock(); + } + } ); + // Add mobile nav toggle. cache.navToggle = document.querySelector( '.site-header__navigation-toggle' ); - cache.navToggle.addEventListener( 'click', () => { - if ( document.body.classList.contains( 'main-nav--is-open' ) ) { - hideMenu(); - } else { - showMenu(); - } - } ); + cache.navToggle.addEventListener( 'click', toggleMenu ); // Add menu item behaviors. cache.nav @@ -108,51 +194,26 @@ function initMainNav() { // Start closed. hideMenu(); -} - -/** - * Show the main-nav menu on mobile. - */ -function showMenu() { - bodyLock.lock(); - document.body.classList.add( 'main-nav--is-open' ); - cache.nav.setAttribute( 'aria-hidden', false ); - cache.navToggle.setAttribute( 'aria-label', 'Hide main navigation menu' ); -} - -/** - * Hide the main-nav menu on mobile. - */ -function hideMenu() { - bodyLock.unlock(); - document.body.classList.remove( 'main-nav--is-open' ); - cache.nav.setAttribute( 'aria-hidden', true ); - cache.navToggle.setAttribute( 'aria-label', 'Show main navigation menu' ); - - // Reset submenus on hide. - cache.menuItems.forEach( ( data ) => { - deactivateMenuItem( data ); - } ); -} +}; /** * Check if our main-nav menu is in mobile mode (vs desktop mode). */ -function menuIsMobile() { +const menuIsMobile = () => { return ( Math.max( document.documentElement.clientWidth || 0, window.innerWidth || 0 ) < cache.desktopBreakpoint ); -} +}; /** * Update a top-level menu item's active status. * * @param {Object} data The menu item data object from cache.menuItems. */ -function updateMenuItem( data ) { +const updateMenuItem = ( data ) => { // On mobile, only open menu items when the associated toggle button is // pressed. if ( menuIsMobile() ) { @@ -168,14 +229,14 @@ function updateMenuItem( data ) { } else if ( ! data.isActive && shouldBeActive ) { activateMenuItem( data ); } -} +}; /** * Mark a top-level menu item as active and show its submenu if it has one. * * @param {Object} data The menu item data object from cache.menuItems. */ -function activateMenuItem( data ) { +const activateMenuItem = ( data ) => { data.menuItem.classList.add( 'menu-item--is-active' ); if ( data.submenu ) { data.submenu.setAttribute( 'aria-hidden', false ); @@ -185,14 +246,14 @@ function activateMenuItem( data ) { } ); } data.isActive = true; -} +}; /** * Mark a top-level menu item as inactive and hide its submenu if it has one. * * @param {Object} data The menu item data object from cache.menuItems. */ -function deactivateMenuItem( data ) { +const deactivateMenuItem = ( data ) => { data.menuItem.classList.remove( 'menu-item--is-active' ); if ( data.submenu ) { data.submenu.setAttribute( 'aria-hidden', true ); @@ -202,11 +263,17 @@ function deactivateMenuItem( data ) { } ); } data.isActive = false; -} +}; const handleResize = () => { - const navElement = document.querySelector( '[data-js="main-nav"]' ); + // Find the site header height. + const siteHeader = document.querySelector( '.site-header__header' ); + document.documentElement.style.setProperty( + '--site-header-height', + siteHeader.clientHeight + 'px' + ); + const navElement = document.querySelector( '[data-js="main-nav"]' ); if ( state.v_width >= NAVIGATION_BREAKPOINT ) { navElement.setAttribute( 'aria-hidden', 'false' ); return; From 03d18b66ac771ac6ef886c0213a7527b1ca232c7 Mon Sep 17 00:00:00 2001 From: Brett Cooper Date: Wed, 12 Jul 2023 11:13:04 -0600 Subject: [PATCH 3/4] Updated styles. --- src/scss/theme-regions/_site-header.scss | 89 +++++++++++++++++++----- 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/src/scss/theme-regions/_site-header.scss b/src/scss/theme-regions/_site-header.scss index 921499b7..8efa374b 100644 --- a/src/scss/theme-regions/_site-header.scss +++ b/src/scss/theme-regions/_site-header.scss @@ -1,29 +1,65 @@ // Site Header +//////////////////////////////////////////////////////////////////////////////// +// Truss Header +//////////////////////////////////////////////////////////////////////////////// + +// In order for the sticky header to show at the top of the viewport while +// open on mobile, the Truss header above it needs to collapse. +.sc-trss-ucsc-header-h { + display: grid; + grid-template-rows: 1fr; + transition: grid-template-rows 0.2s ease; + background-color: var(--wp--preset--color--ucsc-royal-blue); + + .main-nav--is-open & { + grid-template-rows: 0fr; + } + + .main-nav--is-open &, + .main-nav--is-closing & { + + .trss-ucsc-header { + overflow: hidden; + } + } + + .header-region--stuck & { + grid-template-rows: 1fr; + + .trss-ucsc-header { + overflow: auto; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Header Region +//////////////////////////////////////////////////////////////////////////////// + .header-region { position: sticky; top: 0; z-index: 10; width: 100%; - max-height: 100vh; - overflow-x: hidden; - overflow-y: auto; - background-color: var(--wp--preset--color--white); + background-color: var(--wp--preset--color--ucsc-royal-blue); box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); - // At this breakpoint, the WP admin bar is also sticky. - @media (min-width: 783px) { - top: var(--wp-admin--admin-bar--height, 0); - } - @include media-query($desktop-menu) { + background-color: var(--wp--preset--color--white); overflow: visible; } } +//////////////////////////////////////////////////////////////////////////////// +// Site Header Template +//////////////////////////////////////////////////////////////////////////////// + .site-header { position: relative; +} +.site-header__header { // Leave room for the main nav menu toggle button. > .wp-block-group:first-child { padding-right: 60px; @@ -55,7 +91,8 @@ .site-header__separator { margin: 0; - height: 2px !important; + border-bottom: 2px solid !important; + height: 0 !important; } //////////////////////////////////////////////////////////////////////////////// @@ -63,7 +100,7 @@ //////////////////////////////////////////////////////////////////////////////// .site-header__inner { - margin-top: 0; + margin: 0; padding: 0; @include media-query($desktop-menu) { @@ -142,6 +179,29 @@ margin: 0 !important; color: var(--wp--preset--color--white); + background-color: var(--wp--preset--color--ucsc-royal-blue); + overflow: hidden; + width: 100%; + position: absolute; + height: 0; + transition: height 0.2s ease; + + // CASE: The mobile nav is open or opening. + .main-nav--is-open & { + height: calc(100svh - var(--site-header-height)); + } + + // CASE: The mobile nav's opening animation is complete and it is fully open. + .main-nav--is-open:not(.main-nav--is-opening) & { + overflow: auto; + } + + @include media-query($desktop-menu) { + height: auto; + position: static; + background-color: transparent; + overflow: visible; + } .menu-item { list-style: none; @@ -224,21 +284,16 @@ .site-header__navigation .menu { margin: 0; padding: 0; - display: none; + display: flex; flex-direction: column; @include media-query($desktop-menu) { flex-direction: row; flex-wrap: wrap; - display: flex; max-width: var(--wp--style--global--content-size); margin-left: auto; margin-right: auto; } - - .main-nav--is-open & { - display: flex; - } } //////////////////////////////////////////////////////////////////////////////// From 5039a6d12654698634bd84677521a1bbf2c24406 Mon Sep 17 00:00:00 2001 From: Brett Cooper Date: Wed, 19 Jul 2023 08:15:31 -0600 Subject: [PATCH 4/4] Swapped site title in for site logo. --- parts/site-header.html | 6 +++--- src/scss/theme-regions/_site-header.scss | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/parts/site-header.html b/parts/site-header.html index 4de692b9..383b5cff 100644 --- a/parts/site-header.html +++ b/parts/site-header.html @@ -2,9 +2,9 @@
-
- - +
+ +
diff --git a/src/scss/theme-regions/_site-header.scss b/src/scss/theme-regions/_site-header.scss index 8efa374b..f93a39e6 100644 --- a/src/scss/theme-regions/_site-header.scss +++ b/src/scss/theme-regions/_site-header.scss @@ -231,11 +231,17 @@ } //////////////////////////////////////////////////////////////////////////////// -// Logo +// Site title //////////////////////////////////////////////////////////////////////////////// -.ucsc__logo a:hover { - transform: none; +.site-header .wp-block-site-title a { + color: var(--wp--preset--color--white); + transition: 0.2s ease; + + &:hover, + &:focus-visible { + color: var(--wp--preset--color--ucsc-primary-yellow); + } } ////////////////////////////////////////////////////////////////////////////////