diff --git a/src/components.d.ts b/src/components.d.ts index 9ca955009c3351ed10f7daa961a30514b799282a..f883a020bd09bfdcd6a6beb8bd1ec98dc7b0071f 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -29,6 +29,7 @@ import { ProcessFlowBoxVariants, SiteLogoSize, } from './utils/utils'; +import {DesktopLinks} from './components/site-header/hy-desktop-menu-links/hy-desktop-menu-links'; import {FooterBaseLinks, FooterBaseSome} from './components/footer/hy-footer-base/hy-footer-base'; import {FooterInfoLinks} from './components/footer/hy-footer-info/hy-footer-info'; import {KeyFigureValue} from './components/hy-key-figure-group/hy-key-figure-group'; @@ -41,6 +42,7 @@ import {MenuLanguage} from './components/navigation/menu-language/menu-language' import {ComponentLabels} from './components/site-header/site-header'; import {ProcessFlowBoxValue} from './components/process/process'; import {ShortcutLinkValue} from './components/hy-shortcuts/hy-shortcuts'; +import {DesktopLinks as DesktopLinks1} from './components/site-header/site-header'; export namespace Components { interface ColorBox {} interface HyAccordionContainer { @@ -199,6 +201,9 @@ export namespace Components { url?: string; variant: CtaLinkVariants; } + interface HyDesktopMenuLinks { + dataDesktopLinks: DesktopLinks[] | string; + } interface HyDocsContainer {} interface HyFooter {} interface HyFooterAction { @@ -491,6 +496,7 @@ export namespace Components { listHeading: string; } interface HySiteHeader { + dataDesktopLinks: DesktopLinks[] | string; dataMenuDonate: string; dataMenuLanguage: string; dataSiteHeaderLabels: string; @@ -659,6 +665,11 @@ declare global { prototype: HTMLHyCtaLinkElement; new (): HTMLHyCtaLinkElement; }; + interface HTMLHyDesktopMenuLinksElement extends Components.HyDesktopMenuLinks, HTMLStencilElement {} + var HTMLHyDesktopMenuLinksElement: { + prototype: HTMLHyDesktopMenuLinksElement; + new (): HTMLHyDesktopMenuLinksElement; + }; interface HTMLHyDocsContainerElement extends Components.HyDocsContainer, HTMLStencilElement {} var HTMLHyDocsContainerElement: { prototype: HTMLHyDocsContainerElement; @@ -923,6 +934,7 @@ declare global { 'hy-button': HTMLHyButtonElement; 'hy-cta-button': HTMLHyCtaButtonElement; 'hy-cta-link': HTMLHyCtaLinkElement; + 'hy-desktop-menu-links': HTMLHyDesktopMenuLinksElement; 'hy-docs-container': HTMLHyDocsContainerElement; 'hy-footer': HTMLHyFooterElement; 'hy-footer-action': HTMLHyFooterActionElement; @@ -1133,6 +1145,9 @@ declare namespace LocalJSX { url?: string; variant?: CtaLinkVariants; } + interface HyDesktopMenuLinks { + dataDesktopLinks?: DesktopLinks[] | string; + } interface HyDocsContainer {} interface HyFooter {} interface HyFooterAction { @@ -1431,6 +1446,7 @@ declare namespace LocalJSX { listHeading?: string; } interface HySiteHeader { + dataDesktopLinks?: DesktopLinks[] | string; dataMenuDonate?: string; dataMenuLanguage?: string; dataSiteHeaderLabels?: string; @@ -1546,6 +1562,7 @@ declare namespace LocalJSX { 'hy-button': HyButton; 'hy-cta-button': HyCtaButton; 'hy-cta-link': HyCtaLink; + 'hy-desktop-menu-links': HyDesktopMenuLinks; 'hy-docs-container': HyDocsContainer; 'hy-footer': HyFooter; 'hy-footer-action': HyFooterAction; @@ -1615,6 +1632,7 @@ declare module '@stencil/core' { 'hy-button': LocalJSX.HyButton & JSXBase.HTMLAttributes<HTMLHyButtonElement>; 'hy-cta-button': LocalJSX.HyCtaButton & JSXBase.HTMLAttributes<HTMLHyCtaButtonElement>; 'hy-cta-link': LocalJSX.HyCtaLink & JSXBase.HTMLAttributes<HTMLHyCtaLinkElement>; + 'hy-desktop-menu-links': LocalJSX.HyDesktopMenuLinks & JSXBase.HTMLAttributes<HTMLHyDesktopMenuLinksElement>; 'hy-docs-container': LocalJSX.HyDocsContainer & JSXBase.HTMLAttributes<HTMLHyDocsContainerElement>; 'hy-footer': LocalJSX.HyFooter & JSXBase.HTMLAttributes<HTMLHyFooterElement>; 'hy-footer-action': LocalJSX.HyFooterAction & JSXBase.HTMLAttributes<HTMLHyFooterActionElement>; diff --git a/src/components/icon/readme.md b/src/components/icon/readme.md index 1a82cd624c5e07647ad6edfaf018ff2f0fba8490..80ed4364e557a455cd5e535b6d1399f71732c5c2 100644 --- a/src/components/icon/readme.md +++ b/src/components/icon/readme.md @@ -19,6 +19,7 @@ - [hy-button](../button) - [hy-cta-button](../cta-button) - [hy-cta-link](../cta-link) +- [hy-desktop-menu-links](../site-header/hy-desktop-menu-links) - [hy-footer-action](../footer/hy-footer-action) - [hy-footer-base](../footer/hy-footer-base) - [hy-footer-link-item](../footer/hy-footer-link-item) @@ -44,6 +45,7 @@ graph TD; hy-button --> hy-icon hy-cta-button --> hy-icon hy-cta-link --> hy-icon + hy-desktop-menu-links --> hy-icon hy-footer-action --> hy-icon hy-footer-base --> hy-icon hy-footer-link-item --> hy-icon diff --git a/src/components/navigation/menu-item/menu-item.scss b/src/components/navigation/menu-item/menu-item.scss index e780e18d7969c28774af2e09725257420eb1f542..06b73c8c1f4956cc02c4d425414da79d6bbe7d48 100644 --- a/src/components/navigation/menu-item/menu-item.scss +++ b/src/components/navigation/menu-item/menu-item.scss @@ -32,38 +32,6 @@ @include font-weight($bold); } -// Desktop. -:host(.hy-menu-item--desktop.is-hidden) { - height: auto; - visibility: visible !important; -} - -:host(.hy-menu-item--desktop) { - border: 0 none; - --menu-item-display: none; -} - -:host(.hy-menu-item--desktop:first-of-type) { - border: 0 none; - --menu-item-display: none; -} - -:host(.hy-menu-item--desktop.hy-menu-item--alternative) { - @include breakpoint($medium) { - @include font-size(14px, 14px); - @include font-weight($bold); - border-top: 0 none; - } - - @include breakpoint($extrawide) { - @include font-size(16px, 16px); - } - - @include breakpoint($overwide) { - @include font-size(18px, 18px); - } -} - // Sidenav. :host(.hy-menu-item--sidenav) { display: flex; @@ -95,54 +63,27 @@ visibility: visible; } -a { - @include font-size(15px, 20px); - @include font-weight($regular); - align-items: center; - color: var(--brand-main-nearly-black); - display: flex; - font-family: var(--main-font-family); - padding: 24px 16px; - text-decoration: none; - width: 100%; - - &:focus { - outline: solid 2px var(--additional-yellow); - outline-offset: -2px; - } - - &.hy-menu-item--mobile { - background: linear-gradient(270deg, var(--grayscale-background-box) 0%, var(--grayscale-light) 100%); - color: var(--brand-main-light); - padding: 12px 12px 12px 20px; +:host(.hy-menu-item) { + a { + @include font-size(15px, 20px); + @include font-weight($regular); + align-items: center; + color: var(--brand-main-nearly-black); + display: flex; + font-family: var(--main-font-family); + padding: 24px 16px; + text-decoration: none; + width: 100%; - &.is-active, - &.in-active-trail { - @include font-weight($bold); - color: var(--grayscale-black); - position: relative; - - &:before { - border-left: 3px solid var(--grayscale-black); - content: ''; - height: 75%; - left: 10px; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - } + &:focus { + outline: solid 2px var(--additional-yellow); + outline-offset: -2px; } - &.is-heading { - @include font-size(24px, 24px); - @include font-weight($bold); - background: transparent; - border-bottom: 3px solid var(--brand-main-light); + &.hy-menu-item--mobile { + background: linear-gradient(270deg, var(--grayscale-background-box) 0%, var(--grayscale-light) 100%); color: var(--brand-main-light); - margin-top: -24px; - padding-bottom: 24px; - padding-top: 24px; - text-transform: uppercase; + padding: 12px 12px 12px 20px; &.is-active, &.in-active-trail { @@ -151,141 +92,122 @@ a { position: relative; &:before { - border-left-width: 4px; - height: 55%; + border-left: 3px solid var(--grayscale-black); + content: ''; + height: 75%; + left: 10px; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); } } - } - } - &.hy-menu-item--desktop { - @include breakpoint($medium) { - @include font-size(14px, 14px); - @include font-weight($bold); - padding: 10px 15px; - text-transform: uppercase; - } - - @include breakpoint($extrawide) { - @include font-size(15px, 16px); - padding: 10px 8px; + &.is-heading { + @include font-size(24px, 24px); + @include font-weight($bold); + background: transparent; + border-bottom: 3px solid var(--brand-main-light); + color: var(--brand-main-light); + margin-top: -24px; + padding-bottom: 24px; + padding-top: 24px; + text-transform: uppercase; + + &.is-active, + &.in-active-trail { + @include font-weight($bold); + color: var(--grayscale-black); + position: relative; + + &:before { + border-left-width: 4px; + height: 55%; + } + } + } } - @include breakpoint($overwide) { - @include font-size(18px, 16px); - padding: 10px; + &.is-heading { + display: inherit; + @include breakpoint($extrawide) { + display: none; + } } - .hy-menu-item__label { - @include breakpoint($medium) { - border-bottom: 4px solid transparent; - padding-bottom: 8px; - padding-top: 7px; - } + &.hy-menu-item--sidenav { + @include font-size(18px, 24px); + @include font-weight($bold); + color: var(--brand-main-light); + display: var(--hy-menu-item-sidenav-display); + font-family: var(--main-font-family); + margin: 10px 0; + padding: 8px 0; - @include breakpoint($extrawide) { - padding-top: 13px; + &:focus { + outline-offset: 4px; } - @include breakpoint($overwide) { - padding-top: 12px; - padding-bottom: 12px; + &:hover { + color: var(--brand-main-nearly-black); } - } - - &.in-active-trail { - .hy-menu-item__label { - @include breakpoint($medium) { - border-bottom: 4px solid var(--brand-main-nearly-black); - padding-bottom: 8px; - } - @include breakpoint($extrawide) { - padding-bottom: 8px; - padding-top: 14px; - } + &.is-active { + color: var(--brand-main-nearly-black); + text-decoration: none; - @include breakpoint($overwide) { - padding-top: 12px; - padding-bottom: 12px; + .hy-menu-item__label { + padding-bottom: 0; } } - } - } - &.hy-menu-item--sidenav { - @include font-size(18px, 24px); - @include font-weight($bold); - color: var(--brand-main-light); - display: var(--hy-menu-item-sidenav-display); - font-family: var(--main-font-family); - margin: 10px 0; - padding: 8px 0; - - &:focus { - outline-offset: 4px; - } - - &:hover { - color: var(--brand-main-nearly-black); - } + &.is-active--heading { + @include font-size(26px, 40px); + color: var(--brand-main-nearly-black); + text-transform: uppercase; - &.is-active { - color: var(--brand-main-nearly-black); - text-decoration: none; + .hy-menu-item__label { + border-bottom: 4px solid var(--brand-main-nearly-black); + padding: 0; - .hy-menu-item__label { - padding-bottom: 0; + &__icon { + display: none; + } + } } - } - &.is-active--heading { - @include font-size(26px, 40px); - color: var(--brand-main-nearly-black); - text-transform: uppercase; + &.is-active--child { + color: var(--brand-main-light); + text-decoration: none; + } - .hy-menu-item__label { - border-bottom: 4px solid var(--brand-main-nearly-black); - padding: 0; + .hy-menu-item__label__icon { + color: var(--brand-main-light); + display: inline-block; + padding-left: 5px; - &__icon { + .is-active & { display: none; } } - } - - &.is-active--child { - color: var(--brand-main-light); - text-decoration: none; - } - - .hy-menu-item__label__icon { - color: var(--brand-main-light); - display: inline-block; - padding-left: 5px; - - .is-active & { - display: none; - } - } - &.is-parent { - @include font-size(16px, 22px); - @include font-weight($semibold); - align-items: center; - color: var(--brand-main-light); - display: flex; - text-decoration: none; + &.is-parent { + @include font-size(16px, 22px); + @include font-weight($semibold); + align-items: center; + color: var(--brand-main-light); + display: flex; + text-decoration: none; - &:hover { - color: var(--brand-main-nearly-black); - .hy-menu-item__label__icon { + &:hover { color: var(--brand-main-nearly-black); + .hy-menu-item__label__icon { + color: var(--brand-main-nearly-black); + } } - } - .hy-menu-item__label__icon { - margin-right: 8px; + .hy-menu-item__label__icon { + margin-right: 8px; + } } } } diff --git a/src/components/navigation/menu-item/menu-item.tsx b/src/components/navigation/menu-item/menu-item.tsx index c09ed29693b489eccf10d486c2f771643e942e62..50cf3dae5595fa6e94f247bf5f39dc905a4c8dd0 100644 --- a/src/components/navigation/menu-item/menu-item.tsx +++ b/src/components/navigation/menu-item/menu-item.tsx @@ -165,8 +165,19 @@ export class MenuItem { 'is-demo': this.isDemo, }} > + {this.depth == 1 && ( + <span class="hy-menu-item__heading__icon"> + <hy-icon icon={'hy-icon-arrow-right'} size={40} /> + </span> + )} + {this.depth == 2 && ( + <span class="hy-menu-item__heading__icon"> + <hy-icon icon={'hy-icon-caret-right'} size={12} /> + </span> + )} <span class={'hy-menu-item__label'}>{this.label}</span> </a> + {this.hasChildren && <slot />} </Host> ); case MenuType.mobile: diff --git a/src/components/navigation/menu-level-container/menu-level-container.scss b/src/components/navigation/menu-level-container/menu-level-container.scss index b7459214188111781ecd5652343c747d7267de57..a80d5227b2e12810ae74e8011325251d70c07860 100644 --- a/src/components/navigation/menu-level-container/menu-level-container.scss +++ b/src/components/navigation/menu-level-container/menu-level-container.scss @@ -19,14 +19,24 @@ } &--desktop { - align-items: center; + //align-items: center; + align-items: flex-start; display: flex; - flex-flow: row; + flex-flow: column; + //max-width: 500px; // ?? Ask Mikko width: 100%; - &:not(.hy-menu-level-container--level-1) { + &.is-open { + display: block; + visibility: visible; + } + + &:not(.hy-menu-level-container--level-1):not(.hy-menu-level-container--level-2) { display: none; } + &.hy-menu-level-container--level-2 { + background-color: var(--grayscale-background-box); + } } &--sidenav { diff --git a/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss new file mode 100644 index 0000000000000000000000000000000000000000..6c4f9cae403e86466aa6e68bb1d9f734f2faed0c --- /dev/null +++ b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss @@ -0,0 +1,280 @@ +:host { + display: block; +} + +.hy-site-header { + // ul - menu items first level and panels that consist of menu items second level and shortcut items per panel. + &__menu-desktop-container { + align-items: center; + display: flex; + flex-flow: row; + list-style: none; + width: 100%; + + // First level menu items + .desktop-menu-link { + background-color: transparent; + border: none; + color: var(--brand-main-nearly-black); + cursor: pointer; + font-family: var(--main-font-family); + + @include breakpoint($extrawide) { + @include font-size(15px, 16px); + @include font-weight($bold); + + border-top: 0 none; + padding: 10px 8px; + text-transform: uppercase; + } + + @include breakpoint($fullhd) { + @include font-size(18px, 16px); + letter-spacing: -0.5px; + padding: 10px; + } + + // Underline if link is in active trail. + &--is-active-trail { + @include breakpoint($extrawide) { + border-bottom: 4px solid var(--brand-main-nearly-black); + padding-bottom: 8px; + } + + @include breakpoint($overwide) { + padding-bottom: 12px; + } + } + + &__heading__icon { + display: none; + } + + // On hover: change background and show heading icon. + &--is-active { + background-color: var(--grayscale-background-box); + padding: 35px 10px; + position: relative; + + .desktop-menu-link__heading__icon { + bottom: 14px; + display: block; + left: 0; + position: absolute; + width: 100%; + + hy-icon { + justify-content: center; + transform: rotateX(180deg); + svg { + padding: 4px 0; + } + } + } + } + } + + // Panel with second level menu items and shortcuts. + .hy-desktop-menu-panel { + display: none; + + &--is-active { + background-color: var(--grayscale-white); + display: flex; + flex-direction: row; + justify-content: center; + opacity: 1; + position: absolute; + left: 0; + top: 104px; + width: 100%; + z-index: 510; + } + + &__panel-toggle { + background-color: transparent; + border: none; + position: absolute; + right: 10px; + top: 10px; + + &__label { + @include font-size(18px, 22px); + @include font-weight($bold); + color: var(--grayscale-black); + display: flex; + font-family: var(--main-font-family); + letter-spacing: -0.56px; + margin-bottom: 18px; + text-transform: uppercase; + &__title { + padding-right: 5px; + } + } + } + + &__desktop-menu { + display: flex; + position: relative; + + // first level link inside panel + &__first-level-menu-item { + @include font-weight($bold); + //align-items: center; + color: var(--brand-main-nearly-black); + display: flex; + //flex-direction: row; + font-family: var(--main-font-family); + text-decoration: none; + width: 100%; + + @include breakpoint($extrawide) { + @include font-size(24px, 32px); + align-items: flex-start; + background-color: var(--grayscale-background-box); + flex-direction: column; + letter-spacing: -0.75px; + margin-bottom: 4px; + padding: 17px 32px 12px 32px; + position: relative; + text-transform: none; + } + @include breakpoint($fullhd) { + @include font-size(26px, 32px); + letter-spacing: -0.81px; + margin-bottom: 6px; + padding-top: 19px; + } + + .label { + border: none; + margin-left: 14px; + } + .description { + @include font-size(16px, 24px); + @include font-weight($semibold); + color: var(--grayscale-dark); + letter-spacing: 0; + margin-left: 14px; + margin-bottom: 28px; + margin-top: 8px; + } + + span.heading-icon { + position: absolute; + top: 12px; + left: -6px; + @include breakpoint($fullhd) { + top: 27px; + } + svg { + background-color: var(--brand-main-light); + fill: var(--grayscale-white); + padding: 8px; + } + } + } + + // menu item links + &__second-level-menu { + background-color: var(--grayscale-background-box); + list-style: none; + margin: 0; + padding: 0; + + li { + a { + @include font-weight($bold); + align-items: center; + color: var(--brand-main-nearly-black); + display: flex; + flex-direction: row; + font-family: var(--main-font-family); + text-decoration: none; + width: 100%; + + @include breakpoint($extrawide) { + @include font-size(15px, 22px); + align-items: center; + flex-direction: row; + letter-spacing: -0.47px; + padding-left: 24px; + padding-right: 24px; + text-transform: none; + } + + @include breakpoint($fullhd) { + @include font-size(18px, 22px); + letter-spacing: -0.56px; + } + + &:focus { + outline: solid 2px var(--additional-yellow); + outline-offset: -2px; + } + + .label { + @include breakpoint($extrawide) { + border: none; + margin-left: 12px; + padding-top: 12px; + padding-bottom: 12px; + } + } + + span.heading-icon { + svg { + fill: var(--brand-main-light); + @include breakpoint($extrawide) { + padding: 1px 0; + } + } + } + } + } + } + } + } + + // Shortcuts + .shortcuts-panel { + list-style: none; + margin-left: 48px; + + &__title { + @include font-size(18px, 22px); + @include font-weight($bold); + color: var(--grayscale-black); + font-family: var(--main-font-family); + letter-spacing: -0.56px; + margin-bottom: 18px; + text-transform: uppercase; + } + + &__shortcut-item { + border-bottom: 1px solid var(--grayscale-medium-dark); + &__first { + border-top: 1px solid var(--grayscale-medium-dark); + } + + a { + @include font-size(16px, 22px); + @include font-weight($semibold); + color: var(--grayscale-black); + display: flex; + flex-direction: row; + font-family: var(--main-font-family); + letter-spacing: -0.5px; + padding: 19px 0; + text-decoration: none; + + .icon { + svg { + padding: 4px; + } + } + } + } + } + } +} diff --git a/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b4567b984727781851a5921a3495739d16739103 --- /dev/null +++ b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx @@ -0,0 +1,197 @@ +export interface ShortcutLinks { + shortcut_title: string; + shortcut_url: string; + shortcut_is_external: string; + shortcut_aria_label: string; +} + +export interface DesktopLinks { + label: string; + url: string; + description: string; + menuLinkId: string; + isActive: string; + items: Array<DesktopLinks>; + shortcuts: Array<ShortcutLinks>; +} + +import {ColorVariant} from '../../../utils/utils'; +import {Component, h, Element, Prop, State, Watch} from '@stencil/core'; + +@Component({ + tag: 'hy-desktop-menu-links', + styleUrl: 'hy-desktop-menu-links.scss', + shadow: true, +}) +export class HyDesktopMenuLinks { + @Element() el: HTMLElement; + /* + First level menu links to be displayed on Desktop screens. + * */ + @Prop() dataDesktopLinks: DesktopLinks[] | string; + private _dataDesktopLinks: DesktopLinks[]; + @State() firstLevelLinksList: Array<object> = []; + @State() menuLinkItems: Array<object> = []; + + @Watch('dataDesktopLinks') dataDesktopLinksWatcher(data: DesktopLinks[] | string) { + this._dataDesktopLinks = typeof data === 'string' ? JSON.parse(data) : data; + } + + componentWillLoad() { + this.dataDesktopLinksWatcher(this.dataDesktopLinks); + } + + handleDesktopMenuClose() { + const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); + const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); + const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[aria-expanded="true"]`); + + // Return focus to the button of the last desktop panel that was active. + if (activeMenuItem !== null) (activeMenuItem as HTMLElement).focus(); + + // Reset elements by removing the active classes. + menuItems.forEach((item) => { + item.classList.remove('desktop-menu-link--is-active'); + item.setAttribute('aria-expanded', 'false'); + }); + menuPanelItems.forEach((item) => { + item.classList.remove('hy-desktop-menu-panel--is-active'); + item.setAttribute('aria-hidden', 'true'); + }); + } + + handleDesktopMenuToggle(id) { + const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); + const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); // all panels + const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`); + const activeMenuItemSibling = activeMenuItem.nextElementSibling; // current panel + + // Reset elements by removing the active classes. + menuItems.forEach((item) => { + item.classList.remove('desktop-menu-link--is-active'); + item.setAttribute('aria-expanded', 'false'); + }); + menuPanelItems.forEach((item) => { + item.classList.remove('hy-desktop-menu-panel--is-active'); + item.setAttribute('aria-hidden', 'true'); + }); + + // Add active classes to the currently active item and its sibling element. + activeMenuItem.classList.add('desktop-menu-link--is-active'); + activeMenuItem.setAttribute('aria-expanded', 'true'); + activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active'); + activeMenuItemSibling.setAttribute('aria-hidden', 'false'); + } + + componentDidLoad() { + const links = this._dataDesktopLinks as Array<DesktopLinks>; + + let menuLinkItems = []; + + links.map(({menuLinkId: id, shortcuts, items, url, description, label, isActive}) => { + let classAttributes = ['desktop-menu-link', isActive === 'true' ? 'desktop-menu-link--is-active-trail' : ''].join( + ' ' + ); + + menuLinkItems.push( + <li> + <button + type="button" + class={classAttributes} + link-id={id} + onMouseOver={() => this.handleDesktopMenuToggle(id)} + onFocus={() => this.handleDesktopMenuToggle(id)} + aria-expanded="false" + > + {label} + <span class="desktop-menu-link__heading__icon"> + <hy-icon icon={'hy-icon-caret-down'} size={16} /> + </span> + </button> + <div class="hy-desktop-menu-panel" onMouseLeave={() => this.handleDesktopMenuClose()} aria-hidden="true"> + <div class="hy-desktop-menu-panel__desktop-menu"> + <div class="hy-desktop-menu-panel__desktop-menu__menu-items"> + <a + aria-current={label} + href={url} + class="hy-desktop-menu-panel__desktop-menu__first-level-menu-item" + menu-link-id={id} + > + <span class="heading-icon"> + <hy-icon icon={'hy-icon-arrow-right'} size={40} /> + </span> + <span class="label">{label}</span> + {description && <span class="description">{description}</span>} + </a> + <ul class={'hy-desktop-menu-panel__desktop-menu__second-level-menu'} menu-link-id={id}> + {items.map(({label, url}) => ( + <li> + <a href={url}> + <span class="heading-icon"> + <hy-icon icon={'hy-icon-caret-right'} size={12} /> + </span> + <span class="label">{label}</span> + </a> + </li> + ))} + </ul> + </div> + {shortcuts.length > 0 && ( + <ul class="shortcuts-panel"> + <h2 class="shortcuts-panel__title">{'Shortcuts'}</h2> + {shortcuts.map(({shortcut_title, shortcut_url, shortcut_is_external, shortcut_aria_label}, index) => { + let target = shortcut_is_external ? '_blank' : '_self'; + + let shortcutClass = [ + 'shortcuts-panel__shortcut-item', + index == 0 ? 'shortcuts-panel__shortcut-item__first' : '', + ].join(' '); + + return ( + <li class={shortcutClass}> + <a + aria-current={shortcut_aria_label} + href={shortcut_url} + class="shortcut-item__link" + target={target} + aria-label={shortcut_aria_label} + > + <span class="label">{shortcut_title}</span> + <span class="icon"> + <hy-icon icon={'hy-icon-arrow-right'} size={24} /> + </span> + </a> + </li> + ); + })} + </ul> + )} + </div> + <button + onClick={() => this.handleDesktopMenuClose()} + class={{ + 'hy-desktop-menu-panel__panel-toggle': true, + }} + aria-label="Close menu" + > + <span class="hy-desktop-menu-panel__panel-toggle__label"> + <span class="hy-desktop-menu-panel__panel-toggle__label__title">CLOSE</span> + <hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} /> + </span> + </button> + </div> + </li> + ); + }); + + this.menuLinkItems = menuLinkItems; + } + + render() { + return ( + <nav role={'navigation'} class="hy-site-header__menu-desktop"> + <ul class="hy-site-header__menu-desktop-container">{this.menuLinkItems}</ul> + </nav> + ); + } +} diff --git a/src/components/site-header/hy-desktop-menu-links/readme.md b/src/components/site-header/hy-desktop-menu-links/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..97289c9d478d6d75545d620dc6404a7b5125ec91 --- /dev/null +++ b/src/components/site-header/hy-desktop-menu-links/readme.md @@ -0,0 +1,32 @@ +# hy-desktop-menu-links + +<!-- Auto Generated Below --> + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------------ | -------------------- | ----------- | -------------------------- | ----------- | +| `dataDesktopLinks` | `data-desktop-links` | | `DesktopLinks[] \| string` | `undefined` | + +## Dependencies + +### Used by + +- [hy-site-header](..) + +### Depends on + +- [hy-icon](../../icon) + +### Graph + +```mermaid +graph TD; + hy-desktop-menu-links --> hy-icon + hy-site-header --> hy-desktop-menu-links + style hy-desktop-menu-links fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +Helsinki University Design System diff --git a/src/components/site-header/readme.md b/src/components/site-header/readme.md index 7c3ceb9ebe9dfe0a514947b5d084649019d92010..ca762fc5a53111ad826fe88469b75100016fa8c5 100644 --- a/src/components/site-header/readme.md +++ b/src/components/site-header/readme.md @@ -6,6 +6,7 @@ | Property | Attribute | Description | Type | Default | | ---------------------- | ------------------------- | ----------- | ---------------------------------------------------------------------------- | ------------------ | +| `dataDesktopLinks` | `data-desktop-links` | | `DesktopLinks[] \| string` | `undefined` | | `dataMenuDonate` | `data-menu-donate` | | `string` | `undefined` | | `dataMenuLanguage` | `data-menu-language` | | `string` | `undefined` | | `dataSiteHeaderLabels` | `data-site-header-labels` | | `string` | `undefined` | @@ -20,6 +21,7 @@ ### Depends on - [hy-site-logo](site-logo) +- [hy-desktop-menu-links](hy-desktop-menu-links) - [hy-menu-language](../navigation/menu-language) - [hy-site-search](site-search) - [hy-icon](../icon) @@ -29,10 +31,12 @@ ```mermaid graph TD; hy-site-header --> hy-site-logo + hy-site-header --> hy-desktop-menu-links hy-site-header --> hy-menu-language hy-site-header --> hy-site-search hy-site-header --> hy-icon hy-site-logo --> hy-icon + hy-desktop-menu-links --> hy-icon hy-menu-language --> hy-menu-language-item hy-menu-language --> hy-icon hy-site-search --> hy-icon diff --git a/src/components/site-header/site-header.tsx b/src/components/site-header/site-header.tsx index 6ffe0687fb51016e12006eee2e058616419e4997..56de89f5e3d86b860ea3149b9c532b17d31f538d 100644 --- a/src/components/site-header/site-header.tsx +++ b/src/components/site-header/site-header.tsx @@ -1,3 +1,8 @@ +export interface DesktopLinks { + label: string; + url: string; + menuLinkId: string; +} export interface DonateLink { url: string; label: string; @@ -28,8 +33,13 @@ export class SiteHeader { @Prop() menuLabelOpen?: string; @Prop() menuLabelClose?: string; @Prop({reflect: true}) menuType: MenuType = MenuType.default; + /* + First level menu links to be displayed on Desktop screens. + * */ + @Prop() dataDesktopLinks: DesktopLinks[] | string; @State() isMobile: boolean; @State() isMenuOpen: boolean = false; + @State() isDesktopMenuOpen: boolean = false; private ro: ResizeObserver; private donateLink: DonateLink[]; private menuLabels: ComponentLabels[]; @@ -111,13 +121,15 @@ export class SiteHeader { switch (this.menuType) { case MenuType.desktop: - return ( + return [ <header class={classAttributes.join(' ')}> <div class={{'hy-backdrop': true, 'is-active': this.isMenuOpen}} /> <div class={'hy-site-header__logo-container'}> <hy-site-logo size={logoSize} color={logoColor} url={this.logoUrl} label={this.logoLabel} /> </div> - <slot name={'menu'} /> + + <hy-desktop-menu-links data-desktop-links={this.dataDesktopLinks}></hy-desktop-menu-links> + <div class={'menu--secondary'}> <hy-menu-language class={'menu--secondary__item is-first'} @@ -141,8 +153,8 @@ export class SiteHeader { ); })} </div> - </header> - ); + </header>, + ]; case MenuType.tablet: return ( <header class={classAttributes.join(' ')}> @@ -252,13 +264,5 @@ export class SiteHeader { </header> ); } - - /* return this.isMobile ? ( - // Mobile. - - ) : ( - // Desktop. - - ); */ } }