diff --git a/scss/bitstyles.scss b/scss/bitstyles.scss index eacf48bcb..2fcc62fed 100644 --- a/scss/bitstyles.scss +++ b/scss/bitstyles.scss @@ -15,6 +15,7 @@ @forward 'bitstyles/generic/'; @forward 'bitstyles/base/'; @forward 'bitstyles/atoms/'; +@forward 'bitstyles/molecules/'; @forward 'bitstyles/organisms/'; // diff --git a/scss/bitstyles/atoms/dropdown/Dropdown.js b/scss/bitstyles/atoms/dropdown/Dropdown.js index 5be985a5c..aa0a8bd97 100644 --- a/scss/bitstyles/atoms/dropdown/Dropdown.js +++ b/scss/bitstyles/atoms/dropdown/Dropdown.js @@ -11,7 +11,7 @@ export default ({ alignment = [], children }) => { }); wrapper.appendChild(button); const dropdown = document.createElement('div'); - dropdown.innerHTML = children || 'Dropdown'; + dropdown.appendChild(children); dropdown.classList.add('a-dropdown', 'u-overflow-y-auto'); alignment.forEach((variant) => { dropdown.classList.add(`a-dropdown--${variant}`); diff --git a/scss/bitstyles/design-tokens/_typography.scss b/scss/bitstyles/design-tokens/_typography.scss index 5ef441058..c3f47f104 100644 --- a/scss/bitstyles/design-tokens/_typography.scss +++ b/scss/bitstyles/design-tokens/_typography.scss @@ -1,5 +1,6 @@ @use '../tools/custom-property'; @use 'sass:list'; +@use 'sass:map'; // // Font-weights ///////////////////////////////////////// @@ -26,37 +27,37 @@ $webfont-variants: ( 'normal': ( 'font-family': $webfont-family-name, 'font-style': normal, - 'font-weight': var(custom-property.name('font-weight', 'normal')), + 'font-weight': map.get($font-weights, 'normal'), 'filename': 'poppins-v20-latin-400', ), 'italic': ( 'font-family': $webfont-family-name, 'font-style': italic, - 'font-weight': var(custom-property.name('font-weight', 'normal')), + 'font-weight': map.get($font-weights, 'normal'), 'filename': 'poppins-v20-latin-400italic', ), 'medium': ( 'font-family': $webfont-family-name, 'font-style': normal, - 'font-weight': var(custom-property.name('font-weight', 'medium')), + 'font-weight': map.get($font-weights, 'medium'), 'filename': 'poppins-v20-latin-500', ), 'medium-italic': ( 'font-family': $webfont-family-name, 'font-style': italic, - 'font-weight': var(custom-property.name('font-weight', 'medium')), + 'font-weight': map.get($font-weights, 'medium'), 'filename': 'poppins-v20-latin-500italic', ), 'semibold': ( 'font-family': $webfont-family-name, 'font-style': normal, - 'font-weight': var(custom-property.name('font-weight', 'semibold')), + 'font-weight': map.get($font-weights, 'semibold'), 'filename': 'poppins-v20-latin-600', ), 'semibold-italic': ( 'font-family': $webfont-family-name, 'font-style': italic, - 'font-weight': var(custom-property.name('font-weight', 'semibold')), + 'font-weight': map.get($font-weights, 'semibold'), 'filename': 'poppins-v20-latin-600italic', ), ) !default; diff --git a/scss/bitstyles/molecules/_index.scss b/scss/bitstyles/molecules/_index.scss new file mode 100644 index 000000000..2b46b38a9 --- /dev/null +++ b/scss/bitstyles/molecules/_index.scss @@ -0,0 +1 @@ +@forward './notification' as notification-*; diff --git a/scss/bitstyles/molecules/notification/Notification.js b/scss/bitstyles/molecules/notification/Notification.js new file mode 100644 index 000000000..38daab263 --- /dev/null +++ b/scss/bitstyles/molecules/notification/Notification.js @@ -0,0 +1,46 @@ +import icons from '../../../../assets/images/icons.svg'; +import Button from '../../atoms/button/Button'; + +const CloseButton = () => { + return Button({ + colorVariant: ['secondary'], + children: `Remove notification`, + classname: ['m-notification__button'], + }); +}; + +export default ({ title, subtitle, theme = 'default' }) => { + const notification = document.createElement('article'); + const iconWrapperStart = document.createElement('div'); + const contentWrapper = document.createElement('div'); + const heading = document.createElement('h2'); + const subtitleElement = document.createElement('p'); + + notification.classList.add('m-notification'); + notification.setAttribute('data-theme', theme); + + iconWrapperStart.classList.add('m-notification__highlight'); + iconWrapperStart.innerHTML = ` + + `; + + contentWrapper.classList.add('m-notification__content'); + + heading.classList.add('u-h4', 'u-margin-s6-bottom'); + heading.textContent = title; + + subtitleElement.classList.add('u-margin-0', 'u-font-light'); + subtitleElement.textContent = subtitle; + + notification.appendChild(iconWrapperStart); + contentWrapper.appendChild(heading); + contentWrapper.appendChild(subtitleElement); + notification.appendChild(contentWrapper); + notification.appendChild(CloseButton()); + + return notification; +}; diff --git a/scss/bitstyles/molecules/notification/Notification.stories.js b/scss/bitstyles/molecules/notification/Notification.stories.js new file mode 100644 index 000000000..e255ffa5a --- /dev/null +++ b/scss/bitstyles/molecules/notification/Notification.stories.js @@ -0,0 +1,20 @@ +import Notification from './Notification'; + +export default { + title: 'Molecules/Notification', + component: Notification, + argTypes: {}, +}; + +const Template = (args) => Notification(args); + +export const Base = Template.bind({}); +Base.args = { + title: 'Password update request sent', + subtitle: + 'We sent an email to asdf@example.com. Please click the link inside to confirm your password change', + theme: 'positive', +}; +Base.parameters = { + zeplinLink: 'https://zpl.io/WQKegrn', +}; diff --git a/scss/bitstyles/molecules/notification/_index.scss b/scss/bitstyles/molecules/notification/_index.scss new file mode 100644 index 000000000..768bfd0df --- /dev/null +++ b/scss/bitstyles/molecules/notification/_index.scss @@ -0,0 +1,73 @@ +@forward "./settings"; +@use "./settings"; +@use '../../tools/classname'; +@use '../../tools/design-token'; +@use '../../tools/themes'; +@use 'sass:map'; + +/* prettier-ignore */ +$highlight-color-property: design-token.get('notification', 'highlight-color'); +$highlight-background-color-property: design-token.get('notification', 'highlight-background-color'); +$button-border-top-right-radius-property: design-token.get( + 'button', + 'border', + 'top', + 'right', + 'radius' +); +$button-border-bottom-right-radius-property: design-token.get( + 'button', + 'border', + 'bottom', + 'right', + 'radius' +); +$button-border-bottom-left-radius-property: design-token.get( + 'button', + 'border', + 'bottom', + 'left', + 'radius' +); +$button-border-top-left-radius-property: design-token.get( + 'button', + 'border', + 'top', + 'left', + 'radius' +); + +#{classname.get($classname-items: 'notification', $layer: 'molecule')} { + display: flex; + background-color: var(design-token.get("color", "grayscale", "white")); + color: var(design-token.get("color", "grayscale", "dark-3")); +} + +#{classname.get($classname-items: 'notification__button', $layer: 'molecule')} { + #{$button-border-top-right-radius-property}: 0; + #{$button-border-bottom-right-radius-property}: 0; + #{$button-border-bottom-left-radius-property}: 0; + #{$button-border-top-left-radius-property}: 0; +} + +#{classname.get($classname-items: 'notification__highlight', $layer: 'molecule')} { + flex-shrink: 0; + display: flex; + align-items: center; + padding: 0 var(design-token.get("size", "s1")); + color: var($highlight-color-property, var(design-token.get("color", "brand-1", "dark-1"))); + background-color: var($highlight-background-color-property, var(design-token.get("color", "brand-1", "light-4"))); +} + +#{classname.get($classname-items: 'notification__content', $layer: 'molecule')} { + flex: 1; + min-width: 0; + padding: var(design-token.get("size", "l2")) 0 var(design-token.get("size", "l2")) var(design-token.get("size", "l2")); +} + +@each $theme-name, $theme in settings.$theme-variants { + @include themes.get($theme-name) { + #{$highlight-color-property}: map.get($theme, 'highlight-color'); + #{$highlight-background-color-property}: map.get($theme, 'highlight-background-color'); + } +} diff --git a/scss/bitstyles/molecules/notification/_settings.scss b/scss/bitstyles/molecules/notification/_settings.scss new file mode 100644 index 000000000..856228593 --- /dev/null +++ b/scss/bitstyles/molecules/notification/_settings.scss @@ -0,0 +1,28 @@ +@use '../../tools/design-token'; + +$theme-variants: ( + 'default': ( + 'highlight-background-color': var(design-token.get('color', 'grayscale', 'light-4')), + 'highlight-color': var(design-token.get('color', 'grayscale', 'dark-3')), + ), + 'brand-1': ( + 'highlight-background-color': var(design-token.get('color', 'brand-1', 'light-4')), + 'highlight-color': var(design-token.get('color', 'brand-1', 'dark-1')), + ), + 'brand-2': ( + 'highlight-background-color': var(design-token.get('color', 'brand-2', 'light-4')), + 'highlight-color': var(design-token.get('color', 'brand-2', 'dark-1')), + ), + 'positive': ( + 'highlight-background-color': var(design-token.get('color', 'positive', 'light-4')), + 'highlight-color': var(design-token.get('color', 'positive', 'dark-1')), + ), + 'warning': ( + 'highlight-background-color': var(design-token.get('color', 'warning', 'light-4')), + 'highlight-color': var(design-token.get('color', 'warning', 'dark-1')), + ), + 'danger': ( + 'highlight-background-color': var(design-token.get('color', 'danger', 'light-4')), + 'highlight-color': var(design-token.get('color', 'danger', 'dark-1')), + ), +) !default; diff --git a/scss/bitstyles/molecules/notification/notification.stories.mdx b/scss/bitstyles/molecules/notification/notification.stories.mdx new file mode 100644 index 000000000..b3644c7d5 --- /dev/null +++ b/scss/bitstyles/molecules/notification/notification.stories.mdx @@ -0,0 +1,14 @@ +import { Canvas, Meta, Story } from '@storybook/addon-docs'; +import Notification from './Notification'; + + + +# Notification + +A collection of interactive elements that are closely-related can be visually bound together. + +Commonly, this layout is used for buttons. + + diff --git a/scss/bitstyles/organisms/notification-center/NotificationCenter.js b/scss/bitstyles/organisms/notification-center/NotificationCenter.js new file mode 100644 index 000000000..d2cb0d92c --- /dev/null +++ b/scss/bitstyles/organisms/notification-center/NotificationCenter.js @@ -0,0 +1,27 @@ +import Dropdown from '../../atoms/dropdown/Dropdown'; + +export default ({ children = [], isGlobal = true }) => { + const notificationCenter = document.createElement('ul'); + + if (isGlobal) { + notificationCenter.setAttribute('aria-live', 'polite'); + notificationCenter.classList.add( + 'o-notification-center', + 'a-content', + 'a-content--s' + ); + } + + children.forEach((child) => { + const listItem = document.createElement('li'); + listItem.classList.add('o-notification-center__item'); + listItem.appendChild(child); + notificationCenter.appendChild(listItem); + }); + + if (isGlobal) { + return notificationCenter; + } + + return Dropdown({ children: notificationCenter, alignment: ['right'] }); +}; diff --git a/scss/bitstyles/organisms/notification-center/NotificationCenter.stories.js b/scss/bitstyles/organisms/notification-center/NotificationCenter.stories.js new file mode 100644 index 000000000..6f3fb4cf7 --- /dev/null +++ b/scss/bitstyles/organisms/notification-center/NotificationCenter.stories.js @@ -0,0 +1,68 @@ +import Notification from '../../molecules/notification/Notification'; +import NotificationCenter from './NotificationCenter'; + +export default { + title: 'Organisms/Notification center', + component: NotificationCenter, + argTypes: {}, +}; + +const Template = (args) => NotificationCenter(args); + +export const Base = Template.bind({}); +const baseDecorator = (story) => { + const decorator = document.createElement('div'); + decorator.style.height = '20rem'; + decorator.appendChild(story()); + return decorator; +}; + +const notifications = [ + Notification({ + title: 'Password update request sent', + subtitle: + 'We sent an email to asdf@example.com. Please click the link inside to confirm your password change', + theme: 'positive', + }), + Notification({ + title: 'Well Done!', + subtitle: 'You did something good', + theme: 'brand-1', + }), + Notification({ + title: 'Oops! That wasn’t good', + subtitle: 'Maybe that was a mistake?', + theme: 'danger', + }), +]; + +Base.args = { + children: notifications, +}; +Base.decorators = [baseDecorator]; +Base.parameters = { + zeplinLink: 'https://zpl.io/WQKegrn', +}; + +// export const InDropdown = Template.bind({}); +// const dropdownDecorator = (story) => { +// const decorator = document.createElement('div'); +// decorator.style.height = '30rem'; +// const children = `