diff --git a/package.json b/package.json index 4d597c8bc8c9350d9af468969590904de5cab68d..2a888eab8bc7f345622edd5cdd5e1373d55ad5e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@itcenteratunihelsinki/huds-lib", - "version": "0.0.66", + "version": "0.0.70", "description": "Helsinki University Design System library", "main": "dist/index.js", "module": "dist/index.mjs", diff --git a/src/assets/example.svg b/src/assets/example.svg new file mode 100644 index 0000000000000000000000000000000000000000..24d66224fda7585b21f20e6e8ebff88ba55f722b --- /dev/null +++ b/src/assets/example.svg @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + viewBox="0 -256 1792 1792" + id="svg3013" + version="1.1" + inkscape:version="0.48.3.1 r9886" + width="100%" + height="100%" + sodipodi:docname="download_font_awesome.svg"> + <metadata + id="metadata3023"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs3021" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="640" + inkscape:window-height="480" + id="namedview3019" + showgrid="false" + inkscape:zoom="0.13169643" + inkscape:cx="896" + inkscape:cy="896" + inkscape:window-x="0" + inkscape:window-y="25" + inkscape:window-maximized="0" + inkscape:current-layer="svg3013" /> + <g + transform="matrix(1,0,0,-1,113.89831,1293.0169)" + id="g3015"> + <path + d="m 1120,608 q 0,-12 -10,-24 L 791,265 q -9,-9 -23,-9 -14,0 -23,9 L 425,585 q -9,9 -9,23 0,13 9.5,22.5 9.5,9.5 22.5,9.5 h 192 v 352 q 0,13 9.5,22.5 9.5,9.5 22.5,9.5 h 192 q 13,0 22.5,-9.5 Q 896,1005 896,992 V 640 h 192 q 14,0 23,-9 9,-9 9,-23 z m 160,32 q 0,104 -40.5,198.5 Q 1199,933 1130,1002 1061,1071 966.5,1111.5 872,1152 768,1152 664,1152 569.5,1111.5 475,1071 406,1002 337,933 296.5,838.5 256,744 256,640 256,536 296.5,441.5 337,347 406,278 475,209 569.5,168.5 664,128 768,128 872,128 966.5,168.5 1061,209 1130,278 1199,347 1239.5,441.5 1280,536 1280,640 z m 256,0 Q 1536,431 1433,254.5 1330,78 1153.5,-25 977,-128 768,-128 559,-128 382.5,-25 206,78 103,254.5 0,431 0,640 0,849 103,1025.5 206,1202 382.5,1305 559,1408 768,1408 977,1408 1153.5,1305 1330,1202 1433,1025.5 1536,849 1536,640 z" + id="path3017" + inkscape:connector-curvature="0" + style="fill:currentColor" /> + </g> +</svg> diff --git a/src/components.d.ts b/src/components.d.ts index a4f09efe95e6a13ff5da3dcf778cef1da478a7aa..668ae9da32cd87c760bd51cfd83d49a86f0462a2 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -221,6 +221,10 @@ export namespace Components { variant: ButtonVariants; } interface HyCheckbox { + /** + * Checked attribute + */ + checkboxChecked: boolean; /** * Unique id for checkbox element */ @@ -239,6 +243,7 @@ export namespace Components { variant: CheckboxVariants; } interface HyContentList { + creditsLabel: string; dataItems: string; linkLabel: string; } @@ -568,6 +573,7 @@ export namespace Components { interface HyMenuLanguageItem { abbr: string; isActive: boolean; + isDisabled: boolean; isMobile: boolean; label: string; langCode: string; @@ -731,6 +737,7 @@ export namespace Components { dataSiteHeaderLabels: string; logoLabel?: string; logoUrl?: string; + menuLabel: string; menuLabelClose?: string; menuLabelOpen?: string; menuType: MenuType; @@ -1500,6 +1507,10 @@ declare namespace LocalJSX { variant?: ButtonVariants; } interface HyCheckbox { + /** + * Checked attribute + */ + checkboxChecked?: boolean; /** * Unique id for checkbox element */ @@ -1518,6 +1529,7 @@ declare namespace LocalJSX { variant?: CheckboxVariants; } interface HyContentList { + creditsLabel?: string; dataItems?: string; linkLabel?: string; } @@ -1551,6 +1563,7 @@ declare namespace LocalJSX { } interface HyDesktopMenuLinks { dataDesktopLinks?: DesktopLinks[] | string; + onMenuDesktopToggled?: (event: CustomEvent<any>) => void; } interface HyDocsContainer {} interface HyDropdown { @@ -1852,10 +1865,12 @@ declare namespace LocalJSX { dataMenuLanguage?: MenuLanguage[] | string; isMobile?: boolean; labels?: ComponentLabels[] | string; + onMenuLanguageToggled?: (event: CustomEvent<any>) => void; } interface HyMenuLanguageItem { abbr?: string; isActive?: boolean; + isDisabled?: boolean; isMobile?: boolean; label?: string; langCode?: string; @@ -2020,6 +2035,7 @@ declare namespace LocalJSX { dataSiteHeaderLabels?: string; logoLabel?: string; logoUrl?: string; + menuLabel?: string; menuLabelClose?: string; menuLabelOpen?: string; menuType?: MenuType; diff --git a/src/components/courses/hy-content-list-item/hy-content-list-item.tsx b/src/components/courses/hy-content-list-item/hy-content-list-item.tsx index c08a3fe85af9c18b197cf5d36e300650b5202a39..3df481f1694ed8601f4e8f6f907b32b3a9729507 100644 --- a/src/components/courses/hy-content-list-item/hy-content-list-item.tsx +++ b/src/components/courses/hy-content-list-item/hy-content-list-item.tsx @@ -77,12 +77,9 @@ export class HyContentLstItem { <div class="hy-content-list-item--metadata--item hy-content-list-item--metadata--item--first"> <span>{this._dateValue}</span> </div> - <div class="hy-content-list-item--metadata--item"> + <div class="hy-content-list-item--metadata--item hy-content-list-item--metadata--item--last"> <span>{this.courseStudyFormat}</span> </div> - <div class="hy-content-list-item--metadata--item hy-content-list-item--metadata--item--last "> - <span>{this.courseCredits}</span> - </div> </div> {this._courseTags && ( <div class="hy-content-list-item--tags"> diff --git a/src/components/courses/hy-content-list/hy-content-list.tsx b/src/components/courses/hy-content-list/hy-content-list.tsx index 2555aaffdfafd835b027bec2c128cbaf246e2ccf..10cf3f2af018eb9e37d0d3609b10ebfa7325a984 100644 --- a/src/components/courses/hy-content-list/hy-content-list.tsx +++ b/src/components/courses/hy-content-list/hy-content-list.tsx @@ -8,6 +8,7 @@ import {Component, ComponentInterface, Element, h, Host, Prop, State} from '@ste }) export class HyContentList implements ComponentInterface { @Prop() linkLabel: string = 'Go to course page'; + @Prop() creditsLabel: string = 'cr'; @Prop() dataItems: string; private _dataItems: []; private variant: CourseVariants = CourseVariants.default; @@ -34,8 +35,8 @@ export class HyContentList implements ComponentInterface { let courseItem = courseObject[courseProperty]; let courseCode = courseItem['code']; - let courseName = courseItem['name']; let courseCredits = courseItem['credits']; + //let courseUnitName = courseItem['name'] + ', ' + courseCredits + ' ' + this.creditsLabel; if (courseItem['tags']) { let tags = JSON.parse(JSON.stringify(courseItem['tags'])); @@ -51,6 +52,8 @@ export class HyContentList implements ComponentInterface { for (let realisationProperty in realisations) { let realizationItem = realisations[realisationProperty]; + let courseRealisationName = realizationItem['name']; + let courseRealisationFullName = courseRealisationName + ', ' + courseCredits + ' ' + this.creditsLabel; let courseStudyFormat = realizationItem['studyFormat']; let courseStartDate = realizationItem['startDate']; let courseEndDate = realizationItem['endDate']; @@ -59,17 +62,13 @@ export class HyContentList implements ComponentInterface { const contentListItemClassAttributes = ['item', this.variant].join(' '); - //tabs[index].addEventListener('keydown', this.keydownEventListener); - //contentListItem.addEventListener('keydown', this.keydownEventListener); - //courseRealisations.push(contentListItem); - courseRealisations.push( <hy-content-list-item id={realisationProperty} class={contentListItemClassAttributes} variant={this.variant} course-code={courseCode} - course-name={courseName} + course-name={courseRealisationFullName} course-credits={courseCredits} course-tags={courseTagsJSON} course-start-date={courseStartDate} diff --git a/src/components/courses/hy-content-list/readme.md b/src/components/courses/hy-content-list/readme.md index ec30e6a5df27c16594f22be476c698b8577b8913..53ab92fe3cb7ff82441d25c7630fedf0b6bebef2 100644 --- a/src/components/courses/hy-content-list/readme.md +++ b/src/components/courses/hy-content-list/readme.md @@ -4,10 +4,11 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ----------- | ------------ | ----------- | -------- | --------------------- | -| `dataItems` | `data-items` | | `string` | `undefined` | -| `linkLabel` | `link-label` | | `string` | `'Go to course page'` | +| Property | Attribute | Description | Type | Default | +| -------------- | --------------- | ----------- | -------- | --------------------- | +| `creditsLabel` | `credits-label` | | `string` | `'cr'` | +| `dataItems` | `data-items` | | `string` | `undefined` | +| `linkLabel` | `link-label` | | `string` | `'Go to course page'` | ## Dependencies diff --git a/src/components/heading/heading.scss b/src/components/heading/heading.scss index 7eeea7e01b529044e7e2715d10d919f69824a346..3b62026bd8f9aa03a40bd24d2838ac816fe6d7bb 100644 --- a/src/components/heading/heading.scss +++ b/src/components/heading/heading.scss @@ -284,6 +284,7 @@ h1 { @include breakpoint($extrawide) { // > 1200px + //@todo Check the size. SHould be 46 till 1600, and after 1600px it should be 52px; @include font-size(52px, 64px); letter-spacing: -1.6px; } diff --git a/src/components/hy-checkbox/hy-checkbox.tsx b/src/components/hy-checkbox/hy-checkbox.tsx index 53ab8374cf5e6516a5905be0bc09c9f8c75b841f..fe53d3bdf85da866ce6c205320a49a6adbec5371 100644 --- a/src/components/hy-checkbox/hy-checkbox.tsx +++ b/src/components/hy-checkbox/hy-checkbox.tsx @@ -19,6 +19,10 @@ export class HyCheckbox { * Label for input to describe */ @Prop() checkboxLabel: string; + /** + * Checked attribute + */ + @Prop() checkboxChecked: boolean = false; /** * Variant to deifne what style of checkbox to use */ @@ -32,6 +36,7 @@ export class HyCheckbox { <input type="checkbox" class="hy-checkbox--button__checkbox" + checked={this.checkboxChecked} id={`${this.checkboxId}`} value={`${this.checkboxValue}`} /> @@ -50,6 +55,7 @@ export class HyCheckbox { <input type="checkbox" class="hy-checkbox__checkbox" + checked={this.checkboxChecked} id={`${this.checkboxId}`} value={`${this.checkboxValue}`} /> diff --git a/src/components/hy-checkbox/readme.md b/src/components/hy-checkbox/readme.md index 68265a213d83776c24ffe2d645a2568e43cc08ad..d42a5badc07adf844f2bd167c9c225245dfdca8f 100644 --- a/src/components/hy-checkbox/readme.md +++ b/src/components/hy-checkbox/readme.md @@ -4,12 +4,13 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| --------------- | ---------------- | ----------------------------------------------- | ----------------------------------------------------- | -------------------------- | -| `checkboxId` | `checkbox-id` | Unique id for checkbox element | `number \| string` | `undefined` | -| `checkboxLabel` | `checkbox-label` | Label for input to describe | `string` | `undefined` | -| `checkboxValue` | `checkbox-value` | Value for input element | `number \| string` | `undefined` | -| `variant` | `variant` | Variant to deifne what style of checkbox to use | `CheckboxVariants.button \| CheckboxVariants.default` | `CheckboxVariants.default` | +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ----------------------------------------------- | ----------------------------------------------------- | -------------------------- | +| `checkboxChecked` | `checkbox-checked` | Checked attribute | `boolean` | `false` | +| `checkboxId` | `checkbox-id` | Unique id for checkbox element | `number \| string` | `undefined` | +| `checkboxLabel` | `checkbox-label` | Label for input to describe | `string` | `undefined` | +| `checkboxValue` | `checkbox-value` | Value for input element | `number \| string` | `undefined` | +| `variant` | `variant` | Variant to deifne what style of checkbox to use | `CheckboxVariants.button \| CheckboxVariants.default` | `CheckboxVariants.default` | ## Dependencies diff --git a/src/components/hy-main-content-wrapper/hy-main-content-wrapper.scss b/src/components/hy-main-content-wrapper/hy-main-content-wrapper.scss index e2e51ea473af5d94c3774e3c4ca3e81c9708c987..ff3c95e094b175f8d5c3faca17b0ec54c3d73dd3 100644 --- a/src/components/hy-main-content-wrapper/hy-main-content-wrapper.scss +++ b/src/components/hy-main-content-wrapper/hy-main-content-wrapper.scss @@ -17,7 +17,7 @@ padding: 0 2rem; } - // Large desktop Layout >1441px + // Large desktop Layout >1600px @include breakpoint($xlarge) { max-width: 1216px; padding: 0; @@ -38,9 +38,9 @@ padding: 0 2rem; } - // Large desktop Layout >1441px + // Large desktop Layout >1200px @include breakpoint($extrawide) { - max-width: 1440px; + max-width: 1216px; padding: 0; } } diff --git a/src/components/navigation/menu-language-item/menu-language-item.scss b/src/components/navigation/menu-language-item/menu-language-item.scss index 4f37d85c5ed2620e9207fc7fd6d2a7829012c405..86eaffe2e7fe41e1f246ce65812c697148ce81ca 100644 --- a/src/components/navigation/menu-language-item/menu-language-item.scss +++ b/src/components/navigation/menu-language-item/menu-language-item.scss @@ -3,37 +3,36 @@ } a { - @include font-size(12px, 20px); + @include font-size(12px, 16px); @include font-weight($regular); align-items: center; color: var(--brand-main-nearly-black); display: flex; font-family: var(--main-font-family); - letter-spacing: -0.4px; + letter-spacing: -0.07px; margin-left: 20px; + position: relative; text-decoration: none; text-transform: uppercase; @include breakpoint($wide) { - @include font-size(15px, 20px); + @include font-size(14px, 20px); + @include font-weight($semibold); color: var(--brand-main-light); - font-weight: 700; - padding: 0 40px 32px; + letter-spacing: -0.5px; + padding: 8px 12px; + text-transform: none; &:hover { background-color: var(--grayscale-background-box); color: var(--brand-main); } } - @include breakpoint($extrawide) { - @include font-size(15px, 20px); - color: var(--brand-main-light); - font-weight: 700; - padding: 0 32px 22px; - } + @include breakpoint($xlarge) { - @include font-size(18px, 22px); - padding: 0 40px 32px; + @include font-size(16px, 20px); + letter-spacing: -0.53px; + padding: 12px 12px; } &:focus { @@ -42,25 +41,37 @@ a { } &.is-active { - .hy-menu-language-item__label { - color: var(--grayscale-black); - font-weight: 700; - border-bottom: 2px solid var(--additional-orange); + @include font-weight($bold); + color: var(--grayscale-black); + + @include breakpoint($wide) { + @include font-weight($semibold); + border: 2px solid var(--grayscale-black); + } + + .hy-menu-language-item__label:after { + content: ' '; + border-bottom: 3px solid var(--additional-orange); + bottom: -6px; + left: 0; + position: absolute; + transform: scaleX(-1) scaleY(-1); + width: 100%; @include breakpoint($wide) { - border-bottom: 3px solid var(--grayscale-black); - padding-bottom: 6px; - } - @include breakpoint($extrawide) { - border-bottom: 3px solid var(--grayscale-black); - padding-bottom: 6px; - } - @include breakpoint($xlarge) { - padding-bottom: 8px; + border: none; } } } + &.is-disabled { + color: var(--link-disabled); + &:hover { + background-color: transparent; + color: var(--link-disabled); + } + } + &:not(.is-mobile) { margin: 0; } diff --git a/src/components/navigation/menu-language-item/menu-language-item.tsx b/src/components/navigation/menu-language-item/menu-language-item.tsx index 830850dab833972be03fba4309f0d81f88cd2233..9e949b30702258bb63e6222531acf0371f8b41c1 100644 --- a/src/components/navigation/menu-language-item/menu-language-item.tsx +++ b/src/components/navigation/menu-language-item/menu-language-item.tsx @@ -8,6 +8,7 @@ import {Component, h, Prop, Host} from '@stencil/core'; export class SiteLanguage { @Prop() abbr: string; @Prop() isActive: boolean = false; + @Prop() isDisabled: boolean = false; @Prop() isMobile: boolean = false; @Prop() label: string; @Prop() langCode: string; @@ -18,6 +19,7 @@ export class SiteLanguage { <Host class={{ 'is-active': this.isActive, + 'is-disabled': this.isDisabled, 'hy-menu-language-item': true, }} > @@ -25,6 +27,7 @@ export class SiteLanguage { href={this.url} class={{ 'is-active': this.isActive, + 'is-disabled': this.isDisabled, 'is-mobile': this.isMobile, }} > diff --git a/src/components/navigation/menu-language-item/readme.md b/src/components/navigation/menu-language-item/readme.md index 30f91df8c6c11c0a18f1caee311d36ab203b2cd0..efadc1e0d47be4775769aecda274af351eb90ddf 100644 --- a/src/components/navigation/menu-language-item/readme.md +++ b/src/components/navigation/menu-language-item/readme.md @@ -4,14 +4,15 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ---------- | ----------- | ----------- | --------- | ----------- | -| `abbr` | `abbr` | | `string` | `undefined` | -| `isActive` | `is-active` | | `boolean` | `false` | -| `isMobile` | `is-mobile` | | `boolean` | `false` | -| `label` | `label` | | `string` | `undefined` | -| `langCode` | `lang-code` | | `string` | `undefined` | -| `url` | `url` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------ | ------------- | ----------- | --------- | ----------- | +| `abbr` | `abbr` | | `string` | `undefined` | +| `isActive` | `is-active` | | `boolean` | `false` | +| `isDisabled` | `is-disabled` | | `boolean` | `false` | +| `isMobile` | `is-mobile` | | `boolean` | `false` | +| `label` | `label` | | `string` | `undefined` | +| `langCode` | `lang-code` | | `string` | `undefined` | +| `url` | `url` | | `string` | `undefined` | ## Dependencies diff --git a/src/components/navigation/menu-language/menu-language.scss b/src/components/navigation/menu-language/menu-language.scss index 14d264bd03301fe3f4c3d11a04e097792efedd28..ba583d5651d5cdd6c42f31b753987d324d4c7d15 100644 --- a/src/components/navigation/menu-language/menu-language.scss +++ b/src/components/navigation/menu-language/menu-language.scss @@ -13,20 +13,36 @@ :host(.menu--language:not([is-mobile])) { @include breakpoint($narrow) { + height: 100%; position: relative; right: auto; top: auto; } } +:host(.menu--language__is-open) { + &::after { + @include breakpoint($wide) { + content: ' '; + height: 4px; + background-color: var(--grayscale-black); + display: block; + width: 100%; + position: absolute; + bottom: 0; + } + } +} + .menu--language__toggle { @include font-size(14px, 24px); align-items: center; - background: transparent; + background: var(--grayscale-white); border: 0 none; color: var(--brand-main-nearly-black); display: flex; flex-flow: row; + font-family: var(--main-font-family); font-weight: 600; letter-spacing: -0.4px; margin: 0 -4px; @@ -35,6 +51,7 @@ @include breakpoint($extrawide) { @include font-size(12px, 12px); + font-weight: 400; letter-spacing: -0.6px; } @@ -56,21 +73,6 @@ .menu--language__toggle__caret { transform: rotate(180deg); } - background-color: var(--grayscale-background-box); - @include breakpoint($wide) { - margin-bottom: -28px; - margin-top: -26px; - padding: 26px 8px 28px; - } - @include breakpoint($extrawide) { - margin-bottom: -38px; - margin-top: -26px; - padding: 26px 8px 38px; - } - @include breakpoint($xlarge) { - margin-bottom: -50px; - padding: 26px 12px 50px; - } } > * { @@ -82,35 +84,34 @@ } .menu--language__dropdown { - background-color: var(--grayscale-white); - border-radius: 0 0 5px 5px; - box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2); - display: flex; - flex-flow: column; - justify-items: center; - margin: 0; - padding: 15px; - position: absolute; - right: 5px; - text-transform: uppercase; - top: 40px; + display: none; visibility: hidden; - @include breakpoint($wide) { - padding: 32px 0 0; - top: 70px; - } - @include breakpoint($extrawide) { - top: 80px; - } - @include breakpoint($xlarge) { - top: 90px; - } - &.is-open { + background-color: var(--grayscale-white); + border-radius: 0 0 5px 5px; + box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2); + display: flex; + flex-flow: column; + justify-items: center; + left: -15px; + margin: 0; + padding: 15px; + position: absolute; + text-transform: uppercase; visibility: visible; + width: max-content; z-index: 100; + @include breakpoint($wide) { + left: -20px; + min-width: 160px; + padding: 6px 8px; + } + @include breakpoint($xlarge) { + padding: 8px; + } + a { @include font-size(16px, 20px); margin-left: 0; @@ -132,19 +133,3 @@ width: 16px; } } - -.hy-menu-backdrop { - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; - visibility: hidden; - - &.is-active { - background-color: rgba(0, 0, 0, 0.4); - transition: background-color 300ms; - visibility: visible; - z-index: 99; - } -} diff --git a/src/components/navigation/menu-language/menu-language.tsx b/src/components/navigation/menu-language/menu-language.tsx index 6af1f0e7d552ec7a62012bb43ea20b13dc12ff40..ed0386d3465febec4893f8625cdcde3d9d50a4fc 100644 --- a/src/components/navigation/menu-language/menu-language.tsx +++ b/src/components/navigation/menu-language/menu-language.tsx @@ -6,9 +6,10 @@ export interface MenuLanguage { abbr: string; label: string; isActive?: boolean; + isDisabled?: boolean; } -import {Component, h, Prop, Host, Watch, Element, Listen, State} from '@stencil/core'; +import {Component, h, Prop, Host, Watch, Element, Listen, State, Event, EventEmitter} from '@stencil/core'; @Component({ tag: 'hy-menu-language', @@ -21,6 +22,9 @@ export class MenuLanguage { @Prop() isMobile: boolean = false; @Prop() labels?: ComponentLabels[] | string; @State() isMenuOpen: boolean = false; + + @Event() menuLanguageToggled: EventEmitter; + private _dataMenuLanguage: MenuLanguage[]; private _labels: ComponentLabels[]; @@ -32,45 +36,51 @@ export class MenuLanguage { this._labels = typeof data === 'string' ? JSON.parse(data) : data; } - @Listen('languageMenuToggle') languageMenuToggle() { - this.isMenuOpen = !this.isMenuOpen; + // Close the language menu if user clicks anywhere outside the Menu language component. + @Listen('click', {target: 'window'}) + handleOutsideMenuClick(event) { + this.isMenuOpen = false; + event.stopPropagation(); + } - let hyHeader = this.el.closest('.hy-site-header'); - let hyBackdropDiv = (hyHeader as HTMLElement).children[0]; - - if (hyBackdropDiv) { - if (this.isMenuOpen) { - (hyBackdropDiv as HTMLElement).classList.add('is-active'); - (hyBackdropDiv as HTMLElement).style.top = '90px'; - } else { - (hyBackdropDiv as HTMLElement).classList.remove('is-active'); - (hyBackdropDiv as HTMLElement).style.top = '0'; - } - } + // CLose the language menu if user opens the desktop menu panel. + @Listen('menuDesktopToggled', {target: 'document'}) + desktopMenuToggled() { + this.isMenuOpen = false; } - @Listen('click') - handleComponentClick(event) { + @Listen('focus') + handleComponentFocus(event) { + // Close desktop menu panel if it's open. + this.menuLanguageToggled.emit(); + event.stopPropagation(); } - @Listen('click', {target: 'window'}) - handleClick(event) { + @Listen('click') + handleComponentClick(event) { + this.isMenuOpen = !this.isMenuOpen; + const languageMenuSelector = event.target as HTMLElement; + if (this.isMenuOpen) { - const target = event.target as HTMLTextAreaElement; - const targetElement = target.tagName.toLowerCase(); - - if (targetElement !== 'hy-menu-language') { - const hyHeader = this.el.closest('.hy-site-header'); - const hyBackdropDiv = (hyHeader as HTMLElement).children[0]; - - if (hyBackdropDiv && hyBackdropDiv.classList.contains('is-active')) { - (hyBackdropDiv as HTMLElement).classList.remove('is-active'); - (hyBackdropDiv as HTMLElement).style.top = '0'; - this.isMenuOpen = !this.isMenuOpen; - } - } + // Close desktop menu panel if it's open. + this.menuLanguageToggled.emit(); + + let hyHeader = this.el.closest('.hy-site-header') as HTMLElement; + const headerHeight = `${ + languageMenuSelector.offsetHeight + + hyHeader.offsetTop + + hyHeader.offsetHeight + + 8 - + languageMenuSelector.offsetTop - + languageMenuSelector.offsetHeight + }px`; + const languagePanel = languageMenuSelector.shadowRoot.querySelectorAll( + `.menu--language__dropdown` + )[0] as HTMLElement; + languagePanel.style.top = headerHeight; } + event.stopPropagation(); } @@ -81,7 +91,6 @@ export class MenuLanguage { render() { const black = 'var(--brand-main-nearly-black)'; - const menuLanguageContainerClass = ['menu--language'].join(' '); return this.isMobile ? ( <Host class={'menu--language'}> @@ -93,15 +102,20 @@ export class MenuLanguage { label={item.label} abbr={item.abbr} is-active={item.isActive} + is-disabled={item.isDisabled} is-mobile={this.isMobile} /> ); })} </Host> ) : ( - <Host class={menuLanguageContainerClass}> + <Host + class={{ + 'menu--language': true, + 'menu--language__is-open': this.isMenuOpen, + }} + > <button - onClick={() => this.languageMenuToggle()} class={{ 'menu--language__toggle': true, 'is-open': this.isMenuOpen, @@ -132,6 +146,7 @@ export class MenuLanguage { label={item.label} abbr={item.abbr} is-active={item.isActive} + is-disabled={item.isDisabled} is-mobile={this.isMobile} /> ); diff --git a/src/components/navigation/menu-language/readme.md b/src/components/navigation/menu-language/readme.md index 35ba8fbb916bab9cb105e35b26bb2e52440778a2..cd19087f41c16dbb1539d4d4f160d5dec500384d 100644 --- a/src/components/navigation/menu-language/readme.md +++ b/src/components/navigation/menu-language/readme.md @@ -10,6 +10,12 @@ | `isMobile` | `is-mobile` | | `boolean` | `false` | | `labels` | `labels` | | `ComponentLabels[] \| string` | `undefined` | +## Events + +| Event | Description | Type | +| --------------------- | ----------- | ------------------ | +| `menuLanguageToggled` | | `CustomEvent<any>` | + ## Dependencies ### Used by 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 index adb3f88cb66859db1e18a2260ee5a2ee34df991e..6ea5f7d35e96c7d715b73c1d79ae2435293e8ccb 100644 --- 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 @@ -1,16 +1,34 @@ :host { - display: block; + align-items: center; + display: flex; + flex-flow: row; + justify-content: center; + margin: 0 32px; + padding: 0; + height: 100%; } .hy-site-header { + &__menu-desktop { + height: 100%; + } // 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-direction: row; flex-flow: row; + height: 100%; list-style: none; + margin: 0; + padding: 0; width: 100%; + li { + display: flex; + height: 100%; + } + // First level menu items .desktop-menu-link { background-color: transparent; @@ -20,75 +38,118 @@ font-family: var(--main-font-family); @include breakpoint($extrawide) { - @include font-size(15px, 16px); + @include font-size(14px, 14px); @include font-weight($bold); + align-items: center; border-top: 0 none; - padding: 10px 8px; + display: flex; + flex-direction: row; + justify-content: center; + letter-spacing: -0.6px; + padding: 0 7px; + position: relative; text-transform: uppercase; } - @include breakpoint($fullhd) { - @include font-size(18px, 16px); - letter-spacing: -0.5px; - padding: 10px; + @include breakpoint($xlarge) { + @include font-size(16px, 16px); + letter-spacing: -0.7px; + padding: 0 9px; } - // Underline if link is in active trail. - &--is-active-trail { - @include breakpoint($extrawide) { + &__label { + position: relative; + width: min-content; + @include breakpoint($overwide) { + width: 100%; + } + + &--is-active-trail::after { border-bottom: 4px solid var(--brand-main-nearly-black); - padding-bottom: 8px; + bottom: -12px; + content: ' '; + position: absolute; + right: 0; + width: 100%; + } + &--is-active-trail--disabled::after { + border: none; } + } + hy-icon { + display: inline-block !important; + padding-left: 3px; @include breakpoint($xlarge) { - padding-bottom: 12px; + padding-left: 4px; } - } - &__heading__icon { - display: none; + svg { + height: 8px; + width: 10px; + + @include breakpoint($xlarge) { + height: 8.44px; + width: 12px; + } + } } - // On hover: change background and show heading icon. + // On hover: heading icon is turned 180deg and grows bigger. &--is-active { - background-color: var(--grayscale-background-box); - padding: 35px 10px; position: relative; - - .desktop-menu-link__heading__icon { - bottom: 0; - display: block; - left: 0; - position: absolute; - width: 100%; - + &:hover, + &:focus { + color: var(--link-blue); hy-icon { - justify-content: center; - transform: rotateX(180deg); svg { - padding: 8px 0; + fill: var(--link-blue); } } } + + hy-icon { + transform: rotateX(180deg); + } + + .desktop-menu-link__label--is-active-trail::after { + border: none; + } + } + + // Underline active link when showing menu panel + &--is-active::after { + border-bottom: 4px solid var(--brand-main-nearly-black); + bottom: 0; + content: ' '; + position: absolute; + right: 0; + width: 100%; + } + + &:focus { + outline: none; } } // Panel with second level menu items and shortcuts. .hy-desktop-menu-panel { display: none; + flex-direction: row; + opacity: 0; + transition: none; + position: absolute; + left: 0; + top: 0; + z-index: 510; + width: 100%; &--is-active { - background-color: var(--grayscale-white); + background: radial-gradient(circle, var(--grayscale-light) 0%, var(--grayscale-background-box) 100%); + box-shadow: 0 0 20px 0 rgba(14, 104, 139, 0.1) inset; display: flex; - flex-direction: row; - opacity: 1; - position: absolute; - left: 0; padding-left: 300px; - padding-bottom: 28px; - width: 100%; - z-index: 510; } &__panel-toggle { @@ -115,63 +176,87 @@ &__desktop-menu { display: flex; - //position: relative; + margin-bottom: -8px; + margin-top: 6px; &__menu-items { - //@todo check max-with in Specs - min-width: 450px; - max-width: 550px; + min-width: 440px; + max-width: 540px; } // 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%; + &:hover, + &:focus { + box-shadow: 0 0 16px 0 rgba(0, 83, 121, 0.2); + color: var(--link-blue); + + svg { + //height: 42px; + //width: 42px; + } + } + @include breakpoint($extrawide) { @include font-size(24px, 32px); align-items: flex-start; - background-color: var(--grayscale-background-box); + background-color: var(--grayscale-white); flex-direction: column; + justify-content: center; letter-spacing: -0.75px; margin-bottom: 4px; padding: 17px 32px 12px 32px; position: relative; text-transform: none; } - @include breakpoint($fullhd) { + @include breakpoint($xlarge) { @include font-size(26px, 32px); letter-spacing: -0.81px; margin-bottom: 6px; - padding-top: 19px; + padding: 25px 32px 20px 32px; } .label { border: none; margin-left: 14px; + + &:hover, + &:focus { + color: var(--link-blue); + } } + .description { - @include font-size(16px, 24px); - @include font-weight($semibold); + @include font-size(14px, 18px); + @include font-weight($regular); color: var(--grayscale-dark); - letter-spacing: 0; + letter-spacing: -0.2; margin-left: 14px; - margin-bottom: 28px; - margin-top: 8px; + margin-bottom: 12px; + margin-top: 4px; + + @include breakpoint($xlarge) { + @include font-size(16px, 20px); + letter-spacing: -0.25; + } + &:hover { + color: var(--grayscale-dark); + } } span.heading-icon { position: absolute; top: 12px; left: -6px; - @include breakpoint($fullhd) { - top: 27px; + @include breakpoint($xlarge) { + top: 20px; } svg { background-color: var(--brand-main-light); @@ -183,10 +268,11 @@ // menu item links &__second-level-menu { - background-color: var(--grayscale-background-box); + //background-color: var(--grayscale-background-box); + background-color: var(--grayscale-white); list-style: none; margin: 0; - padding: 0; + padding: 12px 0; li { a { @@ -200,18 +286,18 @@ width: 100%; @include breakpoint($extrawide) { - @include font-size(15px, 22px); + @include font-size(14px, 18px); align-items: center; flex-direction: row; - letter-spacing: -0.47px; + letter-spacing: -0.5px; padding-left: 24px; padding-right: 48px; text-transform: none; } - @include breakpoint($fullhd) { - @include font-size(18px, 22px); - letter-spacing: -0.56px; + @include breakpoint($xlarge) { + @include font-size(16px, 18px); + letter-spacing: -0.5px; } &:focus { @@ -219,6 +305,11 @@ outline-offset: -2px; } + &:hover, + &:focus { + color: var(--link-blue); + } + .label { @include breakpoint($extrawide) { border: none; @@ -244,12 +335,13 @@ // Shortcuts .shortcuts-panel { + background-color: var(--grayscale-white); position: absolute; left: 0; // override in js list-style: none; min-width: 350px; + margin: 6px 4px 0 4px; max-width: 400px; - //margin: 0 48px; padding: 0 48px; top: 0; 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 index f58e62e1eeb89bc764f207d3fa68ddd05edb7e92..03d02953e1a8193670aa1b8ab04d13be35ed65ad 100644 --- 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 @@ -19,7 +19,7 @@ export interface DesktopLinks { } import {ColorVariant} from '../../../utils/utils'; -import {Component, h, Element, Prop, State, Watch} from '@stencil/core'; +import {Component, h, Element, Prop, State, Watch, EventEmitter, Event, Listen} from '@stencil/core'; @Component({ tag: 'hy-desktop-menu-links', @@ -37,9 +37,15 @@ export class HyDesktopMenuLinks { @State() menuLinkItems: Array<object> = []; @State() hasToolbar: boolean = false; @State() isDesktopMenuOpen: boolean = false; + @State() currenOpenMenuId: number = 0; + + @Event() menuDesktopToggled: EventEmitter; private _submenuLeftMargin: number = 32; - private _headerBorderOffset: number = 8; + private _headerBorderOffset: number = 0; + + private _hoverTimer = null; + private _fadeOutTimer = null; @Watch('dataDesktopLinks') dataDesktopLinksWatcher(data: DesktopLinks[] | string) { @@ -58,39 +64,22 @@ export class HyDesktopMenuLinks { if (state === 'open') { hyBackdropDiv.classList.add('is-active'); hyBackdropDiv.style.top = `${top}px`; - } - - if (state === 'close') { - hyBackdropDiv.classList.remove('is-active'); + } else { hyBackdropDiv.style.top = '0'; + hyBackdropDiv.classList.remove('is-active'); } } } - handleDesktopMenuClose() { - this.isDesktopMenuOpen = false; - this.showBackdropShadow(); - - 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"]`) as HTMLElement; + showPanel(id) { + // Close menu lang menu if it's open + this.menuDesktopToggled.emit(); - // Return focus to the button of the last desktop panel that was active. - if (activeMenuItem !== null) activeMenuItem.focus(); + clearTimeout(this._fadeOutTimer); - // 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) { + // Open desktop menu panel this.isDesktopMenuOpen = true; + 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}"]`) as HTMLElement; @@ -104,21 +93,33 @@ export class HyDesktopMenuLinks { menuPanelItems.forEach((item) => { item.classList.remove('hy-desktop-menu-panel--is-active'); item.setAttribute('aria-hidden', 'true'); + (item as HTMLElement).style.transition = 'none'; + (item as HTMLElement).style.opacity = '0'; }); // 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 as HTMLElement).style.opacity = '1'; + if (this.hasToolbar) { activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active--has-toolbar'); } activeMenuItemSibling.setAttribute('aria-hidden', 'false'); + //Hide is-active-trail underlining + const activeTrailMenuItem = this.el.shadowRoot.querySelector( + `.desktop-menu-link__label--is-active-trail` + ) as HTMLElement; + if (activeTrailMenuItem) { + activeTrailMenuItem.classList.add('desktop-menu-link__label--is-active-trail--disabled'); + } + // Add panels top value automatically with the correct header height - const headerHeight = `${ - this.el.parentElement.offsetTop + this.el.parentElement.offsetHeight + this._headerBorderOffset - }px`; + const headerHeight = this.el.parentElement.classList.contains('hy-site-header--sticky-active') + ? `${this.el.parentElement.offsetHeight + this._headerBorderOffset}px` + : `${this.el.parentElement.offsetTop + this.el.parentElement.offsetHeight + this._headerBorderOffset}px`; activeMenuItemSibling.style.top = headerHeight; // Add shadow backdrop @@ -150,38 +151,140 @@ export class HyDesktopMenuLinks { } } - handleDesktopMenuClick(id) { - const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`); - const activeMenuItemSibling = activeMenuItem.nextElementSibling as HTMLElement; // current panel + closePanel(fadeOut = false) { + this.isDesktopMenuOpen = false; + this.currenOpenMenuId = 0; + this.showBackdropShadow(); + this.clearPanelItemsStatus(fadeOut); + clearTimeout(this._hoverTimer); + } - if (!this.isDesktopMenuOpen) { - // Add active classes to the currently active item and its sibling element. - this.isDesktopMenuOpen = true; - activeMenuItem.classList.add('desktop-menu-link--is-active'); - activeMenuItem.setAttribute('aria-expanded', 'true'); - activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active'); - - if (this.hasToolbar) { - activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active--has-toolbar'); - } - activeMenuItemSibling.setAttribute('aria-hidden', 'false'); + clearPanelItemsStatus(fadeOut = false) { + const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); + const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); - let rect = activeMenuItemSibling.getBoundingClientRect(); - this.showBackdropShadow('open', rect.bottom); + //Show is-active-trail underlining + const activeTrailMenuItem = this.el.shadowRoot.querySelector( + `.desktop-menu-link__label--is-active-trail` + ) as HTMLElement; + if (activeTrailMenuItem) { + activeTrailMenuItem.classList.remove('desktop-menu-link__label--is-active-trail--disabled'); + } + + // Reset elements by removing the active classes. + menuItems.forEach((item) => { + item.classList.remove('desktop-menu-link--is-active'); + item.setAttribute('aria-expanded', 'false'); + }); + + if (fadeOut) { + menuPanelItems.forEach((item) => { + (item as HTMLElement).style.opacity = '0'; + (item as HTMLElement).style.transition = 'opacity 1s'; + }); + + this._fadeOutTimer = setTimeout(() => { + menuPanelItems.forEach((item) => { + item.classList.remove('hy-desktop-menu-panel--is-active'); + item.setAttribute('aria-hidden', 'true'); + }); + }, 350); } else { - // Remove active classes to the currently active item and its sibling element. - this.isDesktopMenuOpen = false; - activeMenuItem.classList.remove('desktop-menu-link--is-active'); - activeMenuItem.setAttribute('aria-expanded', 'false'); - activeMenuItemSibling.classList.remove('hy-desktop-menu-panel--is-active'); - if (this.hasToolbar) { - activeMenuItemSibling.classList.remove('hy-desktop-menu-panel--is-active--has-toolbar'); + menuPanelItems.forEach((item) => { + item.classList.remove('hy-desktop-menu-panel--is-active'); + item.setAttribute('aria-hidden', 'true'); + (item as HTMLElement).style.opacity = '0'; + (item as HTMLElement).style.transition = 'none'; + }); + } + } + + handleDesktopMenuClose(event) { + let fadeOut = true; + this.closePanel(fadeOut); + + event.stopPropagation(); + } + + // CLose the desktop menu panel if user opens the language menu. + @Listen('menuLanguageToggled', {target: 'document'}) + menuLanguageToggled() { + let fadeOut = true; + this.closePanel(fadeOut); + } + + handleDesktopMenuEnter(event, id) { + clearTimeout(this._fadeOutTimer); + + this._hoverTimer = setTimeout(() => { + const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`) as HTMLElement; + + // Set focus to the button. + if (activeMenuItem !== null) activeMenuItem.focus(); + + this.currenOpenMenuId = id; + this.showPanel(id); + }, 350); + + event.stopPropagation(); + } + + handleDesktopMenuLeave(event) { + let leaveEvent = event as MouseEvent; + + let hyHeader = this.el.closest('.hy-site-header') as HTMLElement; + const headerHeight = hyHeader.offsetTop + hyHeader.offsetHeight; + + console.log('leave ' + leaveEvent.clientY + ' ' + headerHeight); + if (leaveEvent.clientY < headerHeight - 4) { + this.closePanel(); + } + + event.stopPropagation(); + } + + /* + Close the panel if mouse is moving over the menu label. + * */ + handleDesktopMenuMove(event, id) { + if (this.isDesktopMenuOpen) { + let moveEvent = event as MouseEvent; + + const activeMenuItem = this.el.shadowRoot.querySelector( + `.desktop-menu-link[link-id="${id}"] .desktop-menu-link__label` + ) as HTMLElement; + let topBorder = activeMenuItem.getClientRects()[0].top; + + if (this.currenOpenMenuId == id) { + // Mouse moving around the same menu link + if (moveEvent.clientY < topBorder - 8) { + console.log(topBorder + ' ' + moveEvent.clientY); + this.closePanel(); + } } - activeMenuItemSibling.setAttribute('aria-hidden', 'true'); + event.stopPropagation(); + } + } - this.showBackdropShadow(); + handleDesktopMenuFocus(event, id) { + if (this.currenOpenMenuId != id) { + this.currenOpenMenuId = id; + this.showPanel(id); } + + event.stopPropagation(); + } + + handleDesktopMenuClick(event, id) { + if (!this.isDesktopMenuOpen) { + this.currenOpenMenuId = id; + this.showPanel(id); + } else { + this.handleDesktopMenuClose(event); + } + + event.stopPropagation(); } componentDidLoad() { @@ -212,6 +315,10 @@ export class HyDesktopMenuLinks { 'desktop-menu-link', isActive === 'true' ? 'desktop-menu-link--is-active-trail' : '', ].join(' '); + let classAttributesLabel = [ + 'desktop-menu-link__label', + isActive === 'true' ? 'desktop-menu-link__label--is-active-trail' : '', + ].join(' '); menuLinkItems.push( <li> @@ -219,17 +326,16 @@ export class HyDesktopMenuLinks { type="button" class={classAttributes} link-id={id} - onClick={() => this.handleDesktopMenuClick(id)} - onMouseOver={() => this.handleDesktopMenuToggle(id)} - onFocus={() => this.handleDesktopMenuToggle(id)} + onMouseDown={(e) => this.handleDesktopMenuClick(e, id)} + onFocus={(e) => this.handleDesktopMenuFocus(e, id)} + onMouseEnter={(e) => this.handleDesktopMenuEnter(e, id)} + onMouseMove={(e) => this.handleDesktopMenuMove(e, id)} aria-expanded="false" > - {label} - <span class="desktop-menu-link__heading__icon"> - <hy-icon icon={'hy-icon-caret-down'} size={32} /> - </span> + <span class={classAttributesLabel}>{label}</span> + <hy-icon icon={'hy-icon-caret-down'} size={32} /> </button> - <div class="hy-desktop-menu-panel" onMouseLeave={() => this.handleDesktopMenuClose()} aria-hidden="true"> + <div class="hy-desktop-menu-panel" aria-hidden="true"> <div class="hy-desktop-menu-panel__desktop-menu"> <div class="hy-desktop-menu-panel__desktop-menu__menu-items"> <a @@ -291,7 +397,7 @@ export class HyDesktopMenuLinks { )} </div> <button - onClick={() => this.handleDesktopMenuClose()} + onClick={(e) => this.handleDesktopMenuClose(e)} class={{ 'hy-desktop-menu-panel__panel-toggle': true, }} @@ -314,7 +420,11 @@ export class HyDesktopMenuLinks { render() { return ( - <nav role={'navigation'} class="hy-site-header__menu-desktop"> + <nav + role={'navigation'} + class="hy-site-header__menu-desktop" + onMouseLeave={(e) => this.handleDesktopMenuClose(e)} + > <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 index 97289c9d478d6d75545d620dc6404a7b5125ec91..c35a3a1b94b97dfb8ade60c2e4dcc3f3f0595eb9 100644 --- a/src/components/site-header/hy-desktop-menu-links/readme.md +++ b/src/components/site-header/hy-desktop-menu-links/readme.md @@ -8,6 +8,12 @@ | ------------------ | -------------------- | ----------- | -------------------------- | ----------- | | `dataDesktopLinks` | `data-desktop-links` | | `DesktopLinks[] \| string` | `undefined` | +## Events + +| Event | Description | Type | +| -------------------- | ----------- | ------------------ | +| `menuDesktopToggled` | | `CustomEvent<any>` | + ## Dependencies ### Used by diff --git a/src/components/site-header/readme.md b/src/components/site-header/readme.md index fb281a59b339570530fc72b85daa3f351537e71c..3436d38d4374540bb1aa4295fb77fd3e733b0e2c 100644 --- a/src/components/site-header/readme.md +++ b/src/components/site-header/readme.md @@ -12,6 +12,7 @@ | `dataSiteHeaderLabels` | `data-site-header-labels` | | `string` | `undefined` | | `logoLabel` | `logo-label` | | `string` | `undefined` | | `logoUrl` | `logo-url` | | `string` | `undefined` | +| `menuLabel` | `menu-label` | | `string` | `'Menu'` | | `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` | diff --git a/src/components/site-header/site-header.scss b/src/components/site-header/site-header.scss index 8f4b7e6eaaf30c696dae83fdf08527c69ccbd566..e55a3ac5a0f27f4f2ac02349cb57e83140b5a882 100644 --- a/src/components/site-header/site-header.scss +++ b/src/components/site-header/site-header.scss @@ -11,7 +11,24 @@ place-content: center space-between; z-index: 99; - @include breakpoint($wide) { + &--sticky-active { + transition: transform 200ms linear; + transform: translateY(-100%); + transition-duration: 0.2s; + transition-property: transform; + will-change: transform; + } + &--sticky-visible { + left: 0; + position: fixed; + transform: translateY(0) translateZ(0); + width: 100%; + } + &--sticky-hidden { + top: 0; + } + + @include breakpoint($narrow) { align-content: center; display: flex; flex-flow: row; @@ -20,12 +37,12 @@ max-width: $fullhd; } - @include breakpoint($extrawide) { - height: 96px; + @include breakpoint($wide) { + height: 80px; } @include breakpoint($xlarge) { - height: 120px; + height: 112px; } &__logo-container { @@ -84,6 +101,9 @@ @include breakpoint($narrow) { padding: 15px 28px 15px 15px; } + @include breakpoint($wide) { + padding: 15px 28px 15px 6px; + } &.is-open { position: fixed; @@ -122,6 +142,15 @@ } } } + + &__menu-label { + @include font-size(14px, 24px); + @include font-weight($bold); + font-family: var(--main-font-family); + letter-spacing: -0.45px; + padding-right: 2px; + text-transform: uppercase; + } } .hy-backdrop { @@ -141,29 +170,32 @@ } .menu--secondary { + height: 100%; + @include breakpoint($wide) { align-items: center; display: flex; flex-flow: row; + margin-right: 0; + } + @include breakpoint($extrawide) { + margin-right: 32px; + } - &__item { + &__item { + margin: 0 10px; + padding: 10px 0; + + @include breakpoint($wide) { align-items: center; display: flex; flex-flow: row; - margin: 0 10px; - padding: 10px 0; } - } - - @include breakpoint($extrawide) { - &__item { + @include breakpoint($extrawide) { margin: 0 6px; padding: 10px 0; } - } - - @include breakpoint($xlarge) { - &__item { + @include breakpoint($xlarge) { margin: 0 8px; padding: 10px 0; } @@ -172,8 +204,8 @@ .hy-link__donate { @include breakpoint($wide) { - margin-left: 10px; - margin-right: 10px; + //margin-left: 10px; + //margin-right: 10px; padding: 0; text-decoration: none; @@ -184,13 +216,14 @@ } @include breakpoint($extrawide) { - margin-left: 8px; - margin-right: 32px; + //margin-left: 8px; + //margin-right: 32px; + margin-right: 0; } @include breakpoint($xlarge) { - margin-left: 10px; - margin-right: 32px; + //margin-left: 10px; + //margin-right: 32px; } &__label { @@ -206,6 +239,7 @@ @include breakpoint($extrawide) { @include font-size(12px, 12px); + font-weight: 400; letter-spacing: -0.6px; } diff --git a/src/components/site-header/site-header.tsx b/src/components/site-header/site-header.tsx index 56de89f5e3d86b860ea3149b9c532b17d31f538d..d6dec40165ac7f86f582216791674c1586c41b4a 100644 --- a/src/components/site-header/site-header.tsx +++ b/src/components/site-header/site-header.tsx @@ -30,6 +30,7 @@ export class SiteHeader { @Prop() dataSiteHeaderLabels: string; @Prop() logoUrl?: string; @Prop() logoLabel?: string; + @Prop() menuLabel: string = 'Menu'; @Prop() menuLabelOpen?: string; @Prop() menuLabelClose?: string; @Prop({reflect: true}) menuType: MenuType = MenuType.default; @@ -46,11 +47,24 @@ export class SiteHeader { private searchLabels: ComponentLabels[]; private languageLabels: ComponentLabels[]; + @State() lastScrollTop = 0; + @State() delta = 5; + @State() navbarHeight = 0; + @State() didScroll = false; + @State() intervalId; + // Listener for toggling mobile menu panel on or off. @Listen('mobileMenuToggle') mobileMenuToggle() { this.isMenuOpen = !this.isMenuOpen; } + @Listen('scroll', {target: 'window'}) + handleScroll() { + if (this.el.getAttribute('menu-type') === 'desktop') { + this.didScroll = true; + } + } + componentDidLoad() { // Set the browser resize observer to gather information about browser width. this.ro = new ResizeObserver((entries) => { @@ -62,6 +76,8 @@ export class SiteHeader { // Pass the dataMenuLanguage prop to menu component. this.el.children[0].setAttribute('data-menu-language', this.dataMenuLanguage); + + this.navbarHeight = this.el.getClientRects()[0].height; } componentWillLoad() { @@ -92,6 +108,46 @@ export class SiteHeader { this.el.children[0].setAttribute('menu-language-label-open', this.languageLabels['open']); this.el.children[0].setAttribute('menu-language-label-close', this.languageLabels['close']); this.el.children[0].setAttribute('label-front-page', this.menuLabels['front_page']); + + this.intervalId = setInterval(() => { + this.timer(); + }, 250); + } + + timer() { + if (this.didScroll) { + this.hasScrolled(); + this.didScroll = false; + } + } + + hasScrolled() { + let st = window.pageYOffset; + if (Math.abs(this.lastScrollTop - st) <= this.delta) { + return; + } + + let hySiteHeader = this.el.shadowRoot.querySelector('.hy-site-header') as HTMLElement; + // If current position > last position AND scrolled past navbar... + if (st > this.lastScrollTop && st > this.navbarHeight) { + // Scroll Down + + hySiteHeader.classList.add('hy-site-header--sticky-active'); + hySiteHeader.classList.add('hy-site-header--sticky-hidden'); + hySiteHeader.classList.remove('hy-site-header--sticky-visible'); + } else { + // Scroll Up + if (st < this.el.offsetTop + this.navbarHeight) { + hySiteHeader.classList.remove('hy-site-header--sticky-active'); + hySiteHeader.classList.remove('hy-site-header--sticky-visible'); + hySiteHeader.classList.remove('hy-site-header--sticky-hidden'); + } else { + hySiteHeader.classList.add('hy-site-header--sticky-active'); + hySiteHeader.classList.add('hy-site-header--sticky-visible'); + hySiteHeader.classList.remove('hy-site-header--sticky-hidden'); + } + } + this.lastScrollTop = st; } componentDidUnload() { @@ -186,6 +242,14 @@ export class SiteHeader { })} </div> <div class={'hy-site-header__menu-container'}> + <span + class={{ + 'hy-site-header__menu-label': true, + 'is-visible': this.isMenuOpen, + }} + > + {this.menuLabel} + </span> <button onClick={() => this.mobileMenuToggle()} class={{ diff --git a/src/components/site-header/site-logo/site-logo.scss b/src/components/site-header/site-logo/site-logo.scss index 9e05b7adc8e908c7e8c48338b301d93ebc12eccf..7f4314ec367e3ed40fa419049886092068123490 100644 --- a/src/components/site-header/site-logo/site-logo.scss +++ b/src/components/site-header/site-logo/site-logo.scss @@ -23,35 +23,40 @@ @include font-weight($bold); color: var(--site-logo-color); font-family: var(--main-font-family); - letter-spacing: -0.9px; + letter-spacing: -0.7px; margin-left: 8px; max-width: 90px; text-transform: uppercase; .hy-site-header__logo-container & { @include breakpoint($narrow) { - max-width: none; + min-width: min-content; + max-width: max-content; } } @include breakpoint($narrow) { @include font-size(15px, 16px); + letter-spacing: -0.75px; margin-left: 6px; } @include breakpoint($extrawide) { @include font-size(14px, 14px); + letter-spacing: -0.6px; + margin-left: 4px; } @include breakpoint($xlarge) { @include font-size(16px, 16px); - margin-left: 8px; + letter-spacing: -0.7px; + margin-left: 4px; } } &__icon svg { height: 32px; - width: 34px; + width: 33.41px; @include breakpoint($narrow) { height: 48px; diff --git a/src/components/site-header/site-search/site-search.scss b/src/components/site-header/site-search/site-search.scss index dafd132f6668a65a51566ba7024ac7963b86e017..f9991d1ef717a68f74887c77b025468924fb6e71 100644 --- a/src/components/site-header/site-search/site-search.scss +++ b/src/components/site-header/site-search/site-search.scss @@ -12,7 +12,8 @@ @include breakpoint($wide) { flex-direction: row-reverse; - padding: 4px 0; + //padding: 4px 0; + padding: 0; &:focus { outline: solid 2px var(--additional-yellow); @@ -54,6 +55,7 @@ @include breakpoint($extrawide) { @include font-size(12px, 12px); + font-weight: 400; letter-spacing: -0.6px; } diff --git a/src/global/_breakpoints.scss b/src/global/_breakpoints.scss index 98c483e29a9d9cc6ed0fec600fbde3b169edcb2a..002b6b80052a92b4219b1a939ae096c16742c3ba 100644 --- a/src/global/_breakpoints.scss +++ b/src/global/_breakpoints.scss @@ -10,6 +10,7 @@ $narrow: 30rem; // 480px 480-767 $medium: 48rem; // 768px 768-959 $wide: 60rem; // 960px-1200px; small $extrawide: 75.0625rem; // 1201px-1440px; mid-size +$overwide: 87.5rem; // 1400px-1600px; large-size $xlarge: 1601px; //1601px-1920px, x-large $fullhd: 120.0625rem; // 1921px $max-width: $extrawide; diff --git a/src/global/_colors.scss b/src/global/_colors.scss index 40d3a2fc71bfc05db99dac7cc9659b8b7ecf7560..3de5b728f2a6f3bc58b7f23be16e45f9aa6b4a89 100644 --- a/src/global/_colors.scss +++ b/src/global/_colors.scss @@ -5,6 +5,7 @@ --brand-main-dark: #003146; --brand-main-nearly-black: #000222; --link-blue: #0479a5; + --link-disabled: #767676; --grayscale-white: #fff; --grayscale-light: #f8f8f8; --grayscale-medium: #d2d2d2; diff --git a/src/index.html b/src/index.html index 6193d4b4519bf6e7bcc7722a41744a5bb0232b18..6003be80acaebe2e9c5c61b96192dcf216e80bb0 100644 --- a/src/index.html +++ b/src/index.html @@ -408,17 +408,29 @@ Do you want to shape the future world and understand how the universe is built u </hy-paragraph-text> <hy-box pt="2" pb="2" align="center"> - <hy-checkbox checkbox-id="1" checkbox-value="checkbox_1" checkbox-label="Introduction course"></hy-checkbox> - <hy-checkbox checkbox-id="2" checkbox-value="checkbox_2" checkbox-label="Open online course"></hy-checkbox> + <hy-checkbox + checkbox-id="1" + checkbox-value="checkbox_1" + checkbox-label="Introduction course" + checkbox-checked="true" + ></hy-checkbox> + <hy-checkbox + checkbox-id="2" + checkbox-value="checkbox_2" + checkbox-label="Open online course" + checkbox-checked="false" + ></hy-checkbox> <hy-checkbox checkbox-id="3" checkbox-value="checkbox_3" checkbox-label="Flexible start"></hy-checkbox> <hy-checkbox checkbox-id="4" + checkbox-checked="true" checkbox-value="checkbox_4" checkbox-label="Introduction course long text" ></hy-checkbox> <hy-checkbox checkbox-id="5" checkbox-value="checkbox_5" + checkbox-checked="true" checkbox-label="Open online course very long text" ></hy-checkbox> <hy-checkbox @@ -432,12 +444,14 @@ Do you want to shape the future world and understand how the universe is built u variant="button" checkbox-id="3" checkbox-value="checkbox_3" + checkbox-checked="true" checkbox-label="Web pages (204)" ></hy-checkbox> <hy-checkbox variant="button" checkbox-id="4" checkbox-value="checkbox_4" + checkbox-checked="false" checkbox-label="People (89)" ></hy-checkbox> <hy-checkbox diff --git a/src/utils/utils.ts b/src/utils/utils.ts index c285a372fdfd3e9a8430507e602f6970e27d28fc..f34e08dcf2543ad36d408c5d89581151b7b237fc 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -161,7 +161,7 @@ export enum MenuType { sidenav = 'sidenav', sidepanel = 'sidepanel', mobile = 'mobile', - tablet = 'tabled', + tablet = 'tablet', default = 'desktop', }