From 37c14c10b9760ee5df394844021e8b71d0e680c8 Mon Sep 17 00:00:00 2001 From: AndyEPhipps Date: Mon, 2 Dec 2024 16:40:30 +0000 Subject: [PATCH] Reset to old nav --- .../Header/Burger/BurgerMenu.style.js | 1 - src/components/Organisms/Header/Header.js | 22 +- src/components/Organisms/Header/Header.md | 281 +----------------- .../Organisms/Header/Header.style.js | 65 +--- src/components/Organisms/Header/Nav/Nav.js | 183 ++++++++++++ .../Organisms/Header/Nav/Nav.style.js | 245 +++++++++++++++ .../Organisms/Header/Nav/chevron-down.svg | 3 + src/components/Organisms/Header/data/data.js | 144 +++++---- 8 files changed, 548 insertions(+), 396 deletions(-) create mode 100644 src/components/Organisms/Header/Nav/Nav.js create mode 100644 src/components/Organisms/Header/Nav/Nav.style.js create mode 100644 src/components/Organisms/Header/Nav/chevron-down.svg diff --git a/src/components/Organisms/Header/Burger/BurgerMenu.style.js b/src/components/Organisms/Header/Burger/BurgerMenu.style.js index 81789fcaf..1b6de22e6 100644 --- a/src/components/Organisms/Header/Burger/BurgerMenu.style.js +++ b/src/components/Organisms/Header/Burger/BurgerMenu.style.js @@ -50,7 +50,6 @@ const BurgerWrapper = styled(Link)` ::after { width: 25px; height: 3px; - border-radius: 3px; display: inline-block; } diff --git a/src/components/Organisms/Header/Header.js b/src/components/Organisms/Header/Header.js index efdc76ffa..c1d0253d9 100644 --- a/src/components/Organisms/Header/Header.js +++ b/src/components/Organisms/Header/Header.js @@ -2,36 +2,30 @@ import React from 'react'; import PropTypes from 'prop-types'; import Logos from '../../Molecules/Logos/Logos'; -import HeaderNav from './HeaderNav/HeaderNav'; +import MainNav from './Nav/Nav'; import { - Brand, HeaderWrapper, InnerWrapper, DonateButtonWrapperTop, HeaderMetaIcons, ButtonsAndIcons + Brand, HeaderWrapper, InnerWrapper, MetaIcons } from './Header.style'; const Header = ({ - navItems = {}, metaIcons, campaign = 'Comic Relief', donateButton = null, ...rest + navItems = {}, metaIcons, campaign = 'Comic Relief', ...rest }) => ( - + - - - {metaIcons} - {donateButton} - - + + {metaIcons} ); Header.propTypes = { - // Check data structure example in src/components/moleculecules/header/data/data + /** Check data structure example in file src/components/moleculecules/header/data/data */ navItems: PropTypes.objectOf(PropTypes.shape), - // NB: metaIcons no longer include the Donate button: + /** it can be icons, buttons */ metaIcons: PropTypes.node.isRequired, - // ... and is supplied separately to allow more render control: - donateButton: PropTypes.node, campaign: PropTypes.string }; diff --git a/src/components/Organisms/Header/Header.md b/src/components/Organisms/Header/Header.md index a5d4cbb88..0406b5971 100644 --- a/src/components/Organisms/Header/Header.md +++ b/src/components/Organisms/Header/Header.md @@ -7,9 +7,9 @@ import Link from '../../Atoms/Link/Link';
- + Donate @@ -26,9 +26,9 @@ import Link from '../../Atoms/Link/Link';
- + Donate @@ -45,9 +45,9 @@ import Link from '../../Atoms/Link/Link';
- + Donate @@ -87,15 +87,12 @@ const [success, setSuccess] = React.useState(false);
- + Donate - - } - metaIcons={ - <> +
@@ -114,7 +109,7 @@ const [success, setSuccess] = React.useState(false); />; ``` -# Comic Relief full header #1 +# Comic Relief header with Search and Shop ```js import data from './data/data'; @@ -122,7 +117,6 @@ import Link from '../../Atoms/Link/Link'; import searchIcon from './assets/icon--search--2023.svg'; import shopIcon from './assets/icon--shop--2023.svg'; import payinIcon from './assets/PayIn.svg'; -import esuIcon from './assets/Post.svg'; import Icon from '../../Atoms/SocialIcons/Icon/Icon'; import RichText from '../../Atoms/RichText/RichText'; @@ -147,59 +141,14 @@ const successCopy = ( initialState = { isSuccess: false }; const [success, setSuccess] = React.useState(false); -<>
- + Donate - - } - metaIcons={ - <> -
- -
-
- -
- -
- -
-
- - } -/> -
- -
-; -``` - -# Comic Relief full header #2 - -```js -import data from './data/data-extended'; -import Link from '../../Atoms/Link/Link'; -import searchIcon from './assets/icon--search--2023.svg'; -import shopIcon from './assets/icon--shop--2023.svg'; -import payinIcon from './assets/PayIn.svg'; -import esuIcon from './assets/Post.svg'; - -import Icon from '../../Atoms/SocialIcons/Icon/Icon'; -import RichText from '../../Atoms/RichText/RichText'; - -const title = 'Stay in the know!'; -const topCopy = ( - Get regular email updates and info on what we're up to!

`} - /> -); -const privacyCopy = ( - Our Privacy Policy describes how we handle and protect your information.

If you are under 18, please make sure you have your parents’ permission before providing us with any personal details.

`} - /> -); -const successCopy = ( - Thanks! Your first email will be with you shortly

`} - /> -); - -initialState = { isSuccess: false }; -const [success, setSuccess] = React.useState(false); - -<> -
- - Donate - - - } - metaIcons={ - <> -
- -
-
-
-
-
- -
- -
- - } -/> -
- -
-; -``` - -# Comic Relief full header #3: nav items as per 19/11/24 - -```js -import data from './data/data-live'; -import Link from '../../Atoms/Link/Link'; -import searchIcon from './assets/icon--search--2023.svg'; -import shopIcon from './assets/icon--shop--2023.svg'; -import payinIcon from './assets/PayIn.svg'; -import esuIcon from './assets/Post.svg'; - -import Icon from '../../Atoms/SocialIcons/Icon/Icon'; -import RichText from '../../Atoms/RichText/RichText'; - -const title = 'Stay in the know!'; -const topCopy = ( - Get regular email updates and info on what we're up to!

`} - /> -); -const privacyCopy = ( - Our Privacy Policy describes how we handle and protect your information.

If you are under 18, please make sure you have your parents’ permission before providing us with any personal details.

`} - /> -); -const successCopy = ( - Thanks! Your first email will be with you shortly

`} - /> -); - -initialState = { isSuccess: false }; -const [success, setSuccess] = React.useState(false); - -<> -
- - Donate - - - } - metaIcons={ - <> -
-
-
- -
- -
- -
-
} -/> -
- -
-; +/>; ``` diff --git a/src/components/Organisms/Header/Header.style.js b/src/components/Organisms/Header/Header.style.js index f9005d183..eb818e65d 100644 --- a/src/components/Organisms/Header/Header.style.js +++ b/src/components/Organisms/Header/Header.style.js @@ -4,8 +4,6 @@ import zIndex from '../../../theme/shared/zIndex'; import containers from '../../../theme/shared/containers'; import spacing from '../../../theme/shared/spacing'; -import './annoying.css'; - const HeaderWrapper = styled.header.attrs(() => ({ role: 'banner' }))` @@ -49,57 +47,32 @@ const Brand = styled.div` border: 0; } } - - @media ${({ theme }) => theme.allBreakpoints('Nav')} { - margin-right: 0 - } `; -const DonateButtonWrapperTop = styled.div` - width: 120px; +const MetaIcons = styled.div` + width: auto; display: flex; - justify-content: center; - - // Donate button - a { - width: 90%; - transition: width 0.4s cubic-bezier(0.5, 1.5, 0.5, 0.80); - - &:hover, - &:focus { - width: 100%; - box-shadow: rgba(0, 0, 0, 0.1) 0 0 20px 0; - } - } -`; - -const HeaderMetaIcons = styled.div` - // Hide these when using the mobile navigation, - // now only rendered in the HeaderNav - display: none; + align-items: center; - @media ${({ theme }) => theme.allBreakpoints('Nav')} { + > div { + height: 35px; width: auto; - align-items: center; + display: inline-block; + + > a { + height: inherit; + width: inherit; + margin-left: 0.5rem; - > div { - height: 35px; - width: auto; - display: inline-block; - - > a { + img { + padding: 5px; height: inherit; width: inherit; - margin-right: 20px; - - img { - padding: 5px; - height: inherit; - width: inherit; - } } } + } + @media ${({ theme }) => theme.allBreakpoints('Nav')} { position: relative; display: flex; align-items: center; @@ -109,12 +82,6 @@ const HeaderMetaIcons = styled.div` } `; -const ButtonsAndIcons = styled.div` - margin-left: auto; - display: flex; - // -`; - export { - Brand, HeaderWrapper, InnerWrapper, DonateButtonWrapperTop, HeaderMetaIcons, ButtonsAndIcons + Brand, HeaderWrapper, InnerWrapper, MetaIcons }; diff --git a/src/components/Organisms/Header/Nav/Nav.js b/src/components/Organisms/Header/Nav/Nav.js new file mode 100644 index 000000000..529649cc3 --- /dev/null +++ b/src/components/Organisms/Header/Nav/Nav.js @@ -0,0 +1,183 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; + +import Text from '../../../Atoms/Text/Text'; +import BurgerMenu from '../Burger/BurgerMenu'; +import { breakpointValues } from '../../../../theme/shared/allBreakpoints'; +import { NavHelper } from '../../../../utils/navHelper'; +import { InternalLinkHelper } from '../../../../utils/internalLinkHelper'; +import allowListed from '../../../../utils/allowListed'; +import chevronDown from './chevron-down.svg'; + +import { + Nav, + NavMenu, + NavItem, + NavLink, + SubNavMenu, + SubNavItem, + SubNavLink, + SubNavLinkUnderline, + ChevronWrapper +} from './Nav.style'; + +const MainNav = ({ navItems = {} }) => { + const { menuGroups } = navItems; + const [isExpandable, setIsExpandable] = useState(false); + const [isSubMenuOpen, setIsSubMenuOpen] = useState({}); + const [isKeyPressed, setIsKeyPressed] = useState({}); + + const [isMobile, setIsMobile] = useState(false); + + const toggleBurgerMenu = event => { + event.preventDefault(); + setIsExpandable(!isExpandable); + }; + + const toggleSubMenu = (e, item) => { + e.preventDefault(); + setIsSubMenuOpen({ [item]: !isSubMenuOpen[item] }); + }; + + // Handle tab key on menu nav + const keyPressed = item => () => { + window.onkeyup = e => { + if ( + e.target.querySelector('span') + && e.target.querySelector('span').innerText === item + ) { + setIsKeyPressed({ [item]: !isKeyPressed[item] }); + } else if (!e.target.querySelector('span')) { + setIsKeyPressed({}); + } + }; + }; + + useEffect(() => { + const width = window.innerWidth; + setIsMobile(width < breakpointValues.Nav); + window.addEventListener('onkeyup', setIsKeyPressed); + + return () => { + window.removeEventListener('onkeyup', setIsKeyPressed); + }; + }, []); + return ( + <> + + + Open + + + ); +}; + +MainNav.propTypes = { + navItems: PropTypes.objectOf(PropTypes.shape) +}; + +export default MainNav; diff --git a/src/components/Organisms/Header/Nav/Nav.style.js b/src/components/Organisms/Header/Nav/Nav.style.js new file mode 100644 index 000000000..94a99aed0 --- /dev/null +++ b/src/components/Organisms/Header/Nav/Nav.style.js @@ -0,0 +1,245 @@ +import styled from 'styled-components'; + +import Link from '../../../Atoms/Link/Link'; +import hideVisually from '../../../../theme/shared/hideVisually'; +import zIndex from '../../../../theme/shared/zIndex'; + +const NavLinkClass = styled(Link)` + display: inline-block; + border: 0; + padding: 17px 20px; + line-height: 1.3rem; + height: 46px; + font-weight: 700; + width: 100%; + color: ${({ theme }) => theme.color('deep_violet_dark')}; + :hover { + border: 0; + color: ${({ theme }) => theme.color('deep_violet_dark')}; + font-weight: inherit; + } +`; + +/** + * Navigation menu + */ +const Nav = styled.nav` + display: ${({ isExpandable }) => (isExpandable ? 'block' : 'none')}; + width: 100%; + position: absolute; + top: 75px; + left: 0; + ${zIndex('higher')}; + + @media ${({ theme }) => theme.allBreakpoints('M')} { + width: 50%; + right: 0; + left: inherit; + } + + @media ${({ theme }) => theme.allBreakpoints('Nav')} { + ${zIndex('medium')}; + position: relative; + top: 0; + display: block; + margin: 0 10px; + width: auto; + height: 100%; + } + > h2 { + ${hideVisually}; + } +`; + +/** + * Sub Navigation Menu (second level) + */ +const SubNavMenu = styled.ul` + display: ${({ isSubMenuOpen }) => (isSubMenuOpen ? 'flex' : 'none')}; + padding: 0; + position: relative; + list-style: none outside; + left: 0; + top: 0; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: ${({ theme }) => theme.color('deep_violet_dark')}; + + @media ${({ theme }) => theme.allBreakpoints('Nav')} { + display: none; + display: ${({ isKeyPressed }) => (isKeyPressed ? 'flex' : 'none')}; + top: 90px; + position: absolute; + padding: 0 0 20px; + width: 250px; + height: auto; + } +`; + +/** + * Sub Menu list items + */ +const SubNavItem = styled.li` + padding: 0; + height: 100%; + width: 100%; + :hover { + background-color: ${({ theme }) => theme.color('deep_violet_light')}; + span { + border-bottom: 0; + padding-bottom: 2px; + color: ${({ theme }) => theme.color('white')}; + } + } +`; + +/** + * Sub menu link item + */ +const SubNavLink = styled(NavLinkClass)` + padding: 14px 14px 7px 21px; + color: ${({ theme }) => theme.color('white')}; + height: auto; + position: relative; +`; + +/** + * Sub menu link item underline + */ +const SubNavLinkUnderline = styled(SubNavLink)` + padding: 26px 21px; + ::after { + content: ''; + position: absolute; + width: 14px; + border-bottom: 2px solid ${({ theme }) => theme.color('white')}; + left: 12px; + top: auto; + bottom: 10px; + margin: 0 10px; + } + @media ${({ theme }) => theme.allBreakpoints('Nav')} { + ::before { + display: block; + position: absolute; + content: ''; + left: 34px; + width: 10px; + height: 10px; + border: 11px solid transparent; + border-bottom-color: ${({ theme }) => theme.color('deep_violet_dark')}; + top: -22px; + } + :hover::before { + border-bottom-color: ${({ theme }) => theme.color('deep_violet_light')}; + } + } +`; + +/** + * Navigation Menu (first level) + */ +const NavMenu = styled.ul` + background-color: ${({ theme }) => theme.color('grey_extra_light')}; + list-style: none outside; + padding: 0; + margin: 0; + + @media ${({ theme }) => theme.allBreakpoints('Nav')} { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: flex-start; + background-color: ${({ theme }) => theme.color('white')}; + } +`; + +/** + * Menu item link + */ +const NavLink = styled(NavLinkClass)` + display: flex; + gap: 4px; + font-family: ${({ theme }) => theme.fontFamilies(theme.font.regular)}; + @media ${({ theme }) => theme.allBreakpoints('Nav')} { + padding: 10px 0; + height: auto; + :focus + ${SubNavMenu} { + display: flex; + } + } +`; + +/** + * Menu list items + */ +const NavItem = styled.li` + ${zIndex('medium')}; + position: relative; + font-weight: 700; + :hover { + li { + span { + border-bottom: none; + padding-bottom: 0; + } + } + } + li { + span { + border-bottom: none; + padding-bottom: 0; + } + :hover { + span { + border-bottom: none; + padding-bottom: 0; + } + } + } + :hover { + background-color: ${({ theme }) => theme.color('teal_light')}; + } + @media ${({ theme }) => theme.allBreakpoints('Nav')} { + margin: 0 4px; + padding: 25px 5px; + + :hover > ${SubNavMenu}, :focus-within > ${SubNavMenu} { + visibility: visible; + opacity: 1; + display: flex; + } + + :hover { + background-color: transparent; + ${zIndex('high')}; + span { + border-bottom: 2px solid ${({ theme }) => theme.color('black')}; + padding-bottom: 2px; + } + ${SubNavMenu} { + display: flex; + flex-direction: column; + } + } + } +`; + +const ChevronWrapper = styled.div` + width: 12px; + padding-top: 2px; +`; + +export { + Nav, + NavMenu, + NavItem, + NavLink, + SubNavMenu, + SubNavItem, + SubNavLink, + SubNavLinkUnderline, + ChevronWrapper +}; diff --git a/src/components/Organisms/Header/Nav/chevron-down.svg b/src/components/Organisms/Header/Nav/chevron-down.svg new file mode 100644 index 000000000..8c74e21c4 --- /dev/null +++ b/src/components/Organisms/Header/Nav/chevron-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Organisms/Header/data/data.js b/src/components/Organisms/Header/data/data.js index 5f3a2e91e..98d161a1d 100644 --- a/src/components/Organisms/Header/data/data.js +++ b/src/components/Organisms/Header/data/data.js @@ -2,66 +2,60 @@ export default { title: 'Header', menuGroups: [ { - title: 'GROUP1', - id: 'group1', + title: 'Fundraising - menu group', + id: 'f7dc5eef-f4eb-5405-8a35-08808b55cb33', links: [ { - title: 'Sport Relief', + title: 'Fundraising', path: 'https://www.comicrelief.com/fundraising/pay-in-your-money', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Run 30 Miles in June', + title: 'Red Nose Day', path: 'https://www.comicrelief.com/rednoseday', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Be a Good Sport: Schools', + title: 'Regular donations', path: 'https://www.comicrelief.com/join', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Win a trip to New York with Major League Baseball', + title: 'Squads', path: 'https://www.comicrelief.com/squads', internal: { type: 'ContentfulPageLandingPage' } - } - ] - }, - { - title: 'GROUP2', - id: 'group2', - links: [ - { - title: 'Red Nose Day', - path: 'https://www.comicrelief.com/rednoseday/schools', - internal: { - type: 'ContentfulPageLandingPage' - } }, { - title: 'The New Red Nose', - path: 'https://www.comicrelief.com/rednoseday/schools', + title: 'The Noseys', + path: 'https://www.comicrelief.com/rednoseday/fundraising/the-noseys', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Schools', - path: 'https://www.comicrelief.com/rednoseday/schools', + title: 'Free downloads', + path: + 'https://www.comicrelief.com/rednoseday/fundraising/free-downloads', internal: { type: 'ContentfulPageLandingPage' } - }, + } + ] + }, + { + title: 'Schools & youth - menu group', + id: 'eaec51921-bbb3-5e8d-b966-c53fff34998b5', + links: [ { - title: 'The Red Nose Day Nosey Awards', + title: 'Single menu link', path: 'https://www.comicrelief.com/rednoseday/schools', internal: { type: 'ContentfulPageLandingPage' @@ -70,62 +64,69 @@ export default { ] }, { - title: 'GROUP3', - id: 'group3', + title: 'What your money does - menu group', + id: '9f3980f3-d02b-52e9-ac41-933a778c040a', links: [ { - title: 'Funding', + title: 'What your money does', path: 'https://www.comicrelief.com/what-your-money-does', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Our Funding Practice', - path: 'https://www.comicrelief.com/our-legacy', + title: 'Our legacy', + path: 'https://www.comicrelief.com/What-we-do/our-legacy', + internal: { + type: 'ContentfulPageLandingPage' + } + } + ] + }, + { + title: 'Schools & youth - menu group', + id: 'eaec5191-bbb3-5e8d-b966-c53fff34998b', + links: [ + { + title: 'Schools & youth', + path: 'https://www.comicrelief.com/rednoseday/schools', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Funding opportunities', - path: 'https://www.comicrelief.com/our-legacy', + title: 'Primary schools', + path: + 'https://www.comicrelief.com/rednoseday/schools/primary-schools', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Our Funding strategy', - path: 'https://www.comicrelief.com/our-legacy', + title: 'Secondary schools', + path: + 'https://www.comicrelief.com/rednoseday/schools/secondary-schools', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Managing your funding', - path: 'https://www.comicrelief.com/our-legacy', + title: 'Nurseries', + path: 'https://www.comicrelief.com/rednoseday/schools/nurseries', internal: { type: 'ContentfulPageLandingPage' } - } - ] - }, - { - title: 'GROUP4', - id: 'group4', - links: [ + }, { - title: 'What Your Money Does', - path: - 'https://www.comicrelief.com/rednoseday/schools/primary-schools', + title: 'Youth groups', + path: 'https://www.comicrelief.com/rednoseday/youth', internal: { type: 'ContentfulPageLandingPage' } }, { - title: 'Reports & Publications', - path: - 'https://www.comicrelief.com/rednoseday/schools/secondary-schools', + title: 'Free downloads', + path: 'https://www.comicrelief.com/rednoseday/schools/free-downloads', internal: { type: 'ContentfulPageLandingPage' } @@ -133,47 +134,60 @@ export default { ] }, { - title: 'GROUP5', - id: 'group5', + title: 'Shop', + id: 'eaec51921-bb89b3-5e8d-b9566-c53fff34998b5', links: [ { - title: 'Get Involved', - url: 'https://www.comicrelief.com/working-with-us/', + title: 'Shop', + path: 'https://shop.comicrelief.com', internal: { - type: 'ContentfulComponentLink' + type: 'ContentfulPageLandingPage' } - }, + } + ] + }, + { + title: 'External Links (menu group)', + id: 'eaec5191-bbb3-5e8d-b966-c53fff34998a', + links: [ { - title: 'Do your own fundraising', - url: 'https://www.comicrelief.com/404/', + title: 'Test allowListed external link', + url: 'https://www.sportrelief.com', internal: { type: 'ContentfulComponentLink' } }, { - title: 'Regular Donations', - url: 'https://www.comicrelief.com/404/', + title: 'Test non-allowListed external link', + url: 'https://bing.com', internal: { type: 'ContentfulComponentLink' } }, { - title: 'Run for Comic Relief', - url: 'https://www.comicrelief.com/404/', + title: 'Link comp: URL and Ref', + url: 'https://www.google.com', + reference: { + path: 'test-ref-path-1' + }, internal: { type: 'ContentfulComponentLink' } }, { - title: 'How to pay in your fundraising money', - url: 'https://www.comicrelief.com/404/', + title: 'Link comp: only Ref', + url: null, + reference: { + path: 'test-ref-path-2' + }, internal: { type: 'ContentfulComponentLink' } }, { - title: 'Partners', - url: 'https://www.comicrelief.com/404/', + title: 'Link comp: only URL', + url: 'test-url', + reference: null, internal: { type: 'ContentfulComponentLink' }