diff --git a/libs/blocks/global-navigation/base.css b/libs/blocks/global-navigation/base.css index 9bbffc30c4..f33d21769b 100644 --- a/libs/blocks/global-navigation/base.css +++ b/libs/blocks/global-navigation/base.css @@ -7,30 +7,31 @@ --feds-height-breadcrumbs: 33px; --feds-gutter: 8px; /* Top navigation - backgrounds */ - --feds-background-nav: #fff; - --feds-background-popup: #fafafa; + --feds-background-nav: #F8F8F8; + --feds-background-popup: #F3F3F3; + --feds-background-promo: #FFF; --feds-background-promo--dark: #000; /* Top navigation - borders */ - --feds-borderColor: #eaeaea; - --feds-borderColor-menu: #e1e1e1; - --feds-borderColor-navLink: #2c2c2c; + --feds-borderColor: #EAEAEA; + --feds-borderColor-menu: #E1E1E1; + --feds-borderColor-navLink: #2C2C2C; /* Top navigation - colors */ --feds-color-adobeBrand: #EB1000; --feds-color-headline: #505050; - --feds-color-hamburger: #2d2d2d; - --feds-color-breadcrumbs--current: #2c2c2c; + --feds-color-hamburger: #2D2D2D; + --feds-color-breadcrumbs--current: #2C2C2C; --feds-color-signIn: #4B4B4B; /* Top navigation - misc */ --feds-radius-utilityIcon: 4px; /* Links */ - --feds-background-link--hover: #f5f5f5; - --feds-borderColor-link: #f3f3f3; - --feds-color-link: #2c2c2c; - --feds-color-link--hover: #1473e6; - --feds-color-navLink-description: #656565; + --feds-background-link--hover: #E9E9E9; + --feds-borderColor-link: #E9E9E9; + --feds-color-link: #292929; + --feds-color-link--hover: #274DEA; + --feds-color-navLink-description: #505050; --feds-color-link-breadcrumbs: #707070; /* Footer */ - --feds-background-footer: #fafafa; + --feds-background-footer: #FAFAFA; --feds-borderColor-featuredProducts: #999; --feds-gutter-footer: 32px; } diff --git a/libs/blocks/global-navigation/dark-nav.css b/libs/blocks/global-navigation/dark-nav.css index 9f9caa2819..98326d92b9 100644 --- a/libs/blocks/global-navigation/dark-nav.css +++ b/libs/blocks/global-navigation/dark-nav.css @@ -1,8 +1,8 @@ :root { --text-color: #F2F2F2; --background-color: #111; - --link-color: #1473e6; - --link-hover-color: #1473e6; + --link-color: #1473E6; + --link-hover-color: #1473E6; /* Top navigation - backgrounds */ --feds-background-popup: #111; --feds-background-nav: #222; @@ -11,6 +11,7 @@ --feds-borderColor: #303030; --feds-borderColor-menu: #4B4B4B; --feds-borderColor-navLink: #DBDBDB; + --feds-background-promo: #1D1D1D; /* Top navigation - colors */ --feds-color-adobeBrand: #FFF; --feds-color-headline--mobile: #F2F2F2; @@ -24,8 +25,8 @@ --feds-color-link: #F2F2F2; /* --feds-color-link--mobile: #F2F2F2; */ --feds-color-link--desktop: #DBDBDB; - --feds-color-link--hover: #1473e6; - --feds-color-blue-link: #5eaaf7; + --feds-color-link--hover: #1473E6; + --feds-color-blue-link: #5EAAF7; --feds-color-navLink-description: #B0B0B0; --feds-color-link-breadcrumbs: #B0B0B0; --feds-background-link--hover: #1B1B1B; @@ -166,7 +167,7 @@ @media (min-width: 900px) { .feds--dark .feds-promo { border: 1px solid var(--feds-borderColor); - background: #1D1D1D; + background: var(--feds-background-promo); } .feds--dark .feds-promo--dark, diff --git a/libs/blocks/global-navigation/global-navigation.css b/libs/blocks/global-navigation/global-navigation.css index 90e8f65b0d..c7d6dad911 100644 --- a/libs/blocks/global-navigation/global-navigation.css +++ b/libs/blocks/global-navigation/global-navigation.css @@ -250,15 +250,15 @@ header.global-navigation { } .feds-cta--primary { - background-color: rgb(20, 115, 230); - border-color: rgb(20, 115, 230); + background-color: rgb(59, 99, 251); + border-color: rgb(59, 99, 251); color: rgb(255, 255, 255); } .feds-cta--primary:hover, .feds-cta--primary:focus { - background-color: rgb(13, 102, 208); - border-color: rgb(13, 102, 208); + background-color: rgb(39, 77, 234); + border-color: rgb(39, 77, 234); color: rgb(255, 255, 255); } @@ -665,7 +665,7 @@ header.global-navigation { right: 0; justify-content: center; border-bottom: unset; - box-shadow: 0 3px 2px rgb(142 142 142 / 30%); + border-bottom: 1px solid var(--feds-borderColor); background: var(--feds-background-nav); transform: translate3d(0,0,0); /* Fix Safari issues w/ position: sticky */ } diff --git a/libs/blocks/global-navigation/global-navigation.js b/libs/blocks/global-navigation/global-navigation.js index bc76e60afb..d59c35238d 100644 --- a/libs/blocks/global-navigation/global-navigation.js +++ b/libs/blocks/global-navigation/global-navigation.js @@ -15,6 +15,7 @@ import { getExperienceName, getFedsPlaceholderConfig, hasActiveLink, + isActiveLink, icons, isDesktop, isTangentToViewport, @@ -354,6 +355,7 @@ class Gnav { ${this.decorateBrand()} ${this.elements.navWrapper} + ${getConfig().searchEnabled === 'on' ? toFragment`
` : ''} ${this.useUniversalNav ? this.blocks.universalNav : ''} ${(!this.useUniversalNav && this.blocks.profile.rawElem) ? this.blocks.profile.decoratedElem : ''} ${this.decorateLogo()} @@ -838,7 +840,6 @@ class Gnav { ${isDesktop.matches ? '' : this.decorateSearch()} ${this.elements.mainNav} ${isDesktop.matches ? this.decorateSearch() : ''} - ${getConfig().searchEnabled === 'on' ? toFragment`` : ''} `; @@ -967,21 +968,17 @@ class Gnav { let customLinkModifier = ''; let removeCustomLink = false; const linkElem = item.querySelector('a'); + const customLinksSection = item.closest('.link-group'); linkElem.className = 'feds-navLink'; linkElem.setAttribute('daa-ll', getAnalyticsValue(linkElem.textContent, index + 1)); - if (itemHasActiveLink) { - linkElem.removeAttribute('href'); - linkElem.setAttribute('role', 'link'); - linkElem.setAttribute('aria-disabled', 'true'); - linkElem.setAttribute('aria-current', 'page'); - linkElem.setAttribute('tabindex', 0); - } - const customLinksSection = item.closest('.link-group'); if (customLinksSection) { const removeLink = () => { const url = new URL(linkElem.href); linkElem.setAttribute('href', `${url.origin}${url.pathname}${url.search}`); + if (isActiveLink(linkElem)) { + linkElem.removeAttribute('href'); + } const linkHash = url.hash.slice(2); return !this.customLinks.includes(linkHash); }; @@ -989,6 +986,12 @@ class Gnav { customLinkModifier = ` feds-navItem--${className}`; }); removeCustomLink = removeLink(); + } else if (itemHasActiveLink) { + linkElem.removeAttribute('href'); + linkElem.setAttribute('role', 'link'); + linkElem.setAttribute('aria-disabled', 'true'); + linkElem.setAttribute('aria-current', 'page'); + linkElem.setAttribute('tabindex', 0); } const linkTemplate = toFragment` diff --git a/libs/blocks/global-navigation/utilities/menu/menu.css b/libs/blocks/global-navigation/utilities/menu/menu.css index f9add4aab1..6279aa2e6a 100644 --- a/libs/blocks/global-navigation/utilities/menu/menu.css +++ b/libs/blocks/global-navigation/utilities/menu/menu.css @@ -165,7 +165,7 @@ flex-direction: column; width: 100%; border: 1px solid var(--feds-borderColor); - background: var(--feds-background-nav); + background: var(--feds-background-promo); white-space: normal; box-sizing: content-box; } @@ -223,8 +223,8 @@ width: 100%; display: flex; justify-content: center; - border-top: solid 1px #f3f3f3; - background-color: #fff; + border-top: solid 1px var(--feds-borderColor); + background-color: var(--feds-background-nav); } .feds-crossCloudMenu { diff --git a/libs/blocks/global-navigation/utilities/utilities.js b/libs/blocks/global-navigation/utilities/utilities.js index a5050ea458..2dc258fd0c 100644 --- a/libs/blocks/global-navigation/utilities/utilities.js +++ b/libs/blocks/global-navigation/utilities/utilities.js @@ -266,20 +266,22 @@ export const [setDisableAEDState, getDisableAEDState] = (() => { ]; })(); -export const [hasActiveLink, setActiveLink, getActiveLink] = (() => { +export const [hasActiveLink, setActiveLink, isActiveLink, getActiveLink] = (() => { let activeLinkFound; + const { origin, pathname } = window.location; + const url = `${origin}${pathname}`; return [ () => activeLinkFound, (val) => { activeLinkFound = !!val; }, + (el) => (el.href === url || el.href.startsWith(`${url}?`) || el.href.startsWith(`${url}#`)), (area) => { - const disableAED = getDisableAEDState(); + const isCustomLinks = area.closest('.link-group')?.classList.contains('mobile-only'); + const disableAED = getDisableAEDState() || isCustomLinks; if (disableAED || hasActiveLink() || !(area instanceof HTMLElement)) return null; - const { origin, pathname } = window.location; - const url = `${origin}${pathname}`; const activeLink = [ ...area.querySelectorAll('a:not([data-modal-hash])'), - ].find((el) => (el.href === url || el.href.startsWith(`${url}?`) || el.href.startsWith(`${url}#`))); + ].find(isActiveLink); if (!activeLink) return null; diff --git a/libs/navigation/bootstrapper.js b/libs/navigation/bootstrapper.js index f231b4df6d..d55dc158d6 100644 --- a/libs/navigation/bootstrapper.js +++ b/libs/navigation/bootstrapper.js @@ -1,17 +1,28 @@ export default async function bootstrapBlock(miloLibs, blockConfig) { - const { name, targetEl } = blockConfig; + const { name, targetEl, layout, noBorder, jarvis } = blockConfig; const { getConfig, createTag, loadLink, loadScript } = await import(`${miloLibs}/utils/utils.js`); const { default: initBlock } = await import(`${miloLibs}/blocks/${name}/${name}.js`); const styles = [`${miloLibs}/blocks/${name}/${name}.css`, `${miloLibs}/navigation/navigation.css`]; styles.forEach((url) => loadLink(url, { rel: 'stylesheet' })); + const setNavLayout = () => { + const element = document.querySelector(targetEl); + if (layout === 'fullWidth') { + element.classList.add('feds--full-width'); + } + if (noBorder) { + element.classList.add('feds--no-border'); + } + }; + if (!document.querySelector(targetEl)) { const block = createTag(targetEl, { class: name }); document.body[blockConfig.appendType](block); } // Configure Unav components and redirect uri if (blockConfig.targetEl === 'header') { + setNavLayout(); const metaTags = [ { key: 'unavComponents', name: 'universal-nav' }, { key: 'redirect', name: 'adobe-home-redirect' }, @@ -35,4 +46,43 @@ export default async function bootstrapBlock(miloLibs, blockConfig) { loadPrivacy(getConfig, loadScript); }, blockConfig.delay); } + + /** Jarvis Chat */ + if (jarvis?.id) { + const isChatInitialized = (client) => !!client?.isAdobeMessagingClientInitialized(); + + const redirectToSupport = () => window.location.assign('https://helpx.adobe.com'); + + const isChatOpen = (client) => isChatInitialized(client) && client?.getMessagingExperienceState()?.windowState !== 'hidden'; + + const openChat = (event) => { + const client = window.AdobeMessagingExperienceClient; + + if (!isChatInitialized(client)) { + redirectToSupport(); + return; + } + + const open = client?.openMessagingWindow; + if (typeof open !== 'function' || isChatOpen(client)) { + return; + } + + const sourceType = event?.target.tagName?.toLowerCase(); + const sourceText = sourceType === 'img' ? event.target.alt?.trim() : event.target.innerText?.trim(); + + open(event ? { sourceType, sourceText } : {}); + }; + + const addDomEvents = () => { + document.addEventListener('click', (event) => { + if (!event.target.closest('[href*="#open-jarvis-chat"]')) return; + event.preventDefault(); + openChat(event); + }); + }; + + // Attach DOM events + addDomEvents(); + } } diff --git a/libs/navigation/navigation.css b/libs/navigation/navigation.css index 7accdaca5d..0c9b62bb1f 100644 --- a/libs/navigation/navigation.css +++ b/libs/navigation/navigation.css @@ -1,5 +1,10 @@ /* Extracting the essential styles required for rendering the component independently */ - .global-navigation, .global-footer, .dialog-modal { + :root { + --navigation-link-color: #035FE6; + --navigation-link-color--hover: #136FF6; +} + +.global-navigation, .global-footer, .dialog-modal { font-family: 'Adobe Clean', adobe-clean, 'Trebuchet MS', sans-serif; line-height: 27px; color: #2c2c2c; @@ -12,7 +17,7 @@ } .dialog-modal a { - color: #035FE6; + color: var(--navigation-link-color); } .global-navigation img, .global-footer img { @@ -31,14 +36,23 @@ header.global-navigation, header.global-navigation.feds--dark { @media (min-width: 900px) { .feds-promo-link { - color: #035FE6; + color: var(--navigation-link-color); } + .feds-promo-link:hover { - color: #136FF6; + color: var(--navigation-link-color--hover); } - + + .feds--no-border .feds-topnav-wrapper { + border-bottom: none; + } + .feds--full-width .feds-topnav { max-width: none; padding: 0 15px; } } + +.feds-client-search { + margin-left: auto; +} diff --git a/libs/navigation/navigation.js b/libs/navigation/navigation.js index 993c2399b8..ffc888bc4a 100644 --- a/libs/navigation/navigation.js +++ b/libs/navigation/navigation.js @@ -21,6 +21,18 @@ const envMap = { qa: 'https://gnav--milo--adobecom.hlx.page', }; +const stageDomainsMap = { + 'www.stage.adobe.com': { + 'www.adobe.com': 'origin', + 'helpx.adobe.com': 'helpx.stage.adobe.com', + }, + // Test app + 'adobecom.github.io': { + 'www.adobe.com': 'www.stage.adobe.com', + 'helpx.adobe.com': 'helpx.stage.adobe.com', + }, +}; + function getParamsConfigs(configs) { return blockConfig.reduce((acc, block) => { block.params.forEach((param) => { @@ -66,6 +78,7 @@ export default async function loadBlock(configs, customLib) { contentRoot: authoringPath || footer.authoringPath, theme, ...paramConfigs, + stageDomainsMap, }; setConfig(clientConfig); for await (const block of blockConfig) { @@ -74,7 +87,13 @@ export default async function loadBlock(configs, customLib) { if (configBlock) { await bootstrapBlock(`${miloLibs}/libs`, { ...block, - ...(block.key === 'header' && { unavComponents: configBlock.unav?.unavComponents, redirect: configBlock.redirect }), + ...(block.key === 'header' && { + unavComponents: configBlock.unav?.unavComponents, + redirect: configBlock.redirect, + layout: configBlock.layout, + noBorder: configBlock.noBorder, + jarvis: configBlock.jarvis, + }), }); configBlock.onReady?.(); } diff --git a/test/blocks/global-navigation/global-navigation.test.js b/test/blocks/global-navigation/global-navigation.test.js index d28284a70f..a30b583ed3 100644 --- a/test/blocks/global-navigation/global-navigation.test.js +++ b/test/blocks/global-navigation/global-navigation.test.js @@ -643,13 +643,13 @@ describe('global navigation', () => { describe('Client search feature in global navigation', () => { it('should append the feds-client-search div when search is enabled', async () => { await createFullGlobalNavigation({ customConfig: { searchEnabled: 'on' } }); - expect(document.querySelector(selectors.topNavWrapper).classList.contains('feds-client-search')).to.exist; + expect(document.querySelector(selectors.topNav).classList.contains('feds-client-search')).to.exist; }); }); describe('Custom Links for mobile hamburger menu', () => { it('Add custom links through Link Group block in parallel to large menu\'s', async () => { - const customLinks = 'home,learn'; + const customLinks = 'home,apps,learn'; await createFullGlobalNavigation({ viewport: 'mobile', globalNavigation: navigationWithCustomLinks, diff --git a/test/blocks/global-navigation/mocks/navigation-with-custom-links.plain.js b/test/blocks/global-navigation/mocks/navigation-with-custom-links.plain.js index b58cb5259b..2c8dc0f1ec 100644 --- a/test/blocks/global-navigation/mocks/navigation-with-custom-links.plain.js +++ b/test/blocks/global-navigation/mocks/navigation-with-custom-links.plain.js @@ -46,7 +46,7 @@ export default `