diff --git a/src/components.d.ts b/src/components.d.ts index dcf02cd27caf1fbb8f840923f7e35172d533b89b..d789f00b6aa0865f3b631b78b257d8b520dbd848 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -472,6 +472,26 @@ export namespace Components { parentExpanded: boolean; url: string; } + interface HyMenuItemSidebar { + ariaExpanded: boolean; + depth: number; + hasChildren: boolean; + inActiveTrail: boolean; + isActive: boolean; + isActiveChild?: boolean; + isDemo: boolean; + isHeading: boolean; + isParent: boolean; + label: string; + menuButtonSubmenuExpand?: string; + menuIsOpen: boolean; + menuItemAlternative: boolean; + menuLinkId: string; + menuType: MenuType; + parentAsHeading: string; + parentExpanded: boolean; + url: string; + } interface HyMenuLanguage { dataMenuLanguage: MenuLanguage[] | string; isMobile: boolean; @@ -488,6 +508,14 @@ export namespace Components { interface HyMenuLevelContainer { activeTrailTriggered: boolean; depth: number; + /** + * label for front page for panel first parent + */ + frontLabel: string; + /** + * Url to front page for panel first parent + */ + frontUrl: string; headingItem: any; labelFrontPage?: string; menuButtonSubmenuExpand?: string; @@ -502,6 +530,56 @@ export namespace Components { labelBack: string; labelFrontPage: string; } + interface HyMenuSidebar { + /** + * Isdemo + */ + isDemo: boolean; + /** + * Logo label + */ + logoLabel?: string; + /** + * Url for logo. + */ + logoUrl?: string; + /** + * Is menu open boolean. + */ + menuIsOpen: boolean; + /** + * Menu type. Defaults to sidenav. + */ + menuType: MenuType; + /** + * Previous panel to be toggled to keep track. + */ + minHeight: any; + /** + * Upper menus panel boolean. + */ + panelOpen: boolean; + /** + * Label for panel toggle button. + */ + panelToggleAriaLabel?: string; + /** + * Label for panel toggle button. + */ + panelToggleCloseAriaLabel?: string; + /** + * Label for panel toggle button. + */ + panelToggleCloseLabel?: string; + /** + * Label for panel toggle button. + */ + panelToggleLabel?: string; + /** + * Logo size + */ + size: SiteLogoSize; + } interface HyParagraphText { headerstyle: string; placement: string; @@ -930,6 +1008,11 @@ declare global { prototype: HTMLHyMenuItemElement; new (): HTMLHyMenuItemElement; }; + interface HTMLHyMenuItemSidebarElement extends Components.HyMenuItemSidebar, HTMLStencilElement {} + var HTMLHyMenuItemSidebarElement: { + prototype: HTMLHyMenuItemSidebarElement; + new (): HTMLHyMenuItemSidebarElement; + }; interface HTMLHyMenuLanguageElement extends Components.HyMenuLanguage, HTMLStencilElement {} var HTMLHyMenuLanguageElement: { prototype: HTMLHyMenuLanguageElement; @@ -950,6 +1033,11 @@ declare global { prototype: HTMLHyMenuMobileBreadcrumbElement; new (): HTMLHyMenuMobileBreadcrumbElement; }; + interface HTMLHyMenuSidebarElement extends Components.HyMenuSidebar, HTMLStencilElement {} + var HTMLHyMenuSidebarElement: { + prototype: HTMLHyMenuSidebarElement; + new (): HTMLHyMenuSidebarElement; + }; interface HTMLHyParagraphTextElement extends Components.HyParagraphText, HTMLStencilElement {} var HTMLHyParagraphTextElement: { prototype: HTMLHyParagraphTextElement; @@ -1100,10 +1188,12 @@ declare global { 'hy-main-content-wrapper': HTMLHyMainContentWrapperElement; 'hy-menu': HTMLHyMenuElement; 'hy-menu-item': HTMLHyMenuItemElement; + 'hy-menu-item-sidebar': HTMLHyMenuItemSidebarElement; 'hy-menu-language': HTMLHyMenuLanguageElement; 'hy-menu-language-item': HTMLHyMenuLanguageItemElement; 'hy-menu-level-container': HTMLHyMenuLevelContainerElement; 'hy-menu-mobile-breadcrumb': HTMLHyMenuMobileBreadcrumbElement; + 'hy-menu-sidebar': HTMLHyMenuSidebarElement; 'hy-paragraph-text': HTMLHyParagraphTextElement; 'hy-process': HTMLHyProcessElement; 'hy-process-flow-box': HTMLHyProcessFlowBoxElement; @@ -1555,6 +1645,30 @@ declare namespace LocalJSX { parentExpanded?: boolean; url?: string; } + interface HyMenuItemSidebar { + ariaExpanded?: boolean; + depth?: number; + hasChildren?: boolean; + inActiveTrail?: boolean; + isActive?: boolean; + isActiveChild?: boolean; + isDemo?: boolean; + isHeading?: boolean; + isParent?: boolean; + label?: string; + menuButtonSubmenuExpand?: string; + menuIsOpen?: boolean; + menuItemAlternative?: boolean; + menuLinkId?: string; + menuType?: MenuType; + onAddBreadcrumb?: (event: CustomEvent<any>) => void; + onMenuContainerActiveTrail?: (event: CustomEvent<any>) => void; + onMenuContainerToggled?: (event: CustomEvent<any>) => void; + onRouteClicked?: (event: CustomEvent<any>) => void; + parentAsHeading?: string; + parentExpanded?: boolean; + url?: string; + } interface HyMenuLanguage { dataMenuLanguage?: MenuLanguage[] | string; isMobile?: boolean; @@ -1571,6 +1685,14 @@ declare namespace LocalJSX { interface HyMenuLevelContainer { activeTrailTriggered?: boolean; depth?: number; + /** + * label for front page for panel first parent + */ + frontLabel?: string; + /** + * Url to front page for panel first parent + */ + frontUrl?: string; headingItem?: any; labelFrontPage?: string; menuButtonSubmenuExpand?: string; @@ -1586,6 +1708,56 @@ declare namespace LocalJSX { labelFrontPage?: string; onRemoveBreadcrumb?: (event: CustomEvent<any>) => void; } + interface HyMenuSidebar { + /** + * Isdemo + */ + isDemo?: boolean; + /** + * Logo label + */ + logoLabel?: string; + /** + * Url for logo. + */ + logoUrl?: string; + /** + * Is menu open boolean. + */ + menuIsOpen?: boolean; + /** + * Menu type. Defaults to sidenav. + */ + menuType?: MenuType; + /** + * Previous panel to be toggled to keep track. + */ + minHeight?: any; + /** + * Upper menus panel boolean. + */ + panelOpen?: boolean; + /** + * Label for panel toggle button. + */ + panelToggleAriaLabel?: string; + /** + * Label for panel toggle button. + */ + panelToggleCloseAriaLabel?: string; + /** + * Label for panel toggle button. + */ + panelToggleCloseLabel?: string; + /** + * Label for panel toggle button. + */ + panelToggleLabel?: string; + /** + * Logo size + */ + size?: SiteLogoSize; + } interface HyParagraphText { headerstyle?: string; placement?: string; @@ -1795,10 +1967,12 @@ declare namespace LocalJSX { 'hy-main-content-wrapper': HyMainContentWrapper; 'hy-menu': HyMenu; 'hy-menu-item': HyMenuItem; + 'hy-menu-item-sidebar': HyMenuItemSidebar; 'hy-menu-language': HyMenuLanguage; 'hy-menu-language-item': HyMenuLanguageItem; 'hy-menu-level-container': HyMenuLevelContainer; 'hy-menu-mobile-breadcrumb': HyMenuMobileBreadcrumb; + 'hy-menu-sidebar': HyMenuSidebar; 'hy-paragraph-text': HyParagraphText; 'hy-process': HyProcess; 'hy-process-flow-box': HyProcessFlowBox; @@ -1883,12 +2057,14 @@ declare module '@stencil/core' { JSXBase.HTMLAttributes<HTMLHyMainContentWrapperElement>; 'hy-menu': LocalJSX.HyMenu & JSXBase.HTMLAttributes<HTMLHyMenuElement>; 'hy-menu-item': LocalJSX.HyMenuItem & JSXBase.HTMLAttributes<HTMLHyMenuItemElement>; + 'hy-menu-item-sidebar': LocalJSX.HyMenuItemSidebar & JSXBase.HTMLAttributes<HTMLHyMenuItemSidebarElement>; 'hy-menu-language': LocalJSX.HyMenuLanguage & JSXBase.HTMLAttributes<HTMLHyMenuLanguageElement>; 'hy-menu-language-item': LocalJSX.HyMenuLanguageItem & JSXBase.HTMLAttributes<HTMLHyMenuLanguageItemElement>; 'hy-menu-level-container': LocalJSX.HyMenuLevelContainer & JSXBase.HTMLAttributes<HTMLHyMenuLevelContainerElement>; 'hy-menu-mobile-breadcrumb': LocalJSX.HyMenuMobileBreadcrumb & JSXBase.HTMLAttributes<HTMLHyMenuMobileBreadcrumbElement>; + 'hy-menu-sidebar': LocalJSX.HyMenuSidebar & JSXBase.HTMLAttributes<HTMLHyMenuSidebarElement>; 'hy-paragraph-text': LocalJSX.HyParagraphText & JSXBase.HTMLAttributes<HTMLHyParagraphTextElement>; 'hy-process': LocalJSX.HyProcess & JSXBase.HTMLAttributes<HTMLHyProcessElement>; 'hy-process-flow-box': LocalJSX.HyProcessFlowBox & JSXBase.HTMLAttributes<HTMLHyProcessFlowBoxElement>; diff --git a/src/components/hy-main/hy-main.scss b/src/components/hy-main/hy-main.scss index d8b51533c0dff2dc22ef880b08244071456a4962..f4d31815fbc851c1d16be6dd793358932975ee2c 100644 --- a/src/components/hy-main/hy-main.scss +++ b/src/components/hy-main/hy-main.scss @@ -1,6 +1,5 @@ .hy-main { display: flex; - //margin: var(--gutter-mobile) auto; margin: 0 auto; max-width: $fullhd; padding: 0; @@ -21,6 +20,8 @@ } &.with-sidebar { + position: relative; + .layout-content { @include breakpoint($medium) { margin: 0 auto; @@ -40,13 +41,19 @@ display: none; @include breakpoint($extrawide) { - display: block; - border-right: 2px dotted var(--grayscale-medium); + background: linear-gradient(270deg, #f5f5f5 0%, #f8f8f8 100%); display: block; max-width: 320px; order: 1; - padding: var(--gutter-extrawide); + padding: var(--gutter-extrawide) 13px; width: 20%; + height: auto; + + &.menu-is-open { + background: var(--grayscale-white); + min-height: 100vh; + overflow: auto; + } } } } diff --git a/src/components/icon/DotArrowRight.tsx b/src/components/icon/DotArrowRight.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9ff84c0783b2c979d344b14f03b785d9d3361ce2 --- /dev/null +++ b/src/components/icon/DotArrowRight.tsx @@ -0,0 +1,21 @@ +import {h} from '@stencil/core'; + +function SvgArrowDown(props) { + return ( + <svg viewBox="0 0 26 18" {...props}> + <circle id="Oval" fill="#107EAB" cx="8.5" cy="9" r="2"></circle> + <g id="Icon/arrow/to_right" transform="translate(10.000000, 0.000000)"> + <g transform="translate(9.000000, 9.000000) rotate(270.000000) translate(-9.000000, -9.000000) "> + <path + d="M15.3739539,2.58885408 L9.05563628,10.0114192 L2.62512723,2.58778423 C2.5650068,2.51838293 2.45894051,2.51196471 2.39075562,2.57360208 L0.0533953737,4.68651506 C-0.0121083665,4.74572874 -0.0181566661,4.84589323 0.039753545,4.91243423 L8.93312424,15.1312497 C8.99867166,15.2065661 9.11651053,15.2061936 9.18157232,15.1304643 L17.9609254,4.91164883 C18.018144,4.84504869 18.011809,4.74545823 17.9466045,4.68651506 L15.6092442,2.57360208 C15.5406475,2.51159238 15.4338255,2.5185168 15.3739539,2.58885408 Z" + id="Path" + transform="translate(9.000000, 8.859375) rotate(-360.000000) translate(-9.000000, -8.859375) " + ></path> + </g> + </g> + <circle id="Oval-Copy" fill="#107EAB" cx="2" cy="9" r="2"></circle> + </svg> + ); +} + +export default SvgArrowDown; diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx index ca55788897d5e2fad633166ad4d2f395690571b4..35c38b94740398840c7ef769f9738a8442bf72e1 100644 --- a/src/components/icon/icon.tsx +++ b/src/components/icon/icon.tsx @@ -13,6 +13,7 @@ const iconNames: IconName = { 'hy-icon-caret-down': (p) => <icons.CaretDown {...p} />, 'hy-icon-caret-left': (p) => <icons.CaretLeft {...p} />, 'hy-icon-caret-right': (p) => <icons.CaretRight {...p} />, + 'hy-icon-dot-arrow-right': (p) => <icons.DotArrowRight {...p} />, 'hy-icon-done': (p) => <icons.Done {...p} />, 'hy-icon-euro': (p) => <icons.Euro {...p} />, 'hy-icon-globe': (p) => <icons.Globe {...p} />, diff --git a/src/components/icon/icons.tsx b/src/components/icon/icons.tsx index c3eff2d2eaaacb80493947b681c798fb7e1404ed..5818b0cd927f2a069d5dec14b72808868716b19f 100644 --- a/src/components/icon/icons.tsx +++ b/src/components/icon/icons.tsx @@ -76,6 +76,7 @@ export {default as Date} from './Date'; export {default as Discover} from './Discover'; export {default as Done} from './Done'; export {default as Dot} from './Dot'; +export {default as DotArrowRight} from './DotArrowRight'; export {default as Download} from './Download'; export {default as Drag} from './Drag'; export {default as Dragbutton} from './Dragbutton'; diff --git a/src/components/icon/readme.md b/src/components/icon/readme.md index 552318cc9e2a6f74e240646b3ef9c173a601d33b..c42057f3becc0d5f442783211c25543c9e74b0f5 100644 --- a/src/components/icon/readme.md +++ b/src/components/icon/readme.md @@ -33,8 +33,11 @@ - [hy-introduction](../hy-introduction) - [hy-link-box](../link-box) - [hy-menu-item](../navigation/menu-item) +- [hy-menu-item-sidebar](../navigation/menu-item-sidebar) - [hy-menu-language](../navigation/menu-language) +- [hy-menu-level-container](../navigation/menu-level-container) - [hy-menu-mobile-breadcrumb](../navigation/menu-mobile-breadcrumb) +- [hy-menu-sidebar](../navigation/menu-sidebar) - [hy-quote](../hy-quote) - [hy-search-field](../hy-search-field) - [hy-shortcuts](../hy-shortcuts) @@ -67,8 +70,11 @@ graph TD; hy-introduction --> hy-icon hy-link-box --> hy-icon hy-menu-item --> hy-icon + hy-menu-item-sidebar --> hy-icon hy-menu-language --> hy-icon + hy-menu-level-container --> hy-icon hy-menu-mobile-breadcrumb --> hy-icon + hy-menu-sidebar --> hy-icon hy-quote --> hy-icon hy-search-field --> hy-icon hy-shortcuts --> hy-icon diff --git a/src/components/navigation/menu-item-sidebar/menu-item-sidebar.scss b/src/components/navigation/menu-item-sidebar/menu-item-sidebar.scss new file mode 100644 index 0000000000000000000000000000000000000000..f5d48164532657cbf080a5f6af7221efbb56f12e --- /dev/null +++ b/src/components/navigation/menu-item-sidebar/menu-item-sidebar.scss @@ -0,0 +1,194 @@ +.hy-menu-item-sidebar { + list-style-type: none; + margin-bottom: 6px; + + &--label-container { + @include font-size(18px, 22px); + @include font-weight($bold); + border: 0.5px solid rgba(16, 126, 171, 0.1); + box-sizing: border-box; + background-color: var(--grayscale-white); + color: var(--brand-main-light); + display: flex; + font-family: var(--main-font-family); + justify-content: space-between; + min-height: 48px; + padding: 0; + } + + &:focus { + outline-offset: 4px; + } + + &:hover { + color: var(--brand-main-nearly-black); + } + > .hy-menu-level-container.hy-menu-level-container--sidepanel { + display: none; + } + &.hy-menu-item-sidebar--sidepanel.in-active-trail { + > .hy-menu-item-sidebar--label-container { + border: 1px solid var(--brand-main-light); + text-decoration: none; + + > .hy-menu-item__label__icon { + border: none; + background-color: var(--brand-main-light); + + svg { + fill: var(--grayscale-white); + } + } + } + + > .hy-menu-level-container--sidepanel { + display: flex; + } + } + + &:not(.is-parent):not(.is-parent--sub-level).is-active-item { + > .hy-menu-item-sidebar--label-container { + background: var(--grayscale-white) !important; + text-decoration: none; + > .hy-menu-item-sidebar__label { + border: 1px solid var(--brand-main-light); + border-right: 0; + } + > .hy-menu-item__label__icon { + background-color: var(--brand-main-light); + border: none; + margin-left: 4px; + + svg { + fill: var(--grayscale-white); + } + } + } + } + + &__label { + align-items: center; + color: var(--brand-main-light); + display: flex; + hyphens: auto; + padding: 8px 10px 8px 20px; + text-decoration: none; + width: 100%; + word-break: break-word; + } + + .hy-menu-item__label__icon { + border-top: 0; + border-right: 0; + border-bottom: 0; + background: none; + border-left: 1px dotted var(--brand-main-light); + color: var(--brand-main-light); + display: inline-block; + position: relative; + width: 61.5px; + min-height: 48px; + + svg { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + } + + &:hover { + cursor: pointer; + } + + &:focus { + outline: none; + box-shadow: 0 0 1px 1px rgba(55, 148, 224, 0.5); + border-radius: none; + } + } + + &.is-parent { + align-items: flex-start; + background: none; + display: flex; + flex-direction: row; + justify-content: flex-start; + margin-bottom: 10px; + padding-bottom: 10px; + width: calc(100% - 25px); + max-width: 280px; + + .hy-menu-item-sidebar--label-container { + align-items: flex-start; + background: none; + border: none; + color: var(--brand-main-light); + display: flex; + + .hy-menu-item-sidebar__label { + @include font-size(26px, 26px); + font-family: var(--main-font-family); + font-weight: bold; + letter-spacing: -0.81px; + margin: 0 0 0 0.5rem; + padding: 0; + text-decoration: none; + } + } + + &:hover { + color: var(--brand-main-nearly-black); + + .hy-menu-item__parent__icon__svg { + fill: var(--brand-main-nearly-black); + } + } + + .hy-menu-item__parent__icon { + align-items: center; + display: flex; + flex-direction: row; + height: 26px; + } + + .hy-menu-item__parent__icon__svg svg { + fill: var(--brand-main-light); + } + + &.is-parent--sub-level { + align-items: flex-end; + background: none; + border-bottom: 1px solid var(--brand-main-light); + display: flex; + margin-bottom: 12px; + padding-bottom: 18px; + position: absolute; + transform: translateY(calc(-100% - 12px)); + width: calc(100% - 25px); + + .hy-menu-item-parent__icon { + bottom: 20px; + left: -20px; + position: absolute; + } + + svg { + fill: var(--brand-main-light); + } + + > .hy-menu-item-sidebar--label-container { + align-items: flex-end; + margin: 0; + padding: 0; + } + } + } + + &.is-current-page { + span.hy-menu-item-sidebar__label { + border-left: 4px solid var(--grayscale-black); + color: var(--grayscale-black); + padding: 8px 10px 8px 6px !important; + } + } +} diff --git a/src/components/navigation/menu-item-sidebar/menu-item-sidebar.tsx b/src/components/navigation/menu-item-sidebar/menu-item-sidebar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0dc5e683e6d39f7a61d658b374a6fee8400bfc54 --- /dev/null +++ b/src/components/navigation/menu-item-sidebar/menu-item-sidebar.tsx @@ -0,0 +1,198 @@ +import {Component, Element, Event, EventEmitter, h, Prop, Listen} from '@stencil/core'; +import {MenuType} from '../../../utils/utils'; + +@Component({ + tag: 'hy-menu-item-sidebar', + styleUrl: 'menu-item-sidebar.scss', + shadow: false, +}) +export class MenuItemSidebar { + @Element() el: HTMLElement; + @Event() addBreadcrumb: EventEmitter; + @Event() menuContainerActiveTrail: EventEmitter; + @Event() menuContainerToggled: EventEmitter; + @Event() routeClicked: EventEmitter; + @Prop() inActiveTrail: boolean = false; + @Prop() isActive: boolean = false; + @Prop() isActiveChild?: boolean = false; + @Prop() isHeading: boolean = false; + @Prop() isParent: boolean = false; + @Prop() isDemo: boolean = false; + @Prop() menuItemAlternative: boolean = false; + @Prop() menuLinkId: string = ''; + @Prop() menuType: MenuType = MenuType.sidenav; + @Prop() menuButtonSubmenuExpand?: string = ''; + @Prop() menuIsOpen = false; + @Prop({mutable: true}) ariaExpanded: boolean = false; + @Prop({mutable: true, reflect: true}) depth: number = 0; + @Prop({mutable: true}) hasChildren: boolean = null; + @Prop({mutable: true}) label: string = ''; + @Prop({mutable: true}) parentAsHeading: string = ''; + @Prop({mutable: true, reflect: true}) parentExpanded: boolean = false; + @Prop({mutable: true}) url: string = ''; + + @Listen('sidebarTopLevelToggle') sidebarTopLevelToggle(e) { + if (this.depth !== 1) { + return; + } + + const body = document.querySelector('body') as HTMLElement; + const container = document.querySelector('.hy-menu-sidebar--container') as HTMLElement; + const menuItem = e.target.closest('.hy-menu-item-sidebar') as HTMLElement; + + if (container.classList.contains('sidebar-open') && menuItem.classList.contains('is-active-item')) { + container.classList.remove('sidebar-open'); + body.classList.remove('hy-menu-sidebar__no-scroll'); + } else { + container.classList.add('sidebar-open'); + body.classList.add('hy-menu-sidebar__no-scroll'); + } + + e.preventDefault(); + } + + componentWillLoad() { + // If is-active class is added by system, add it to menu component as well. + if (this.el.classList.contains('is-active')) { + this.isActive = true; + } + + // Notify breadcrumbs if item is in active trail. + if (this.inActiveTrail && !this.isActive) { + const currentParent = this.el.parentNode; + this.addBreadcrumb.emit({ + url: this.url, + label: currentParent.parentElement.getAttribute('label'), + bid: this.menuLinkId, + }); + } + if (this.inActiveTrail) { + const currentParent = this.el.parentNode as any; + if (this.menuType === MenuType.sidepanel) { + currentParent.classList.add('is-open'); + } + } + + // If current menu item is active, trigger all parent menuLevelContainer + // elements in the same active-trail to open the menu. + if (this.isActive) { + const getParents = (elem) => { + let parents = []; + while (elem.parentNode && elem.parentNode.nodeName.toLowerCase() != 'hy-menu-sidebar') { + elem = elem.parentNode; + parents.push(elem); + } + return parents; + }; + + const parents = getParents(this.el); + parents.forEach((element) => { + if (element.tagName.toLowerCase() === 'hy-menu-item-sidebar') { + this.menuContainerActiveTrail.emit({ + triggerItem: element.getAttribute('menu-link-id'), + }); + } + }); + + // If side navigation menu item has is-active state, prepare the menu items + // for the last children. + parents.forEach((element) => { + if (element.tagName.toLowerCase() === 'hy-menu-item-sidebar') { + element.classList.add('is-hidden--child'); + } + }); + + // If current active menu item have children, set the child + // menu-level-container open. + if (this.el.children.length > 0) { + this.el.children[0].setAttribute('class', 'is-open-on-top'); + } + } + } + + componentWillRender() { + // Assign depth value to current menu item instance; 1st level, 2nd level, etc. + this.hasChildren = this.el.getElementsByTagName('hy-menu-level-container').length >= 1; + let parentMenuItem = this.el.closest('hy-menu-item-sidebar'); + let nextParentMenuItem; + this.depth = 0; + while (parentMenuItem) { + nextParentMenuItem = parentMenuItem.parentElement.closest('hy-menu-item-sidebar'); + if (nextParentMenuItem === parentMenuItem) { + break; + } else { + if (nextParentMenuItem !== null) { + this.parentAsHeading = nextParentMenuItem; + } + parentMenuItem = nextParentMenuItem; + this.depth = this.depth + 1; + } + } + } + + render() { + let classAttributes = [ + 'hy-menu-item-sidebar', + this.menuType ? `hy-menu-item-sidebar--${this.menuType}` : '', + this.depth != null ? 'hy-menu-item--level-' + this.depth : '', + this.isDemo ? 'is-demo' : '', + this.isActive ? 'is-current-page' : '', + this.isParent ? 'is-parent' : '', + this.hasChildren ? 'has-children' : '', + this.inActiveTrail ? 'in-active-trail' : '', + this.isActive && this.hasChildren ? 'is-active--heading' : '', + ]; + let anchorClassAttributes = ['hy-menu-item-sidebar__label']; + classAttributes = [...classAttributes]; + + if (this.url) { + return ( + <li + data-link-id={`menu-link-sidebar-${this.menuLinkId}`} + class={classAttributes.join(' ')} + aria-current={this.isActive ? 'true' : 'false'} + item-level={this.depth} + > + {this.isParent && ( + <span class={'hy-menu-item__parent__icon'}> + <hy-icon + class={'hy-menu-item__parent__icon__svg'} + icon={'hy-icon-caret-left'} + fill={'currentColor'} + size={10} + /> + </span> + )} + <div class="hy-menu-item-sidebar--label-container"> + {this.isActive ? ( + <span class={anchorClassAttributes.join(' ')}>{this.label}</span> + ) : ( + <a class={anchorClassAttributes.join(' ')} href={this.url}> + {this.label} + </a> + )} + {this.hasChildren && ( + <button + aria-labelledby={this.label} + aria-expanded={this.inActiveTrail && !this.isActive ? 'true' : 'false'} + type="button" + class={'hy-menu-item__label__icon'} + onClick={(e) => this.sidebarTopLevelToggle(e)} + > + <hy-icon + class={'hy-menu-item__label__icon__svg'} + icon={'hy-icon-caret-right'} + fill={'currentColor'} + size={18} + /> + </button> + )} + </div> + {this.hasChildren && <slot />} + </li> + ); + } else { + return; + } + } +} diff --git a/src/components/navigation/menu-item-sidebar/readme.md b/src/components/navigation/menu-item-sidebar/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..a96477cc2974daa77d4e623dcd3b5a9fcb669856 --- /dev/null +++ b/src/components/navigation/menu-item-sidebar/readme.md @@ -0,0 +1,53 @@ +# menu-item-sidebar + +<!-- Auto Generated Below --> + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------------------- | ---------------------------- | ----------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `ariaExpanded` | `aria-expanded` | | `boolean` | `false` | +| `depth` | `depth` | | `number` | `0` | +| `hasChildren` | `has-children` | | `boolean` | `null` | +| `inActiveTrail` | `in-active-trail` | | `boolean` | `false` | +| `isActive` | `is-active` | | `boolean` | `false` | +| `isActiveChild` | `is-active-child` | | `boolean` | `false` | +| `isDemo` | `is-demo` | | `boolean` | `false` | +| `isHeading` | `is-heading` | | `boolean` | `false` | +| `isParent` | `is-parent` | | `boolean` | `false` | +| `label` | `label` | | `string` | `''` | +| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `''` | +| `menuIsOpen` | `menu-is-open` | | `boolean` | `false` | +| `menuItemAlternative` | `menu-item-alternative` | | `boolean` | `false` | +| `menuLinkId` | `menu-link-id` | | `string` | `''` | +| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.sidepanel \| MenuType.tablet` | `MenuType.sidenav` | +| `parentAsHeading` | `parent-as-heading` | | `string` | `''` | +| `parentExpanded` | `parent-expanded` | | `boolean` | `false` | +| `url` | `url` | | `string` | `''` | + +## Events + +| Event | Description | Type | +| -------------------------- | ----------- | ------------------ | +| `addBreadcrumb` | | `CustomEvent<any>` | +| `menuContainerActiveTrail` | | `CustomEvent<any>` | +| `menuContainerToggled` | | `CustomEvent<any>` | +| `routeClicked` | | `CustomEvent<any>` | + +## Dependencies + +### Depends on + +- [hy-icon](../../icon) + +### Graph + +```mermaid +graph TD; + hy-menu-item-sidebar --> hy-icon + style hy-menu-item-sidebar fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +Helsinki University Design System diff --git a/src/components/navigation/menu-item/menu-item.scss b/src/components/navigation/menu-item/menu-item.scss index 451c3592e43967b64d9b7edb2af24a182356cbbc..09e7bf87e7c2c2990b1c6a4d8772960720795208 100644 --- a/src/components/navigation/menu-item/menu-item.scss +++ b/src/components/navigation/menu-item/menu-item.scss @@ -39,15 +39,6 @@ --hy-menu-item-sidenav-display: block; } -:host(.hy-menu-item--sidenav.is-hidden--child) { - --hy-menu-item-sidenav-display: none; -} - -:host(.hy-menu-item--sidenav:not(.is-parent)) { - display: none; - visibility: hidden; -} - :host(.hy-menu-item--sidenav.is-active) { display: block; visibility: visible; diff --git a/src/components/navigation/menu-item/menu-item.tsx b/src/components/navigation/menu-item/menu-item.tsx index 34c7be30b0bc9507ca5d930701686a405b8a32c4..016fcb8b8c91b97eac263a5ff31ad0cbbebb00d0 100644 --- a/src/components/navigation/menu-item/menu-item.tsx +++ b/src/components/navigation/menu-item/menu-item.tsx @@ -1,8 +1,6 @@ import {Component, Element, Event, EventEmitter, h, Host, Listen, Prop} from '@stencil/core'; import {MenuType} from '../../../utils/utils'; -// import {MenuItemVariants} from '../../utils/utils'; - @Component({ tag: 'hy-menu-item', styleUrl: 'menu-item.scss', @@ -61,10 +59,6 @@ export class MenuItem { label: currentParent.parentElement.getAttribute('label'), bid: this.menuLinkId, }); - - if (this.menuType === MenuType.sidenav) { - this.el.children[0].setAttribute('class', 'is-open'); - } } // If current menu item is active, trigger all parent menuLevelContainer @@ -87,37 +81,6 @@ export class MenuItem { }); } }); - - // If side navigation menu item has is-active state, prepare the menu items - // for the last children. - if (this.menuType === MenuType.sidenav) { - parents.forEach((element) => { - if (element.tagName.toLowerCase() === 'hy-menu-item') { - element.classList.add('is-hidden--child'); - } - }); - - // If current active menu item have children, set the child - // menu-level-container open. - if (this.el.children.length > 0) { - this.el.children[0].setAttribute('class', 'is-open'); - } - // If current active menu item does not have any children, mock the - // current menu item and parent menu item to behave like there would - // be child menu items available. - else { - const parentMenuItem = this.el.parentElement.closest('hy-menu-item'); - const parentMenuItemAnchor = parentMenuItem.shadowRoot.querySelector('a.hy-menu-item--sidenav'); - parentMenuItem.classList.remove('is-hidden--child'); - parentMenuItemAnchor.classList.add('is-active--heading'); - const menuItemSiblings = Array.prototype.slice.call(this.el.closest('hy-menu-level-container').children); - menuItemSiblings.forEach((element) => { - if (element.tagName.toLowerCase() === 'hy-menu-item') { - element.classList.add('is-active--child'); - } - }); - } - } } } @@ -233,28 +196,14 @@ export class MenuItem { ]; let anchorClassAttributes = [...classAttributes, this.isHeading ? 'is-heading' : '']; classAttributes = [...classAttributes, 'hy-menu-item']; - - return this.isParent ? ( - <Host class={classAttributes.join(' ')}> - <a href={this.url} class={anchorClassAttributes.join(' ')}> - <span class={'hy-menu-item__label__icon'}> - <hy-icon icon={'hy-icon-arrow-left'} fill={'currentColor'} size={18} /> - </span> - <span class={'hy-menu-item__label'}>{this.label}</span> - </a> - </Host> - ) : ( - <Host class={classAttributes.join(' ')}> - <a aria-current={this.isHeading.toString()} href={this.url} class={anchorClassAttributes.join(' ')}> - <span class={'hy-menu-item__label'}>{this.label}</span> - {this.hasChildren && ( - <span class={'hy-menu-item__label__icon'}> - <hy-icon icon={'hy-icon-caret-right'} fill={'currentColor'} size={12} /> - </span> - )} + return ( + <li class={classAttributes.join(' ')}> + <a class={anchorClassAttributes.join(' ')} href={this.url}> + {this.label} </a> + {this.hasChildren && <slot />} - </Host> + </li> ); } } diff --git a/src/components/navigation/menu-item/readme.md b/src/components/navigation/menu-item/readme.md index 17763127c5e51733e3630322ac415fcb2f34d926..aa75cc3843d0a5d4e47da4163a1e81fbb1b71aa0 100644 --- a/src/components/navigation/menu-item/readme.md +++ b/src/components/navigation/menu-item/readme.md @@ -4,25 +4,25 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------------- | ---------------------------- | ----------- | ---------------------------------------------------------------------------- | ------------------ | -| `ariaExpanded` | `aria-expanded` | | `boolean` | `false` | -| `depth` | `depth` | | `number` | `0` | -| `hasChildren` | `has-children` | | `boolean` | `null` | -| `inActiveTrail` | `in-active-trail` | | `boolean` | `false` | -| `isActive` | `is-active` | | `boolean` | `false` | -| `isActiveChild` | `is-active-child` | | `boolean` | `false` | -| `isDemo` | `is-demo` | | `boolean` | `false` | -| `isHeading` | `is-heading` | | `boolean` | `false` | -| `isParent` | `is-parent` | | `boolean` | `false` | -| `label` | `label` | | `string` | `''` | -| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `''` | -| `menuItemAlternative` | `menu-item-alternative` | | `boolean` | `false` | -| `menuLinkId` | `menu-link-id` | | `string` | `''` | -| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.tablet` | `MenuType.desktop` | -| `parentAsHeading` | `parent-as-heading` | | `string` | `''` | -| `parentExpanded` | `parent-expanded` | | `boolean` | `false` | -| `url` | `url` | | `string` | `''` | +| Property | Attribute | Description | Type | Default | +| ------------------------- | ---------------------------- | ----------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `ariaExpanded` | `aria-expanded` | | `boolean` | `false` | +| `depth` | `depth` | | `number` | `0` | +| `hasChildren` | `has-children` | | `boolean` | `null` | +| `inActiveTrail` | `in-active-trail` | | `boolean` | `false` | +| `isActive` | `is-active` | | `boolean` | `false` | +| `isActiveChild` | `is-active-child` | | `boolean` | `false` | +| `isDemo` | `is-demo` | | `boolean` | `false` | +| `isHeading` | `is-heading` | | `boolean` | `false` | +| `isParent` | `is-parent` | | `boolean` | `false` | +| `label` | `label` | | `string` | `''` | +| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `''` | +| `menuItemAlternative` | `menu-item-alternative` | | `boolean` | `false` | +| `menuLinkId` | `menu-link-id` | | `string` | `''` | +| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.sidepanel \| MenuType.tablet` | `MenuType.desktop` | +| `parentAsHeading` | `parent-as-heading` | | `string` | `''` | +| `parentExpanded` | `parent-expanded` | | `boolean` | `false` | +| `url` | `url` | | `string` | `''` | ## Events 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 a80d5227b2e12810ae74e8011325251d70c07860..0160314c1bcebd8be2968aadeb8cf3d9f5d60046 100644 --- a/src/components/navigation/menu-level-container/menu-level-container.scss +++ b/src/components/navigation/menu-level-container/menu-level-container.scss @@ -19,7 +19,6 @@ } &--desktop { - //align-items: center; align-items: flex-start; display: flex; flex-flow: column; @@ -39,18 +38,166 @@ } } - &--sidenav { + &--sidepanel { + background-color: var(--grayscale-white); + border-left: 1px solid rgba(0, 0, 0, 0.2); display: flex; - flex-flow: column; + flex-direction: column; + height: 100vh; + left: 0; + margin: 0; + padding-left: 13px; + padding-right: 13px; + padding-top: 240px; + position: absolute; + top: 0; + visibility: visible; + width: 261px; + z-index: 123; - &.is-open { - display: block; - visibility: visible; + &:not(.hy-menu-level-container--level-1) { + display: none; + min-height: var(--minHeight); + transform: translateX(calc(100% - 1px)); + + &.active-trail-panel, + &.is-open { + display: flex; + } + } + &.is-open, + &.active-trail-panel { + height: fit-content; + min-height: var(--minHeight); } + } - &:not(.is-open):not(.hy-menu-level-container--level-1) { + &--sidenav { + flex-flow: column; + margin: 0; + padding: 0; + position: relative; + + &:not(.hy-menu-level-container--level-1) { + opacity: 0; display: none; visibility: hidden; + + &.is-closed { + animation-direction: normal; + animation-duration: 0.25s; + animation-fill-mode: backwards; + animation-name: slide-panel-in; + } + + &.is-open { + animation-direction: normal; + animation-duration: 0.25s; + animation-fill-mode: forwards; + animation-name: slide-panel-in; + display: flex; + height: auto; + opacity: 1; + visibility: visible; + } + } + + &.is-open.is-open-on-top { + display: none; + transform: none !important; + } + + &.hy-menu-level-container.is-open { + max-width: 280px; + } + + .hy-menu-level-container--level-1 { + display: flex; } + + &:not(.hy-menu-level-container--level-1) { + background-color: var(--grayscale-white); + border-left: 1px solid rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + height: 100vh; + left: 0; + margin: -100vh 0; + min-height: var(--minHeight); + padding-left: 13px; + padding-right: 13px; + position: absolute; + transform: translateX(calc(100% - 1px)); + width: 281px; + z-index: 123; + + &.hy-menu-level-container--level-2 { + transform: translateX(calc(100% + 16px)) !important; + } + + &:before { + background: white; + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + content: ''; + display: none; + height: 96px; + left: -1px; + position: absolute; + top: 70vh; + width: 261px; + } + } + + .hy-menu-level-container--level-2 { + margin: -100vh 0; + padding: 100vh 13px; + top: 0; + } + + .hy-menu-level-container--level-3, + .hy-menu-level-container--level-4, + .hy-menu-level-container--level-5, + .hy-menu-level-container--level-6, + .hy-menu-level-container--level-7 { + padding: 100vh 13px; + top: 100vh; + } + } +} + +@keyframes slide-panel-in { + from { + transform: translateX(0); + display: none; + opacity: 0; + z-index: 1; + } + + 95% { + display: flex; + } + + to { + transform: translateX(calc(100% - 1px)); + opacity: 1; + z-index: 123; + } +} + +@keyframes slide-panel-out { + from { + transform: translateX(100%); + opacity: 1; + z-index: 123; + } + + 95% { + transform: translateX(0); + opacity: 0; + z-index: 1; + } + + to { + display: none; } } diff --git a/src/components/navigation/menu-level-container/menu-level-container.tsx b/src/components/navigation/menu-level-container/menu-level-container.tsx index ec25ffff57debd5610e2eb84300390d48a94a7bd..335ab0a016c6f9e5f933f038bec71163735094d0 100644 --- a/src/components/navigation/menu-level-container/menu-level-container.tsx +++ b/src/components/navigation/menu-level-container/menu-level-container.tsx @@ -16,6 +16,14 @@ export class MenuLevelContainer { @Prop({mutable: true, reflect: true}) depth: number = 0; @Prop({mutable: true}) headingItem: any; @Prop({mutable: true, reflect: true}) triggerItem: string; + /** + * Url to front page for panel first parent + */ + @Prop() frontUrl: string; + /** + * label for front page for panel first parent + */ + @Prop() frontLabel: string; @State() menuIsOpen: boolean = false; // Add/Remove is-hidden class from each upper level menu-items @@ -109,7 +117,8 @@ export class MenuLevelContainer { // Set is-active-child and menu-level attributes to all sibling menu-items. if (this.menuType === MenuType.sidenav) { - const parentMenuItem = this.el.closest('hy-menu-item'); + const parentMenuItem = this.el.closest('hy-menu-item-sidebar'); + if (parentMenuItem && parentMenuItem.classList.contains('is-active')) { this.menuIsOpen = true; const items = Array.from(this.el.children); @@ -123,7 +132,6 @@ export class MenuLevelContainer { render() { let classAttributes = ['hy-menu-level-container', 'hy-menu-level-container--level-' + this.depth]; - switch (this.menuType) { case MenuType.desktop: classAttributes = [...classAttributes, 'hy-menu-level-container--desktop']; @@ -161,25 +169,90 @@ export class MenuLevelContainer { ); } case MenuType.sidenav: - classAttributes = [...classAttributes, 'hy-menu-level-container--sidenav']; - if (this.depth === 1) { - classAttributes = [...classAttributes, 'is-open']; + const shouldBeHidden = this.depth != null && this.depth === 1 ? 'is-open' : ''; + classAttributes = [...classAttributes, 'hy-menu-level-container--sidenav', shouldBeHidden]; return ( - <Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}> + <ul data-menu-level={this.depth} class={classAttributes.join(' ')}> <slot /> - </Host> + </ul> ); } else { - classAttributes = [...classAttributes, this.menuIsOpen ? 'is-open' : null]; + const isMenuOpen = this.menuIsOpen ? 'is-open_is-open__sub-level' : null; + const shouldBeHidden = this.depth != null && this.depth === 1 ? 'is-open' : ''; + const parentMenuItem = this.el.closest('hy-menu-item-sidebar') as any; + const parentClone = parentMenuItem.cloneNode(true) as any; + const parentLink = parentClone.querySelector('.hy-menu-item-sidebar__label'); + classAttributes = [...classAttributes, 'hy-menu-level-container--sidenav', shouldBeHidden, isMenuOpen]; return ( - <Host aria-expanded={this.menuIsOpen.toString()} class={classAttributes.join(' ')} tabindex={'-1'}> + <ul data-menu-level={this.depth} class={classAttributes.join(' ')}> + {parentLink && ( + <li class="hy-menu-item-sidebar is-parent is-parent--sub-level"> + <hy-icon + class={'hy-menu-item-parent__icon'} + icon={'hy-icon-dot-arrow-right'} + fill={'currentColor'} + size={20} + /> + <span + aria-level={this.depth} + role="heading" + class="hy-menu-item-sidebar--label-container" + innerHTML={parentLink.outerHTML} + ></span> + </li> + )} <slot /> - </Host> + </ul> ); } + + case MenuType.sidepanel: + //const shouldBeHidden = (this.depth != null && this.depth === 1) ? 'is-open' : ''; + + classAttributes = [...classAttributes, 'hy-menu-level-container--sidepanel']; + const parentMenuItem = this.el.closest('hy-menu-item-sidebar') as any; + const parentClone = parentMenuItem ? (parentMenuItem.cloneNode(true) as any) : null; + const parentLink = parentClone ? parentClone.querySelector('.hy-menu-item-sidebar__label') : null; + return ( + <ul data-menu-level={this.depth} class={classAttributes.join(' ')}> + {parentLink ? ( + <li class="hy-menu-item-sidebar is-parent is-parent--sub-level"> + <hy-icon + class={'hy-menu-item-parent__icon'} + icon={'hy-icon-dot-arrow-right'} + fill={'currentColor'} + size={20} + /> + <span + aria-level={this.depth} + role="heading" + class="hy-menu-item-sidebar--label-container" + innerHTML={parentLink.outerHTML} + ></span> + </li> + ) : ( + <li class="hy-menu-item-sidebar is-parent is-parent--sub-level is-parent--frontpage"> + <span class={'hy-menu-item__parent__icon'}> + <hy-icon + class={'hy-menu-item__parent__icon__svg'} + icon={'hy-icon-caret-left'} + fill={'currentColor'} + size={10} + /> + </span> + <div class="hy-menu-item-sidebar--label-container"> + <a class="hy-menu-item-sidebar__label" href={this.frontUrl}> + {this.frontLabel} + </a> + </div> + </li> + )} + <slot /> + </ul> + ); } } } diff --git a/src/components/navigation/menu-level-container/readme.md b/src/components/navigation/menu-level-container/readme.md index 723ff6434f76c8d4725ea639948121489c9ee19f..91efe19f73d218ed046b5120ea08973e2b55b3a0 100644 --- a/src/components/navigation/menu-level-container/readme.md +++ b/src/components/navigation/menu-level-container/readme.md @@ -4,28 +4,32 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------------- | ---------------------------- | ----------- | ---------------------------------------------------------------------------- | ----------------- | -| `activeTrailTriggered` | `active-trail-triggered` | | `boolean` | `false` | -| `depth` | `depth` | | `number` | `0` | -| `headingItem` | `heading-item` | | `any` | `undefined` | -| `labelFrontPage` | `label-front-page` | | `string` | `undefined` | -| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `undefined` | -| `menuLevel` | `menu-level` | | `number` | `undefined` | -| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.tablet` | `MenuType.mobile` | -| `triggerItem` | `trigger-item` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------------- | ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------- | ----------------- | +| `activeTrailTriggered` | `active-trail-triggered` | | `boolean` | `false` | +| `depth` | `depth` | | `number` | `0` | +| `frontLabel` | `front-label` | label for front page for panel first parent | `string` | `undefined` | +| `frontUrl` | `front-url` | Url to front page for panel first parent | `string` | `undefined` | +| `headingItem` | `heading-item` | | `any` | `undefined` | +| `labelFrontPage` | `label-front-page` | | `string` | `undefined` | +| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `undefined` | +| `menuLevel` | `menu-level` | | `number` | `undefined` | +| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.sidepanel \| MenuType.tablet` | `MenuType.mobile` | +| `triggerItem` | `trigger-item` | | `string` | `undefined` | ## Dependencies ### Depends on - [hy-menu-item](../menu-item) +- [hy-icon](../../icon) ### Graph ```mermaid graph TD; hy-menu-level-container --> hy-menu-item + hy-menu-level-container --> hy-icon hy-menu-item --> hy-icon style hy-menu-level-container fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/navigation/menu-sidebar/menu-sidebar.scss b/src/components/navigation/menu-sidebar/menu-sidebar.scss new file mode 100644 index 0000000000000000000000000000000000000000..ac42203a60e18f1eb010d1367b28f02ff89caad6 --- /dev/null +++ b/src/components/navigation/menu-sidebar/menu-sidebar.scss @@ -0,0 +1,173 @@ +:host { + display: block; +} + +.hy-menu-sidebar__no-scroll { + height: 200vh; + overflow: hidden; +} + +.hy-menu-sidepanel__no-scroll { + height: 100vh; + overflow: hidden; +} + +.hy-menu-sidebar--container { + background: none; + position: relative; + + &.sidebar-open { + background: linear-gradient(to right, #fff 380px, rgba(0, 0, 0, 0.5) 10%); + bottom: 0; + display: block; + height: auto; + left: 16px; + overflow: auto; + position: absolute; + right: 0; + top: -96px; + transition: all 0.25s ease-in; + z-index: 5; + + .hy-menu-sidebar__logo { + align-items: center; + display: flex; + height: 96px; + margin-bottom: var(--gutter-extrawide); + + .hy-site-logo__label { + max-width: 200px; + } + } + .hy-menu-sidebar__panel-toggle { + display: flex; + } + + // Open sidenav panels. Set background color to non-active items + :not(.is-parent):not(.is-active-item).hy-menu-item-sidebar .hy-menu-item-sidebar--label-container { + background: linear-gradient(270deg, #f5f5f5 0%, #f8f8f8 100%); + } + } + .hy-menu-sidebar__panel-toggle, + .hy-menu-sidebar__logo { + display: none; + } +} + +.hy-menu-sidepanel--container { + animation-direction: normal; + animation-duration: 0.25s; + animation-fill-mode: forwards; + animation-name: sidepanel-moveout; + bottom: 0; + display: none; + left: 0; + overflow: auto; + position: absolute; + right: 0; + top: -96px; + transform: translateX(-105%); + visibility: hidden; + z-index: 124; + + &.sidepanel-open { + animation-direction: normal; + animation-duration: 0.35s; + animation-fill-mode: forwards; + animation-name: sidepanel-movein; + display: flex; + height: auto; + width: 100%; + } +} + +.hy-menu-sidebar { + display: none; + + @include breakpoint($extrawide) { + display: block; + max-width: 280px; // Should be in the wrapper. + + &[aria-hidden='false'] { + min-height: var(--minHeight); + } + } +} + +.hy-menu-sidebar__panel-toggle { + @include font-size(14px, 20px); + align-items: center; + background-color: transparent; + border: none; + color: var(--brand-main-light); + display: flex; + flex-direction: row; + font-family: var(--main-font-family); + font-weight: 600; + letter-spacing: -0.5px; + margin-bottom: 1rem; + + &:hover { + cursor: pointer; + } + + svg { + fill: var(--brand-main-light); + } + + hy-icon:last-child { + margin-right: 0.75rem; + } +} + +.hy-menu-sidepanel__logo-container { + display: flex; + flex-direction: column; + height: 150px; + justify-content: space-between; + margin: 20px; + position: relative; + z-index: 125; +} + +@keyframes sidepanel-movein { + from { + display: none; + transform: translateX(-105%); + visibility: hidden; + } + 5% { + display: flex; + } + + 50% { + background-color: rgba(0, 0, 0, 0); + } + + to { + background-color: rgba(0, 0, 0, 0.5); + transform: translateX(0); + visibility: visible; + } +} + +@keyframes sidepanel-moveout { + from { + background-color: rgba(0, 0, 0, 0.5); + transform: translateX(0); + visibility: visible; + } + + 75% { + background-color: rgba(0, 0, 0, 0); + } + + 90% { + transform: translateX(-105%); + } + + to { + display: none; + visibility: hidden; + } +} diff --git a/src/components/navigation/menu-sidebar/menu-sidebar.tsx b/src/components/navigation/menu-sidebar/menu-sidebar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8e0dcd02fa6ed7734436053b05b674f67f9b95c7 --- /dev/null +++ b/src/components/navigation/menu-sidebar/menu-sidebar.tsx @@ -0,0 +1,368 @@ +import {Component, Element, h, State, Listen, Prop} from '@stencil/core'; +import {MenuType, SiteLogoSize, ColorVariant} from '../../../utils/utils'; + +@Component({ + tag: 'hy-menu-sidebar', + styleUrl: 'menu-sidebar.scss', + shadow: false, +}) +export class MenuSidebar { + @Element() el: HTMLElement; + /** + * Is menu open boolean. + */ + @Prop() menuIsOpen = false; + /** + * Menu type. Defaults to sidenav. + */ + @Prop() menuType: MenuType = MenuType.sidenav; + /** + * Upper menus panel boolean. + */ + @Prop() panelOpen = false; + /** + * Label for panel toggle button. + */ + @Prop() panelToggleLabel?: string; + /** + * Label for panel toggle button. + */ + @Prop() panelToggleAriaLabel?: string; + /** + * Label for panel toggle button. + */ + @Prop() panelToggleCloseLabel?: string; + /** + * Label for panel toggle button. + */ + @Prop() panelToggleCloseAriaLabel?: string; + /** + * Url for logo. + */ + @Prop() logoUrl?: string; + /** + * Logo label + */ + @Prop() logoLabel?: string; + /** + * Logo size + */ + @Prop() size: SiteLogoSize = SiteLogoSize.big; + /** + * Isdemo + */ + @Prop() isDemo: boolean = false; + /** + * Previous panel to be toggled to keep track. + */ + @Prop({mutable: true}) minHeight: any = null; + @State() previousPanel: HTMLElement; + /** + * Previous item to be toggle to keep track. + */ + @State() previousItem; + //@State() previousItem: HTMLElement; + + @Listen('panelToggle') panelToggle(e) { + if (this.menuIsOpen) { + this.closeWholeTree(); + const body = document.querySelector('body') as HTMLElement; + + this.panelOpen = !this.panelOpen; + this.panelOpen + ? body.classList.add('hy-menu-sidepanel__no-scroll') + : body.classList.remove('hy-menu-sidepanel__no-scroll'); + } else { + this.panelOpen = !this.panelOpen; + const body = document.querySelector('body') as HTMLElement; + this.panelOpen + ? body.classList.add('hy-menu-sidepanel__no-scroll') + : body.classList.remove('hy-menu-sidepanel__no-scroll'); + } + + e.preventDefault(); + e.stopPropagation(); + } + + componentWillLoad() { + const sideBar = document.querySelector('.layout-sidebar-first'); + if (this.menuIsOpen) { + sideBar.classList.add('menu-is-open'); + } else if (sideBar.classList.contains('menu-is-open')) { + sideBar.classList.remove('menu-is-open'); + } + } + + componentDidLoad() { + const sidebarContainer = document.querySelector('.hy-menu-sidebar--container'); + sidebarContainer.addEventListener('click', (e) => { + if ((e.target as HTMLElement).classList.contains('sidebar-open')) { + this.closeWholeTree(); + } + }); + const sidepanelContainer = document.querySelector('.hy-menu-sidepanel--container'); + sidepanelContainer.addEventListener('click', (e) => { + if ((e.target as HTMLElement).classList.contains('sidepanel-open')) { + this.panelToggle(e); + } + }); + + const panels = document.querySelectorAll('.hy-menu-level-container'); + if (panels) { + const height = Math.max.apply( + Math, + [...panels].map((panel) => panel.scrollHeight) + ); + this.minHeight = height; + } + } + + componentWillUpdate() { + const sideBar = document.querySelector('.layout-sidebar-first'); + + if (this.menuIsOpen) { + sideBar.classList.add('menu-is-open'); + } else if (sideBar.classList.contains('menu-is-open')) { + sideBar.classList.remove('menu-is-open'); + } + } + + @Listen('click') + handlePanel(e) { + const target = e.target; + + const targetElement = target.tagName.toLowerCase(); + const possibleTags = [targetElement].some((r) => ['svg', 'path'].indexOf(r) >= 0); + + if (target.classList.contains('hy-menu-item__label__icon') || possibleTags) { + const menuItem = target.closest('.hy-menu-item-sidebar'); + const menuItemId = menuItem.getAttribute('data-link-id'); + const menuItemLevel = menuItem.getAttribute('item-level'); + const menuPanel = menuItem.closest('.hy-menu-level-container'); + const childList = menuItem.querySelector('.hy-menu-level-container'); + + // If no previous, as in first time clicking menu + if (!this.previousPanel) { + this.updatePrevious(menuPanel, menuItem); + this.togglePanel(menuItem, childList); + return; + } + + const prevId = this.previousItem.dataset.linkId; + const prevLevel = this.previousItem.getAttribute('item-level'); + + // If clicking same menu item again. + if (menuItemId === prevId) { + if (menuItem.classList.contains('is-active-item')) { + this.togglePanel(menuItem, childList, true); + if (menuItemLevel == 1) { + this.menuIsOpen = false; + } + } else { + this.togglePanel(menuItem, childList); + } + return; + } + + // If clicking menu item on same level or going back up + if (menuItemLevel <= prevLevel) { + // If clicking already active, close children + if (menuItem.classList.contains('is-active-item')) { + this.togglePanel(menuItem, childList, true); + this.updatePrevious(menuPanel, menuItem); + return; + } + // Close previous panels + this.togglePanel(this.previousItem, menuPanel, true); + // Open newly clicked panel + this.togglePanel(menuItem, childList); + // Update previous + this.updatePrevious(menuPanel, menuItem); + } else if (menuItemLevel > prevLevel) { + this.togglePanel(menuItem, childList); + this.updatePrevious(menuPanel, menuItem); + } + } + e.stopImmediatePropagation(); + e.stopPropagation(); + } + + updatePrevious(panel, item) { + this.previousPanel = panel; + this.previousItem = item; + } + + closeWholeTree() { + const sidebarLevel1 = document.querySelector('.hy-menu-level-container--level-1') as HTMLElement; + const firstItem = document.querySelector( + '.hy-menu-item-sidebar--sidenav.hy-menu-item--level-1.is-active-item' + ) as HTMLElement; + this.togglePanel(firstItem, sidebarLevel1, true); + const body = document.querySelector('body') as HTMLElement; + const container = document.querySelector('.hy-menu-sidebar--container') as HTMLElement; + + if (container.classList.contains('sidebar-open') && firstItem) { + container.classList.remove('sidebar-open'); + body.classList.remove('hy-menu-sidebar__no-scroll'); + } + } + + togglePanel(menuItem, panel, shouldClose = false) { + const buttonElement = menuItem.querySelector('button'); + const level = menuItem.getAttribute('item-level'); + if (level == 1 && !this.menuIsOpen) { + if (window.pageYOffset > 50 && !this.isDemo) { + window.scrollTo({top: 0}); + } + this.menuIsOpen = true; + } + if (shouldClose) { + const children = panel.querySelectorAll('.hy-menu-item-sidebar'); + const activeChild = [...children].filter((c) => c.classList.contains('is-active-item')); + if (level == 1 && activeChild) { + this.menuIsOpen = false; + } + if (activeChild.length > 0) { + for (let i = 0; i < activeChild.length; i++) { + const element = activeChild[i]; + this.closeChildren(element); + } + } + buttonElement.setAttribute('aria-expanded', 'false'); + this.closeChildren(menuItem); + //this.menuIsOpen = level == 1 ? true : false; + return; + } + buttonElement.setAttribute('aria-expanded', 'true'); + panel.classList.add('is-open'); + menuItem.classList.add('is-active-item'); + } + + closeChildren(menuItem) { + if (menuItem.classList.contains('is-active-item')) { + menuItem.classList.remove('is-active-item'); + } + if (menuItem.classList.contains('has-children')) { + const menuButton = menuItem.querySelector('button'); + menuButton.setAttribute('aria-expanded', 'false'); + const childList = menuItem.querySelector('.hy-menu-level-container'); + childList.classList.remove('is-open'); + const childItems = childList.querySelectorAll('.hy-menu-item-sidebar'); + if (childList.classList.contains('is-active')) { + childList.classList.remove('is-active'); + } + childItems.forEach((element) => { + element.classList.remove('is-active-item'); + if (element.classList.contains('has-children')) { + const menuButton = element.querySelector('button'); + menuButton.setAttribute('aria-expanded', 'false'); + this.closeChildren(element); + } else { + return; + } + }); + } + } + + render() { + const logoColor = ColorVariant.black; + const panelClassAttributes = ['hy-menu-sidepanel--container', this.panelOpen ? 'sidepanel-open' : ''].join(' '); + switch (this.menuType) { + case MenuType.sidepanel: + return ( + <div + class="hy-menu-sidebar__container" + style={{ + '--minHeight': `${this.minHeight}px` as 'minHeight', + }} + > + <button + aria-label={this.panelToggleAriaLabel} + class="hy-menu-sidebar__panel-toggle" + onClick={(e) => this.panelToggle(e)} + > + <hy-icon icon={'hy-icon-caret-left'} fill={'currentColor'} size={10} /> + <hy-icon icon={'hy-icon-caret-left'} fill={'currentColor'} size={10} /> + + {this.panelToggleLabel} + </button> + <div + class={panelClassAttributes} + aria-hidden={this.panelOpen ? 'false' : 'true'} + aria-expanded={this.panelOpen ? 'true' : 'false'} + > + <div class="hy-menu-sidepanel__nav-container"> + <div class="hy-menu-sidepanel__logo-container"> + <div + class="hy-menu-sidepanel__logo" + aria-hidden={this.panelOpen ? 'false' : 'true'} + tabindex={this.panelOpen ? '0' : '-1'} + > + <hy-site-logo size={56} color={logoColor} url={this.logoUrl} label={this.logoLabel} /> + </div> + <button + aria-label={this.panelToggleCloseAriaLabel} + aria-hidden={this.panelOpen ? 'false' : 'true'} + tabindex={this.panelOpen ? '0' : '-1'} + class="hy-menu-sidebar__panel-toggle" + onClick={(e) => this.panelToggle(e)} + > + <hy-icon icon={'hy-icon-remove'} fill={'currentColor'} size={10} /> + + {this.panelToggleCloseLabel} + </button> + </div> + <nav + role={'navigation'} + aria-hidden={this.panelOpen ? 'false' : 'true'} + tabindex={this.panelOpen ? '0' : '-1'} + class={{ + 'hy-menu': true, + 'hy-menu-sidepanel': true, + 'is-demo': this.isDemo, + }} + > + <slot /> + </nav> + </div> + </div> + </div> + ); + + case MenuType.sidenav: + return ( + <div + class="hy-menu-sidebar--container" + style={{ + '--minHeight': `${this.minHeight}px` as 'minHeight', + }} + > + <div class="hy-menu-sidebar__logo"> + <hy-site-logo size={56} color={logoColor} url={this.logoUrl} label={this.logoLabel} /> + </div> + <button + aria-label={this.panelToggleAriaLabel} + class="hy-menu-sidebar__panel-toggle" + onClick={(e) => this.panelToggle(e)} + > + <hy-icon icon={'hy-icon-caret-left'} fill={'currentColor'} size={10} /> + <hy-icon icon={'hy-icon-caret-left'} fill={'currentColor'} size={10} /> + + {this.panelToggleLabel} + </button> + <nav + role={'navigation'} + aria-hidden={this.menuIsOpen ? 'false' : 'true'} + class={{ + 'hy-menu': true, + 'hy-menu-sidebar': true, + 'is-demo': this.isDemo, + }} + > + <slot /> + </nav> + </div> + ); + } + } +} diff --git a/src/components/navigation/menu-sidebar/readme.md b/src/components/navigation/menu-sidebar/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..b327245c2be75690c472cb49efb0b0cb67e3e4e3 --- /dev/null +++ b/src/components/navigation/menu-sidebar/readme.md @@ -0,0 +1,41 @@ +# hy-menu-sidebar + +<!-- Auto Generated Below --> + +## Properties + +| Property | Attribute | Description | Type | Default | +| --------------------------- | ------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `isDemo` | `is-demo` | Isdemo | `boolean` | `false` | +| `logoLabel` | `logo-label` | Logo label | `string` | `undefined` | +| `logoUrl` | `logo-url` | Url for logo. | `string` | `undefined` | +| `menuIsOpen` | `menu-is-open` | Is menu open boolean. | `boolean` | `false` | +| `menuType` | `menu-type` | Menu type. Defaults to sidenav. | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.sidepanel \| MenuType.tablet` | `MenuType.sidenav` | +| `minHeight` | `min-height` | Previous panel to be toggled to keep track. | `any` | `null` | +| `panelOpen` | `panel-open` | Upper menus panel boolean. | `boolean` | `false` | +| `panelToggleAriaLabel` | `panel-toggle-aria-label` | Label for panel toggle button. | `string` | `undefined` | +| `panelToggleCloseAriaLabel` | `panel-toggle-close-aria-label` | Label for panel toggle button. | `string` | `undefined` | +| `panelToggleCloseLabel` | `panel-toggle-close-label` | Label for panel toggle button. | `string` | `undefined` | +| `panelToggleLabel` | `panel-toggle-label` | Label for panel toggle button. | `string` | `undefined` | +| `size` | `size` | Logo size | `SiteLogoSize.big \| SiteLogoSize.large \| SiteLogoSize.small` | `SiteLogoSize.big` | + +## Dependencies + +### Depends on + +- [hy-icon](../../icon) +- [hy-site-logo](../../site-header/site-logo) + +### Graph + +```mermaid +graph TD; + hy-menu-sidebar --> hy-icon + hy-menu-sidebar --> hy-site-logo + hy-site-logo --> hy-icon + style hy-menu-sidebar fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +Helsinki University Design System diff --git a/src/components/navigation/menu/menu.scss b/src/components/navigation/menu/menu.scss index a6bd0ac8768afa9f9d2ce66a7377818c2b08c250..f8aa62a6995f1471cd400dd8f8f31f2efb9a3486 100644 --- a/src/components/navigation/menu/menu.scss +++ b/src/components/navigation/menu/menu.scss @@ -86,15 +86,6 @@ padding: 16px 28px; } } - - &--sidenav { - display: none; - - @include breakpoint($extrawide) { - display: block; - max-width: 20vw; // Should be in the wrapper. - } - } } .hy-link__donate { diff --git a/src/components/navigation/menu/menu.tsx b/src/components/navigation/menu/menu.tsx index 9ab50e0ac8492b288f3feb13e4159d23912b93f8..73b477776a0892f5afab5b9f3acdf6949a23b363 100644 --- a/src/components/navigation/menu/menu.tsx +++ b/src/components/navigation/menu/menu.tsx @@ -177,21 +177,6 @@ export class Menu { </div> </nav> ); - - case MenuType.sidenav: - return ( - <nav - role={'navigation'} - aria-hidden={this.menuIsOpen ? 'false' : 'true'} - class={{ - 'hy-menu': true, - 'hy-menu--sidenav': true, - 'is-demo': this.isDemo, - }} - > - <slot /> - </nav> - ); } } } diff --git a/src/components/navigation/menu/readme.md b/src/components/navigation/menu/readme.md index 841305ec950f521d311c1c2a2f13eabb192cac0c..baad4577f70315dd590dd4a65ea1bbd106279c1f 100644 --- a/src/components/navigation/menu/readme.md +++ b/src/components/navigation/menu/readme.md @@ -4,18 +4,18 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ---------------------------- | ------------------------------- | ----------- | ---------------------------------------------------------------------------- | ------------------ | -| `dataMenuDonate` | `data-menu-donate` | | `string` | `undefined` | -| `dataMenuLanguage` | `data-menu-language` | | `string` | `undefined` | -| `isDemo` | `is-demo` | | `boolean` | `false` | -| `labelFrontPage` | `label-front-page` | | `string` | `undefined` | -| `logoLabel` | `logo-label` | | `string` | `undefined` | -| `logoUrl` | `logo-url` | | `string` | `undefined` | -| `menuButtonBreadcrumbReturn` | `menu-button-breadcrumb-return` | | `string` | `undefined` | -| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `undefined` | -| `menuIsOpen` | `menu-is-open` | | `boolean` | `true` | -| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.tablet` | `MenuType.desktop` | +| Property | Attribute | Description | Type | Default | +| ---------------------------- | ------------------------------- | ----------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `dataMenuDonate` | `data-menu-donate` | | `string` | `undefined` | +| `dataMenuLanguage` | `data-menu-language` | | `string` | `undefined` | +| `isDemo` | `is-demo` | | `boolean` | `false` | +| `labelFrontPage` | `label-front-page` | | `string` | `undefined` | +| `logoLabel` | `logo-label` | | `string` | `undefined` | +| `logoUrl` | `logo-url` | | `string` | `undefined` | +| `menuButtonBreadcrumbReturn` | `menu-button-breadcrumb-return` | | `string` | `undefined` | +| `menuButtonSubmenuExpand` | `menu-button-submenu-expand` | | `string` | `undefined` | +| `menuIsOpen` | `menu-is-open` | | `boolean` | `true` | +| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.sidepanel \| MenuType.tablet` | `MenuType.desktop` | ## Events diff --git a/src/components/site-header/readme.md b/src/components/site-header/readme.md index ca762fc5a53111ad826fe88469b75100016fa8c5..fb281a59b339570530fc72b85daa3f351537e71c 100644 --- a/src/components/site-header/readme.md +++ b/src/components/site-header/readme.md @@ -4,17 +4,17 @@ ## Properties -| 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` | -| `logoLabel` | `logo-label` | | `string` | `undefined` | -| `logoUrl` | `logo-url` | | `string` | `undefined` | -| `menuLabelClose` | `menu-label-close` | | `string` | `undefined` | -| `menuLabelOpen` | `menu-label-open` | | `string` | `undefined` | -| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.tablet` | `MenuType.default` | +| 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` | +| `logoLabel` | `logo-label` | | `string` | `undefined` | +| `logoUrl` | `logo-url` | | `string` | `undefined` | +| `menuLabelClose` | `menu-label-close` | | `string` | `undefined` | +| `menuLabelOpen` | `menu-label-open` | | `string` | `undefined` | +| `menuType` | `menu-type` | | `MenuType.desktop \| MenuType.mobile \| MenuType.sidenav \| MenuType.sidepanel \| MenuType.tablet` | `MenuType.default` | ## Dependencies diff --git a/src/components/site-header/site-logo/readme.md b/src/components/site-header/site-logo/readme.md index 24fb530f21102a30a16100f4c6a5c50982a1f206..6ca8f13049d858c93942fb48a91d43d31cca698b 100644 --- a/src/components/site-header/site-logo/readme.md +++ b/src/components/site-header/site-logo/readme.md @@ -17,6 +17,7 @@ - [hy-footer-base](../../footer/hy-footer-base) - [hy-menu](../../navigation/menu) +- [hy-menu-sidebar](../../navigation/menu-sidebar) - [hy-site-header](..) - [hy-user-login-form](../../hy-user-login-form) @@ -31,6 +32,7 @@ graph TD; hy-site-logo --> hy-icon hy-footer-base --> hy-site-logo hy-menu --> hy-site-logo + hy-menu-sidebar --> hy-site-logo hy-site-header --> hy-site-logo hy-user-login-form --> hy-site-logo style hy-site-logo fill:#f9f,stroke:#333,stroke-width:4px diff --git a/src/index.html b/src/index.html index 5f06571b8d299c4a6c4461c8507a31aa85184595..6d625609c548333d9a40d293dd6cfcceb5b7eaa4 100644 --- a/src/index.html +++ b/src/index.html @@ -984,7 +984,82 @@ </div> <aside class="layout-sidebar-first" role="complementary"> - THIS IS SIDEBAR + <hy-menu-sidebar slot="menu" menu-type="sidenav" open="true" is-demo="true"> + <hy-menu-level-container menu-type="sidenav" menu-level="1"> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="1" url="#" label="News"> + <hy-menu-level-container menu-type="sidenav" menu-level="2"> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="2" url="#" label="News"></hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="42345" url="#" label="Research"> + <hy-menu-level-container menu-type="sidenav" menu-level="2"> + <hy-menu-item-sidebar + menu-type="sidenav" + menu-link-id="123" + url="#" + label="Top Research" + ></hy-menu-item-sidebar> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="22" url="#" label="Middle Research"> + <hy-menu-level-container menu-type="sidenav" menu-level="3"> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="232" url="#" label="Middle Top Research"> + <hy-menu-level-container menu-type="sidenav" menu-level="4"> + <hy-menu-item-sidebar + menu-type="sidenav" + menu-link-id="21" + url="#" + label="Top" + ></hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + <hy-menu-item-sidebar + menu-type="sidenav" + menu-link-id="242" + url="#" + label="Middle Middle Research" + ></hy-menu-item-sidebar> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="252" url="#" label="Middle Bottom Research"> + <hy-menu-level-container menu-type="sidenav" menu-level="4"> + <hy-menu-item-sidebar + menu-type="sidenav" + menu-link-id="2134" + url="#" + label="Bottom" + ></hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + <hy-menu-item-sidebar + menu-type="sidenav" + menu-link-id="222" + url="#" + label="Bottom Research" + ></hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + <hy-menu-item-sidebar + menu-type="sidenav" + menu-link-id="4905" + url="#" + label="Admissions" + ></hy-menu-item-sidebar> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="4776" url="#" label="Cooperation"> + <hy-menu-level-container menu-type="sidenav" menu-level="2"> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="455725" url="#" label="Admissions 2"> + <hy-menu-level-container menu-type="sidenav" menu-level="3"> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="4235653" url="#" label="Admissions 2"> + <hy-menu-level-container menu-type="sidenav" menu-level="4"> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="1235653" url="#" label="Admissions 3"> + </hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-item-sidebar> + <hy-menu-item-sidebar menu-type="sidenav" menu-link-id="47" url="#" label="About us"></hy-menu-item-sidebar> + </hy-menu-level-container> + </hy-menu-sidebar> </aside> </hy-main> <div style="max-width: 1216px; margin: 0 auto;"> diff --git a/src/utils/utils.ts b/src/utils/utils.ts index d42623658c9fc4aa8b9eacfadcb58f0de55a1b3c..d16c1f46e1710d40d57d6ce41ea2d060ef549021 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -130,6 +130,7 @@ export enum GridAlignVariants { export enum MenuType { desktop = 'desktop', sidenav = 'sidenav', + sidepanel = 'sidepanel', mobile = 'mobile', tablet = 'tabled', default = 'desktop',