diff --git a/src/ui/Header/Header.jsx b/src/ui/Header/Header.jsx index fb1eb0eece..cf85df871b 100644 --- a/src/ui/Header/Header.jsx +++ b/src/ui/Header/Header.jsx @@ -17,6 +17,7 @@ import HeaderMenuPopUp from './HeaderMenuPopUp'; import PropTypes from 'prop-types'; import { isInternalURL } from '@plone/volto/helpers'; +import config from '@plone/volto/registry'; Header.propTypes = { transparency: PropTypes.bool, @@ -143,6 +144,7 @@ const TopDropdownMenu = ({ const Main = ({ logo, menuItems, + menuItemsLayouts, renderMenuItem, renderGlobalMenuItem, headerSearchBox, @@ -159,6 +161,7 @@ const Main = ({ const [burger, setBurger] = React.useState(''); const searchInputRef = React.useRef(null); const [isClient, setIsClient] = React.useState(); + const itemsLayouts = menuItemsLayouts || config.settings?.menuItemsLayouts; React.useEffect(() => setIsClient(true), []); @@ -357,6 +360,7 @@ const Main = ({ renderMenuItem={renderMenuItem} activeItem={activeItem} menuItems={menuItems} + menuItemsLayouts={itemsLayouts} pathName={pathname} onClose={menuOnClickOutside} triggerRefs={[mobileMenuBurgerRef, desktopMenuRef]} diff --git a/src/ui/Header/Header.stories.js b/src/ui/Header/Header.stories.js index d7db39d332..7c57618702 100644 --- a/src/ui/Header/Header.stories.js +++ b/src/ui/Header/Header.stories.js @@ -12,6 +12,7 @@ import cx from 'classnames'; export default { title: 'Layout/Header', component: Header, + excludeStories: /menuItems$/, argTypes: { links: { table: { @@ -98,7 +99,7 @@ const languages = [ { name: 'Türkçe', code: 'tr' }, ]; -const menuItems = [ +export const menuItems = [ { '@id': 'Topics', items: [ @@ -483,7 +484,7 @@ const menuItems = [ ], review_state: null, title: 'Topics', - url: '/#', + url: '/en/topics', }, { '@id': 'Analysis-and-data', @@ -887,7 +888,7 @@ const menuItems = [ ], review_state: null, title: 'Countries', - url: '/#', + url: '/en/countries', }, { '@id': 'Newsroom', @@ -1143,7 +1144,7 @@ const menuItems = [ ], review_state: null, title: 'About Us', - url: '/#', + url: '/en/about', }, ]; @@ -1179,6 +1180,26 @@ const debounce = (func) => { }; }; +const menuItemsLayouts = { + '/en/topics': { + menuItemChildrenListColumns: [1, 4], + menuItemColumns: [ + 'at-a-glance three wide column', + 'topics-right-column nine wide column', + ], + hideChildrenFromNavigation: false, + }, + '/en/countries': { + menuItemColumns: ['eight wide column', 'four wide column'], + menuItemChildrenListColumns: [5, 2], + appendExtraMenuItemsToLastColumn: true, + hideChildrenFromNavigation: false, + }, + '/en/about': { + hideChildrenFromNavigation: false, + }, +}; + const handleDropdownClick = (event) => { event.stopPropagation(); }; @@ -1320,6 +1341,7 @@ const Template = (args) => { pathname={pathname} logo={} menuItems={menuItems} + menuItemsLayouts={menuItemsLayouts} headerSearchBox={headerSearchBox} renderMenuItem={(item, options = {}, props) => { const { onClick } = options; diff --git a/src/ui/Header/HeaderMenuPopUp.js b/src/ui/Header/HeaderMenuPopUp.js index 12acd34004..fdc61fb0e8 100644 --- a/src/ui/Header/HeaderMenuPopUp.js +++ b/src/ui/Header/HeaderMenuPopUp.js @@ -1,13 +1,19 @@ -import React, { useState, useEffect } from 'react'; -import { Transition } from 'semantic-ui-react'; -import { Container, Grid, List, Icon, Accordion } from 'semantic-ui-react'; +import React, { useEffect, useState } from 'react'; +import { + Accordion, + Container, + Grid, + Icon, + List, + Transition, +} from 'semantic-ui-react'; import { cloneDeep } from 'lodash'; import { useClickOutside } from '@eeacms/volto-eea-design-system/helpers'; const createColumns = (item, renderMenuItem, item_id) => { - const itemList = item.items.map((item, index) => ( + return item.items.map((item, index) => ( {renderMenuItem(item, { className: 'item', @@ -16,16 +22,23 @@ const createColumns = (item, renderMenuItem, item_id) => { })} )); - return itemList; }; -const ItemGrid = ({ sectionTitle, item, columns, renderMenuItem }) => { +const ItemGrid = ({ + item, + columns, + renderMenuItem, + hideChildrenFromNavigation, +}) => { const item_id = item.title.toLowerCase().replaceAll(' ', '-') + '-sub-title'; return ( <> {renderMenuItem(item, { className: 'sub-title', id: item_id })} - {item.items.length ? ( - + {item.items.length && !hideChildrenFromNavigation ? ( + 1 ? `has--${columns}--columns` : ''} + > {createColumns(item, renderMenuItem, item_id)} ) : null} @@ -33,7 +46,13 @@ const ItemGrid = ({ sectionTitle, item, columns, renderMenuItem }) => { ); }; -const Item = ({ item, icon = false, iconName, renderMenuItem }) => { +const Item = ({ + item, + icon = false, + iconName, + renderMenuItem, + hideChildrenFromNavigation, +}) => { const item_id = item.title.toLowerCase().replaceAll(' ', '-') + '-sub-title'; return ( <> @@ -41,97 +60,93 @@ const Item = ({ item, icon = false, iconName, renderMenuItem }) => { className: 'sub-title', id: item_id, })} - - {item.items.map((listItem, index) => ( - - {renderMenuItem( - listItem, - { - className: 'item', - key: index, - }, - { children: icon && }, - )} - - ))} - + {!hideChildrenFromNavigation && ( + + {item.items.map((listItem, index) => ( + + {renderMenuItem( + listItem, + { + className: 'item', + key: index, + }, + { children: icon && }, + )} + + ))} + + )} ); }; -const Topics = ({ menuItem, renderMenuItem }) => ( - - {menuItem.items.map((section, index) => ( - - {section.title === 'At a glance' ? ( - - - - ) : ( - - - - )} - - ))} - -); +const RenderItem = ({ layout, section, renderMenuItem, index }) => { + const hideChildrenFromNavigation = + layout.hideChildrenFromNavigation === undefined + ? true + : layout.hideChildrenFromNavigation; + return !layout.menuItemChildrenListColumns || + layout.menuItemChildrenListColumns[index] === 1 ? ( + + ) : ( + + ); +}; + +export const StandardMegaMenuGrid = ({ menuItem, renderMenuItem, layout }) => { + const menuItemColumns = layout && layout.menuItemColumns; + const menuItemColumnsLength = + (menuItemColumns && menuItemColumns.length - 1) || 0; + + const renderColumnContent = (section, columnIndex) => ( + + ); -const Countries = ({ menuItem, renderMenuItem }) => ( - - + const renderColumns = () => ( + + {menuItemColumns.map((section, columnIndex) => ( +
+ {columnIndex !== menuItemColumnsLength + ? renderColumnContent(menuItem.items[columnIndex], columnIndex) + : menuItem.items + .slice(menuItemColumnsLength) + .map((section, _idx) => + renderColumnContent(section, columnIndex), + )} +
+ ))} +
+ ); + + const renderDefaultColumns = () => ( +
{menuItem.items.map((section, index) => ( - - {index === 0 && ( - - )} - + + {renderColumnContent(section, index)} + ))} - - - - {menuItem.items.map((section, index) => ( - - {index !== 0 && ( - - - - )} - - ))} - - - -); +
+ ); -const StandardMegaMenuGrid = ({ menuItem, renderMenuItem }) => ( - - {menuItem.items.map((section, index) => ( - - - - ))} - -); + return menuItemColumns ? renderColumns() : renderDefaultColumns(); +}; const FirstLevelContent = ({ element, renderMenuItem, pathName }) => { - const topics = element.title === 'Topics' ? true : false; + const topics = element.title === 'Topics'; let defaultIndex = -1; return ( @@ -308,6 +323,7 @@ const NestedAccordion = ({ menuItems, renderMenuItem, pathName }) => { function HeaderMenuPopUp({ menuItems, + menuItemsLayouts, renderMenuItem, pathName, onClose, @@ -322,6 +338,11 @@ function HeaderMenuPopUp({ (current) => current.url === activeItem || current['@id'] === activeItem, ); + const layout = + !!menuItemsLayouts && + Object.keys(menuItemsLayouts).includes(menuItem?.url) && + menuItemsLayouts[menuItem.url]; + return (
@@ -351,19 +372,11 @@ function HeaderMenuPopUp({ )}
)} - {menuItem.title === 'Topics' ? ( - - ) : menuItem.title === 'Countries' ? ( - - ) : ( - - )} + )}
diff --git a/theme/themes/eea/extras/header.less b/theme/themes/eea/extras/header.less index 13228b3198..74240a1ee2 100644 --- a/theme/themes/eea/extras/header.less +++ b/theme/themes/eea/extras/header.less @@ -747,6 +747,7 @@ #mega-menu .ui.list { margin: 0; + gap: @megaMenuListGap; } #mega-menu .item { @@ -770,7 +771,7 @@ } } -#at-a-glance { +.at-a-glance { .item { margin: @megaMenuGlanceListItemMargin; font-size: @megaMenuGlanceListItemFontSize; @@ -782,30 +783,10 @@ } } -// add negative margin to the first column subtitle from nested grid -// so that the subtitle lines up with the subtitle from the left column -#mega-menu .nested-grid > .column:first-of-type .sub-title { - margin-top: @megaMenuSubTitleCountriesNestedGridMarginTop; -} - -#topics-right-column { +.topics-right-column { padding-left: @topicsRightColumnPaddingLeft; } -.ui.grid > .column > .ui.grid { - margin-top: 0; -} - -#mega-menu .ui.grid { - div.column:first-child { - padding-left: 0.625rem; - } - - div.column:last-child { - padding-right: 0.625rem; - } -} - #mega-menu .active:not(.title-link):not(.button) > span { padding-left: @megaMenuListItemActivePadding; border-left: @megaMenuListItemActiveBorder; diff --git a/theme/themes/eea/extras/header.variables b/theme/themes/eea/extras/header.variables index 81b396e604..91bf981eb8 100644 --- a/theme/themes/eea/extras/header.variables +++ b/theme/themes/eea/extras/header.variables @@ -182,9 +182,9 @@ @megaMenuSubTitleFontWeight: @font-weight-7; @megaMenuSubTitlePadding: 0.5rem 0; @megaMenuSubTitleDisplay: block; -@megaMenuSubTitleCountriesNestedGridMarginTop: -1rem; /* List Item */ +@megaMenuListGap: 0 2rem; @megaMenuListItemFontSize: @font-size-1; @megaMenuListItemFontWeight: @font-weight-4; @megaMenuListItemPadding: @rem-space-2 0;