Skip to content
Snippets Groups Projects
Commit 0a057e38 authored by Tuukka Turu's avatar Tuukka Turu
Browse files

Nxstage 610 breadcrumb

parent c3db32b8
No related branches found
No related tags found
No related merge requests found
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
* It contains typing information for all components that exist in this project. * It contains typing information for all components that exist in this project.
*/ */
import {HTMLStencilElement, JSXBase} from '@stencil/core/internal'; import {HTMLStencilElement, JSXBase} from '@stencil/core/internal';
import {Breadcrumb} from './components/hy-breadcrumbs/hy-breadcrumbs';
import { import {
BreadcrumbVariants,
ButtonVariants, ButtonVariants,
ColorVariant, ColorVariant,
CtaLinkButtonVariants, CtaLinkButtonVariants,
...@@ -129,6 +131,11 @@ export namespace Components { ...@@ -129,6 +131,11 @@ export namespace Components {
*/ */
wrap: boolean; wrap: boolean;
} }
interface HyBreadcrumbs {
dataItems: Breadcrumb[] | string;
headerstyle: string;
variant: BreadcrumbVariants;
}
interface HyButton { interface HyButton {
/** /**
* Aria label for the element * Aria label for the element
...@@ -557,6 +564,11 @@ declare global { ...@@ -557,6 +564,11 @@ declare global {
prototype: HTMLHyBoxContainerElement; prototype: HTMLHyBoxContainerElement;
new (): HTMLHyBoxContainerElement; new (): HTMLHyBoxContainerElement;
}; };
interface HTMLHyBreadcrumbsElement extends Components.HyBreadcrumbs, HTMLStencilElement {}
var HTMLHyBreadcrumbsElement: {
prototype: HTMLHyBreadcrumbsElement;
new (): HTMLHyBreadcrumbsElement;
};
interface HTMLHyButtonElement extends Components.HyButton, HTMLStencilElement {} interface HTMLHyButtonElement extends Components.HyButton, HTMLStencilElement {}
var HTMLHyButtonElement: { var HTMLHyButtonElement: {
prototype: HTMLHyButtonElement; prototype: HTMLHyButtonElement;
...@@ -827,6 +839,7 @@ declare global { ...@@ -827,6 +839,7 @@ declare global {
'hy-baseline': HTMLHyBaselineElement; 'hy-baseline': HTMLHyBaselineElement;
'hy-box': HTMLHyBoxElement; 'hy-box': HTMLHyBoxElement;
'hy-box-container': HTMLHyBoxContainerElement; 'hy-box-container': HTMLHyBoxContainerElement;
'hy-breadcrumbs': HTMLHyBreadcrumbsElement;
'hy-button': HTMLHyButtonElement; 'hy-button': HTMLHyButtonElement;
'hy-cta-button': HTMLHyCtaButtonElement; 'hy-cta-button': HTMLHyCtaButtonElement;
'hy-cta-link': HTMLHyCtaLinkElement; 'hy-cta-link': HTMLHyCtaLinkElement;
...@@ -971,6 +984,11 @@ declare namespace LocalJSX { ...@@ -971,6 +984,11 @@ declare namespace LocalJSX {
*/ */
wrap?: boolean; wrap?: boolean;
} }
interface HyBreadcrumbs {
dataItems?: Breadcrumb[] | string;
headerstyle?: string;
variant?: BreadcrumbVariants;
}
interface HyButton { interface HyButton {
/** /**
* Aria label for the element * Aria label for the element
...@@ -1368,6 +1386,7 @@ declare namespace LocalJSX { ...@@ -1368,6 +1386,7 @@ declare namespace LocalJSX {
'hy-baseline': HyBaseline; 'hy-baseline': HyBaseline;
'hy-box': HyBox; 'hy-box': HyBox;
'hy-box-container': HyBoxContainer; 'hy-box-container': HyBoxContainer;
'hy-breadcrumbs': HyBreadcrumbs;
'hy-button': HyButton; 'hy-button': HyButton;
'hy-cta-button': HyCtaButton; 'hy-cta-button': HyCtaButton;
'hy-cta-link': HyCtaLink; 'hy-cta-link': HyCtaLink;
...@@ -1435,6 +1454,7 @@ declare module '@stencil/core' { ...@@ -1435,6 +1454,7 @@ declare module '@stencil/core' {
'hy-baseline': LocalJSX.HyBaseline & JSXBase.HTMLAttributes<HTMLHyBaselineElement>; 'hy-baseline': LocalJSX.HyBaseline & JSXBase.HTMLAttributes<HTMLHyBaselineElement>;
'hy-box': LocalJSX.HyBox & JSXBase.HTMLAttributes<HTMLHyBoxElement>; 'hy-box': LocalJSX.HyBox & JSXBase.HTMLAttributes<HTMLHyBoxElement>;
'hy-box-container': LocalJSX.HyBoxContainer & JSXBase.HTMLAttributes<HTMLHyBoxContainerElement>; 'hy-box-container': LocalJSX.HyBoxContainer & JSXBase.HTMLAttributes<HTMLHyBoxContainerElement>;
'hy-breadcrumbs': LocalJSX.HyBreadcrumbs & JSXBase.HTMLAttributes<HTMLHyBreadcrumbsElement>;
'hy-button': LocalJSX.HyButton & JSXBase.HTMLAttributes<HTMLHyButtonElement>; 'hy-button': LocalJSX.HyButton & JSXBase.HTMLAttributes<HTMLHyButtonElement>;
'hy-cta-button': LocalJSX.HyCtaButton & JSXBase.HTMLAttributes<HTMLHyCtaButtonElement>; 'hy-cta-button': LocalJSX.HyCtaButton & JSXBase.HTMLAttributes<HTMLHyCtaButtonElement>;
'hy-cta-link': LocalJSX.HyCtaLink & JSXBase.HTMLAttributes<HTMLHyCtaLinkElement>; 'hy-cta-link': LocalJSX.HyCtaLink & JSXBase.HTMLAttributes<HTMLHyCtaLinkElement>;
......
:host {
display: block;
}
// Default variant
.hy-breadcrumbs {
display: inline-block;
width: auto;
&.is-condensed {
width: 100%;
}
ol {
margin: 0;
padding: 0;
}
.breadcrumb-container {
color: var(--grayscale-dark);
display: flex;
flex-wrap: nowrap;
font-family: var(--main-font-family);
list-style-type: none;
margin: 0;
min-height: 72px;
overflow: hidden;
padding: 0;
@include breakpoint($narrow) {
min-height: 76px;
}
@include breakpoint($wide) {
min-height: 86px;
}
@include breakpoint($extrawide) {
min-height: 94px;
}
}
.breadcrumb-item {
display: flex;
flex-direction: row;
align-items: center;
flex: 0 0 auto;
a {
color: var(--brand-main-light);
display: flex;
flex-direction: row;
align-items: center;
margin-right: 20px;
position: relative;
text-decoration: none;
@include breakpoint($medium) {
margin-right: 28px;
}
@include breakpoint($wide) {
margin-right: 30px;
}
.breadcrumb-item-caret {
position: absolute;
right: -15px;
top: 50%;
transform: translateY(-50%);
@include breakpoint($medium) {
right: -18px;
}
@include breakpoint($wide) {
right: -19px;
}
&:hover {
cursor: default;
}
}
}
a.default {
@include font-size(14px, 20px);
@include breakpoint($narrow) {
@include font-size(16px, 24px);
}
}
&:focus {
outline: auto;
}
&.hidden {
display: none;
}
}
.breadcrumb-item.home {
hy-icon.default {
svg {
fill: var(--brand-main-light);
stroke: var(--brand-main-light);
}
}
}
.breadcrumb-item.main {
min-width: 0;
}
.breadcrumb-item__more {
display: none;
flex-direction: row;
align-items: center;
position: relative;
margin-right: 20px;
@include breakpoint($medium) {
margin-right: 25px;
}
@include breakpoint($wide) {
margin-right: 30px;
}
&.visible {
display: flex;
}
.breadcrumb-item-caret {
position: absolute;
right: -15px;
top: 50%;
transform: translateY(-50%);
@include breakpoint($medium) {
right: -18px;
}
&:hover {
cursor: default;
}
&__drop {
position: absolute;
right: 5.5px;
top: 50%;
transform: translateY(-50%);
}
}
}
.breadcrumb-item-dropdown-button {
display: flex;
flex-direction: row;
color: var(--brand-main-light);
cursor: pointer;
border: 1.5px solid var(--brand-main-light);
font-size: 1.5rem;
line-height: 10px;
border-radius: 3px;
background-color: var(--grayscale-white);
box-shadow: 0 0 10px 0 rgba(14, 104, 139, 0.1);
padding: 0 25px 9px 10px;
position: relative;
hy-icon {
svg {
fill: var(--brand-main-light);
margin: 0 0 -3px 10px;
transform: rotate(90deg);
}
}
}
.breadcrumb-item-dropdown-button.is-open {
background-color: var(--brand-main-light);
color: var(--grayscale-white);
svg {
fill: var(--grayscale-white);
margin: 0 0 -3px 10px;
transform: rotate(270deg);
}
}
.breadcrumb-hidden-items {
display: none;
visibility: hidden;
&__is-open {
background: var(--grayscale-white);
box-shadow: 0 0 10px 0 rgba(14, 104, 139, 0.1);
display: block;
margin-top: -9px;
padding: 32px 16px 6px 16px;
position: absolute;
visibility: visible;
z-index: 5;
@include breakpoint($narrow) {
padding: 32px 64px 6px 32px;
}
a {
margin: 0;
padding-bottom: 26px;
}
}
}
.breadcrumb-item__current {
flex: 0 2 auto;
min-width: 0;
}
.breadcrumb-item__current a {
color: var(--grayscale-dark);
font-family: var(--main-font-family);
text-decoration: none;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-height: auto;
&:hover {
cursor: default;
}
}
.intermediate {
display: flex;
text-overflow: initial;
}
.intermediate.hidden {
display: none;
visibility: hidden;
}
#more,
.more {
display: none;
visibility: hidden;
}
#more.visible,
.more.visible {
display: flex;
visibility: visible;
}
}
// Large variant. Do not show Breadcrumbs if there is a hero and a sidebar on Large/Medium screens
.hy-breadcrumbs.large.with-sidebar {
display: block;
visibility: visible;
a.large {
@include font-size(26px, 26px);
color: var(--grayscale-black);
font-weight: 700;
//@todo change home icon to be 20px x 20px and be as in the specs
.breadcrumb-item-caret {
// @todo set styles for caret near the home icon
// should be bold
// padding: 0 6px 0 8px; (mobile) && padding: 0 8px 0 10px (tablet + desktop);
}
}
.breadcrumb-container {
color: var(--grayscale-black);
display: flex;
flex-wrap: nowrap;
font-family: var(--main-font-family);
list-style-type: none;
margin: 0;
min-height: 64px;
overflow: hidden;
padding: 0;
@include breakpoint($narrow) {
min-height: 84px;
}
.breadcrumb-item.home {
svg {
fill: var(--grayscale-black);
stroke: var(--grayscale-black);
stroke-width: 30;
}
}
}
@include breakpoint($extrawide) {
display: none;
visibility: hidden;
}
}
export interface Breadcrumb {
url: string;
text: string;
}
let breadcrumbsWidth = null;
import {Component, Element, h, Listen, Prop, State, Watch} from '@stencil/core';
import {BreadcrumbVariants} from '../../utils/utils';
@Component({
tag: 'hy-breadcrumbs',
styleUrl: 'hy-breadcrumbs.scss',
shadow: false,
})
export class HyBreadcrumbs {
private _dataItems: Breadcrumb[];
@Prop() dataItems: Breadcrumb[] | string;
@Prop() variant: BreadcrumbVariants = BreadcrumbVariants.default as any;
@Prop() headerstyle: string = 'with-sidebar';
@State() menuOpen: boolean = false;
@Element() el: HTMLElement;
@Watch('dataItems')
arrayDataWatcher(newValue: Breadcrumb[] | string) {
if (typeof newValue === 'string') {
this._dataItems = JSON.parse(newValue);
} else {
this._dataItems = newValue;
}
}
componentWillLoad() {
this.arrayDataWatcher(this.dataItems);
}
componentDidLoad() {
let hyMainDiv = this.el.closest('.hy-main');
if (hyMainDiv) {
if (!hyMainDiv.classList.contains('with-sidebar')) {
this.headerstyle = 'without-sidebar';
}
}
// Set breadcumbs width + paddings.
breadcrumbsWidth = this.el.offsetWidth + 64;
if (breadcrumbsWidth >= document.body.scrollWidth) {
this.adjustBreadcrumbsMenuVisibility();
}
}
adjustBreadcrumbsMenuVisibility(showMenu = true) {
// Show ... and Hide intermediate links
if (!showMenu) {
this.closeMoreMenu();
}
const crumbContainer = document.querySelectorAll('.hy-breadcrumbs')[0];
const moreDotsItem = document.querySelectorAll('#more')[0];
const moreDotsItemWrapper = document.querySelectorAll('.breadcrumb-item__more')[0];
if (moreDotsItem) {
if (showMenu) {
crumbContainer.classList.add('is-condensed');
moreDotsItem.classList.add('visible');
moreDotsItemWrapper.classList.add('visible');
} else {
crumbContainer.classList.remove('is-condensed');
moreDotsItem.classList.remove('visible');
moreDotsItemWrapper.classList.remove('visible');
}
}
const intermediateItems = document.querySelectorAll('.intermediate');
if (intermediateItems) {
for (let i = 0; i < intermediateItems.length; i++) {
if (showMenu) {
intermediateItems[i].classList.add('hidden');
} else {
intermediateItems[i].classList.remove('hidden');
}
}
}
}
HomeItem(url) {
const homeItemClass = ['hy-icon-wrapper', this.variant].join(' ');
return (
<li class="breadcrumb-item home">
<a href={url} class={homeItemClass}>
<hy-icon icon={'hy-icon-home'} class={`${this.variant}`} size={20} />
<hy-icon icon={'hy-icon-caret-right'} class={'breadcrumb-item-caret'} size={10} />
</a>
</li>
);
}
BreadcrumbItem(label, url, className = '', withCaret = true) {
const breadcrumbClass = ['breadcrumb-item', className].join(' ');
const caretClass = ['breadcrumb-item-caret', this.variant].join(' ');
if (url) {
if (withCaret) {
return (
<li class={breadcrumbClass}>
<a href={url} class={`${this.variant}`}>
{label}
<hy-icon icon={'hy-icon-caret-right'} class={caretClass} size={10} />
</a>
</li>
);
} else {
return (
<li class={breadcrumbClass}>
<a href={url} class={`${this.variant}`}>
{label}
</a>
</li>
);
}
} else {
return (
<li class={`${breadcrumbClass} breadcrumb-item__current`}>
<a aria-current="page" href={url} class={`${this.variant}`}>
{label}
</a>
</li>
);
}
}
BreadcrumbTextItem(label, className = '') {
const breadcrumbClass = ['breadcrumb-item', className].join(' ');
return <li class={breadcrumbClass}>{label}</li>;
}
DropdownMenuItem() {
return (
<li class="breadcrumb-item__more">
<button
type="button"
aria-hidden="true"
aria-expanded="false"
id="more"
key="more"
class="breadcrumb-item-dropdown-button"
>
...
<hy-icon
icon={'hy-icon-caret-right'}
class={'breadcrumb-item-caret__drop breadcrumb-item__more__icon'}
size={10}
/>
</button>
<hy-icon icon={'hy-icon-caret-right'} class={'breadcrumb-item-caret'} size={10} />
</li>
);
}
adjustHiddenMenuWidth() {
// set width to the menu area equal to the widest link + paddings
const moreMenu = document.querySelectorAll('.breadcrumb-hidden-items')[0];
if (moreMenu) {
if (document.body.scrollWidth < 480) {
(moreMenu as HTMLElement).style.width = '100%';
} else {
//maxIntermediateLinkWidth
var maxIntermediateLinkWidth = 0;
const moreMenuLinks = document.querySelectorAll('.breadcrumb-hidden-items .breadcrumb-item a');
if (moreMenuLinks) {
for (let i = 0; i < moreMenuLinks.length; i++) {
if (maxIntermediateLinkWidth < (moreMenuLinks[i] as HTMLElement).offsetWidth) {
maxIntermediateLinkWidth = (moreMenuLinks[i] as HTMLElement).offsetWidth;
}
}
maxIntermediateLinkWidth = maxIntermediateLinkWidth + 32 + 64;
}
(moreMenu as HTMLElement).style.width = maxIntermediateLinkWidth.toString().concat('px');
}
}
}
closeMoreMenu() {
const moreMenu = document.querySelectorAll('.breadcrumb-hidden-items')[0];
if (moreMenu) {
moreMenu.classList.remove('breadcrumb-hidden-items__is-open');
this.menuOpen = false;
}
const moreBreadcrumb = document.querySelectorAll('#more')[0];
if (moreBreadcrumb) {
moreBreadcrumb.classList.remove('is-open');
}
}
// When a ... is clicked, show/hide the Menu with hidden breadcrumbs
@Listen('click')
clickEventListener(event) {
if (!event) return;
const target = event.target;
const moreMenu = document.querySelectorAll('.breadcrumb-hidden-items')[0];
const moreButton = document.querySelectorAll('.breadcrumb-item-dropdown-button')[0];
// Trigger if target is button or svg icon
// TODO: Make this if prettier
if (
target &&
(target.id === 'more' ||
((target.tagName == 'svg' || 'path') &&
target.closest('hy-icon').classList.contains('breadcrumb-item__more__icon')))
) {
//@todo Show the menu on the right place of the screen
if (moreMenu) {
if (this.menuOpen) {
moreMenu.classList.remove('breadcrumb-hidden-items__is-open');
moreButton.classList.remove('is-open');
moreButton.setAttribute('aria-expanded', 'false');
} else {
moreMenu.classList.add('breadcrumb-hidden-items__is-open');
moreButton.classList.add('is-open');
moreButton.setAttribute('aria-expanded', 'true');
if (document.body.scrollWidth < 480) {
(moreMenu as HTMLElement).style.left = '16px';
} else {
var rect = (moreButton as HTMLElement).getBoundingClientRect();
(moreMenu as HTMLElement).style.left = (rect.left - 64).toString().concat('px');
this.adjustHiddenMenuWidth();
}
}
this.menuOpen = !this.menuOpen;
}
} else {
this.closeMoreMenu();
}
event.stopPropagation();
event.stopImmediatePropagation();
}
@Listen('resize', {target: 'window'})
resizeEventListener(event) {
if (!event) return;
const breadcrumbsElement = document.querySelectorAll('.hy-breadcrumbs')[0];
if (breadcrumbsElement) {
if (breadcrumbsWidth + 64 >= document.body.scrollWidth) {
this.adjustBreadcrumbsMenuVisibility(true);
} else {
this.adjustBreadcrumbsMenuVisibility(false);
}
}
}
render() {
//@todo Accesibility
const TOTAL_ITEMS = this._dataItems.length;
const MAX_ITEMS_TO_SHOW = 3;
let isMenuNeeded = TOTAL_ITEMS > MAX_ITEMS_TO_SHOW;
let itemsBreadcrumbs = [];
let itemsToShowInMenu = [];
if (this.variant == BreadcrumbVariants.landingLarge) {
// Landing pages, Large variant
this._dataItems.map((x, index) => {
if (index < 2) {
if (index == 0) {
itemsBreadcrumbs.push(this.HomeItem(x.url));
} else {
//itemsBreadcrumbs.push(this.BreadcrumbTextItem(x.text, 'main'));
itemsBreadcrumbs.push(this.BreadcrumbItem(x.text, '', 'main'));
}
}
});
} else {
// Landing and Content pages, Standard variant
this._dataItems.map((x, index) => {
let breadcrumbEl = this.BreadcrumbItem(x.text, x.url, '', false);
if (isMenuNeeded && index > 1 && index < TOTAL_ITEMS - 1) {
itemsToShowInMenu.push(<div>{breadcrumbEl}</div>);
if (index === 2) {
itemsBreadcrumbs.push(this.DropdownMenuItem());
}
itemsBreadcrumbs.push(this.BreadcrumbItem(x.text, x.url, 'intermediate'));
return;
} else {
if (index == 0) {
itemsBreadcrumbs.push(this.HomeItem(x.url));
} else {
itemsBreadcrumbs.push(this.BreadcrumbItem(x.text, x.url, 'main'));
}
}
});
}
const breadcrumbsClass = ['hy-breadcrumbs', this.variant, this.headerstyle].join(' ');
return (
<nav aria-label="Breadcrumb" role="navigation" aria-labelledby="system-breadcrumb" class={breadcrumbsClass}>
<ol class="breadcrumb-container">{itemsBreadcrumbs}</ol>
{itemsToShowInMenu && <ol class="breadcrumb-hidden-items">{itemsToShowInMenu}</ol>}
</nav>
);
}
}
# hy-breadcrumbs
<!-- Auto Generated Below -->
## Properties
| Property | Attribute | Description | Type | Default |
| ------------- | ------------- | ----------- | --------------------------------------------------------------- | ----------------------------------- |
| `dataItems` | `data-items` | | `Breadcrumb[] \| string` | `undefined` |
| `headerstyle` | `headerstyle` | | `string` | `'with-sidebar'` |
| `variant` | `variant` | | `BreadcrumbVariants.default \| BreadcrumbVariants.landingLarge` | `BreadcrumbVariants.default as any` |
## Dependencies
### Depends on
- [hy-icon](../icon)
### Graph
```mermaid
graph TD;
hy-breadcrumbs --> hy-icon
style hy-breadcrumbs fill:#f9f,stroke:#333,stroke-width:4px
```
---
Helsinki University Design System
...@@ -2,11 +2,11 @@ import {h} from '@stencil/core'; ...@@ -2,11 +2,11 @@ import {h} from '@stencil/core';
function SvgHome(props) { function SvgHome(props) {
return ( return (
<svg viewBox="0 0 1000 1000" {...props}> <svg viewBox="0 0 1000 1000" {...props} stroke="black" stroke-width="1">
<path <path
d="M345.3,998.7c-30.3,0-55.4-25.2-55.4-55.6c0-30.4,25.1-55.6,55.4-55.6h479.9l0-509.9L500,114.2L174.8,377.6 d="M345.3,998.7c-30.3,0-55.4-25.2-55.4-55.6c0-30.4,25.1-55.6,55.4-55.6h479.9l0-509.9L500,114.2L174.8,377.6
v565.5c0,30.4-25.1,55.6-55.4,55.6c-30.3,0-55.4-25.2-55.4-55.6l0-567.6c0-31.5,14.6-61.9,38.7-81.9L434.1,25 v565.5c0,30.4-25.1,55.6-55.4,55.6c-30.3,0-55.4-25.2-55.4-55.6l0-567.6c0-31.5,14.6-61.9,38.7-81.9L434.1,25
c37.7-30.4,93-30.4,130.7,0l332.5,268.6c25.1,19.9,38.7,49.3,38.7,81.9v568.7c0,29.4-25.1,54.6-55.4,54.6L345.3,998.7z" c37.7-30.4,93-30.4,130.7,0l332.5,268.6c25.1,19.9,38.7,49.3,38.7,81.9v568.7c0,29.4-25.1,54.6-55.4,54.6L345.3,998.7z"
/> />
</svg> </svg>
); );
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
### Used by ### Used by
- [hy-accordion-item](../accordion-item) - [hy-accordion-item](../accordion-item)
- [hy-breadcrumbs](../hy-breadcrumbs)
- [hy-button](../button) - [hy-button](../button)
- [hy-cta-button](../cta-button) - [hy-cta-button](../cta-button)
- [hy-cta-link](../cta-link) - [hy-cta-link](../cta-link)
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
```mermaid ```mermaid
graph TD; graph TD;
hy-accordion-item --> hy-icon hy-accordion-item --> hy-icon
hy-breadcrumbs --> hy-icon
hy-button --> hy-icon hy-button --> hy-icon
hy-cta-button --> hy-icon hy-cta-button --> hy-icon
hy-cta-link --> hy-icon hy-cta-link --> hy-icon
......
...@@ -12,6 +12,11 @@ export type IconName = { ...@@ -12,6 +12,11 @@ export type IconName = {
[key: string]: (props: any) => FunctionalComponent; [key: string]: (props: any) => FunctionalComponent;
}; };
export enum BreadcrumbVariants {
default = 'default',
landingLarge = 'large',
}
export enum HeadingVarians { export enum HeadingVarians {
default = 'h1', default = 'h1',
h2 = 'h2', h2 = 'h2',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment