diff --git a/package.json b/package.json index d6b12ea4b71e3f39d3fc3ecbace955bec6315885..b7c0b33119d5c4dc5f555feebe2c15df3c9b6819 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@itcenteratunihelsinki/huds-lib", - "version": "0.0.61", + "version": "0.0.62", "description": "Helsinki University Design System library", "main": "dist/index.js", "module": "dist/index.mjs", diff --git a/src/components.d.ts b/src/components.d.ts index d789f00b6aa0865f3b631b78b257d8b520dbd848..208b883686b202183d3aa557d83b2d0008cc3c4d 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -5,10 +5,11 @@ * It contains typing information for all components that exist in this project. */ import {HTMLStencilElement, JSXBase} from '@stencil/core/internal'; -import {Breadcrumb} from './components/hy-breadcrumbs/hy-breadcrumbs'; import { + AccordionVariants, BreadcrumbVariants, ButtonVariants, + CheckboxVariants, ColorVariant, CourseVariants, CtaLinkButtonVariants, @@ -26,10 +27,13 @@ import { LinkBoxVariants, LinkVariants, MenuType, + PaginationItemVariants, + PersonCardVariants, ProcessFlowBoxStepStates, ProcessFlowBoxVariants, SiteLogoSize, } from './utils/utils'; +import {Breadcrumb} from './components/hy-breadcrumbs/hy-breadcrumbs'; import {TagValue} from './components/courses/hy-content-list-item/hy-content-list-item'; import {DesktopLinks} from './components/site-header/hy-desktop-menu-links/hy-desktop-menu-links'; import {IDropdownItem} from './components/hy-dropdown/hy-dropdown'; @@ -54,6 +58,7 @@ export namespace Components { } interface HyAccordionItem { accordiontitle?: string; + variant: AccordionVariants; } interface HyAdjacentImageText { imageAlt: string; @@ -191,9 +196,22 @@ export namespace Components { variant: ButtonVariants; } interface HyCheckbox { + /** + * Unique id for checkbox element + */ checkboxId: string | number; + /** + * Label for input to describe + */ checkboxLabel: string; + /** + * Value for input element + */ checkboxValue: string | number; + /** + * Variant to deifne what style of checkbox to use + */ + variant: CheckboxVariants; } interface HyContentList { dataItems: string; @@ -437,6 +455,14 @@ export namespace Components { dataItems: CtaLinkValue[] | string; listHeading: string; } + interface HyListItem { + isExternal: boolean; + itemDescription?: string; + itemTitle?: string; + itemType?: string; + scLabel?: string; + url?: string; + } interface HyMain { hasSidebar: boolean; } @@ -580,11 +606,34 @@ export namespace Components { */ size: SiteLogoSize; } + interface HyPager {} + interface HyPagerItem { + itemLabel?: string; + itemUrl?: string; + scAriaLabel?: string; + variant: PaginationItemVariants; + } interface HyParagraphText { headerstyle: string; placement: string; variant: string; } + interface HyPersonCard { + categoryTitle?: string; + department?: string; + email?: string; + field?: string; + firstName?: string; + imageAlt?: string; + imageUrl?: string; + isExternal: boolean; + lastName?: string; + phone?: string; + positionTitle?: string; + scLabel?: string; + url?: string; + variant: PersonCardVariants; + } interface HyProcess { dataItems: ProcessFlowBoxValue[] | string; numberTerm: string; @@ -988,6 +1037,11 @@ declare global { prototype: HTMLHyLinkListElement; new (): HTMLHyLinkListElement; }; + interface HTMLHyListItemElement extends Components.HyListItem, HTMLStencilElement {} + var HTMLHyListItemElement: { + prototype: HTMLHyListItemElement; + new (): HTMLHyListItemElement; + }; interface HTMLHyMainElement extends Components.HyMain, HTMLStencilElement {} var HTMLHyMainElement: { prototype: HTMLHyMainElement; @@ -1038,11 +1092,26 @@ declare global { prototype: HTMLHyMenuSidebarElement; new (): HTMLHyMenuSidebarElement; }; + interface HTMLHyPagerElement extends Components.HyPager, HTMLStencilElement {} + var HTMLHyPagerElement: { + prototype: HTMLHyPagerElement; + new (): HTMLHyPagerElement; + }; + interface HTMLHyPagerItemElement extends Components.HyPagerItem, HTMLStencilElement {} + var HTMLHyPagerItemElement: { + prototype: HTMLHyPagerItemElement; + new (): HTMLHyPagerItemElement; + }; interface HTMLHyParagraphTextElement extends Components.HyParagraphText, HTMLStencilElement {} var HTMLHyParagraphTextElement: { prototype: HTMLHyParagraphTextElement; new (): HTMLHyParagraphTextElement; }; + interface HTMLHyPersonCardElement extends Components.HyPersonCard, HTMLStencilElement {} + var HTMLHyPersonCardElement: { + prototype: HTMLHyPersonCardElement; + new (): HTMLHyPersonCardElement; + }; interface HTMLHyProcessElement extends Components.HyProcess, HTMLStencilElement {} var HTMLHyProcessElement: { prototype: HTMLHyProcessElement; @@ -1184,6 +1253,7 @@ declare global { 'hy-link-box': HTMLHyLinkBoxElement; 'hy-link-box-list': HTMLHyLinkBoxListElement; 'hy-link-list': HTMLHyLinkListElement; + 'hy-list-item': HTMLHyListItemElement; 'hy-main': HTMLHyMainElement; 'hy-main-content-wrapper': HTMLHyMainContentWrapperElement; 'hy-menu': HTMLHyMenuElement; @@ -1194,7 +1264,10 @@ declare global { 'hy-menu-level-container': HTMLHyMenuLevelContainerElement; 'hy-menu-mobile-breadcrumb': HTMLHyMenuMobileBreadcrumbElement; 'hy-menu-sidebar': HTMLHyMenuSidebarElement; + 'hy-pager': HTMLHyPagerElement; + 'hy-pager-item': HTMLHyPagerItemElement; 'hy-paragraph-text': HTMLHyParagraphTextElement; + 'hy-person-card': HTMLHyPersonCardElement; 'hy-process': HTMLHyProcessElement; 'hy-process-flow-box': HTMLHyProcessFlowBoxElement; 'hy-prominent-image': HTMLHyProminentImageElement; @@ -1222,6 +1295,7 @@ declare namespace LocalJSX { } interface HyAccordionItem { accordiontitle?: string; + variant?: AccordionVariants; } interface HyAdjacentImageText { imageAlt?: string; @@ -1359,9 +1433,22 @@ declare namespace LocalJSX { variant?: ButtonVariants; } interface HyCheckbox { + /** + * Unique id for checkbox element + */ checkboxId?: string | number; + /** + * Label for input to describe + */ checkboxLabel?: string; + /** + * Value for input element + */ checkboxValue?: string | number; + /** + * Variant to deifne what style of checkbox to use + */ + variant?: CheckboxVariants; } interface HyContentList { dataItems?: string; @@ -1605,6 +1692,14 @@ declare namespace LocalJSX { dataItems?: CtaLinkValue[] | string; listHeading?: string; } + interface HyListItem { + isExternal?: boolean; + itemDescription?: string; + itemTitle?: string; + itemType?: string; + scLabel?: string; + url?: string; + } interface HyMain { hasSidebar?: boolean; } @@ -1758,11 +1853,34 @@ declare namespace LocalJSX { */ size?: SiteLogoSize; } + interface HyPager {} + interface HyPagerItem { + itemLabel?: string; + itemUrl?: string; + scAriaLabel?: string; + variant?: PaginationItemVariants; + } interface HyParagraphText { headerstyle?: string; placement?: string; variant?: string; } + interface HyPersonCard { + categoryTitle?: string; + department?: string; + email?: string; + field?: string; + firstName?: string; + imageAlt?: string; + imageUrl?: string; + isExternal?: boolean; + lastName?: string; + phone?: string; + positionTitle?: string; + scLabel?: string; + url?: string; + variant?: PersonCardVariants; + } interface HyProcess { dataItems?: ProcessFlowBoxValue[] | string; numberTerm?: string; @@ -1963,6 +2081,7 @@ declare namespace LocalJSX { 'hy-link-box': HyLinkBox; 'hy-link-box-list': HyLinkBoxList; 'hy-link-list': HyLinkList; + 'hy-list-item': HyListItem; 'hy-main': HyMain; 'hy-main-content-wrapper': HyMainContentWrapper; 'hy-menu': HyMenu; @@ -1973,7 +2092,10 @@ declare namespace LocalJSX { 'hy-menu-level-container': HyMenuLevelContainer; 'hy-menu-mobile-breadcrumb': HyMenuMobileBreadcrumb; 'hy-menu-sidebar': HyMenuSidebar; + 'hy-pager': HyPager; + 'hy-pager-item': HyPagerItem; 'hy-paragraph-text': HyParagraphText; + 'hy-person-card': HyPersonCard; 'hy-process': HyProcess; 'hy-process-flow-box': HyProcessFlowBox; 'hy-prominent-image': HyProminentImage; @@ -2052,6 +2174,7 @@ declare module '@stencil/core' { 'hy-link-box': LocalJSX.HyLinkBox & JSXBase.HTMLAttributes<HTMLHyLinkBoxElement>; 'hy-link-box-list': LocalJSX.HyLinkBoxList & JSXBase.HTMLAttributes<HTMLHyLinkBoxListElement>; 'hy-link-list': LocalJSX.HyLinkList & JSXBase.HTMLAttributes<HTMLHyLinkListElement>; + 'hy-list-item': LocalJSX.HyListItem & JSXBase.HTMLAttributes<HTMLHyListItemElement>; 'hy-main': LocalJSX.HyMain & JSXBase.HTMLAttributes<HTMLHyMainElement>; 'hy-main-content-wrapper': LocalJSX.HyMainContentWrapper & JSXBase.HTMLAttributes<HTMLHyMainContentWrapperElement>; @@ -2065,7 +2188,10 @@ declare module '@stencil/core' { 'hy-menu-mobile-breadcrumb': LocalJSX.HyMenuMobileBreadcrumb & JSXBase.HTMLAttributes<HTMLHyMenuMobileBreadcrumbElement>; 'hy-menu-sidebar': LocalJSX.HyMenuSidebar & JSXBase.HTMLAttributes<HTMLHyMenuSidebarElement>; + 'hy-pager': LocalJSX.HyPager & JSXBase.HTMLAttributes<HTMLHyPagerElement>; + 'hy-pager-item': LocalJSX.HyPagerItem & JSXBase.HTMLAttributes<HTMLHyPagerItemElement>; 'hy-paragraph-text': LocalJSX.HyParagraphText & JSXBase.HTMLAttributes<HTMLHyParagraphTextElement>; + 'hy-person-card': LocalJSX.HyPersonCard & JSXBase.HTMLAttributes<HTMLHyPersonCardElement>; 'hy-process': LocalJSX.HyProcess & JSXBase.HTMLAttributes<HTMLHyProcessElement>; 'hy-process-flow-box': LocalJSX.HyProcessFlowBox & JSXBase.HTMLAttributes<HTMLHyProcessFlowBoxElement>; 'hy-prominent-image': LocalJSX.HyProminentImage & JSXBase.HTMLAttributes<HTMLHyProminentImageElement>; diff --git a/src/components/accordion-item/accordion-item.scss b/src/components/accordion-item/accordion-item.scss index 3ad458625556370f64208122a4cc0bb6ce2a619f..ddeb1f521f069507eba82c1b99cab1a4ae6cfe22 100644 --- a/src/components/accordion-item/accordion-item.scss +++ b/src/components/accordion-item/accordion-item.scss @@ -22,6 +22,39 @@ } } +.hy-accordion__item.mini { + margin-bottom: 1rem; + margin-top: 1rem; +} +.hy-accordion__item__is-open.mini { + margin-bottom: 0; + margin-top: 0; + + .hy-accordion__item--container { + border-bottom: 1px solid var(--grayscale-medium-dark); + border-top: 1px solid var(--grayscale-medium-dark); + padding-top: 16px; + padding-bottom: 32px; + margin-top: -1px; + transition: padding 0.5s ease-in-out; + + @include breakpoint($narrow) { + padding-top: 28px; + padding-bottom: 30px; + } + @include breakpoint($wide) { + padding-top: 32px; + padding-bottom: 40px; + } + } +} + +.hy-accordion__item.hy-accordion__item__is-open.mini { + background-color: var(--grayscale-white); + border: none; + box-shadow: 0 -10px 10px -10px rgba(0, 49, 70, 0.05); +} + .hy-accordion--heading { justify-content: flex-start; letter-spacing: -0.69px; @@ -87,6 +120,55 @@ } } +.hy-accordion--heading.mini { + // accordion clickable header + .hy-accordion__button { + @include font-size(18px, 22px); + background-color: var(--grayscale-white); + color: var(--link-blue); + letter-spacing: -0.56px; + padding: 0; + + @include breakpoint($narrow) { + @include font-size(22px, 28px); + letter-spacing: -0.69px; + padding: 0; + } + + &[aria-expanded='true'] { + color: var(--grayscale-black); + + margin-bottom: 20px; + @include breakpoint($narrow) { + margin-bottom: 28px; + } + @include breakpoint($wide) { + margin-bottom: 32px; + } + } + } + + //accordion arrow + .hy-accordion--heading__icon { + margin-right: 0.5rem; + z-index: 0; + + @include breakpoint($narrow) { + margin-right: 10px; + } + + svg { + fill: var(--brand-main-light); + height: 14px; + width: 14px; + @include breakpoint($narrow) { + height: 16px; + width: 16px; + } + } + } +} + .hy-accordion__content { display: block; height: 0; @@ -104,3 +186,9 @@ } } } + +.hy-accordion__content.mini { + hy-box { + padding: 0; + } +} diff --git a/src/components/accordion-item/accordion-item.tsx b/src/components/accordion-item/accordion-item.tsx index fada4423e84338eef399d0263bab2fa2630478ab..2276011589ebb82ca687422b0cdc3c4eaed5111e 100644 --- a/src/components/accordion-item/accordion-item.tsx +++ b/src/components/accordion-item/accordion-item.tsx @@ -1,4 +1,16 @@ import {Component, Listen, Prop, State, Element, h} from '@stencil/core'; +import {AccordionVariants} from '../../utils/utils'; + +let keys = { + enter: 'Enter', //13 + tab: 'Tab', //9 + pageUp: 'PageUp', //33 + pageDown: 'PageDown', //34 + arrowUp: 'ArrowUp', // 38 + arrowDown: 'ArrowDown', //40 + home: 'Home', //36 + end: 'End', //35 +}; @Component({ tag: 'hy-accordion-item', @@ -8,6 +20,7 @@ import {Component, Listen, Prop, State, Element, h} from '@stencil/core'; export class AccordionItem { @Element() el: HTMLElement; @Prop() accordiontitle?: string; + @Prop() variant: AccordionVariants = AccordionVariants.default; @State() ready: boolean = false; componentDidLoad() { @@ -34,31 +47,28 @@ export class AccordionItem { const triggers = Array.prototype.slice.call(accordion.querySelectorAll('.hy-accordion__button')); let target = event.target as HTMLButtonElement; - const key = event.which.toString(); + const key = event.code; - // 33 = Page Up, 34 = Page Down - const ctrlModifier = event.ctrlKey && key.match(/33|34/); + const ctrlModifier = event.ctrlKey && [keys.pageDown, keys.pageUp].includes(key); //key.match(/33|34/); if (target.classList.contains('hy-accordion__button')) { // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations - // 38 = Up, 40 = Down - if (key.match(/38|40/) || ctrlModifier) { + if ([keys.arrowDown, keys.arrowUp].includes(key) || ctrlModifier) { const index = triggers.indexOf(target); - const direction = key.match(/34|40/) ? 1 : -1; + const direction = [keys.arrowDown, keys.pageDown].includes(key) ? 1 : -1; const length = triggers.length; const newIndex = (index + length + direction) % length; triggers[newIndex].focus(); event.preventDefault(); - } else if (key.match(/35|36/)) { - // 35 = End, 36 = Home keyboard operations + } else if ([keys.home, keys.end].includes(key)) { switch (key) { // Go to first accordion - case '36': + case keys.home: triggers[0].focus(); break; // Go to last accordion - case '35': + case keys.end: triggers[triggers.length - 1].focus(); break; } @@ -179,40 +189,46 @@ export class AccordionItem { }); } - const classAttributes = ['hy-accordion__item']; + const classAttributes = ['hy-accordion__item', this.variant].join(' '); + const classInnerWrapper = ['hy-accordion__item--container', this.variant].join(' '); + const classHeadingAttributes = ['hy-accordion--heading', this.variant].join(' '); + const classContentAttributes = ['hy-accordion__content', this.variant].join(' '); + const titleAsId = this.accordiontitle.toLowerCase().replace(/\W/g, '-'); const accordionItemHref = '#' + titleAsId + '--title'; return ( - <div class={classAttributes.join(' ')}> - <div class="hy-accordion--heading"> - <a href={accordionItemHref} class="hy-accordion__link" tabindex="-1"> - <button - aria-expanded="false" - aria-controls={`${titleAsId}--content`} - class="hy-accordion__button" - id={`${titleAsId}--title`} - > - <span class="hy-accordion--heading__icon"> - <hy-icon icon={'hy-icon-caret-down'} size={20} /> - </span> - {this.accordiontitle} - </button> - </a> - </div> - <div - aria-labelledBy={`${titleAsId}--title`} - class="hy-accordion__content" - id={`${titleAsId}--content`} - role="region" - aria-hidden="true" - style={{display: 'none'}} - > - <hy-box pt="0" pb="0" pl="0.75" pr="0.75"> - <div class="hy-accordion__content--inner-wrapper"> - <slot></slot> - </div> - </hy-box> + <div class={classAttributes}> + <div class={classInnerWrapper}> + <div class={classHeadingAttributes}> + <a href={accordionItemHref} class="hy-accordion__link" tabindex="-1"> + <button + aria-expanded="false" + aria-controls={`${titleAsId}--content`} + class="hy-accordion__button" + id={`${titleAsId}--title`} + > + <span class="hy-accordion--heading__icon"> + <hy-icon icon={'hy-icon-caret-down'} size={20} /> + </span> + {this.accordiontitle} + </button> + </a> + </div> + <div + aria-labelledBy={`${titleAsId}--title`} + class={classContentAttributes} + id={`${titleAsId}--content`} + role="region" + aria-hidden="true" + style={{display: 'none'}} + > + <hy-box pt="0" pb="0" pl="0.75" pr="0.75"> + <div class="hy-accordion__content--inner-wrapper"> + <slot></slot> + </div> + </hy-box> + </div> </div> </div> ); diff --git a/src/components/accordion-item/readme.md b/src/components/accordion-item/readme.md index b54677a5131a7334b22b80209227401f6aa65180..858fdfd91a7f60426bbc714012699a76a7194c8b 100644 --- a/src/components/accordion-item/readme.md +++ b/src/components/accordion-item/readme.md @@ -39,9 +39,10 @@ Accordion component ## Properties -| Property | Attribute | Description | Type | Default | -| ---------------- | ---------------- | ----------- | -------- | ----------- | -| `accordiontitle` | `accordiontitle` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ---------------- | ---------------- | ----------- | ----------------------------------------------------- | --------------------------- | +| `accordiontitle` | `accordiontitle` | | `string` | `undefined` | +| `variant` | `variant` | | `AccordionVariants.default \| AccordionVariants.mini` | `AccordionVariants.default` | ## Dependencies diff --git a/src/components/hy-checkbox/hy-checkbox.scss b/src/components/hy-checkbox/hy-checkbox.scss index 1a5ddc416702ca19d80d1c81b06d88a8e223ecc5..5af23e8a19ceea5bd164aec1de2e6252dc563130 100644 --- a/src/components/hy-checkbox/hy-checkbox.scss +++ b/src/components/hy-checkbox/hy-checkbox.scss @@ -81,3 +81,113 @@ } } } + +.hy-checkbox--button { + display: inline-block; + margin-right: 4px; + position: relative; + + &__label { + @include font-size(12px, 14px); + + align-items: center; + border: 0.5px solid var(--grayscale-medium-dark); + color: var(--link-blue); + display: inline-flex; + font-family: var(--main-font-family); + font-weight: 600; + letter-spacing: -0.3px; + padding: 12px 15px 12px 13px; + z-index: 1; + + @include breakpoint($wide) { + @include font-size(14px, 18px); + + letter-spacing: -0.4px; + padding: 9px 8px 9px 8px; + } + } + + &__checkmark { + position: absolute; + right: 12px; + top: 0; + bottom: 0; + + @include breakpoint($wide) { + right: 10px; + bottom: calc(50% + 10px); + } + + svg { + bottom: 0; + left: 0; + position: absolute; + visibility: hidden; + } + } + + &__label-icon { + height: 13px; + position: absolute; + width: 12px; + + @include breakpoint($wide) { + padding: 10px; + right: -6px; + top: calc(50% + 5px); + } + + svg { + background: var(--grayscale-white); + height: 12px; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 12px; + } + } + + &__checkbox { + height: 100%; + margin: 0; + opacity: 0; + position: absolute; + width: 100%; + z-index: 10; + + &:checked { + & + label { + border: 1px solid var(--grayscale-black); + color: var(--grayscale-black); + padding: 12px 15px 12px 13px; + + @include breakpoint($wide) { + border: 2px solid var(--grayscale-black); + padding: 8px 26px 8px 7px; + } + + .hy-checkbox--button__checkmark { + .hy-checkbox--button__label-icon { + background: var(--grayscale-white); + } + + svg { + visibility: visible; + } + } + } + } + + &:hover { + cursor: pointer; + } + + &:focus { + & + label { + outline-offset: 1px; + outline: 1px solid var(--link-blue); + } + } + } +} diff --git a/src/components/hy-checkbox/hy-checkbox.tsx b/src/components/hy-checkbox/hy-checkbox.tsx index 67999a9a0dbcdc874335f18ac5941598bc4ff3f0..53ab8374cf5e6516a5905be0bc09c9f8c75b841f 100644 --- a/src/components/hy-checkbox/hy-checkbox.tsx +++ b/src/components/hy-checkbox/hy-checkbox.tsx @@ -1,4 +1,5 @@ import {Component, Host, h, Prop} from '@stencil/core'; +import {CheckboxVariants} from '../../utils/utils'; @Component({ tag: 'hy-checkbox', @@ -6,25 +7,60 @@ import {Component, Host, h, Prop} from '@stencil/core'; shadow: false, }) export class HyCheckbox { + /** + * Unique id for checkbox element + */ @Prop() checkboxId: string | number; + /** + * Value for input element + */ @Prop() checkboxValue: string | number; + /** + * Label for input to describe + */ @Prop() checkboxLabel: string; + /** + * Variant to deifne what style of checkbox to use + */ + @Prop() variant: CheckboxVariants = CheckboxVariants.default; + render() { - return ( - <Host class="hy-checkbox"> - <input - type="checkbox" - class="hy-checkbox__checkbox" - id={`${this.checkboxId}`} - value={`${this.checkboxValue}`} - /> - <label class="hy-checkbox__label" htmlFor={`${this.checkboxId}`}> - <span class="hy-checkbox__checkmark"> - <hy-icon class="hy-checkbox__label-icon" icon={'hy-icon-done'} size={23} aria-hidden="true" /> - </span> - {this.checkboxLabel} - </label> - </Host> - ); + switch (this.variant) { + case 'button': + return ( + <Host class="hy-checkbox--button"> + <input + type="checkbox" + class="hy-checkbox--button__checkbox" + id={`${this.checkboxId}`} + value={`${this.checkboxValue}`} + /> + <label class="hy-checkbox--button__label" htmlFor={`${this.checkboxId}`}> + {this.checkboxLabel} + <span class="hy-checkbox--button__checkmark"> + <hy-icon class="hy-checkbox--button__label-icon" icon={'hy-icon-done'} size={14} aria-hidden="true" /> + </span> + </label> + </Host> + ); + + default: + return ( + <Host class="hy-checkbox"> + <input + type="checkbox" + class="hy-checkbox__checkbox" + id={`${this.checkboxId}`} + value={`${this.checkboxValue}`} + /> + <label class="hy-checkbox__label" htmlFor={`${this.checkboxId}`}> + <span class="hy-checkbox__checkmark"> + <hy-icon class="hy-checkbox__label-icon" icon={'hy-icon-done'} size={23} aria-hidden="true" /> + </span> + {this.checkboxLabel} + </label> + </Host> + ); + } } } diff --git a/src/components/hy-checkbox/readme.md b/src/components/hy-checkbox/readme.md index d9e3e32efc2f21053c130c6aa079d3d5ecf6e51e..68265a213d83776c24ffe2d645a2568e43cc08ad 100644 --- a/src/components/hy-checkbox/readme.md +++ b/src/components/hy-checkbox/readme.md @@ -4,11 +4,12 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| --------------- | ---------------- | ----------- | ------------------ | ----------- | -| `checkboxId` | `checkbox-id` | | `number \| string` | `undefined` | -| `checkboxLabel` | `checkbox-label` | | `string` | `undefined` | -| `checkboxValue` | `checkbox-value` | | `number \| string` | `undefined` | +| 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` | ## Dependencies diff --git a/src/components/hy-list-item/hy-list-item.scss b/src/components/hy-list-item/hy-list-item.scss new file mode 100644 index 0000000000000000000000000000000000000000..f67c979296f11da075fe193ba4140dd68fa8105f --- /dev/null +++ b/src/components/hy-list-item/hy-list-item.scss @@ -0,0 +1,84 @@ +:host { + display: block; +} + +.hy-list-item { + display: flex; + font-family: var(--main-font-family); + margin-bottom: 28px; + text-decoration: none; + + @include breakpoint($wide) { + margin-bottom: 32px; + } + + &__info-container { + &__header { + @include font-size(12px, 14px); + color: var(--grayscale-dark); + letter-spacing: 0; + margin-bottom: 4px; + + @include breakpoint($narrow) { + @include font-size(14px, 18px); + margin-bottom: 2px; + } + } + + &__title { + @include font-size(18px, 22px); + @include font-weight($bold); + color: var(--brand-main-light); + letter-spacing: -0.56px; + margin-bottom: 6px; + + @include breakpoint($narrow) { + @include font-size(22px, 28px); + letter-spacing: -0.69px; + margin-bottom: 10px; + } + @include breakpoint($fullhd) { + @include font-size(26px, 32px); + letter-spacing: -0.8px; + margin-bottom: 8px; + } + } + + &__link-container { + align-items: center; + display: flex; + margin-bottom: 6px; + + @include breakpoint($narrow) { + margin-bottom: 8px; + } + } + + &__link { + @include font-size(12px, 16px); + color: var(--grayscale-dark); + letter-spacing: -0.07px; + margin-left: 4px; + + @include breakpoint($narrow) { + margin-left: 5px; + } + + &__icon { + svg { + fill: var(--grayscale-dark); + } + } + } + + &__description { + @include font-size(14px, 20px); + color: var(--grayscale-black); + letter-spacing: 0; + + @include breakpoint($narrow) { + @include font-size(16px, 24px); + } + } + } +} diff --git a/src/components/hy-list-item/hy-list-item.tsx b/src/components/hy-list-item/hy-list-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f06fdd00935c525749325c40054d9a3b3e4e0a2f --- /dev/null +++ b/src/components/hy-list-item/hy-list-item.tsx @@ -0,0 +1,42 @@ +import {Component, h, Prop} from '@stencil/core'; + +@Component({ + tag: 'hy-list-item', + styleUrl: 'hy-list-item.scss', + shadow: false, +}) +export class HyListItem { + @Prop() itemType?: string; + @Prop() itemTitle?: string; + @Prop() itemDescription?: string; + @Prop() url?: string; + @Prop() isExternal: boolean = false; + @Prop() scLabel?: string; + + render() { + const classAttributes = ['hy-list-item'].join(' '); + const target = this.isExternal ? '_blank' : '_self'; + + return ( + <article> + <a class={classAttributes} href={this.url} target={target} aria-label={this.scLabel}> + <div class="hy-list-item__info-container"> + <div class="hy-list-item__info-container__header">{this.itemType}</div> + <div class="hy-list-item__info-container__title">{this.itemTitle}</div> + + <div class="hy-list-item__info-container__link-container"> + <span class="hy-list-item__info-container__link__icon"> + <hy-icon icon={'hy-icon-link'} size={15} /> + </span> + <div class="hy-list-item__info-container__link">{this.url}</div> + </div> + + {this.itemDescription && ( + <div class="hy-list-item__info-container__description">{this.itemDescription}</div> + )} + </div> + </a> + </article> + ); + } +} diff --git a/src/components/hy-list-item/readme.md b/src/components/hy-list-item/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..f9f00fefe6f4b29e3f80198a690658facc788399 --- /dev/null +++ b/src/components/hy-list-item/readme.md @@ -0,0 +1,32 @@ +# hy-list-item + +<!-- Auto Generated Below --> + +## Properties + +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ----------- | --------- | ----------- | +| `isExternal` | `is-external` | | `boolean` | `false` | +| `itemDescription` | `item-description` | | `string` | `undefined` | +| `itemTitle` | `item-title` | | `string` | `undefined` | +| `itemType` | `item-type` | | `string` | `undefined` | +| `scLabel` | `sc-label` | | `string` | `undefined` | +| `url` | `url` | | `string` | `undefined` | + +## Dependencies + +### Depends on + +- [hy-icon](../icon) + +### Graph + +```mermaid +graph TD; + hy-list-item --> hy-icon + style hy-list-item fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +Helsinki University Design System diff --git a/src/components/hy-person-card/hy-person-card.scss b/src/components/hy-person-card/hy-person-card.scss new file mode 100644 index 0000000000000000000000000000000000000000..fabd0b77dde9c3b1082df1a10a9e1021d401e66a --- /dev/null +++ b/src/components/hy-person-card/hy-person-card.scss @@ -0,0 +1,298 @@ +:host { + display: block; +} + +.hy-person-card-container { + font-family: var(--main-font-family); + margin-bottom: 28px; + + @include breakpoint($wide) { + margin-bottom: 32px; + } + + &__category-title { + @include font-size(12px, 14px); + color: var(--grayscale-dark); + letter-spacing: 0; + margin-bottom: 8px; + + @include breakpoint($narrow) { + @include font-size(14px, 18px); + } + + @include breakpoint($fullhd) { + @include font-size(14px, 18px); //>1920 desktop + } + } + + &__link { + text-decoration: none; + } +} + +.hy-person-card { + display: flex; + flex-direction: row; + font-family: var(--main-font-family); + + &__image-container { + margin-right: 12px; + + @include breakpoint($narrow) { + margin-right: 16px; + } + + &__image { + height: 70px; + width: 70px; + + @include breakpoint($narrow) { + height: 112px; + width: 112px; + } + + @include breakpoint($fullhd) { + //1920 + height: 140px; + width: 140px; + } + img { + height: 70px; + width: 70px; + object-fit: cover; + + @include breakpoint($narrow) { + height: 112px; + width: 112px; + } + + @include breakpoint($fullhd) { + height: 140px; + width: 140px; + } + } + } + &__no-image { + height: 70px; + width: 70px; + + align-items: center; + background-color: var(--brand-main-light); + display: flex; + justify-content: center; + + @include breakpoint($narrow) { + height: 112px; + width: 112px; + } + + @include breakpoint($fullhd) { + height: 140px; + width: 140px; + } + + &__initials { + @include font-size(18px, 24px); + @include font-weight($bold); + color: var(--grayscale-white); + letter-spacing: -0.56px; + + @include breakpoint($narrow) { + @include font-size(32px, 32px); + letter-spacing: 0.96px; + } + } + } + } + + &__info-container { + &__full-name { + @include font-size(18px, 24px); + @include font-weight($bold); + + color: var(--brand-main-light); + letter-spacing: -0.56px; + margin-bottom: 4px; + + @include breakpoint($narrow) { + @include font-size(22px, 28px); + letter-spacing: -0.69px; + margin-bottom: 3px; + } + + @include breakpoint($fullhd) { + @include font-size(26px, 28px); + letter-spacing: -0.81px; + margin-bottom: 5px; + } + } + + &__position-title { + @include font-size(14px, 19px); + @include font-weight($bold); + color: var(--brand-main-nearly-black); + letter-spacing: 0; + margin-bottom: 3px; + + @include breakpoint($narrow) { + @include font-size(16px, 20px); + letter-spacing: -0.5px; + margin-bottom: 4px; + } + + @include breakpoint($fullhd) { + @include font-size(18px, 24px); + letter-spacing: -0.56px; + margin-bottom: 8px; + } + } + + &__department { + @include font-size(12px, 17px); + color: var(--brand-main-nearly-black); + letter-spacing: 0; + margin-bottom: 3px; + text-transform: uppercase; + + @include breakpoint($narrow) { + @include font-size(14px, 19px); + margin-bottom: 6px; + } + + @include breakpoint($fullhd) { + @include font-size(14px, 16px); + margin-bottom: 9px; + } + } + + &__field { + @include font-size(12px, 17px); + color: var(--brand-main-nearly-black); + letter-spacing: 0; + margin-bottom: 4px; + + @include breakpoint($narrow) { + @include font-size(14px, 19px); + margin-bottom: 6px; + } + + @include breakpoint($fullhd) { + @include font-size(14px, 16px); + margin-bottom: 9px; + } + } + + &__email-container { + align-items: center; + display: flex; + margin-bottom: 4px; + } + &__email { + @include font-size(12px, 17px); + color: var(--brand-main-nearly-black); + letter-spacing: 0; + margin-left: 11px; + + @include breakpoint($narrow) { + @include font-size(14px, 19px); + margin-left: 8px; + } + + &__icon { + svg { + height: 15px; + width: 16px; + + @include breakpoint($narrow) { + height: 12px; + width: 16px; + } + } + } + } + + &__phone-container { + align-items: center; + display: flex; + } + &__phone { + @include font-size(12px, 17px); + color: var(--brand-main-nearly-black); + letter-spacing: 0; + margin-left: 11px; + + @include breakpoint($narrow) { + @include font-size(14px, 19px); + margin-left: 8px; + } + + &__icon { + svg { + height: 13px; + width: 13px; + + @include breakpoint($narrow) { + height: 14px; + width: 14px; + } + } + } + } + } + + &.search-panel { + margin-bottom: 12px; + + @include breakpoint($narrow) { + margin-bottom: 14px; + } + + .hy-person-card__info-container__full-name { + @include font-size(14px, 20px); + @include font-weight($semibold); + color: var(--grayscale-dark); + letter-spacing: 0; + margin-bottom: 0; + + @include breakpoint($narrow) { + letter-spacing: -0.3px; + } + + @include breakpoint($fullhd) { + @include font-size(16px, 24px); + letter-spacing: 0; + } + } + + .hy-person-card__info-container__position-title { + @include font-size(12px, 16px); + color: var(--grayscale-dark); + letter-spacing: -0.07px; + margin-bottom: 0; + } + + .hy-person-card__image-container { + margin-right: 12px; + + &__image { + height: 60px; + width: 60px; + img { + height: 60px; + width: 60px; + } + } + &__no-image { + height: 60px; + width: 60px; + + &__initials { + color: var(--grayscale-white); + @include font-size(16px, 32px); + @include font-weight($bold); + letter-spacing: 0.48px; + } + } + } + } +} diff --git a/src/components/hy-person-card/hy-person-card.tsx b/src/components/hy-person-card/hy-person-card.tsx new file mode 100644 index 0000000000000000000000000000000000000000..06c191ef82c4e175f4467e09ed27a7979c8edde6 --- /dev/null +++ b/src/components/hy-person-card/hy-person-card.tsx @@ -0,0 +1,97 @@ +import {Component, h, Prop} from '@stencil/core'; +import {PersonCardVariants} from '../../utils/utils'; + +@Component({ + tag: 'hy-person-card', + styleUrl: 'hy-person-card.scss', + shadow: false, +}) +export class HyPersonCard { + @Prop() variant: PersonCardVariants = PersonCardVariants.default; + @Prop() categoryTitle?: string; + @Prop() imageUrl?: string; + @Prop() imageAlt?: string; + @Prop() firstName?: string; + @Prop() lastName?: string; + @Prop() url?: string; + @Prop() isExternal: boolean = false; + @Prop() scLabel?: string; + @Prop() positionTitle?: string; + @Prop() department?: string; + @Prop() field?: string; + @Prop() email?: string; + @Prop() phone?: string; + private _fullName: string; + private _initials: string; + + componentWillLoad() { + this._fullName = this.firstName && this.lastName ? `${this.firstName} ${this.lastName}` : ''; + this._initials = + this.imageUrl && this.firstName && this.lastName ? '' : `${this.firstName.charAt(0)}${this.lastName.charAt(0)}`; + if (!this.imageAlt) { + this.imageAlt = this._fullName; + } + if (!this.scLabel) { + this.scLabel = 'Link to the person profile'; + } + } + + render() { + const classLinkAttributes = ['hy-person-card-container__link', this.variant].join(' '); + const classAttributes = ['hy-person-card', this.variant].join(' '); + const target = this.isExternal ? '_blank' : '_self'; + + return ( + <article class="hy-person-card-container"> + <a class={classLinkAttributes} href={this.url} target={target} aria-label={this.scLabel}> + {this.categoryTitle && this.variant == PersonCardVariants.default && ( + <div class="hy-person-card-container__category-title">{this.categoryTitle}</div> + )} + <div class={classAttributes}> + <div class="hy-person-card__image-container"> + {this.imageUrl ? ( + <div class="hy-person-card__image-container__image"> + <img aria-hidden="true" src={this.imageUrl} alt={this.imageAlt} /> + </div> + ) : ( + <div class="hy-person-card__image-container__no-image"> + <div class="hy-person-card__image-container__no-image__initials">{this._initials}</div> + </div> + )} + </div> + <div class="hy-person-card__info-container"> + <div class="hy-person-card__info-container__full-name">{this._fullName}</div> + {this.positionTitle && ( + <div class="hy-person-card__info-container__position-title">{this.positionTitle}</div> + )} + {this.department && this.variant == PersonCardVariants.default && ( + <div class="hy-person-card__info-container__department">{this.department}</div> + )} + {this.field && this.variant == PersonCardVariants.default && ( + <div class="hy-person-card__info-container__field">{this.field}</div> + )} + {this.email && + this.variant == PersonCardVariants.default && [ + <div class="hy-person-card__info-container__email-container"> + <span class="hy-person-card__info-container__email__icon"> + <hy-icon icon={'hy-icon-email'} size={16} /> + </span> + <span class="hy-person-card__info-container__email">{this.email}</span> + </div>, + ]} + {this.phone && + this.variant == PersonCardVariants.default && [ + <div class="hy-person-card__info-container__phone-container"> + <span class="hy-person-card__info-container__phone__icon"> + <hy-icon icon={'hy-icon-phone'} size={14} /> + </span> + <span class="hy-person-card__info-container__phone">{this.phone}</span> + </div>, + ]} + </div> + </div> + </a> + </article> + ); + } +} diff --git a/src/components/hy-person-card/readme.md b/src/components/hy-person-card/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..e89c3058ff5c949ec5f39645353173522b45079f --- /dev/null +++ b/src/components/hy-person-card/readme.md @@ -0,0 +1,40 @@ +# hy-person-card + +<!-- Auto Generated Below --> + +## Properties + +| Property | Attribute | Description | Type | Default | +| --------------- | ---------------- | ----------- | -------------------------------------------------------------- | ---------------------------- | +| `categoryTitle` | `category-title` | | `string` | `undefined` | +| `department` | `department` | | `string` | `undefined` | +| `email` | `email` | | `string` | `undefined` | +| `field` | `field` | | `string` | `undefined` | +| `firstName` | `first-name` | | `string` | `undefined` | +| `imageAlt` | `image-alt` | | `string` | `undefined` | +| `imageUrl` | `image-url` | | `string` | `undefined` | +| `isExternal` | `is-external` | | `boolean` | `false` | +| `lastName` | `last-name` | | `string` | `undefined` | +| `phone` | `phone` | | `string` | `undefined` | +| `positionTitle` | `position-title` | | `string` | `undefined` | +| `scLabel` | `sc-label` | | `string` | `undefined` | +| `url` | `url` | | `string` | `undefined` | +| `variant` | `variant` | | `PersonCardVariants.default \| PersonCardVariants.searchPanel` | `PersonCardVariants.default` | + +## Dependencies + +### Depends on + +- [hy-icon](../icon) + +### Graph + +```mermaid +graph TD; + hy-person-card --> hy-icon + style hy-person-card fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +Helsinki University Design System diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx index 35c38b94740398840c7ef769f9738a8442bf72e1..851e564ac6bb56847aede98960bffa8e2745ed45 100644 --- a/src/components/icon/icon.tsx +++ b/src/components/icon/icon.tsx @@ -16,9 +16,12 @@ const iconNames: IconName = { '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-link': (p) => <icons.Url {...p} />, 'hy-icon-globe': (p) => <icons.Globe {...p} />, 'hy-icon-hamburger': (p) => <icons.Hamburger {...p} />, 'hy-icon-home': (p) => <icons.Home {...p} />, + 'hy-icon-email': (p) => <icons.Mail {...p} />, + 'hy-icon-phone': (p) => <icons.Phone {...p} />, 'hy-icon-hy-logo': (p) => <icons.HyLogo {...p} />, 'hy-icon-image-gallery': (p) => <icons.ImageGallery {...p} />, 'hy-icon-link-arrow-down': (p) => <icons.LinkArrowDown {...p} />, diff --git a/src/components/icon/readme.md b/src/components/icon/readme.md index c42057f3becc0d5f442783211c25543c9e74b0f5..ccd10150fd514cf1f8657e311293101c7c0f7513 100644 --- a/src/components/icon/readme.md +++ b/src/components/icon/readme.md @@ -32,12 +32,15 @@ - [hy-footer-link-item](../footer/hy-footer-link-item) - [hy-introduction](../hy-introduction) - [hy-link-box](../link-box) +- [hy-list-item](../hy-list-item) - [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-pager-item](../pagination/hy-pager-item) +- [hy-person-card](../hy-person-card) - [hy-quote](../hy-quote) - [hy-search-field](../hy-search-field) - [hy-shortcuts](../hy-shortcuts) @@ -69,12 +72,15 @@ graph TD; hy-footer-link-item --> hy-icon hy-introduction --> hy-icon hy-link-box --> hy-icon + hy-list-item --> 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-pager-item --> hy-icon + hy-person-card --> hy-icon hy-quote --> hy-icon hy-search-field --> hy-icon hy-shortcuts --> hy-icon 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 0160314c1bcebd8be2968aadeb8cf3d9f5d60046..fa01163b38cf4467dc0e74d41f1825a59fc26872 100644 --- a/src/components/navigation/menu-level-container/menu-level-container.scss +++ b/src/components/navigation/menu-level-container/menu-level-container.scss @@ -67,7 +67,7 @@ } &.is-open, &.active-trail-panel { - height: fit-content; + height: 100vh; min-height: var(--minHeight); } } diff --git a/src/components/navigation/menu-sidebar/menu-sidebar.scss b/src/components/navigation/menu-sidebar/menu-sidebar.scss index 907d4d233064c18c3dfa39513233f1390dcf808d..6d953a3c23f3c31eb151b3e8428255b63451c041 100644 --- a/src/components/navigation/menu-sidebar/menu-sidebar.scss +++ b/src/components/navigation/menu-sidebar/menu-sidebar.scss @@ -72,6 +72,7 @@ animation-name: sidepanel-movein; display: flex; height: auto; + min-height: 100vh; width: 100%; // Open sidenav panels. Set background color to non-active items diff --git a/src/components/navigation/menu-sidebar/menu-sidebar.tsx b/src/components/navigation/menu-sidebar/menu-sidebar.tsx index 8e0dcd02fa6ed7734436053b05b674f67f9b95c7..c643207b9382309dd735d738a5f8a0918259a895 100644 --- a/src/components/navigation/menu-sidebar/menu-sidebar.tsx +++ b/src/components/navigation/menu-sidebar/menu-sidebar.tsx @@ -86,26 +86,32 @@ export class MenuSidebar { 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'); + if (sideBar) { + 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(); - } - }); + if (sidebarContainer) { + 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); - } - }); + if (sidepanelContainer) { + 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) { diff --git a/src/components/pagination/hy-pager-item/hy-pager-item.scss b/src/components/pagination/hy-pager-item/hy-pager-item.scss new file mode 100644 index 0000000000000000000000000000000000000000..cbc959212dba05da94e938d5c4ca6518b0c12b8c --- /dev/null +++ b/src/components/pagination/hy-pager-item/hy-pager-item.scss @@ -0,0 +1,84 @@ +:host { + display: block; +} + +.hy-pager__item { + @include font-size(14px, 24px); + @include font-weight($bold); + align-items: center; + background-color: var(--brand-main-light); + color: var(--grayscale-white); + display: flex; + flex-direction: row; + font-family: var(--main-font-family); + justify-content: center; + letter-spacing: -0.4px; + margin-bottom: 4px; + margin-right: 8px; + min-height: 36px; + min-width: 36px; + text-align: center; + + @include breakpoint($wide) { + margin-right: 6px; + min-height: 40px; + min-width: 40px; + } + + a { + @include font-size(14px, 24px); + @include font-weight($bold); + align-items: center; + color: var(--grayscale-white); + display: flex; + flex-direction: row; + justify-content: center; + letter-spacing: -0.4px; + min-height: 36px; + min-width: 36px; + text-decoration: none; + + @include breakpoint($wide) { + @include font-size(16px, 24px); + letter-spacing: -0.5px; + min-height: 40px; + min-width: 40px; + } + } + + &__current { + background-color: var(--grayscale-white); + box-sizing: border-box; + border: 2px solid var(--grayscale-black); + a { + color: var(--brand-main-nearly-black); + + @include breakpoint($wide) { + @include font-size(18px, 24px); + letter-spacing: -0.56px; + } + } + } + + &__next, + &__previous { + a { + padding: 7px 12px 5px 12px; + + @include breakpoint($wide) { + padding: 8px 12px; + } + } + + .hy-icon-wrapper { + margin: 0 4px; + @include breakpoint($wide) { + margin: 0 6px; + } + + svg { + fill: var(--grayscale-white); + } + } + } +} diff --git a/src/components/pagination/hy-pager-item/hy-pager-item.tsx b/src/components/pagination/hy-pager-item/hy-pager-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..332ce92590c7fe4ad039fe85063e6f27eb13db01 --- /dev/null +++ b/src/components/pagination/hy-pager-item/hy-pager-item.tsx @@ -0,0 +1,76 @@ +import {Component, h, Prop} from '@stencil/core'; +import {PaginationItemVariants} from '../../../utils/utils'; + +@Component({ + tag: 'hy-pager-item', + styleUrl: 'hy-pager-item.scss', + shadow: true, +}) +export class HyPagerItem { + @Prop() variant: PaginationItemVariants = PaginationItemVariants.default; + @Prop() itemLabel?: string; + @Prop() itemUrl?: string; + @Prop() scAriaLabel?: string; + + render() { + let classAttributes = ['hy-pager__item'].join(' '); + switch (this.variant) { + case PaginationItemVariants.current: { + classAttributes = ['hy-pager__item', 'hy-pager__item__current'].join(' '); + return ( + <li class={classAttributes}> + <a href={this.itemUrl} aria-current="true"> + {this.itemLabel} + </a> + </li> + ); + } + case PaginationItemVariants.next: { + classAttributes = ['hy-pager__item', 'hy-pager__item__next'].join(' '); + const iconClassAttributes = ['link-icon'].join(' '); + return ( + <li class={classAttributes}> + <a href={this.itemUrl} aria-label={this.scAriaLabel}> + {this.itemLabel} + <span class={'hy-icon-wrapper'}> + <div class={iconClassAttributes}> + <hy-icon icon={'hy-icon-arrow-to-right'} size={12} /> + </div> + </span> + </a> + </li> + ); + } + case PaginationItemVariants.previous: { + classAttributes = ['hy-pager__item', 'hy-pager__item__previous'].join(' '); + const iconClassAttributes = ['link-icon'].join(' '); + return ( + <li class={classAttributes}> + <a href={this.itemUrl} aria-label={this.scAriaLabel}> + <span class={'hy-icon-wrapper'}> + <div class={iconClassAttributes}> + <hy-icon icon={'hy-icon-arrow-left'} size={12} /> + </div> + </span> + {this.itemLabel} + </a> + </li> + ); + } + case PaginationItemVariants.ellipsis: { + classAttributes = ['hy-pager__item', 'hy-pager__item__ellipsis'].join(' '); + return <li class={classAttributes}>...</li>; + } + default: { + classAttributes = ['hy-pager__item'].join(' '); + return ( + <li class={classAttributes}> + <a href={this.itemUrl} aria-label={this.scAriaLabel}> + {this.itemLabel} + </a> + </li> + ); + } + } + } +} diff --git a/src/components/pagination/hy-pager-item/readme.md b/src/components/pagination/hy-pager-item/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..ad8db57d5ebb0d5631a48ae39afd6678badef1ef --- /dev/null +++ b/src/components/pagination/hy-pager-item/readme.md @@ -0,0 +1,30 @@ +# hy-pager-item + +<!-- Auto Generated Below --> + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------- | --------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | +| `itemLabel` | `item-label` | | `string` | `undefined` | +| `itemUrl` | `item-url` | | `string` | `undefined` | +| `scAriaLabel` | `sc-aria-label` | | `string` | `undefined` | +| `variant` | `variant` | | `PaginationItemVariants.current \| PaginationItemVariants.default \| PaginationItemVariants.ellipsis \| PaginationItemVariants.next \| PaginationItemVariants.previous` | `PaginationItemVariants.default` | + +## Dependencies + +### Depends on + +- [hy-icon](../../icon) + +### Graph + +```mermaid +graph TD; + hy-pager-item --> hy-icon + style hy-pager-item fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +Helsinki University Design System diff --git a/src/components/pagination/hy-pager/hy-pager.scss b/src/components/pagination/hy-pager/hy-pager.scss new file mode 100644 index 0000000000000000000000000000000000000000..93bd7b5de625820d777e36818ebc157df8c1aae5 --- /dev/null +++ b/src/components/pagination/hy-pager/hy-pager.scss @@ -0,0 +1,13 @@ +:host { + display: block; +} + +.hy-pager { + align-items: center; + display: flex; + justify-content: center; + flex-direction: row; + flex-wrap: wrap; + font-family: var(--main-font-family); + list-style: none; +} diff --git a/src/components/pagination/hy-pager/hy-pager.tsx b/src/components/pagination/hy-pager/hy-pager.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0b3c6338d9d500e84a4fcf4ed9695b8c464aead9 --- /dev/null +++ b/src/components/pagination/hy-pager/hy-pager.tsx @@ -0,0 +1,18 @@ +import {Component, h} from '@stencil/core'; + +@Component({ + tag: 'hy-pager', + styleUrl: 'hy-pager.scss', + shadow: true, +}) +export class HyPager { + render() { + const classAttributes = ['hy-pager'].join(' '); + + return ( + <ul class={classAttributes}> + <slot></slot> + </ul> + ); + } +} diff --git a/src/components/pagination/hy-pager/readme.md b/src/components/pagination/hy-pager/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..d10ef690e45de55cf2ef493e851fc1d760248fab --- /dev/null +++ b/src/components/pagination/hy-pager/readme.md @@ -0,0 +1,7 @@ +# hy-pager + +<!-- Auto Generated Below --> + +--- + +Helsinki University Design System diff --git a/src/index.html b/src/index.html index 6d625609c548333d9a40d293dd6cfcceb5b7eaa4..c422381d7db057255f7f54a1978f45597057e5f8 100644 --- a/src/index.html +++ b/src/index.html @@ -178,10 +178,146 @@ sc-label="Aria label" ></hy-hero> + <hy-paragraph-text> + THIS IS Pagination + </hy-paragraph-text> + <hy-pager> + <hy-pager-item + variant="previous" + item-label="Previous" + item-url="https://helsinki.fi/sv/utbildning/program?page=1" + > + </hy-pager-item> + <hy-pager-item variant="current" item-label="1" item-url="https://helsinki.fi/sv/utbildning/program"> + </hy-pager-item> + <hy-pager-item + item-label="2" + item-url="https://helsinki.fi/sv/utbildning/program?page=1" + sc-aria-label="Go to page 2" + > + </hy-pager-item> + <hy-pager-item + item-label="3" + item-url="https://helsinki.fi/sv/utbildning/program?page=2" + sc-aria-label="Go to page 3" + > + </hy-pager-item> + <hy-pager-item + item-label="4" + item-url="https://helsinki.fi/sv/utbildning/program?page=3" + sc-aria-label="Go to page 4" + > + </hy-pager-item> + <hy-pager-item variant="ellipsis" item-label="..."> </hy-pager-item> + <hy-pager-item variant="next" item-label="Next" item-url="https://helsinki.fi/sv/utbildning/program?page=1"> + </hy-pager-item> + </hy-pager> + <hy-paragraph-text> THIS IS MAIN CONTENT </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-box> + <hy-row> + <hy-checkbox + variant="button" + checkbox-id="3" + checkbox-value="checkbox_3" + checkbox-label="Web pages (204)" + ></hy-checkbox> + <hy-checkbox + variant="button" + checkbox-id="4" + checkbox-value="checkbox_4" + checkbox-label="People (89)" + ></hy-checkbox> + <hy-checkbox + variant="button" + checkbox-id="5" + checkbox-value="checkbox_5" + checkbox-label="Filter with long label goes here (859)" + ></hy-checkbox> + </hy-row> + + <hy-list-item + item-type="News | 20.12.2020" + item-title="Lorem ipsum dolor sit amet, consectetur adipiscing elit cras dapibus vulputate diam eu pretium" + item-description="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras dapibus vulputate diam eu pretium. Mauris elit orci, ultricies id fermentum vel, porta et eros. Vestibulum condimentum lectus in convallis feugiat…" + url="https://www.helsinki.fi/en/faculty-of-arts/admissions/apply-to-the-faculty" + is-external="true" + sc-label="Link opens up in a new tab" + > + </hy-list-item> + <hy-list-item + item-type="Web page | Sub site" + item-title="Explore our international master's programmes | Admissions" + item-description="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras dapibus vulputate diam eu pretium. Mauris elit orci, ultricies id fermentum vel, porta et eros. Vestibulum condimentum lectus in convallis feugiat…" + url="https://www.helsinki.fi/en/faculty-of-arts/admissions/apply-to-the-faculty" + is-external="false" + sc-label="Internal links" + > + </hy-list-item> + + <hy-person-card + variant="search-panel" + category-title="People" + image-url="https://flamma.helsinki.fi/documents/20142/1322159/upload_00015721.jpg" + image-alt="professor" + first-name="Dolor" + last-name="Sit-amet" + url="https://www.helsinki.fi/sv/people/people-finder/person-by-id/9038938" + sc-label="Link opens up in a new tab" + position-title="Postdoctoral Researcher" + department="DEPARTMENT OF BIOCHEMISTRY AND DEVELOPMENTAL BIOLOGY" + field="Fields of science: Biochemistry, cell and molecular biology" + email="lorem.ipsumlorem@helsinki.fi" + phone="0212345678" + > + </hy-person-card> + <hy-person-card + variant="search-panel" + category-title="People" + first-name="Paula" + last-name="Elomaa" + url="https://www.helsinki.fi/sv/people/people-finder/person-by-id/9038938" + is-external="true" + position-title="professor" + department="Agrikultur-forstvetenskapliga fakulteten" + email="paula.elomaa@helsinki.fi" + phone="0504480427" + > + </hy-person-card> + + <hy-person-card + category-title="People" + image-url="https://flamma.helsinki.fi/documents/20142/1322159/upload_00015721.jpg" + image-alt="professor" + first-name="Dolor" + last-name="Sit-amet" + url="https://www.helsinki.fi/sv/people/people-finder/person-by-id/9038938" + is-external="true" + sc-label="Link opens up in a new tab" + position-title="Postdoctoral Researcher" + department="DEPARTMENT OF BIOCHEMISTRY AND DEVELOPMENTAL BIOLOGY" + field="Fields of science: Biochemistry, cell and molecular biology" + email="lorem.ipsumlorem@helsinki.fi" + phone="0212345678" + > + </hy-person-card> + <hy-person-card + first-name="Paula" + last-name="Elomaa" + url="https://www.helsinki.fi/sv/people/people-finder/person-by-id/9038938" + position-title="professor" + department="Agrikultur-forstvetenskapliga fakulteten" + email="paula.elomaa@helsinki.fi" + phone="0504480427" + > + </hy-person-card> + <hy-link-list list-heading="link list heading number one" data-items='[ @@ -967,20 +1103,6 @@ > </hy-content-list> </hy-main-content-wrapper> - - <hy-main-content-wrapper> - <hy-accordion-container accordionId="example-accordion"> - <hy-accordion-item accordiontitle="This is a accordion item 1"> - <hy-paragraph-text>Accordion content</hy-paragraph-text> - </hy-accordion-item> - <hy-accordion-item accordiontitle="This is a accordion item 2"> - <hy-paragraph-text>Accordion content</hy-paragraph-text> - </hy-accordion-item> - <hy-accordion-item accordiontitle="This is a accordion item 3"> - <hy-paragraph-text>Accordion content</hy-paragraph-text> - </hy-accordion-item> - </hy-accordion-container> - </hy-main-content-wrapper> </div> <aside class="layout-sidebar-first" role="complementary"> diff --git a/src/utils/utils.ts b/src/utils/utils.ts index d16c1f46e1710d40d57d6ce41ea2d060ef549021..5b18b9cc6fa44620e05c833c19d5a04f846b4932 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -12,6 +12,11 @@ export type IconName = { [key: string]: (props: any) => FunctionalComponent; }; +export enum AccordionVariants { + default = 'default', + mini = 'mini', +} + export enum BreadcrumbVariants { default = 'default', landingLarge = 'large', @@ -73,6 +78,19 @@ export enum CourseVariants { grid = 'grid', } +export enum PersonCardVariants { + default = 'results', + searchPanel = 'search-panel', +} + +export enum PaginationItemVariants { + default = 'default', + current = 'current', + previous = 'previous', + next = 'next', + ellipsis = 'ellipsis', +} + export enum GridColumnsSm { columnsSm1 = '1', columnsSm2 = '2', @@ -159,3 +177,8 @@ export enum FooterLinkItemColor { black = 'black', white = 'white', } + +export enum CheckboxVariants { + default = 'default', + button = 'button', +}