├── .prettierignore ├── docs ├── img │ ├── figma-file.png │ ├── copy-figma-id.png │ ├── create-config.png │ ├── duplicate-file.png │ ├── figma-file-tiny.png │ └── get-access-token.png ├── RESOURCES.md └── STYLEDICTIONARY.md ├── figma.config.template.json ├── bin └── figma-tokens ├── .storybook ├── manager.js ├── main.js ├── theme.js ├── preview.js └── preview-head.html ├── .gitignore ├── figma.config.json ├── tokens ├── android │ ├── font_dimens.xml │ └── colors.xml ├── json │ ├── radius.json │ ├── shadow.json │ ├── breakpoint.json │ ├── spacing.json │ ├── color.json │ └── typography.json ├── ios │ ├── TokensSpacing.h │ ├── TokensSpacing.m │ ├── TokensColor.h │ └── TokensColor.m ├── ios-swift │ ├── TokensSpacing.swift │ ├── TokensColor.swift │ └── Tokens.swift ├── scss │ └── _variables.scss ├── json-flat │ └── variables.json ├── css │ └── variables.css └── js │ └── tokens.js ├── src ├── styles │ ├── theme │ │ ├── shadows.js │ │ ├── radius.js │ │ ├── spacing.js │ │ ├── index.js │ │ ├── colors.js │ │ ├── layout.js │ │ └── typography.js │ └── GlobalStyle │ │ └── index.js ├── index.js ├── decorators │ ├── SBContainer │ │ └── index.js │ └── ThemeWrapper │ │ └── index.js ├── components │ ├── molecules │ │ └── Card │ │ │ ├── Card.styles.js │ │ │ ├── index.js │ │ │ ├── __tests__ │ │ │ ├── Card.test.js │ │ │ └── __snapshots__ │ │ │ │ └── Card.test.js.snap │ │ │ └── __stories__ │ │ │ └── Card.stories.mdx │ ├── pages │ │ └── ZapatillasFromMars │ │ │ ├── __stories__ │ │ │ └── ZapatillasFromMars.stories.mdx │ │ │ ├── ZapatillasFromMars.styles.js │ │ │ └── index.js │ └── atoms │ │ ├── Button │ │ ├── index.js │ │ ├── __stories__ │ │ │ └── Button.stories.mdx │ │ ├── __tests__ │ │ │ ├── Button.test.js │ │ │ └── __snapshots__ │ │ │ │ └── Button.test.js.snap │ │ └── Button.styles.js │ │ └── Heading │ │ ├── index.js │ │ ├── Heading.styles.js │ │ ├── __tests__ │ │ ├── Heading.test.js │ │ └── __snapshots__ │ │ │ └── Heading.test.js.snap │ │ └── __stories__ │ │ └── Heading.stories.mdx ├── docs │ ├── designTokens │ │ ├── radius │ │ │ ├── radius.stories.mdx │ │ │ └── index.js │ │ ├── spacing │ │ │ ├── spacing.stories.mdx │ │ │ └── index.js │ │ ├── breakpoints │ │ │ ├── breakpoints.stories.mdx │ │ │ └── index.js │ │ ├── typography │ │ │ ├── typography.stories.mdx │ │ │ └── index.js │ │ ├── shadows │ │ │ ├── shadows.stories.mdx │ │ │ └── index.js │ │ └── colors │ │ │ ├── colors.stories.mdx │ │ │ └── index.js │ └── intro.stories.mdx └── figma-tokens │ ├── types │ ├── getSpacing.js │ ├── getRadius.js │ ├── getBreakpoints.js │ ├── getShadows.js │ ├── getColors.js │ └── getTypography.js │ ├── cli.js │ ├── utils.js │ └── gen.js ├── package.json ├── config.json └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | tokens/ -------------------------------------------------------------------------------- /docs/img/figma-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klaufel/pattern-library-skeleton/HEAD/docs/img/figma-file.png -------------------------------------------------------------------------------- /figma.config.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "FIGMA_APIKEY": "YOUR FIGMA API KEY", 3 | "FIGMA_ID": "YOUR FIGMA ID" 4 | } 5 | -------------------------------------------------------------------------------- /docs/img/copy-figma-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klaufel/pattern-library-skeleton/HEAD/docs/img/copy-figma-id.png -------------------------------------------------------------------------------- /docs/img/create-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klaufel/pattern-library-skeleton/HEAD/docs/img/create-config.png -------------------------------------------------------------------------------- /docs/img/duplicate-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klaufel/pattern-library-skeleton/HEAD/docs/img/duplicate-file.png -------------------------------------------------------------------------------- /bin/figma-tokens: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require = require('esm')(module) 4 | require('../src/figma-tokens/cli').cli() 5 | -------------------------------------------------------------------------------- /docs/img/figma-file-tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klaufel/pattern-library-skeleton/HEAD/docs/img/figma-file-tiny.png -------------------------------------------------------------------------------- /docs/img/get-access-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klaufel/pattern-library-skeleton/HEAD/docs/img/get-access-token.png -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import {addons} from '@storybook/addons' 2 | import theme from './theme' 3 | 4 | addons.setConfig({ 5 | theme: theme 6 | }) 7 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../src/**/*.stories.(js|mdx)'], 3 | addons: ['@storybook/addon-docs', '@storybook/addon-knobs/register'] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public/ 3 | dist/ 4 | storybook/ 5 | npm-debug.log 6 | .idea/ 7 | .vscode/ 8 | .env 9 | .env.test 10 | .tern-port 11 | .DS_Store 12 | .npmrc -------------------------------------------------------------------------------- /figma.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "FIGMA_APIKEY": "36994-b8de2bc7-3189-4089-9a16-9494c87b93b8", 3 | "FIGMA_ID": "IGr2xoqcZX91CU7CDr4ZsI", 4 | "FIGMA_ID_👟🚀": "wfqn57L89K7TBoElc5I1vr" 5 | } 6 | -------------------------------------------------------------------------------- /tokens/android/font_dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tokens/json/radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "radius": { 3 | "sm": { 4 | "value": "8px" 5 | }, 6 | "md": { 7 | "value": "16px" 8 | }, 9 | "rounded": { 10 | "value": "100px" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/styles/theme/shadows.js: -------------------------------------------------------------------------------- 1 | import tokens from '../../../tokens/json/shadow' 2 | 3 | const shadows = { 4 | sm: tokens.shadow.sm.value, 5 | md: tokens.shadow.md.value, 6 | lg: tokens.shadow.lg.value 7 | } 8 | 9 | export default shadows 10 | -------------------------------------------------------------------------------- /src/styles/theme/radius.js: -------------------------------------------------------------------------------- 1 | import tokens from '../../../tokens/json/radius' 2 | 3 | const radius = { 4 | sm: tokens.radius.sm.value, 5 | md: tokens.radius.md.value, 6 | rounded: tokens.radius.rounded.value 7 | } 8 | 9 | export default radius 10 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import {create} from '@storybook/theming/create' 2 | 3 | const theme = create({ 4 | base: 'light', 5 | brandTitle: '#zapatillasFromMars👟🚀', 6 | brandUrl: 'https://github.com/klaufel/pattern-library-skeleton' 7 | }) 8 | 9 | export default theme 10 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // Atoms 2 | import Button from './components/atoms/Button' 3 | import Heading from './components/atoms/Heading' 4 | 5 | // Molecules 6 | import Card from './components/molecules/Card' 7 | 8 | export default { 9 | Button, 10 | Heading, 11 | Card 12 | } 13 | -------------------------------------------------------------------------------- /src/decorators/SBContainer/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | 4 | const Container = styled.div` 5 | padding: 16px; 6 | ` 7 | 8 | const SBContainer = storyFn => {storyFn()} 9 | 10 | export default SBContainer 11 | -------------------------------------------------------------------------------- /tokens/json/shadow.json: -------------------------------------------------------------------------------- 1 | { 2 | "shadow": { 3 | "sm": { 4 | "value": "0px 4px 8px rgba(0, 0, 0, 0.25)" 5 | }, 6 | "md": { 7 | "value": "0px 4px 16px rgba(0, 0, 0, 0.25)" 8 | }, 9 | "lg": { 10 | "value": "0px 4px 24px rgba(0, 0, 0, 0.25)" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/components/molecules/Card/Card.styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export const Wrapper = styled.div` 4 | max-width: 640px; 5 | margin: 80px auto; 6 | padding: ${props => props.theme.spacing.md}; 7 | border-radius: ${props => props.theme.radius.sm}; 8 | box-shadow: ${props => props.theme.shadows.sm}; 9 | ` 10 | -------------------------------------------------------------------------------- /tokens/json/breakpoint.json: -------------------------------------------------------------------------------- 1 | { 2 | "breakpoint": { 3 | "xl": { 4 | "value": "1460px" 5 | }, 6 | "lg": { 7 | "value": "1200px" 8 | }, 9 | "md": { 10 | "value": "992px" 11 | }, 12 | "sm": { 13 | "value": "768px" 14 | }, 15 | "xs": { 16 | "value": "576px" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/styles/theme/spacing.js: -------------------------------------------------------------------------------- 1 | import tokens from '../../../tokens/json/spacing' 2 | 3 | const spacing = { 4 | xxs: tokens.spacing.xxs.value, 5 | xs: tokens.spacing.xs.value, 6 | sm: tokens.spacing.sm.value, 7 | md: tokens.spacing.md.value, 8 | lg: tokens.spacing.lg.value, 9 | xl: tokens.spacing.xl.value, 10 | xxl: tokens.spacing.xxl.value 11 | } 12 | 13 | export default spacing 14 | -------------------------------------------------------------------------------- /src/styles/theme/index.js: -------------------------------------------------------------------------------- 1 | import colors from './colors' 2 | import typography from './typography' 3 | import spacing from './spacing' 4 | import layout from './layout' 5 | import shadows from './shadows' 6 | import radius from './radius' 7 | 8 | const theme = { 9 | colors, 10 | typography, 11 | spacing, 12 | layout, 13 | shadows, 14 | radius 15 | } 16 | 17 | export default theme 18 | -------------------------------------------------------------------------------- /src/docs/designTokens/radius/radius.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Preview} from '@storybook/addon-docs/blocks' 2 | import radius from '../../../styles/theme/radius' 3 | import Radius from '.' 4 | 5 | 6 | 7 | # 🌀 Radius 8 | 9 | `Radius` foundations. 10 | 11 | ### Radius 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/decorators/ThemeWrapper/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {ThemeProvider} from 'styled-components' 3 | import theme from '../../styles/theme' 4 | import GlobalStyle from '../../styles/GlobalStyle' 5 | 6 | const ThemeWrapper = storyFn => ( 7 | 8 | <> 9 | 10 | {storyFn()} 11 | 12 | 13 | ) 14 | 15 | export default ThemeWrapper 16 | -------------------------------------------------------------------------------- /src/docs/designTokens/spacing/spacing.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Preview} from '@storybook/addon-docs/blocks' 2 | import spacing from '../../../styles/theme/spacing' 3 | import Spacing from '.' 4 | 5 | 6 | 7 | # 📐 Spacing 8 | 9 | `Spacing` foundations. 10 | 11 | ### 8-Point Grid System 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tokens/json/spacing.json: -------------------------------------------------------------------------------- 1 | { 2 | "spacing": { 3 | "xxl": { 4 | "value": "48px" 5 | }, 6 | "xl": { 7 | "value": "40px" 8 | }, 9 | "lg": { 10 | "value": "32px" 11 | }, 12 | "md": { 13 | "value": "24px" 14 | }, 15 | "sm": { 16 | "value": "16px" 17 | }, 18 | "xs": { 19 | "value": "8px" 20 | }, 21 | "xxs": { 22 | "value": "4px" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import {addParameters, addDecorator} from '@storybook/react' 2 | import {withKnobs} from '@storybook/addon-knobs' 3 | import ThemeWrapper from '../src/decorators/ThemeWrapper' 4 | import SBContainer from '../src/decorators/SBContainer' 5 | 6 | addParameters({ 7 | options: { 8 | showRoots: true 9 | } 10 | }) 11 | 12 | addDecorator(ThemeWrapper) 13 | 14 | addDecorator(SBContainer) 15 | 16 | addDecorator(withKnobs) 17 | -------------------------------------------------------------------------------- /tokens/ios/TokensSpacing.h: -------------------------------------------------------------------------------- 1 | 2 | // TokensSpacing.h 3 | // 4 | // Do not edit directly 5 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 6 | // 7 | 8 | #import 9 | 10 | 11 | 12 | extern float const SpacingXxl; 13 | extern float const SpacingXl; 14 | extern float const SpacingLg; 15 | extern float const SpacingMd; 16 | extern float const SpacingSm; 17 | extern float const SpacingXs; 18 | extern float const SpacingXxs; 19 | -------------------------------------------------------------------------------- /tokens/ios/TokensSpacing.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // TokensSpacing.m 4 | // 5 | // Do not edit directly 6 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 7 | // 8 | 9 | #import "TokensSpacing.h" 10 | 11 | 12 | 13 | float const SpacingXxl = 48px; 14 | float const SpacingXl = 40px; 15 | float const SpacingLg = 32px; 16 | float const SpacingMd = 24px; 17 | float const SpacingSm = 16px; 18 | float const SpacingXs = 8px; 19 | float const SpacingXxs = 4px; 20 | -------------------------------------------------------------------------------- /src/docs/designTokens/breakpoints/breakpoints.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Preview} from '@storybook/addon-docs/blocks' 2 | import layout from '../../../styles/theme/layout' 3 | import Breakpoints from '.' 4 | 5 | 6 | 7 | # 🍪 Breakpoints 8 | 9 | `Breakpoints` foundations. 10 | 11 | ### Breakpoints 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tokens/ios-swift/TokensSpacing.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // TokensSpacing.swift 4 | // 5 | // Do not edit directly 6 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 7 | // 8 | 9 | import UIKit 10 | 11 | public enum TokensSpacing { 12 | public static let lg = 32px 13 | public static let md = 24px 14 | public static let sm = 16px 15 | public static let xl = 40px 16 | public static let xs = 8px 17 | public static let xxl = 48px 18 | public static let xxs = 4px 19 | } 20 | -------------------------------------------------------------------------------- /docs/RESOURCES.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 👋 Welcome to Pattern Library Skeleton! 4 |
5 |

6 | 7 |

A awesome design system for your products and experiences!

8 | 9 | # Resources: 10 | 11 | https://designsystemchecklist.com/category/design-tokens/ 12 | 13 | https://github.com/sturobson/Awesome-Design-Tokens 14 | 15 | A designer’s guide to the Figma API 16 | https://medium.com/@danhollick/a-designers-guide-to-the-figma-api-64f2755969d5 17 | -------------------------------------------------------------------------------- /src/components/pages/ZapatillasFromMars/__stories__/ZapatillasFromMars.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Props, Story, Preview} from '@storybook/addon-docs/blocks' 2 | import {text, boolean, select} from '@storybook/addon-knobs' 3 | import ZapatillasFromMars from '..' 4 | 5 | 6 | 7 | # #zapatillasFromMars👟🚀 8 | 9 | The web of this awesome event! 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/figma-tokens/types/getSpacing.js: -------------------------------------------------------------------------------- 1 | import {getTokens, camelCase} from '../utils' 2 | 3 | const getSpacing = (layerName, stylesArtboard) => { 4 | const palette = {spacing: {}} 5 | const decorator = element => { 6 | const {name, absoluteBoundingBox} = element 7 | const tokens = { 8 | [camelCase(name)]: {value: `${absoluteBoundingBox.width}px`} 9 | } 10 | Object.assign(palette.spacing, tokens) 11 | } 12 | 13 | return getTokens(layerName, stylesArtboard, palette, decorator) 14 | } 15 | 16 | export default getSpacing 17 | -------------------------------------------------------------------------------- /src/docs/designTokens/typography/typography.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Preview} from '@storybook/addon-docs/blocks' 2 | import typography from '../../../styles/theme/typography' 3 | import Typography from '.' 4 | 5 | 6 | 7 | # 🖋 Typography 8 | 9 | `Typography` foundations. 10 | 11 | ### Headings 12 | 13 | 14 | 15 | 16 | 17 | ### Body 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/figma-tokens/types/getRadius.js: -------------------------------------------------------------------------------- 1 | import {getTokens, camelCase} from '../utils' 2 | 3 | const getRadius = (layerName, stylesArtboard) => { 4 | const palette = {radius: {}} 5 | const decorator = element => { 6 | const {name} = element 7 | const {cornerRadius} = element.children[0] 8 | const tokens = { 9 | [camelCase(name)]: {value: `${cornerRadius}px`} 10 | } 11 | Object.assign(palette.radius, tokens) 12 | } 13 | 14 | return getTokens(layerName, stylesArtboard, palette, decorator) 15 | } 16 | 17 | export default getRadius 18 | -------------------------------------------------------------------------------- /src/figma-tokens/types/getBreakpoints.js: -------------------------------------------------------------------------------- 1 | import {getTokens, camelCase} from '../utils' 2 | 3 | const getBreakpoints = (layerName, stylesArtboard) => { 4 | const palette = {breakpoint: {}} 5 | const decorator = element => { 6 | const {name, absoluteBoundingBox} = element 7 | const tokens = { 8 | [camelCase(name)]: {value: `${absoluteBoundingBox.width}px`} 9 | } 10 | Object.assign(palette.breakpoint, tokens) 11 | } 12 | 13 | return getTokens(layerName, stylesArtboard, palette, decorator) 14 | } 15 | 16 | export default getBreakpoints 17 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /src/figma-tokens/types/getShadows.js: -------------------------------------------------------------------------------- 1 | import {getTokens, camelCase, genShadow} from '../utils' 2 | 3 | const getShadows = (layerName, stylesArtboard) => { 4 | const palette = {shadow: {}} 5 | const decorator = element => { 6 | const {name} = element 7 | const {color, offset, radius} = element.effects[0] 8 | const tokens = { 9 | [camelCase(name)]: {value: genShadow(color, offset, radius)} 10 | } 11 | Object.assign(palette.shadow, tokens) 12 | } 13 | 14 | return getTokens(layerName, stylesArtboard, palette, decorator) 15 | } 16 | 17 | export default getShadows 18 | -------------------------------------------------------------------------------- /tokens/ios/TokensColor.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // TokensColor.h 4 | // 5 | // Do not edit directly 6 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef NS_ENUM(NSInteger, TokensColorName) { 13 | ColorAlertWarning, 14 | ColorAlertError, 15 | ColorAlertSuccess, 16 | ColorNeutral00, 17 | ColorNeutral05, 18 | ColorNeutral20, 19 | ColorNeutral40, 20 | ColorNeutral80, 21 | ColorPrimaryDark, 22 | ColorPrimaryMain, 23 | ColorPrimaryLight 24 | }; 25 | 26 | @interface TokensColor : NSObject 27 | + (NSArray *)values; 28 | + (UIColor *)color:(TokensColorName)color; 29 | @end 30 | -------------------------------------------------------------------------------- /src/docs/designTokens/shadows/shadows.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Preview} from '@storybook/addon-docs/blocks' 2 | import shadows from '../../../styles/theme/shadows' 3 | import Shadows from '.' 4 | 5 | 6 | 7 | # 🌚 Shadows 8 | 9 | `Shadows` foundations. 10 | 11 | ### Shadows 12 | 13 | 14 | 15 | 16 | 17 | ### Rounded 18 | 19 | 20 | 21 | 22 | 23 | ### Rectangle 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/docs/designTokens/colors/colors.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Preview} from '@storybook/addon-docs/blocks' 2 | import colors from '../../../styles/theme/colors' 3 | import Colors from '.' 4 | 5 | 6 | 7 | # 🎨 Colors 8 | 9 | `Colors` foundations. 10 | 11 | ### Primary colors 12 | 13 | 14 | 15 | 16 | 17 | ### Neutral colors 18 | 19 | 20 | 21 | 22 | 23 | ### Alert colors 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/molecules/Card/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import {Wrapper} from './Card.styles' 4 | import Heading from '../../atoms/Heading' 5 | 6 | const Card = ({title, children}) => ( 7 | 8 | {title && ( 9 | 10 | {title} 11 | 12 | )} 13 | {children} 14 | 15 | ) 16 | 17 | Card.displayName = 'Card' 18 | 19 | Card.propTypes = { 20 | /** Title to displayin the card */ 21 | title: PropTypes.string, 22 | /** Content to be included in the card */ 23 | children: PropTypes.node.isRequired 24 | } 25 | 26 | export default Card 27 | -------------------------------------------------------------------------------- /src/figma-tokens/types/getColors.js: -------------------------------------------------------------------------------- 1 | import {getTokens, camelCase, rgbaGenObject, fullColorHex} from '../utils' 2 | 3 | const getColors = (layerName, stylesArtboard) => { 4 | const palette = {color: {}} 5 | const decorator = element => { 6 | const {name} = element 7 | const {r, g, b, a} = element.children[0].fills[0].color 8 | const colorRGBA = rgbaGenObject(r, g, b, a) 9 | const tokens = { 10 | [camelCase(name)]: { 11 | value: `${fullColorHex(colorRGBA.r, colorRGBA.g, colorRGBA.b)}` 12 | } 13 | } 14 | Object.assign(palette.color, tokens) 15 | } 16 | 17 | return getTokens(layerName, stylesArtboard, palette, decorator) 18 | } 19 | 20 | export default getColors 21 | -------------------------------------------------------------------------------- /src/styles/theme/colors.js: -------------------------------------------------------------------------------- 1 | import tokens from '../../../tokens/json/color' 2 | 3 | const colors = { 4 | primary: { 5 | light: tokens.color.primaryLight.value, 6 | main: tokens.color.primaryMain.value, 7 | dark: tokens.color.primaryDark.value 8 | }, 9 | neutral: { 10 | percent00: tokens.color.neutral00.value, 11 | percent05: tokens.color.neutral05.value, 12 | percent20: tokens.color.neutral20.value, 13 | percent40: tokens.color.neutral40.value, 14 | percent80: tokens.color.neutral80.value 15 | }, 16 | alert: { 17 | success: tokens.color.alertSuccess.value, 18 | warning: tokens.color.alertWarning.value, 19 | error: tokens.color.alertError.value 20 | } 21 | } 22 | 23 | export default colors 24 | -------------------------------------------------------------------------------- /src/styles/theme/layout.js: -------------------------------------------------------------------------------- 1 | import tokens from '../../../tokens/json/breakpoint' 2 | 3 | const layout = { 4 | grid: { 5 | width: tokens.breakpoint.xl.value, 6 | columns: 12, 7 | gutter: { 8 | xs: '8px', 9 | sm: '16px', 10 | md: '24px', 11 | lg: '24px', 12 | xl: '24px' 13 | }, 14 | margin: { 15 | xs: '16px', 16 | sm: '24px', 17 | md: '32px', 18 | lg: '32px', 19 | xl: '32px' 20 | } 21 | }, 22 | breakpoints: { 23 | xs: tokens.breakpoint.xs.value, 24 | sm: tokens.breakpoint.sm.value, 25 | md: tokens.breakpoint.md.value, 26 | lg: tokens.breakpoint.lg.value, 27 | xl: tokens.breakpoint.xl.value 28 | } 29 | } 30 | 31 | export default layout 32 | -------------------------------------------------------------------------------- /tokens/json/color.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "alertWarning": { 4 | "value": "#ffa90d" 5 | }, 6 | "alertError": { 7 | "value": "#e5363a" 8 | }, 9 | "alertSuccess": { 10 | "value": "#109c42" 11 | }, 12 | "neutral00": { 13 | "value": "#ffffff" 14 | }, 15 | "neutral05": { 16 | "value": "#f2f2f2" 17 | }, 18 | "neutral20": { 19 | "value": "#cccccc" 20 | }, 21 | "neutral40": { 22 | "value": "#999999" 23 | }, 24 | "neutral80": { 25 | "value": "#333333" 26 | }, 27 | "primaryDark": { 28 | "value": "#1d698f" 29 | }, 30 | "primaryMain": { 31 | "value": "#2587b8" 32 | }, 33 | "primaryLight": { 34 | "value": "#56a4c9" 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /tokens/android/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | #ffffa90d 9 | #ffe5363a 10 | #ff109c42 11 | #ffffffff 12 | #fff2f2f2 13 | #ffcccccc 14 | #ff999999 15 | #ff333333 16 | #ff1d698f 17 | #ff2587b8 18 | #ff56a4c9 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/figma-tokens/types/getTypography.js: -------------------------------------------------------------------------------- 1 | import {getTokens, camelCase} from '../utils' 2 | 3 | const getTypography = (layerName, stylesArtboard) => { 4 | const palette = {typography: {}} 5 | const decorator = element => { 6 | const {name} = element 7 | const { 8 | fontFamily, 9 | fontSize, 10 | lineHeightPx, 11 | fontWeight 12 | } = element.children[0].style 13 | 14 | const tokens = { 15 | [camelCase(name)]: { 16 | fontFamily: {value: `'${fontFamily}'`}, 17 | fontSize: {value: `${fontSize}px`}, 18 | lineHeight: {value: `${Math.floor(lineHeightPx)}px`}, 19 | fontWeight: {value: fontWeight} 20 | } 21 | } 22 | Object.assign(palette.typography, tokens) 23 | } 24 | 25 | return getTokens(layerName, stylesArtboard, palette, decorator) 26 | } 27 | 28 | export default getTypography 29 | -------------------------------------------------------------------------------- /src/components/molecules/Card/__tests__/Card.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import 'jest-styled-components' 3 | import {render} from '@testing-library/react' 4 | import {ThemeProvider} from 'styled-components' 5 | import theme from '../../../../styles/theme' 6 | import Card from '..' 7 | 8 | describe('Card', () => { 9 | test('it works default', () => { 10 | const {container} = render( 11 | 12 | 13 |

Lorem ipsum dolor

14 |
15 |
16 | ) 17 | expect(container.firstChild).toMatchSnapshot() 18 | }) 19 | 20 | test('it works with title', () => { 21 | const {container} = render( 22 | 23 | 24 |

Lorem ipsum dolor

25 |
26 |
27 | ) 28 | expect(container.firstChild).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /src/components/atoms/Button/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styles from './Button.styles' 4 | 5 | const Button = ({disabled, secondary, ghost, onClick, children}) => ( 6 | 15 | ) 16 | 17 | Button.displayName = 'Button' 18 | 19 | Button.propTypes = { 20 | /** Content to be included in the button */ 21 | children: PropTypes.node.isRequired, 22 | /** This Boolean attribute prevents the user from interacting with the button */ 23 | disabled: PropTypes.bool, 24 | /** This Boolean attribute to display secondary button variation */ 25 | secondary: PropTypes.bool, 26 | /** This Boolean attribute to display ghost button variation */ 27 | ghost: PropTypes.bool, 28 | /** Click event */ 29 | onClick: PropTypes.func 30 | } 31 | 32 | export default Button 33 | -------------------------------------------------------------------------------- /src/components/molecules/Card/__tests__/__snapshots__/Card.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Card it works default 1`] = ` 4 | .c0 { 5 | max-width: 640px; 6 | margin: 80px auto; 7 | padding: 24px; 8 | border-radius: 8px; 9 | box-shadow: 0px 4px 8px rgba(0,0,0,0.25); 10 | } 11 | 12 |
15 |

16 | Lorem ipsum dolor 17 |

18 |
19 | `; 20 | 21 | exports[`Card it works with title 1`] = ` 22 | .c0 { 23 | max-width: 640px; 24 | margin: 80px auto; 25 | padding: 24px; 26 | border-radius: 8px; 27 | box-shadow: 0px 4px 8px rgba(0,0,0,0.25); 28 | } 29 | 30 | .c1 { 31 | font-size: 24px; 32 | line-height: 28px; 33 | font-weight: 700; 34 | margin: 0 0 24px; 35 | font-size: 28px; 36 | line-height: 32px; 37 | font-weight: 700; 38 | } 39 | 40 |
43 |

46 | Card title 47 |

48 |

49 | Lorem ipsum dolor 50 |

51 |
52 | `; 53 | -------------------------------------------------------------------------------- /src/components/atoms/Heading/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import {Wrapper} from './Heading.styles' 4 | 5 | export const HEADINGS_TYPES = { 6 | h1: 'h1', 7 | h2: 'h2', 8 | h3: 'h3', 9 | h4: 'h4', 10 | h5: 'h5', 11 | h6: 'h6', 12 | span: 'span' 13 | } 14 | 15 | export const HEADINGS_SIZES = { 16 | small: 'small', 17 | normal: 'normal', 18 | big: 'big' 19 | } 20 | 21 | const Heading = ({ 22 | type = HEADINGS_TYPES.h1, 23 | size = HEADINGS_SIZES.normal, 24 | children, 25 | ...props 26 | }) => ( 27 | 28 | {children} 29 | 30 | ) 31 | 32 | Heading.displayName = 'Heading' 33 | 34 | Heading.propTypes = { 35 | /** HTML tag to render */ 36 | type: PropTypes.oneOf(Object.keys(HEADINGS_TYPES)), 37 | /** Size of heading */ 38 | size: PropTypes.oneOf(Object.keys(HEADINGS_SIZES)), 39 | /** Content to be included in the heading */ 40 | children: PropTypes.node.isRequired 41 | } 42 | 43 | export default Heading 44 | -------------------------------------------------------------------------------- /src/components/atoms/Heading/Heading.styles.js: -------------------------------------------------------------------------------- 1 | import styled, {css} from 'styled-components' 2 | 3 | export const Wrapper = styled.h1` 4 | font-size: ${props => props.theme.typography.heading.normal.fontSize}; 5 | line-height: ${props => props.theme.typography.heading.normal.lineHeight}; 6 | font-weight: ${props => props.theme.typography.heading.normal.fontWeight}; 7 | margin: 0 0 ${props => props.theme.spacing.md}; 8 | 9 | ${props => 10 | props.size === 'big' && 11 | css` 12 | font-size: ${props => props.theme.typography.heading.big.fontSize}; 13 | line-height: ${props => props.theme.typography.heading.big.lineHeight}; 14 | font-weight: ${props => props.theme.typography.heading.big.fontWeight}; 15 | `} 16 | 17 | ${props => 18 | props.size === 'small' && 19 | css` 20 | font-size: ${props => props.theme.typography.heading.small.fontSize}; 21 | line-height: ${props => props.theme.typography.heading.small.lineHeight}; 22 | font-weight: ${props => props.theme.typography.heading.small.fontWeight}; 23 | `} 24 | ` 25 | -------------------------------------------------------------------------------- /src/styles/theme/typography.js: -------------------------------------------------------------------------------- 1 | import tokens from '../../../tokens/json/typography' 2 | 3 | const typography = { 4 | global: { 5 | family: "'Open Sans'" 6 | }, 7 | heading: { 8 | big: { 9 | fontSize: tokens.typography.headingBig.fontSize.value, 10 | lineHeight: tokens.typography.headingBig.lineHeight.value, 11 | fontWeight: tokens.typography.headingBig.fontWeight.value 12 | }, 13 | normal: { 14 | fontSize: tokens.typography.headingNormal.fontSize.value, 15 | lineHeight: tokens.typography.headingNormal.lineHeight.value, 16 | fontWeight: tokens.typography.headingNormal.fontWeight.value 17 | }, 18 | small: { 19 | fontSize: tokens.typography.headingSmall.fontSize.value, 20 | lineHeight: tokens.typography.headingSmall.lineHeight.value, 21 | fontWeight: tokens.typography.headingSmall.fontWeight.value 22 | } 23 | }, 24 | body: { 25 | normal: { 26 | fontSize: tokens.typography.bodyNormal.fontSize.value, 27 | lineHeight: tokens.typography.bodyNormal.lineHeight.value 28 | } 29 | } 30 | } 31 | 32 | export default typography 33 | -------------------------------------------------------------------------------- /tokens/ios-swift/TokensColor.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // TokensColor.swift 4 | // 5 | // Do not edit directly 6 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 7 | // 8 | 9 | import UIKit 10 | 11 | public enum TokensColor { 12 | public static let alertError = UIColor(red: 0.898, green: 0.212, blue: 0.227, alpha:1) 13 | public static let alertSuccess = UIColor(red: 0.063, green: 0.612, blue: 0.259, alpha:1) 14 | public static let alertWarning = UIColor(red: 1.000, green: 0.663, blue: 0.051, alpha:1) 15 | public static let neutral00 = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha:1) 16 | public static let neutral05 = UIColor(red: 0.949, green: 0.949, blue: 0.949, alpha:1) 17 | public static let neutral20 = UIColor(red: 0.800, green: 0.800, blue: 0.800, alpha:1) 18 | public static let neutral40 = UIColor(red: 0.600, green: 0.600, blue: 0.600, alpha:1) 19 | public static let neutral80 = UIColor(red: 0.200, green: 0.200, blue: 0.200, alpha:1) 20 | public static let primaryDark = UIColor(red: 0.114, green: 0.412, blue: 0.561, alpha:1) 21 | public static let primaryLight = UIColor(red: 0.337, green: 0.643, blue: 0.788, alpha:1) 22 | public static let primaryMain = UIColor(red: 0.145, green: 0.529, blue: 0.722, alpha:1) 23 | } 24 | -------------------------------------------------------------------------------- /src/figma-tokens/cli.js: -------------------------------------------------------------------------------- 1 | import fs from 'file-system' 2 | import genTokens from './gen' 3 | const path = './figma.config.json' 4 | 5 | export function cli() { 6 | fs.access(path, fs.F_OK, err => { 7 | if (err) { 8 | throw new Error( 9 | '\x1b[31m\n\n❌ Config file was not found!\n\nPlease, create a `figma.config.json` in the root folder with the FIGMA_APIKEY and FIGMA_ID keys\n\n' 10 | ) 11 | } 12 | fs.readFile(path, 'utf8', (err, data) => { 13 | if (err) throw err 14 | const {FIGMA_APIKEY, FIGMA_ID} = JSON.parse(data) 15 | const FIGMA_OUTDIR = 'tokens/json' 16 | if (!FIGMA_APIKEY) { 17 | throw new Error('\x1b[31m\n\n❌ No Figma API key found!\n\n') 18 | } else if (!FIGMA_ID) { 19 | throw new Error('\x1b[31m\n\n❌ No Figma ID found!\n\n') 20 | } else { 21 | if (!FIGMA_OUTDIR) 22 | // eslint-disable-next-line no-console 23 | console.warn('⚠️ No outdir found, default outdir is `./tokens.json`') 24 | fs.mkdir(FIGMA_OUTDIR, null, err => { 25 | if (err) { 26 | throw new Error(`\x1b[31m\n\n❌ ${err}!\n\n`) 27 | } 28 | genTokens(FIGMA_APIKEY, FIGMA_ID, FIGMA_OUTDIR) 29 | }) 30 | } 31 | }) 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /tokens/json/typography.json: -------------------------------------------------------------------------------- 1 | { 2 | "typography": { 3 | "bodyNormal": { 4 | "fontFamily": { 5 | "value": "'Open Sans'" 6 | }, 7 | "fontSize": { 8 | "value": "16px" 9 | }, 10 | "lineHeight": { 11 | "value": "20px" 12 | }, 13 | "fontWeight": { 14 | "value": 400 15 | } 16 | }, 17 | "headingSmall": { 18 | "fontFamily": { 19 | "value": "'Open Sans'" 20 | }, 21 | "fontSize": { 22 | "value": "18px" 23 | }, 24 | "lineHeight": { 25 | "value": "22px" 26 | }, 27 | "fontWeight": { 28 | "value": 700 29 | } 30 | }, 31 | "headingNormal": { 32 | "fontFamily": { 33 | "value": "'Open Sans'" 34 | }, 35 | "fontSize": { 36 | "value": "24px" 37 | }, 38 | "lineHeight": { 39 | "value": "28px" 40 | }, 41 | "fontWeight": { 42 | "value": 700 43 | } 44 | }, 45 | "headingBig": { 46 | "fontFamily": { 47 | "value": "'Open Sans'" 48 | }, 49 | "fontSize": { 50 | "value": "28px" 51 | }, 52 | "lineHeight": { 53 | "value": "32px" 54 | }, 55 | "fontWeight": { 56 | "value": 700 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /tokens/ios/TokensColor.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // TokensColor.m 4 | // 5 | // Do not edit directly 6 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 7 | // 8 | 9 | #import "TokensColor.h" 10 | 11 | 12 | @implementation TokensColor 13 | 14 | + (UIColor *)color:(TokensColorName)colorEnum{ 15 | return [[self values] objectAtIndex:colorEnum]; 16 | } 17 | 18 | + (NSArray *)values { 19 | static NSArray* colorArray; 20 | static dispatch_once_t onceToken; 21 | 22 | dispatch_once(&onceToken, ^{ 23 | colorArray = @[ 24 | [UIColor colorWithRed:1.000f green:0.663f blue:0.051f alpha:1.000f], 25 | [UIColor colorWithRed:0.898f green:0.212f blue:0.227f alpha:1.000f], 26 | [UIColor colorWithRed:0.063f green:0.612f blue:0.259f alpha:1.000f], 27 | [UIColor colorWithRed:1.000f green:1.000f blue:1.000f alpha:1.000f], 28 | [UIColor colorWithRed:0.949f green:0.949f blue:0.949f alpha:1.000f], 29 | [UIColor colorWithRed:0.800f green:0.800f blue:0.800f alpha:1.000f], 30 | [UIColor colorWithRed:0.600f green:0.600f blue:0.600f alpha:1.000f], 31 | [UIColor colorWithRed:0.200f green:0.200f blue:0.200f alpha:1.000f], 32 | [UIColor colorWithRed:0.114f green:0.412f blue:0.561f alpha:1.000f], 33 | [UIColor colorWithRed:0.145f green:0.529f blue:0.722f alpha:1.000f], 34 | [UIColor colorWithRed:0.337f green:0.643f blue:0.788f alpha:1.000f] 35 | ]; 36 | }); 37 | 38 | return colorArray; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /src/docs/designTokens/colors/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, {ThemeProvider} from 'styled-components' 4 | import theme from '../../../styles/theme' 5 | import GlobalStyle from '../../../styles/GlobalStyle' 6 | 7 | export const Wrapper = styled.div` 8 | display: flex; 9 | flex-wrap: wrap; 10 | ` 11 | 12 | const Block = styled.div` 13 | display: flex; 14 | flex-direction: column; 15 | margin: 8px; 16 | ` 17 | 18 | const Background = styled.div` 19 | width: 158px; 20 | height: 60px; 21 | background: ${props => props.color}; 22 | border: 1px solid #eee; 23 | display: flex; 24 | padding: 8px; 25 | align-items: flex-end; 26 | border-radius: 4px; 27 | margin-bottom: 8px; 28 | ` 29 | 30 | const Info = styled.span` 31 | font-size: 12px; 32 | ` 33 | 34 | const Colors = ({colors}) => ( 35 | 36 | 37 | 38 | {Object.values(colors).map((item, index) => { 39 | const colorNames = Object.keys(colors) 40 | return ( 41 | 42 | 43 | 44 | {colorNames[index]} / {item} 45 | 46 | 47 | ) 48 | })} 49 | 50 | 51 | ) 52 | 53 | Colors.propTypes = { 54 | colors: PropTypes.object 55 | } 56 | 57 | export default Colors 58 | -------------------------------------------------------------------------------- /src/docs/designTokens/radius/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, {ThemeProvider} from 'styled-components' 4 | import theme from '../../../styles/theme' 5 | import GlobalStyle from '../../../styles/GlobalStyle' 6 | 7 | export const Wrapper = styled.div` 8 | display: flex; 9 | flex-wrap: wrap; 10 | ` 11 | 12 | const Name = styled.span` 13 | font-size: 12px; 14 | display: block; 15 | margin-bottom: 8px; 16 | min-width: 80px; 17 | ` 18 | 19 | const Block = styled.div` 20 | display: flex; 21 | flex-direction: column; 22 | align-items: center; 23 | text-align: center; 24 | width: 33%; 25 | margin-bottom: 16px; 26 | ` 27 | 28 | const Grid = styled.div` 29 | width: 100px; 30 | height: 100px; 31 | background: ${props => props.theme.colors.neutral.percent20}; 32 | margin-bottom: 16px; 33 | border-radius: ${props => props.borderRadius}; 34 | ` 35 | 36 | const Radius = ({radius}) => ( 37 | 38 | 39 | 40 | {Object.values(radius).map((item, index) => { 41 | const shadowName = Object.keys(radius) 42 | return ( 43 | 44 | {shadowName[index]} 45 | 46 | 47 | ) 48 | })} 49 | 50 | 51 | ) 52 | 53 | Radius.propTypes = { 54 | radius: PropTypes.object 55 | } 56 | 57 | export default Radius 58 | -------------------------------------------------------------------------------- /src/docs/designTokens/spacing/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, {ThemeProvider} from 'styled-components' 4 | import theme from '../../../styles/theme' 5 | import GlobalStyle from '../../../styles/GlobalStyle' 6 | 7 | export const Wrapper = styled.div` 8 | display: flex; 9 | flex-wrap: wrap; 10 | ` 11 | 12 | const Name = styled.span` 13 | font-size: 12px; 14 | display: block; 15 | margin-bottom: 8px; 16 | min-width: 80px; 17 | ` 18 | 19 | const Block = styled.div` 20 | display: flex; 21 | align-items: flex-start; 22 | width: 100%; 23 | 24 | &:not(:last-of-type) { 25 | padding-bottom: 16px; 26 | } 27 | ` 28 | 29 | const Grid = styled.div` 30 | width: ${props => props.size}; 31 | height: ${props => props.size}; 32 | background: ${props => props.theme.colors.neutral.percent20}; 33 | margin-bottom: 8px; 34 | ` 35 | 36 | const Spacing = ({spaces}) => ( 37 | 38 | 39 | 40 | {Object.values(spaces).map((item, index) => { 41 | const spaceName = Object.keys(spaces) 42 | return ( 43 | 44 | 45 | {spaceName[index]} / {item} 46 | 47 | 48 | 49 | ) 50 | })} 51 | 52 | 53 | ) 54 | 55 | Spacing.propTypes = { 56 | spaces: PropTypes.object 57 | } 58 | 59 | export default Spacing 60 | -------------------------------------------------------------------------------- /src/docs/designTokens/breakpoints/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, {ThemeProvider} from 'styled-components' 4 | import theme from '../../../styles/theme' 5 | import GlobalStyle from '../../../styles/GlobalStyle' 6 | 7 | export const Wrapper = styled.div` 8 | display: flex; 9 | flex-wrap: wrap; 10 | ` 11 | 12 | const Name = styled.span` 13 | font-size: 12px; 14 | display: block; 15 | margin-bottom: 8px; 16 | min-width: 80px; 17 | ` 18 | 19 | const Block = styled.div` 20 | display: flex; 21 | align-items: center; 22 | width: 100%; 23 | 24 | &:not(:last-of-type) { 25 | padding-bottom: 16px; 26 | } 27 | ` 28 | 29 | const Breakpoint = styled.div` 30 | width: ${props => props.size}; 31 | height: 24px; 32 | background: ${props => props.theme.colors.neutral.percent20}; 33 | margin-bottom: 8px; 34 | ` 35 | 36 | const Breakpoints = ({breakpoints}) => ( 37 | 38 | 39 | 40 | {Object.values(breakpoints).map((item, index) => { 41 | const spaceName = Object.keys(breakpoints) 42 | return ( 43 | 44 | 45 | {spaceName[index]} / {item} 46 | 47 | 48 | 49 | ) 50 | })} 51 | 52 | 53 | ) 54 | 55 | Breakpoints.propTypes = { 56 | breakpoints: PropTypes.object 57 | } 58 | 59 | export default Breakpoints 60 | -------------------------------------------------------------------------------- /src/components/atoms/Heading/__tests__/Heading.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import 'jest-styled-components' 3 | import {render} from '@testing-library/react' 4 | import {ThemeProvider} from 'styled-components' 5 | import theme from '../../../../styles/theme' 6 | import Heading, {HEADINGS_TYPES, HEADINGS_SIZES} from '..' 7 | 8 | const HeadingTypes = () => 9 | Object.keys(HEADINGS_TYPES).map(type => ( 10 | 11 | Minions ipsum chasy baboiii bappleees 12 | 13 | )) 14 | 15 | const HeadingSizes = () => 16 | Object.keys(HEADINGS_SIZES).map(size => ( 17 | 18 | Minions ipsum chasy baboiii bappleees 19 | 20 | )) 21 | 22 | describe('Heading', () => { 23 | test('it works default', () => { 24 | const {container} = render( 25 | 26 | Minions ipsum chasy baboiii bappleees 27 | 28 | ) 29 | expect(container.firstChild).toMatchSnapshot() 30 | }) 31 | 32 | test('it works with all sizes variations', () => { 33 | const {container} = render( 34 | 35 | 36 | 37 | ) 38 | expect(container).toMatchSnapshot() 39 | }) 40 | 41 | test('it works with all types variations', () => { 42 | const {container} = render( 43 | 44 | 45 | 46 | ) 47 | expect(container).toMatchSnapshot() 48 | }) 49 | }) 50 | -------------------------------------------------------------------------------- /src/components/atoms/Button/__stories__/Button.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Props, Story, Preview} from '@storybook/addon-docs/blocks' 2 | import {text, boolean} from '@storybook/addon-knobs' 3 | import Button from '..' 4 | 5 | export const knobsProps = () => ({ 6 | children: text('text', 'Default button'), 7 | secondary: boolean('secondary', false), 8 | ghost: boolean('ghost', false), 9 | disabled: boolean('disabled', false) 10 | }) 11 | 12 | 13 | 14 | # Button 15 | 16 | The `Button` usually act as the main call to action for the users, focusing their attention on what they need to do at each moment. 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ## Props 31 | 32 | 33 | 34 | ## Stories 35 | 36 | ### Disabled 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | ## Knobs 55 | 56 | 57 | 58 | 41 | 42 | 43 | 44 | 45 | ## Props 46 | 47 | 48 | 49 | ## Knobs 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/figma-tokens/utils.js: -------------------------------------------------------------------------------- 1 | export const filterArtboard = (layerName, stylesArtboard) => 2 | stylesArtboard.filter(item => item.name === layerName)[0].children 3 | 4 | export const filterElements = (layerName, stylesArtboard) => 5 | filterArtboard(layerName, stylesArtboard).filter( 6 | item => item.type === 'COMPONENT' 7 | ) 8 | 9 | export const getTokens = (layerName, stylesArtboard, palette, decorator) => { 10 | const elements = filterElements(layerName, stylesArtboard) 11 | elements.map(element => decorator(element)) 12 | return palette 13 | } 14 | 15 | export const camelCase = string => { 16 | const stringUpdate = string 17 | .toLowerCase() 18 | .replace(/(?:(^.)|([-_\s]+.))/g, match => 19 | match.charAt(match.length - 1).toUpperCase() 20 | ) 21 | return stringUpdate.charAt(0).toLowerCase() + stringUpdate.substring(1) 22 | } 23 | 24 | export const trim = str => str.replace(/^\s+|\s+$/gm, '') 25 | 26 | export const getColor = color => Math.round(color * 255) 27 | 28 | export const rgbaGen = (r, g, b, a) => 29 | `rgba(${getColor(r)}, ${getColor(g)}, ${getColor(b)}, ${a})` 30 | 31 | export const rgbaGenObject = (r, g, b, a) => { 32 | return {r: getColor(r), g: getColor(g), b: getColor(b), a: a} 33 | } 34 | 35 | export const rgbGen = (r, g, b) => { 36 | const getColor = color => Math.round(color * 255) 37 | return `rgba(${getColor(r)}, ${getColor(g)}, ${getColor(b)})` 38 | } 39 | 40 | export const rgbToHex = rgb => { 41 | const hex = Number(rgb).toString(16) 42 | return hex.length < 2 ? `0${hex}` : hex 43 | } 44 | 45 | export const fullColorHex = (r, g, b) => { 46 | const red = rgbToHex(r) 47 | const green = rgbToHex(g) 48 | const blue = rgbToHex(b) 49 | return `#${red + green + blue}` 50 | } 51 | 52 | export const parseRGBA = color => { 53 | const {r, g, b, a} = color 54 | return `rgba(${r}, ${g}, ${b}, ${a})` 55 | } 56 | 57 | export const genShadow = (color, offset, radius) => { 58 | const {x, y} = offset 59 | return `${x}px ${y}px ${radius}px ${parseRGBA(color)}` 60 | } 61 | -------------------------------------------------------------------------------- /src/components/atoms/Button/__tests__/Button.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import 'jest-styled-components' 3 | import {render} from '@testing-library/react' 4 | import {ThemeProvider} from 'styled-components' 5 | import theme from '../../../../styles/theme' 6 | import Button from '..' 7 | 8 | describe('Button', () => { 9 | test('it works default', () => { 10 | const {container} = render( 11 | 12 | 13 | 14 | ) 15 | expect(container.firstChild).toMatchSnapshot() 16 | }) 17 | 18 | test('it works disabled', () => { 19 | const {container} = render( 20 | 21 | 22 | 23 | ) 24 | expect(container.firstChild).toMatchSnapshot() 25 | }) 26 | 27 | test('it works with secondary variation', () => { 28 | const {container} = render( 29 | 30 | 31 | 32 | ) 33 | expect(container.firstChild).toMatchSnapshot() 34 | }) 35 | 36 | test('it works with secondary and disabled variation', () => { 37 | const {container} = render( 38 | 39 | 42 | 43 | ) 44 | expect(container.firstChild).toMatchSnapshot() 45 | }) 46 | 47 | test('it works with ghost variation', () => { 48 | const {container} = render( 49 | 50 | 51 | 52 | ) 53 | expect(container.firstChild).toMatchSnapshot() 54 | }) 55 | 56 | test('it works with ghost and disabled variation', () => { 57 | const {container} = render( 58 | 59 | 62 | 63 | ) 64 | expect(container.firstChild).toMatchSnapshot() 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /src/components/atoms/Button/Button.styles.js: -------------------------------------------------------------------------------- 1 | import {css} from 'styled-components' 2 | 3 | export default css` 4 | align-items: center; 5 | border-radius: 4px; 6 | cursor: pointer; 7 | display: flex; 8 | font-size: ${props => props.theme.typography.body.normal.fontSize}; 9 | line-height: ${props => props.theme.typography.body.normal.lineHeight}; 10 | font-family: inherit; 11 | outline: none; 12 | border: 1px solid transparent; 13 | padding: ${props => props.theme.spacing.sm} ${props => props.theme.spacing.md}; 14 | background-color: ${props => props.theme.colors.primary.main}; 15 | color: ${props => props.theme.colors.neutral.percent00}; 16 | transition: color 0.2s, background-color 0.2s, box-shadow 0.2s; 17 | 18 | &:hover, 19 | &:active { 20 | background-color: ${props => props.theme.colors.primary.light}; 21 | } 22 | 23 | &:active { 24 | box-shadow: 0 0 4px ${props => props.theme.colors.primary.light}; 25 | } 26 | 27 | &:disabled { 28 | cursor: not-allowed; 29 | opacity: 0.5; 30 | 31 | &:hover { 32 | background-color: ${props => props.theme.colors.primary.main}; 33 | } 34 | } 35 | 36 | ${props => 37 | props.secondary && 38 | css` 39 | background-color: ${props.theme.colors.neutral.percent00}; 40 | border-color: ${props.theme.colors.neutral.percent20}; 41 | color: ${props.theme.colors.neutral.percent80}; 42 | 43 | &:hover, 44 | &:active { 45 | background-color: ${props.theme.colors.neutral.percent05}; 46 | } 47 | 48 | &:disabled { 49 | &:hover { 50 | background-color: ${props.theme.colors.neutral.percent00}; 51 | } 52 | } 53 | `} 54 | 55 | ${props => 56 | props.ghost && 57 | css` 58 | background-color: ${props.theme.colors.neutral.percent00}; 59 | color: ${props.theme.colors.neutral.percent80}; 60 | 61 | &:hover, 62 | &:active { 63 | background-color: ${props.theme.colors.neutral.percent05}; 64 | } 65 | 66 | &:disabled { 67 | &:hover { 68 | background-color: ${props.theme.colors.neutral.percent00}; 69 | } 70 | } 71 | `} 72 | ` 73 | -------------------------------------------------------------------------------- /src/components/atoms/Heading/__tests__/__snapshots__/Heading.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Heading it works default 1`] = ` 4 | .c0 { 5 | font-size: 24px; 6 | line-height: 28px; 7 | font-weight: 700; 8 | margin: 0 0 24px; 9 | } 10 | 11 |

14 | Minions ipsum chasy baboiii bappleees 15 |

16 | `; 17 | 18 | exports[`Heading it works with all sizes variations 1`] = ` 19 | .c0 { 20 | font-size: 24px; 21 | line-height: 28px; 22 | font-weight: 700; 23 | margin: 0 0 24px; 24 | font-size: 18px; 25 | line-height: 22px; 26 | font-weight: 700; 27 | } 28 | 29 | .c1 { 30 | font-size: 24px; 31 | line-height: 28px; 32 | font-weight: 700; 33 | margin: 0 0 24px; 34 | } 35 | 36 | .c2 { 37 | font-size: 24px; 38 | line-height: 28px; 39 | font-weight: 700; 40 | margin: 0 0 24px; 41 | font-size: 28px; 42 | line-height: 32px; 43 | font-weight: 700; 44 | } 45 | 46 |
47 |

50 | Minions ipsum chasy baboiii bappleees 51 |

52 |

55 | Minions ipsum chasy baboiii bappleees 56 |

57 |

60 | Minions ipsum chasy baboiii bappleees 61 |

62 |
63 | `; 64 | 65 | exports[`Heading it works with all types variations 1`] = ` 66 | .c0 { 67 | font-size: 24px; 68 | line-height: 28px; 69 | font-weight: 700; 70 | margin: 0 0 24px; 71 | } 72 | 73 |
74 |

77 | Minions ipsum chasy baboiii bappleees 78 |

79 |

82 | Minions ipsum chasy baboiii bappleees 83 |

84 |

87 | Minions ipsum chasy baboiii bappleees 88 |

89 |

92 | Minions ipsum chasy baboiii bappleees 93 |

94 |
97 | Minions ipsum chasy baboiii bappleees 98 |
99 |
102 | Minions ipsum chasy baboiii bappleees 103 |
104 | 107 | Minions ipsum chasy baboiii bappleees 108 | 109 |
110 | `; 111 | -------------------------------------------------------------------------------- /src/components/atoms/Heading/__stories__/Heading.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Props, Story, Preview} from '@storybook/addon-docs/blocks' 2 | import {select, text} from '@storybook/addon-knobs' 3 | import Heading, {HEADINGS_TYPES, HEADINGS_SIZES} from '..' 4 | 5 | export const knobsProps = () => ({ 6 | type: select('type', HEADINGS_TYPES), 7 | size: select('size', HEADINGS_SIZES), 8 | children: text('text', 'Minions ipsum chasy baboiii bappleees') 9 | }) 10 | 11 | 12 | 13 | # Heading 14 | 15 | Let's define a story for our `Heading` component: 16 | 17 | 18 | 19 |
20 | Minions ipsum chasy baboiii bappleees 21 | Minions ipsum chasy baboiii bappleees 22 | Minions ipsum chasy baboiii bappleees 23 |
24 |
25 |
26 | 27 | ## Props 28 | 29 | 30 | 31 | ## Stories 32 | 33 | ### Sizes 34 | 35 | ##### Small 36 | 37 | 38 | 39 | Minions ipsum chasy baboiii bappleees 40 | 41 | 42 | 43 | ##### Normal 44 | 45 | 46 | 47 | Minions ipsum chasy baboiii bappleees 48 | 49 | 50 | 51 | ##### Big 52 | 53 | 54 | 55 | Minions ipsum chasy baboiii bappleees 56 | 57 | 58 | 59 | ### Types 60 | 61 | 62 | 63 |
64 | Heading normal as `h1` tag 65 | Heading normal as `h2` tag 66 | Heading normal as `h3` tag 67 | Heading normal as `h4` tag 68 | Heading normal as `h5` tag 69 | Heading normal as `h6` tag 70 | Heading normal as `span` tag 71 |
72 |
73 |
74 | 75 | ## Knobs 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /tokens/js/tokens.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Do not edit directly 3 | * Generated on Thu, 20 Aug 2020 15:47:39 GMT 4 | */ 5 | 6 | export const BreakpointXl = "1460px"; 7 | export const BreakpointLg = "1200px"; 8 | export const BreakpointMd = "992px"; 9 | export const BreakpointSm = "768px"; 10 | export const BreakpointXs = "576px"; 11 | export const ColorAlertWarning = "#ffa90d"; 12 | export const ColorAlertError = "#e5363a"; 13 | export const ColorAlertSuccess = "#109c42"; 14 | export const ColorNeutral00 = "#ffffff"; 15 | export const ColorNeutral05 = "#f2f2f2"; 16 | export const ColorNeutral20 = "#cccccc"; 17 | export const ColorNeutral40 = "#999999"; 18 | export const ColorNeutral80 = "#333333"; 19 | export const ColorPrimaryDark = "#1d698f"; 20 | export const ColorPrimaryMain = "#2587b8"; 21 | export const ColorPrimaryLight = "#56a4c9"; 22 | export const RadiusSm = "8px"; 23 | export const RadiusMd = "16px"; 24 | export const RadiusRounded = "100px"; 25 | export const ShadowSm = "0px 4px 8px rgba(0, 0, 0, 0.25)"; 26 | export const ShadowMd = "0px 4px 16px rgba(0, 0, 0, 0.25)"; 27 | export const ShadowLg = "0px 4px 24px rgba(0, 0, 0, 0.25)"; 28 | export const SpacingXxl = "48px"; 29 | export const SpacingXl = "40px"; 30 | export const SpacingLg = "32px"; 31 | export const SpacingMd = "24px"; 32 | export const SpacingSm = "16px"; 33 | export const SpacingXs = "8px"; 34 | export const SpacingXxs = "4px"; 35 | export const TypographyBodyNormalFontFamily = "'Open Sans'"; 36 | export const TypographyBodyNormalFontSize = "16px"; 37 | export const TypographyBodyNormalLineHeight = "20px"; 38 | export const TypographyBodyNormalFontWeight = 400; 39 | export const TypographyHeadingSmallFontFamily = "'Open Sans'"; 40 | export const TypographyHeadingSmallFontSize = "18px"; 41 | export const TypographyHeadingSmallLineHeight = "22px"; 42 | export const TypographyHeadingSmallFontWeight = 700; 43 | export const TypographyHeadingNormalFontFamily = "'Open Sans'"; 44 | export const TypographyHeadingNormalFontSize = "24px"; 45 | export const TypographyHeadingNormalLineHeight = "28px"; 46 | export const TypographyHeadingNormalFontWeight = 700; 47 | export const TypographyHeadingBigFontFamily = "'Open Sans'"; 48 | export const TypographyHeadingBigFontSize = "28px"; 49 | export const TypographyHeadingBigLineHeight = "32px"; 50 | export const TypographyHeadingBigFontWeight = 700; -------------------------------------------------------------------------------- /src/figma-tokens/gen.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import fetch from 'node-fetch' 3 | import getColors from './types/getColors' 4 | import getTypography from './types/getTypography' 5 | import getSpacing from './types/getSpacing' 6 | import getShadows from './types/getShadows' 7 | import getBreakpoints from './types/getBreakpoints' 8 | import getRadius from './types/getRadius' 9 | 10 | const emojis = { 11 | color: '🎨', 12 | typography: '🖋 ', 13 | spacing: '📐', 14 | shadow: '🌚', 15 | breakpoint: '🍪', 16 | radius: '🌀' 17 | } 18 | 19 | const genFile = (name, tokens, outDir) => 20 | fs.writeFile( 21 | `${outDir}/${name}.json`, 22 | JSON.stringify(tokens, null, 2), 23 | err => { 24 | if (err) { 25 | throw new Error(`\x1b[31m\n\n❌ ${err}\n\n`) 26 | } 27 | // eslint-disable-next-line no-console 28 | console.log( 29 | `\x1b[32m ${ 30 | emojis[name] 31 | } ${name.toUpperCase()} tokens created!\x1b[0m\n` 32 | ) 33 | } 34 | ) 35 | 36 | const genTokens = (apikey, id, outDir) => { 37 | // eslint-disable-next-line no-console 38 | console.log('\x1b[40m 👟 🚀 Connecting from mars... \x1b[0m\n') 39 | const FETCH_URL = `https://api.figma.com/v1/files/${id}` 40 | const FETCH_DATA = { 41 | method: 'GET', 42 | headers: { 43 | 'X-Figma-Token': apikey 44 | } 45 | } 46 | 47 | try { 48 | fetch(FETCH_URL, FETCH_DATA) 49 | .then(response => { 50 | // eslint-disable-next-line no-console 51 | console.log( 52 | ' Connection with Figma is successful...\n\n----------------\n' 53 | ) 54 | return response.json() 55 | }) 56 | .then(styles => { 57 | if (styles.status !== 403 && styles.status !== 404) { 58 | const figmaTree = styles.document.children[0].children 59 | 60 | genFile('color', getColors('Colors', figmaTree), outDir) 61 | genFile('spacing', getSpacing('Spacings', figmaTree), outDir) 62 | genFile('typography', getTypography('Typography', figmaTree), outDir) 63 | genFile('shadow', getShadows('Shadows', figmaTree), outDir) 64 | genFile('radius', getRadius('Radius', figmaTree), outDir) 65 | genFile( 66 | 'breakpoint', 67 | getBreakpoints('Breakpoints', figmaTree), 68 | outDir 69 | ) 70 | } 71 | }) 72 | .catch(err => { 73 | throw new Error(`\x1b[31m\n\n❌ ${err}\n\n`) 74 | }) 75 | } catch (err) { 76 | throw new Error(`\x1b[31m\n\n❌ ${err}\n\n`) 77 | } 78 | } 79 | 80 | export default genTokens 81 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pattern-library-skeleton", 3 | "version": "1.0.0", 4 | "description": "A awesome pattern library for your products and experiences!", 5 | "license": "ISC", 6 | "author": "Juan Carlos Ruiz ", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/klaufel/pattern-library-skeleton.git" 10 | }, 11 | "scripts": { 12 | "tokens": "npm run tokens:api && npm run tokens:build", 13 | "tokens:api": "bin/figma-tokens", 14 | "tokens:build": "style-dictionary build", 15 | "storybook": "start-storybook -p 9001", 16 | "storybook:build": "build-storybook -o storybook -c .storybook", 17 | "prettier:check": "prettier \"./**/*.{js,mdx}\" --check", 18 | "prettier:write": "prettier \"./**/*.{js,mdx}\" --write", 19 | "test": "jest", 20 | "test:watch": "jest --watch", 21 | "test:update": "jest --updateSnapshot", 22 | "test:coverage": "jest --coverage", 23 | "test:coverage-web": "npm run test:coverage && open coverage/lcov-report/index.html", 24 | "lint": "sui-lint js" 25 | }, 26 | "husky": { 27 | "hooks": { 28 | "pre-commit": "npm run prettier:write", 29 | "pre-push": "npm run test" 30 | } 31 | }, 32 | "babel": { 33 | "presets": [ 34 | "@babel/preset-env", 35 | "@babel/preset-react" 36 | ], 37 | "plugins": [ 38 | [ 39 | "babel-plugin-styled-components", 40 | { 41 | "displayName": false 42 | } 43 | ], 44 | "react-docgen" 45 | ] 46 | }, 47 | "devDependencies": { 48 | "@babel/core": "^7.9.0", 49 | "@babel/preset-env": "^7.9.5", 50 | "@babel/preset-react": "^7.9.4", 51 | "@s-ui/lint": "^3.14.0", 52 | "@storybook/addon-actions": "^5.3.18", 53 | "@storybook/addon-docs": "^5.3.18", 54 | "@storybook/addon-knobs": "^5.3.18", 55 | "@storybook/react": "^5.3.18", 56 | "@testing-library/react": "^10.0.2", 57 | "babel-jest": "^25.3.0", 58 | "babel-loader": "^8.1.0", 59 | "babel-plugin-react-docgen": "^4.1.0", 60 | "babel-plugin-styled-components": "^1.10.7", 61 | "babel-polyfill": "^6.26.0", 62 | "esm": "^3.2.25", 63 | "file-system": "^2.2.2", 64 | "husky": "^4.2.5", 65 | "jest": "^25.3.0", 66 | "jest-styled-components": "^7.0.2", 67 | "node-fetch": "^2.6.0", 68 | "style-dictionary": "^2.8.3" 69 | }, 70 | "dependencies": { 71 | "react": "^16.13.1", 72 | "react-dom": "^16.13.1", 73 | "prop-types": "^15.7.2", 74 | "styled-components": "^5.1.0" 75 | }, 76 | "eslintConfig": { 77 | "extends": [ 78 | "./node_modules/@s-ui/lint/eslintrc.js" 79 | ], 80 | "env": { 81 | "jest": true 82 | } 83 | }, 84 | "prettier": "./node_modules/@s-ui/lint/.prettierrc.js", 85 | "stylelint": { 86 | "extends": "./node_modules/@s-ui/lint/stylelint.config.js" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tokens/ios-swift/Tokens.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Tokens.swift 4 | // 5 | // Do not edit directly 6 | // Generated on Thu, 20 Aug 2020 15:47:39 GMT 7 | // 8 | 9 | 10 | import UIKit 11 | 12 | public class Tokens { 13 | public static let breakpointLg = 1200px 14 | public static let breakpointMd = 992px 15 | public static let breakpointSm = 768px 16 | public static let breakpointXl = 1460px 17 | public static let breakpointXs = 576px 18 | public static let colorAlertError = UIColor(red: 0.898, green: 0.212, blue: 0.227, alpha:1) 19 | public static let colorAlertSuccess = UIColor(red: 0.063, green: 0.612, blue: 0.259, alpha:1) 20 | public static let colorAlertWarning = UIColor(red: 1.000, green: 0.663, blue: 0.051, alpha:1) 21 | public static let colorNeutral00 = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha:1) 22 | public static let colorNeutral05 = UIColor(red: 0.949, green: 0.949, blue: 0.949, alpha:1) 23 | public static let colorNeutral20 = UIColor(red: 0.800, green: 0.800, blue: 0.800, alpha:1) 24 | public static let colorNeutral40 = UIColor(red: 0.600, green: 0.600, blue: 0.600, alpha:1) 25 | public static let colorNeutral80 = UIColor(red: 0.200, green: 0.200, blue: 0.200, alpha:1) 26 | public static let colorPrimaryDark = UIColor(red: 0.114, green: 0.412, blue: 0.561, alpha:1) 27 | public static let colorPrimaryLight = UIColor(red: 0.337, green: 0.643, blue: 0.788, alpha:1) 28 | public static let colorPrimaryMain = UIColor(red: 0.145, green: 0.529, blue: 0.722, alpha:1) 29 | public static let radiusMd = 16px 30 | public static let radiusRounded = 100px 31 | public static let radiusSm = 8px 32 | public static let shadowLg = 0px 4px 24px rgba(0, 0, 0, 0.25) 33 | public static let shadowMd = 0px 4px 16px rgba(0, 0, 0, 0.25) 34 | public static let shadowSm = 0px 4px 8px rgba(0, 0, 0, 0.25) 35 | public static let spacingLg = 32px 36 | public static let spacingMd = 24px 37 | public static let spacingSm = 16px 38 | public static let spacingXl = 40px 39 | public static let spacingXs = 8px 40 | public static let spacingXxl = 48px 41 | public static let spacingXxs = 4px 42 | public static let typographyBodyNormalFontFamily = 'Open Sans' 43 | public static let typographyBodyNormalFontSize = 16px 44 | public static let typographyBodyNormalFontWeight = 400 45 | public static let typographyBodyNormalLineHeight = 20px 46 | public static let typographyHeadingBigFontFamily = 'Open Sans' 47 | public static let typographyHeadingBigFontSize = 28px 48 | public static let typographyHeadingBigFontWeight = 700 49 | public static let typographyHeadingBigLineHeight = 32px 50 | public static let typographyHeadingNormalFontFamily = 'Open Sans' 51 | public static let typographyHeadingNormalFontSize = 24px 52 | public static let typographyHeadingNormalFontWeight = 700 53 | public static let typographyHeadingNormalLineHeight = 28px 54 | public static let typographyHeadingSmallFontFamily = 'Open Sans' 55 | public static let typographyHeadingSmallFontSize = 18px 56 | public static let typographyHeadingSmallFontWeight = 700 57 | public static let typographyHeadingSmallLineHeight = 22px 58 | } 59 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": ["tokens/**/*.json"], 3 | "platforms": { 4 | "css": { 5 | "transformGroup": "css", 6 | "buildPath": "tokens/css/", 7 | "files": [ 8 | { 9 | "destination": "variables.css", 10 | "format": "css/variables" 11 | } 12 | ] 13 | }, 14 | "scss": { 15 | "transformGroup": "scss", 16 | "buildPath": "tokens/scss/", 17 | "files": [ 18 | { 19 | "destination": "_variables.scss", 20 | "format": "scss/variables" 21 | } 22 | ] 23 | }, 24 | "json-flat": { 25 | "transformGroup": "web", 26 | "buildPath": "tokens/json-flat/", 27 | "files": [ 28 | { 29 | "destination": "variables.json", 30 | "format": "json/flat" 31 | } 32 | ] 33 | }, 34 | "js": { 35 | "transformGroup": "js", 36 | "buildPath": "tokens/js/", 37 | "files": [ 38 | { 39 | "destination": "tokens.js", 40 | "format": "javascript/es6" 41 | } 42 | ] 43 | }, 44 | "android": { 45 | "transformGroup": "android", 46 | "buildPath": "tokens/android/", 47 | "files": [ 48 | { 49 | "destination": "font_dimens.xml", 50 | "format": "android/fontDimens" 51 | }, 52 | { 53 | "destination": "colors.xml", 54 | "format": "android/colors" 55 | } 56 | ] 57 | }, 58 | "ios": { 59 | "transformGroup": "ios", 60 | "buildPath": "tokens/ios/", 61 | "files": [ 62 | { 63 | "destination": "TokensColor.h", 64 | "format": "ios/colors.h", 65 | "className": "TokensColor", 66 | "type": "TokensColorName", 67 | "filter": { 68 | "attributes": { 69 | "category": "color" 70 | } 71 | } 72 | }, 73 | { 74 | "destination": "TokensColor.m", 75 | "format": "ios/colors.m", 76 | "className": "TokensColor", 77 | "type": "TokensColorName", 78 | "filter": { 79 | "attributes": { 80 | "category": "color" 81 | } 82 | } 83 | }, 84 | { 85 | "destination": "TokensSpacing.h", 86 | "format": "ios/static.h", 87 | "className": "TokensSpacing", 88 | "type": "float", 89 | "filter": { 90 | "attributes": { 91 | "category": "spacing" 92 | } 93 | } 94 | }, 95 | { 96 | "destination": "TokensSpacing.m", 97 | "format": "ios/static.m", 98 | "className": "TokensSpacing", 99 | "type": "float", 100 | "filter": { 101 | "attributes": { 102 | "category": "spacing" 103 | } 104 | } 105 | } 106 | ] 107 | }, 108 | "ios-swift": { 109 | "transformGroup": "ios-swift", 110 | "buildPath": "tokens/ios-swift/", 111 | "files": [ 112 | { 113 | "destination": "Tokens.swift", 114 | "format": "ios-swift/class.swift", 115 | "className": "Tokens", 116 | "filter": {} 117 | } 118 | ] 119 | }, 120 | "ios-swift-separate-enums": { 121 | "transformGroup": "ios-swift-separate", 122 | "buildPath": "tokens/ios-swift/", 123 | "files": [ 124 | { 125 | "destination": "TokensColor.swift", 126 | "format": "ios-swift/enum.swift", 127 | "className": "TokensColor", 128 | "filter": { 129 | "attributes": { 130 | "category": "color" 131 | } 132 | } 133 | }, 134 | { 135 | "destination": "TokensSpacing.swift", 136 | "format": "ios-swift/enum.swift", 137 | "className": "TokensSpacing", 138 | "type": "float", 139 | "filter": { 140 | "attributes": { 141 | "category": "spacing" 142 | } 143 | } 144 | } 145 | ] 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /docs/STYLEDICTIONARY.md: -------------------------------------------------------------------------------- 1 | # Basic Style Dictionary 2 | 3 | This example code is bare-bones to show you what this framework can do. If you have the style-dictionary module installed globally, you can `cd` into this directory and run: 4 | 5 | ```bash 6 | style-dictionary build 7 | ``` 8 | 9 | You should see something like this output: 10 | 11 | ``` 12 | Copying starter files... 13 | 14 | Source style dictionary starter files created! 15 | 16 | Running `style-dictionary build` for the first time to generate build artifacts. 17 | 18 | 19 | scss 20 | ✔︎ build/scss/_variables.scss 21 | 22 | android 23 | ✔︎ build/android/font_dimens.xml 24 | ✔︎ build/android/colors.xml 25 | 26 | ios 27 | ✔︎ build/ios/StyleDictionaryColor.h 28 | ✔︎ build/ios/StyleDictionaryColor.m 29 | ✔︎ build/ios/StyleDictionarySize.h 30 | ✔︎ build/ios/StyleDictionarySize.m 31 | 32 | ios-swift 33 | ✔︎ build/ios-swift/StyleDictionary.swift 34 | 35 | ios-swift-separate-enums 36 | ✔︎ build/ios-swift/StyleDictionaryColor.swift 37 | ✔︎ build/ios-swift/StyleDictionarySize.swift 38 | ``` 39 | 40 | Pat yourself on the back, you have now built your first style dictionary! Moving on, take a look at what we have built. This should have created a build directory and it should look like this: 41 | 42 | ``` 43 | ├── README.md 44 | ├── config.json 45 | ├── properties/ 46 | │ ├── color/ 47 | │ ├── base.json 48 | │ ├── font.json 49 | │ ├── size/ 50 | │ ├── font.json 51 | ├── build/ 52 | │ ├── android/ 53 | │ ├── font_dimens.xml 54 | │ ├── colors.xml 55 | │ ├── scss/ 56 | │ ├── _variables.scss 57 | │ ├── ios/ 58 | │ ├── StyleDictionaryColor.h 59 | │ ├── StyleDictionaryColor.m 60 | │ ├── StyleDictionarySize.h 61 | │ ├── StyleDictionarySize.m 62 | │ ├── ios-swift/ 63 | │ ├── StyleDictionary.swift 64 | │ ├── StyleDictionaryColor.swift 65 | │ ├── StyleDictionarySize.swift 66 | ``` 67 | 68 | If you open `config.json` you will see there are 3 platforms defined: scss, android, ios. Each platform has a transformGroup, buildPath, and files. The buildPath and files of the platform should match up to the files what were built. The files built should look like these: 69 | 70 | **Android** 71 | 72 | ```xml 73 | 74 | 75 | 12.00sp 76 | 16.00sp 77 | 32.00sp 78 | 16.00sp 79 | 80 | 81 | 82 | 83 | #ffcccccc 84 | #ff999999 85 | #ff111111 86 | #ffff0000 87 | #ff00ff00 88 | #ffff0000 89 | #ff00ff00 90 | #ffcccccc 91 | 92 | ``` 93 | 94 | **SCSS** 95 | 96 | ```scss 97 | // variables.scss 98 | $color-base-gray-light: #cccccc; 99 | $color-base-gray-medium: #999999; 100 | $color-base-gray-dark: #111111; 101 | $color-base-red: #ff0000; 102 | $color-base-green: #00ff00; 103 | $color-font-base: #ff0000; 104 | $color-font-secondary: #00ff00; 105 | $color-font-tertiary: #cccccc; 106 | $size-font-small: 0.75rem; 107 | $size-font-medium: 1rem; 108 | $size-font-large: 2rem; 109 | $size-font-base: 1rem; 110 | ``` 111 | 112 | **iOS** 113 | 114 | ```objc 115 | #import "StyleDictionaryColor.h" 116 | 117 | @implementation StyleDictionaryColor 118 | 119 | + (UIColor *)color:(StyleDictionaryColorName)colorEnum{ 120 | return [[self values] objectAtIndex:colorEnum]; 121 | } 122 | 123 | + (NSArray *)values { 124 | static NSArray* colorArray; 125 | static dispatch_once_t onceToken; 126 | 127 | dispatch_once(&onceToken, ^{ 128 | colorArray = @[ 129 | [UIColor colorWithRed:0.800f green:0.800f blue:0.800f alpha:1.000f], 130 | [UIColor colorWithRed:0.600f green:0.600f blue:0.600f alpha:1.000f], 131 | [UIColor colorWithRed:0.067f green:0.067f blue:0.067f alpha:1.000f], 132 | [UIColor colorWithRed:1.000f green:0.000f blue:0.000f alpha:1.000f], 133 | [UIColor colorWithRed:0.000f green:1.000f blue:0.000f alpha:1.000f], 134 | [UIColor colorWithRed:1.000f green:0.000f blue:0.000f alpha:1.000f], 135 | [UIColor colorWithRed:0.000f green:1.000f blue:0.000f alpha:1.000f], 136 | [UIColor colorWithRed:0.800f green:0.800f blue:0.800f alpha:1.000f] 137 | ]; 138 | }); 139 | 140 | return colorArray; 141 | } 142 | 143 | @end 144 | ``` 145 | 146 | Pretty nifty! This shows a few things happening: 147 | 148 | 1. The build system does a deep merge of all the property JSON files defined in the `source` attribute of `config.json`. This allows you to split up the property JSON files however you want. There are 2 JSON files with `color` as the top level key, but they get merged properly. 149 | 1. The build system resolves references to other style properties. `{size.font.medium.value}` gets resolved properly. 150 | 1. The build system handles references to property values in other files as well as you can see in `properties/color/font.json`. 151 | 152 | Now let's make a change and see how that affects things. Open up `properties/color/base.json` and change `"#111111"` to `"#000000"`. After you make that change, save the file and re-run the build command `style-dictionary build`. Open up the build files and take a look. 153 | 154 | **Huzzah!** 155 | 156 | Now go forth and create! Take a look at all the built-in [transforms](https://amzn.github.io/style-dictionary/#/transforms?id=pre-defined-transforms) and [formats](https://amzn.github.io/style-dictionary/#/formats?id=pre-defined-formats). 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | #zapatillasFromMars👟🚀 3 |

4 | 👋 Welcome to pattern library skeleton 5 |

6 |

7 | 8 |

An awesome design system for your products and experiences!

9 | 10 |

11 | 12 | Netlify Status 13 | 14 |

15 | 16 |

17 | Overview • 18 | Getting Started • 19 | Architecture • 20 | Guidelines • 21 | Testing 22 |

23 | 24 |

25 | Design tokens figma file 26 |

27 | 28 | ## :fire: Overview 29 | 30 | We use the best tools to improve our workflow, allowing us to create an awesome library of components! 31 | 32 | - [ReactJs](https://facebook.github.io/react/) v16 33 | - Type checking with [PropTypes](https://www.npmjs.com/package/prop-types) 34 | - [styled-components](https://styled-components.com/) for styling components and application 35 | - Compiling of modern JavaScript with [Babel](https://github.com/babel/babel) and bundling with [Webpack](https://webpack.js.org/) 36 | - [Jest](https://jestjs.io/) and [Testing library](https://testing-library.com/) for unit/ui testing 37 | - Automated Git hooks with [Husky](https://github.com/typicode/husky) 38 | - Code linting using [Eslint](https://github.com/eslint/eslint) 39 | - Code formatter using [Prettier](https://prettier.io/) 40 | - Developing isolated UI components with [Storybook](https://storybook.js.org/) 41 | 42 | ## :rocket: Getting Started 43 | 44 | To get started you need to meet the prerequisites, and then follow the installation instructions. 45 | 46 | #### Figma design tokens example 47 | 48 | **Figma file:** [https://www.figma.com/file/IGr2xoqcZX91CU7CDr4ZsI](https://www.figma.com/file/IGr2xoqcZX91CU7CDr4ZsI) 49 | 50 | For more info on configuring your design tokens file, visit ["How to configure design tokens with Figma API"](https://pattern-library-skeleton.netlify.com/?path=/docs/overview-intro--page) 51 | 52 | #### Installing 53 | 54 | You can clone our Git repository: 55 | 56 | `$ git clone git@github.com:klaufel/pattern-library-skeleton.git` 57 | 58 | #### Wiring up your development environment 59 | 60 | Hooking it up is as easy as running: 61 | 62 | `$ npm run install` 63 | 64 | This command will install all the required dependencies. Please note that `npm install` is only required on your first start, or in case of updated dependencies. 65 | 66 | #### Initializing Storybook 67 | 68 | `$ npm run storybook` 69 | 70 | #### Generate design tokens as variables 71 | 72 | `$ npm run tokens` 73 | 74 | ## :triangular_ruler: Architecture 75 | 76 | Based on the [Atomic Design](https://bradfrost.com/blog/post/atomic-web-design/) principles, a methodology for creating design systems, there are five distinct levels of components: 77 | 78 | - Atomic Design component structure: 79 | - Atoms 80 | - Molecules 81 | - Organism 82 | - Templates 83 | - Pages 84 | 85 | When we use a UI library, the highest abstraction of components that we expose would be an `organism`. The rest of the `template` and `page` components are built within the application that imports the library. 86 | 87 | ##### Source project structure: 88 | 89 | ``` 90 | └── src 91 | ├── components 92 | │ ├── atoms 93 | │ ├── molecules 94 | │ ├── organism 95 | │ └── pages * 96 | ├── docs 97 | ├── figma-tokens 98 | ├── styles 99 | └── index.js (entry point) 100 | ``` 101 | 102 | - `src`: The place where we put our application source code - `components` Add your components here! This folder is divided from [Atomic Design](https://bradfrost.com/blog/post/atomic-web-design/) principles. 103 | - `docs` Our documentation as stories for the design system. 104 | - `figma-tokens` Directory containing functions to generate figma design tokens with API. 105 | - `styles` Directory to add global styles and theme to build components. 106 | - `index.js` Entry point, import all components and export to generate package to use in project as a dependency. 107 | 108 | --- 109 | 110 | ##### Example of `component` structure 111 | 112 | ``` 113 | └── MyComponent 114 | ├── __stories__ 115 | │ └── MyComponent.stories.{js|mdx} 116 | ├── __tests__ 117 | │ ├── __snapshots__ 118 | │ │ └── MyComponent.test.js.snap 119 | │ └── MyComponent.test.js 120 | ├── MyComponent.styles.js 121 | └── index.js 122 | ``` 123 | 124 | - **mycomponent**: Directory containing our component. 125 | - `__stories__`: Directory containing the stories for Storybook. 126 | - `MyComponent.stories.js`: File containing the component stories. 127 | - `__tests__`: Directory containing the tests for Jest. 128 | - `__snapshots__`: Directory containing the autogenerated Jest Snapshots. 129 | - `MyComponent.test.js.snap`: Autogenerated Snapshot file. 130 | - `MyComponent.test.js`: File containing the component tests. 131 | - `MyComponent.styles.js`: File containing the component styles (styled-components / CSS-in-JS). 132 | - `index.js`: File containing the React component, HTML or other imports from ui-library. 133 | 134 | ## :nail_care: Guidelines 135 | 136 | ###### Linting 137 | 138 | `$ npm run lint` Find problems in your code `(js)` 139 | 140 | ###### Formatter 141 | 142 | `$ npm run prettier:check` Find format problems in your code. 143 | 144 | `$ npm run prettier:write` Fix format problems in your code. 145 | 146 | ## :pray: Testing the application 147 | 148 | [Jest](https://jestjs.io/), a delightful javascript testing framework and [Testing Library](https://testing-library.com/) build on top of DOM testing library by adding APIs for working with React components. 149 | 150 | #### Running your tests 151 | 152 | `$ npm run test` Will perform your unit testing. 153 | 154 | `$ npm run test:update` Will perform your unit testing and update snapshots. 155 | 156 | `$ npm run test:watch` Will perform your unit testing and watchers tests. 157 | 158 | `$ npm run test:coverage` Will perform your unit testing and show coverage. 159 | 160 | `$ npm run test:coverage-web` Will perform your unit testing, show coverage, and open the report in your default browser. 161 | -------------------------------------------------------------------------------- /src/components/pages/ZapatillasFromMars/ZapatillasFromMars.styles.js: -------------------------------------------------------------------------------- 1 | import styled, {createGlobalStyle} from 'styled-components' 2 | 3 | export const GlobalStyle = createGlobalStyle` 4 | 5 | :root { 6 | --dark-bg: ${props => props.theme.colors.primary.dark}; 7 | --mark: ${props => props.theme.colors.primary.light}; 8 | --bg: ${props => props.theme.colors.primary.main}; 9 | --manatee: ${props => props.theme.colors.neutral.percent20}; 10 | --alto: ${props => props.theme.colors.neutral.percent05}; 11 | --white: ${props => props.theme.colors.neutral.percent00}; 12 | } 13 | 14 | @font-face { 15 | font-family: 'Px Grotesk'; 16 | src: url('https://www.uifrommars.com/zapatillas/fonts/Px-Grotesk-Bold.woff2') format('woff2'); 17 | font-weight: 700; 18 | font-style: normal; 19 | } 20 | 21 | * { 22 | margin: 0; 23 | padding: 0; 24 | box-sizing: border-box; 25 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 26 | -webkit-font-smoothing: antialiased; 27 | -moz-osx-font-smoothing: grayscale; 28 | } 29 | 30 | body, 31 | .sbdocs.sbdocs-preview div[id^="story--pages"] { 32 | background-color: var(--dark-bg); 33 | font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Helvetica, Arial, sans-serif; 34 | font-weight: 600; 35 | font-size: ${props => props.theme.typography.body.normal.fontSize}; 36 | color: var(--manatee); 37 | } 38 | ` 39 | 40 | export const Wrapper = styled.div` 41 | margin: -16px; 42 | 43 | p > span { 44 | color: var(--white); 45 | } 46 | 47 | h1 { 48 | font-family: 'Px Grotesk', Helvetica, Arial, sans-serif; 49 | font-weight: ${props => props.theme.typography.heading.big.fontWeight}; 50 | font-size: ${props => props.theme.typography.heading.big.fontSize}; 51 | line-height: ${props => props.theme.typography.heading.big.lineHeight}; 52 | color: var(--white); 53 | } 54 | 55 | table, 56 | p { 57 | display: inline-block; 58 | font-size: ${props => props.theme.typography.body.normal.fontSize}; 59 | margin-bottom: 1.5rem; 60 | } 61 | 62 | table { 63 | display: inline-table; 64 | } 65 | 66 | mark { 67 | background-color: var(--mark); 68 | color: var(--white); 69 | padding: 0.125rem 0.5rem 0.25rem; 70 | } 71 | 72 | table { 73 | border-collapse: collapse; 74 | margin: 0; 75 | padding: 0; 76 | width: 100%; 77 | table-layout: fixed; 78 | } 79 | 80 | table caption { 81 | font-size: 1.5em; 82 | margin: 0.5em 0 0.75em; 83 | } 84 | 85 | table tr { 86 | border-bottom: 1px solid var(--manatee); 87 | padding: 0.35em; 88 | } 89 | 90 | table th, 91 | table td { 92 | padding: 0.625em; 93 | text-align: left; 94 | } 95 | 96 | table th { 97 | color: var(--white); 98 | } 99 | 100 | @media (max-width: 768px) { 101 | table { 102 | border: 0; 103 | } 104 | 105 | table caption { 106 | font-size: 1.3em; 107 | } 108 | 109 | table thead { 110 | border: none; 111 | clip: rect(0 0 0 0); 112 | height: 1px; 113 | margin: -1px; 114 | overflow: hidden; 115 | padding: 0; 116 | position: absolute; 117 | width: 1px; 118 | } 119 | 120 | table th, 121 | table td { 122 | padding-left: 0; 123 | padding-right: 0; 124 | } 125 | 126 | table tr { 127 | border-bottom: 1px solid var(--manatee); 128 | display: block; 129 | margin-bottom: 1.5rem; 130 | } 131 | 132 | table td { 133 | border-bottom: 1px solid var(--manatee); 134 | display: block; 135 | text-align: left; 136 | } 137 | 138 | table td::before { 139 | /* 140 | * aria-label has no advantage, it won't be read inside a table 141 | content: attr(aria-label); 142 | */ 143 | /* content: attr(data-label); */ 144 | float: left; 145 | color: var(--white); 146 | } 147 | 148 | table td:first-child { 149 | color: var(--white); 150 | border-bottom: 0; 151 | padding-bottom: 0; 152 | } 153 | 154 | table td:nth-child(2) { 155 | border-bottom: 0; 156 | padding-bottom: 0; 157 | } 158 | 159 | table td:last-child { 160 | border-bottom: 0; 161 | } 162 | } 163 | 164 | a.button { 165 | background-color: var(--alto); 166 | color: #111; 167 | display: block; 168 | margin: 1.5rem 0 0 0; 169 | padding: 1rem 5.5rem; 170 | border-radius: 0.5rem; 171 | width: auto; 172 | text-align: center; 173 | text-decoration: none; 174 | animation: none; 175 | position: relative; 176 | transition: all 0.2s ease-out; 177 | } 178 | 179 | a.button:hover { 180 | background: var(--white); 181 | transform: translateY(-2px); 182 | transition: all 0.2s ease-out; 183 | } 184 | 185 | section.intro, 186 | section.schedule, 187 | footer { 188 | display: flex; 189 | flex-flow: row wrap; 190 | justify-content: center; 191 | margin: 0; 192 | height: auto; 193 | } 194 | 195 | div.wrap { 196 | display: flex; 197 | flex-flow: row wrap; 198 | padding-left: 1rem; 199 | padding-right: 1rem; 200 | margin: 5.5rem 0; 201 | width: 1366px; 202 | justify-content: center; 203 | } 204 | 205 | div.wrap:first-of-type { 206 | margin: 8.75rem 0 5.5rem 0; 207 | } 208 | 209 | div.title { 210 | flex: 1 1 100%; 211 | margin-bottom: 20px; 212 | } 213 | 214 | div.explanation { 215 | flex: 1 0 48%; 216 | height: auto; 217 | order: 1; 218 | margin: 0 1rem 0 0; 219 | } 220 | 221 | div.form { 222 | flex: 1 0 48%; 223 | height: auto; 224 | order: 2; 225 | margin: 0 0 0 1rem; 226 | } 227 | 228 | div.credits { 229 | display: flex; 230 | flex-direction: row; 231 | margin: 1rem 0 0 0; 232 | } 233 | 234 | div.credits > a img { 235 | border: 0; 236 | margin-right: 2rem; 237 | } 238 | 239 | div.credits > img:first-of-type { 240 | margin-right: 2.5rem; 241 | } 242 | 243 | div.credits > a:hover img { 244 | opacity: 0.5; 245 | } 246 | 247 | section.schedule { 248 | background-color: var(--bg); 249 | } 250 | 251 | div.table-wrapper { 252 | max-width: 70%; 253 | min-width: 70%; 254 | overflow-x: auto; 255 | overflow-y: hidden; 256 | } 257 | 258 | footer a { 259 | color: var(--white); 260 | } 261 | 262 | footer a:hover { 263 | text-decoration: none; 264 | } 265 | 266 | .bounce { 267 | animation: bounce 5s infinite; 268 | } 269 | 270 | @keyframes bounce { 271 | 0%, 272 | 25%, 273 | 50%, 274 | 75%, 275 | 100% { 276 | transform: translateY(0); 277 | } 278 | 40% { 279 | transform: translateY(-8px); 280 | } 281 | 60% { 282 | transform: translateY(-8px); 283 | } 284 | } 285 | 286 | @media (max-width: 768px) { 287 | div.wrap { 288 | margin: 2.5rem 0; 289 | } 290 | div.wrap:first-of-type { 291 | margin: 3.5rem 0; 292 | } 293 | div.title { 294 | margin: 0; 295 | } 296 | div.explanation, 297 | div.title, 298 | div.form { 299 | flex: 1 1 100%; 300 | padding-right: 0; 301 | } 302 | div.credits { 303 | margin: 1rem 0 1.5rem 0; 304 | } 305 | div.credits > img:first-of-type { 306 | display: none; 307 | } 308 | h1 { 309 | font-size: 1.5rem; 310 | } 311 | p { 312 | font-size: 1rem; 313 | } 314 | table { 315 | font-size: 1rem; 316 | } 317 | div.table-wrapper { 318 | min-width: 100%; 319 | } 320 | mark { 321 | padding: 0.125rem 0.25rem 0.125rem; 322 | } 323 | div.cookieinfo span { 324 | font-size: 0.75rem; 325 | } 326 | div.cookieinfo-close { 327 | float: none !important; 328 | } 329 | } 330 | ` 331 | -------------------------------------------------------------------------------- /src/components/atoms/Button/__tests__/__snapshots__/Button.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Button it works default 1`] = ` 4 | .c0 { 5 | -webkit-align-items: center; 6 | -webkit-box-align: center; 7 | -ms-flex-align: center; 8 | align-items: center; 9 | border-radius: 4px; 10 | cursor: pointer; 11 | display: -webkit-box; 12 | display: -webkit-flex; 13 | display: -ms-flexbox; 14 | display: flex; 15 | font-size: 16px; 16 | line-height: 20px; 17 | font-family: inherit; 18 | outline: none; 19 | border: 1px solid transparent; 20 | padding: 16px 24px; 21 | background-color: #2587b8; 22 | color: #ffffff; 23 | -webkit-transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 24 | transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 25 | } 26 | 27 | .c0:hover, 28 | .c0:active { 29 | background-color: #56a4c9; 30 | } 31 | 32 | .c0:active { 33 | box-shadow: 0 0 4px #56a4c9; 34 | } 35 | 36 | .c0:disabled { 37 | cursor: not-allowed; 38 | opacity: 0.5; 39 | } 40 | 41 | .c0:disabled:hover { 42 | background-color: #2587b8; 43 | } 44 | 45 | 50 | `; 51 | 52 | exports[`Button it works disabled 1`] = ` 53 | .c0 { 54 | -webkit-align-items: center; 55 | -webkit-box-align: center; 56 | -ms-flex-align: center; 57 | align-items: center; 58 | border-radius: 4px; 59 | cursor: pointer; 60 | display: -webkit-box; 61 | display: -webkit-flex; 62 | display: -ms-flexbox; 63 | display: flex; 64 | font-size: 16px; 65 | line-height: 20px; 66 | font-family: inherit; 67 | outline: none; 68 | border: 1px solid transparent; 69 | padding: 16px 24px; 70 | background-color: #2587b8; 71 | color: #ffffff; 72 | -webkit-transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 73 | transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 74 | } 75 | 76 | .c0:hover, 77 | .c0:active { 78 | background-color: #56a4c9; 79 | } 80 | 81 | .c0:active { 82 | box-shadow: 0 0 4px #56a4c9; 83 | } 84 | 85 | .c0:disabled { 86 | cursor: not-allowed; 87 | opacity: 0.5; 88 | } 89 | 90 | .c0:disabled:hover { 91 | background-color: #2587b8; 92 | } 93 | 94 | 100 | `; 101 | 102 | exports[`Button it works with ghost and disabled variation 1`] = ` 103 | .c0 { 104 | -webkit-align-items: center; 105 | -webkit-box-align: center; 106 | -ms-flex-align: center; 107 | align-items: center; 108 | border-radius: 4px; 109 | cursor: pointer; 110 | display: -webkit-box; 111 | display: -webkit-flex; 112 | display: -ms-flexbox; 113 | display: flex; 114 | font-size: 16px; 115 | line-height: 20px; 116 | font-family: inherit; 117 | outline: none; 118 | border: 1px solid transparent; 119 | padding: 16px 24px; 120 | background-color: #2587b8; 121 | color: #ffffff; 122 | -webkit-transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 123 | transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 124 | background-color: #ffffff; 125 | color: #333333; 126 | } 127 | 128 | .c0:hover, 129 | .c0:active { 130 | background-color: #56a4c9; 131 | } 132 | 133 | .c0:active { 134 | box-shadow: 0 0 4px #56a4c9; 135 | } 136 | 137 | .c0:disabled { 138 | cursor: not-allowed; 139 | opacity: 0.5; 140 | } 141 | 142 | .c0:disabled:hover { 143 | background-color: #2587b8; 144 | } 145 | 146 | .c0:hover, 147 | .c0:active { 148 | background-color: #f2f2f2; 149 | } 150 | 151 | .c0:disabled:hover { 152 | background-color: #ffffff; 153 | } 154 | 155 | 161 | `; 162 | 163 | exports[`Button it works with ghost variation 1`] = ` 164 | .c0 { 165 | -webkit-align-items: center; 166 | -webkit-box-align: center; 167 | -ms-flex-align: center; 168 | align-items: center; 169 | border-radius: 4px; 170 | cursor: pointer; 171 | display: -webkit-box; 172 | display: -webkit-flex; 173 | display: -ms-flexbox; 174 | display: flex; 175 | font-size: 16px; 176 | line-height: 20px; 177 | font-family: inherit; 178 | outline: none; 179 | border: 1px solid transparent; 180 | padding: 16px 24px; 181 | background-color: #2587b8; 182 | color: #ffffff; 183 | -webkit-transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 184 | transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 185 | background-color: #ffffff; 186 | color: #333333; 187 | } 188 | 189 | .c0:hover, 190 | .c0:active { 191 | background-color: #56a4c9; 192 | } 193 | 194 | .c0:active { 195 | box-shadow: 0 0 4px #56a4c9; 196 | } 197 | 198 | .c0:disabled { 199 | cursor: not-allowed; 200 | opacity: 0.5; 201 | } 202 | 203 | .c0:disabled:hover { 204 | background-color: #2587b8; 205 | } 206 | 207 | .c0:hover, 208 | .c0:active { 209 | background-color: #f2f2f2; 210 | } 211 | 212 | .c0:disabled:hover { 213 | background-color: #ffffff; 214 | } 215 | 216 | 221 | `; 222 | 223 | exports[`Button it works with secondary and disabled variation 1`] = ` 224 | .c0 { 225 | -webkit-align-items: center; 226 | -webkit-box-align: center; 227 | -ms-flex-align: center; 228 | align-items: center; 229 | border-radius: 4px; 230 | cursor: pointer; 231 | display: -webkit-box; 232 | display: -webkit-flex; 233 | display: -ms-flexbox; 234 | display: flex; 235 | font-size: 16px; 236 | line-height: 20px; 237 | font-family: inherit; 238 | outline: none; 239 | border: 1px solid transparent; 240 | padding: 16px 24px; 241 | background-color: #2587b8; 242 | color: #ffffff; 243 | -webkit-transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 244 | transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 245 | background-color: #ffffff; 246 | border-color: #cccccc; 247 | color: #333333; 248 | } 249 | 250 | .c0:hover, 251 | .c0:active { 252 | background-color: #56a4c9; 253 | } 254 | 255 | .c0:active { 256 | box-shadow: 0 0 4px #56a4c9; 257 | } 258 | 259 | .c0:disabled { 260 | cursor: not-allowed; 261 | opacity: 0.5; 262 | } 263 | 264 | .c0:disabled:hover { 265 | background-color: #2587b8; 266 | } 267 | 268 | .c0:hover, 269 | .c0:active { 270 | background-color: #f2f2f2; 271 | } 272 | 273 | .c0:disabled:hover { 274 | background-color: #ffffff; 275 | } 276 | 277 | 283 | `; 284 | 285 | exports[`Button it works with secondary variation 1`] = ` 286 | .c0 { 287 | -webkit-align-items: center; 288 | -webkit-box-align: center; 289 | -ms-flex-align: center; 290 | align-items: center; 291 | border-radius: 4px; 292 | cursor: pointer; 293 | display: -webkit-box; 294 | display: -webkit-flex; 295 | display: -ms-flexbox; 296 | display: flex; 297 | font-size: 16px; 298 | line-height: 20px; 299 | font-family: inherit; 300 | outline: none; 301 | border: 1px solid transparent; 302 | padding: 16px 24px; 303 | background-color: #2587b8; 304 | color: #ffffff; 305 | -webkit-transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 306 | transition: color 0.2s,background-color 0.2s,box-shadow 0.2s; 307 | background-color: #ffffff; 308 | border-color: #cccccc; 309 | color: #333333; 310 | } 311 | 312 | .c0:hover, 313 | .c0:active { 314 | background-color: #56a4c9; 315 | } 316 | 317 | .c0:active { 318 | box-shadow: 0 0 4px #56a4c9; 319 | } 320 | 321 | .c0:disabled { 322 | cursor: not-allowed; 323 | opacity: 0.5; 324 | } 325 | 326 | .c0:disabled:hover { 327 | background-color: #2587b8; 328 | } 329 | 330 | .c0:hover, 331 | .c0:active { 332 | background-color: #f2f2f2; 333 | } 334 | 335 | .c0:disabled:hover { 336 | background-color: #ffffff; 337 | } 338 | 339 | 344 | `; 345 | -------------------------------------------------------------------------------- /src/components/pages/ZapatillasFromMars/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {GlobalStyle, Wrapper} from './ZapatillasFromMars.styles' 3 | 4 | const ZapatillasFromMars = () => ( 5 | <> 6 | 7 | 8 |
9 |
10 |
11 |

#zapatillasFromMars 👟🚀

12 |
13 |
14 |

15 | Qué 👉 Aprovechando que tod@s estamos en casa y que 16 | hay varios eventos cancelados, pensé… ¿por qué no aprovechar estos 17 | contenidos y montar un pequeño evento online? 18 |

19 |

20 | Hemos organizado evento gratuito en remoto, con 13 charlas de 30 21 | minutos sobre UI, UX, SEO, performance, neurociencia, creative 22 | coding, CRO… 23 |

24 |
25 | Ir al programa 33 | 40 | uiFromMars 47 | 48 | 55 | Holaluz 62 | 63 |
64 |
65 |
66 |

67 | Cuándo 👉 Sábado 11 de Abril a las 15h hora española 68 | (en remoto). 69 |

70 |

71 | Sigue a uiFromMars en Twitch y recibirás una notificación cuando 72 | empiece el directo 😉 73 |
74 | 81 | Accede a Twitch 82 | 83 |

84 |
85 |
86 |
87 | 88 |
89 |
90 |
91 | 92 | 93 | 94 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 113 | 114 | 115 | 116 | 117 | 120 | 121 | 122 | 123 | 124 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 168 | 169 | 170 | 171 | 172 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 |
95 | Hora 96 | PonenteCharla
15:00hCris BusquetsBienvenida
15:30hSeñor Muñoz 111 | Por qué los SEOs no quieren tantos enlaces 112 |
16:00hCristina Santamarina 118 | Diseño en interfaces conversacionales 119 |
16:30hJoan León 125 | Herramientas de Optimización de Imágenes para diseñadores 126 |
17:00hAlberto García ArizaMás de 50 años de Creative Coding
17:30hJavier Velilla 137 | ¿Cómo afecta el ciclo de vida de tu producto a tu marca? 138 |
18:00hJuan Carlos RuizDesign tokens con superpoderes
18:30hNoemi Cortizas Martínez 149 | CMF: Diseño sensorial o UX fisico/organico 150 |
19:00hLo de ProductoLo de lanzar un SaaS en 30 días
19:30hmeri FernandezNeurociencia y UX
20:00hLuz de León 166 | Metodología: diseño de un plan de investigación 167 |
20:30hÁlvaro Bernal 173 | Diseñar como freelance sin morir en el intento 174 |
21:00hFani SánchezCRO y Diseño basado en datos
21:30hSergio de la Casa 185 | El contrato con el usuario y sus variaciones en tiempos de 186 | crisis 187 |
22:00hCris BusquetsDespedida y cierre
196 |
197 |
198 |
199 | 200 | 225 |
226 | 227 | ) 228 | 229 | export default ZapatillasFromMars 230 | -------------------------------------------------------------------------------- /src/styles/GlobalStyle/index.js: -------------------------------------------------------------------------------- 1 | import {createGlobalStyle} from 'styled-components' 2 | 3 | const GlobalStyle = createGlobalStyle` 4 | 5 | /* Fonts 6 | ========================================================================== */ 7 | 8 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700'); 9 | 10 | 11 | /* Document 12 | ========================================================================== */ 13 | 14 | /** 15 | * 1. Correct the line height in all browsers. 16 | * 2. Prevent adjustments of font size after orientation changes in 17 | * IE on Windows Phone and in iOS. 18 | */ 19 | 20 | html { 21 | line-height: 1.15; /* 1 */ 22 | -ms-text-size-adjust: 100%; /* 2 */ 23 | -webkit-text-size-adjust: 100%; /* 2 */ 24 | } 25 | 26 | /* Sections 27 | ========================================================================== */ 28 | 29 | /** 30 | * Add the correct display in IE 9-. 31 | */ 32 | 33 | article, 34 | aside, 35 | footer, 36 | header, 37 | nav, 38 | section { 39 | display: block; 40 | } 41 | 42 | /** 43 | * Correct the font size and margin on 'h1' elements within 'section' and 44 | * 'article' contexts in Chrome, Firefox, and Safari. 45 | */ 46 | 47 | h1 { 48 | font-size: 2em; 49 | margin: 0.67em 0; 50 | } 51 | 52 | /* Grouping content 53 | ========================================================================== */ 54 | 55 | /** 56 | * Add the correct display in IE 9-. 57 | * 1. Add the correct display in IE. 58 | */ 59 | 60 | figcaption, 61 | figure, 62 | main { /* 1 */ 63 | display: block; 64 | } 65 | 66 | /** 67 | * Add the correct margin in IE 8. 68 | */ 69 | 70 | figure { 71 | margin: 1em 40px; 72 | } 73 | 74 | /** 75 | * 1. Add the correct box sizing in Firefox. 76 | * 2. Show the overflow in Edge and IE. 77 | */ 78 | 79 | hr { 80 | box-sizing: content-box; /* 1 */ 81 | height: 0; /* 1 */ 82 | overflow: visible; /* 2 */ 83 | } 84 | 85 | /** 86 | * 1. Correct the inheritance and scaling of font size in all browsers. 87 | * 2. Correct the odd 'em' font sizing in all browsers. 88 | */ 89 | 90 | pre { 91 | font-family: monospace, monospace; /* 1 */ 92 | font-size: 1em; /* 2 */ 93 | } 94 | 95 | /* Text-level semantics 96 | ========================================================================== */ 97 | 98 | /** 99 | * 1. Remove the gray background on active links in IE 10. 100 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 101 | */ 102 | 103 | a { 104 | background-color: transparent; /* 1 */ 105 | -webkit-text-decoration-skip: objects; /* 2 */ 106 | } 107 | 108 | /** 109 | * 1. Remove the bottom border in Chrome 57- and Firefox 39-. 110 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 111 | */ 112 | 113 | abbr[title] { 114 | border-bottom: none; /* 1 */ 115 | text-decoration: underline; /* 2 */ 116 | text-decoration: underline dotted; /* 2 */ 117 | } 118 | 119 | /** 120 | * Prevent the duplicate application of 'bolder' by the next rule in Safari 6. 121 | */ 122 | 123 | b, 124 | strong { 125 | font-weight: inherit; 126 | } 127 | 128 | /** 129 | * Add the correct font weight in Chrome, Edge, and Safari. 130 | */ 131 | 132 | b, 133 | strong { 134 | font-weight: bolder; 135 | } 136 | 137 | /** 138 | * 1. Correct the inheritance and scaling of font size in all browsers. 139 | * 2. Correct the odd 'em' font sizing in all browsers. 140 | */ 141 | 142 | code, 143 | kbd, 144 | samp { 145 | font-family: monospace, monospace; /* 1 */ 146 | font-size: 1em; /* 2 */ 147 | } 148 | 149 | /** 150 | * Add the correct font style in Android 4.3-. 151 | */ 152 | 153 | dfn { 154 | font-style: italic; 155 | } 156 | 157 | /** 158 | * Add the correct background and color in IE 9-. 159 | */ 160 | 161 | mark { 162 | background-color: #ff0; 163 | color: #000; 164 | } 165 | 166 | /** 167 | * Add the correct font size in all browsers. 168 | */ 169 | 170 | small { 171 | font-size: 80%; 172 | } 173 | 174 | /** 175 | * Prevent 'sub' and 'sup' elements from affecting the line height in 176 | * all browsers. 177 | */ 178 | 179 | sub, 180 | sup { 181 | font-size: 75%; 182 | line-height: 0; 183 | position: relative; 184 | vertical-align: baseline; 185 | } 186 | 187 | sub { 188 | bottom: -0.25em; 189 | } 190 | 191 | sup { 192 | top: -0.5em; 193 | } 194 | 195 | /* Embedded content 196 | ========================================================================== */ 197 | 198 | /** 199 | * Add the correct display in IE 9-. 200 | */ 201 | 202 | audio, 203 | video { 204 | display: inline-block; 205 | } 206 | 207 | /** 208 | * Add the correct display in iOS 4-7. 209 | */ 210 | 211 | audio:not([controls]) { 212 | display: none; 213 | height: 0; 214 | } 215 | 216 | /** 217 | * Remove the border on images inside links in IE 10-. 218 | */ 219 | 220 | img { 221 | border-style: none; 222 | } 223 | 224 | /** 225 | * Hide the overflow in IE. 226 | */ 227 | 228 | svg:not(:root) { 229 | overflow: hidden; 230 | } 231 | 232 | /* Forms 233 | ========================================================================== */ 234 | 235 | /** 236 | * Remove the margin in Firefox and Safari. 237 | */ 238 | 239 | button, 240 | input, 241 | optgroup, 242 | select, 243 | textarea { 244 | margin: 0; 245 | } 246 | 247 | /** 248 | * Show the overflow in IE. 249 | * 1. Show the overflow in Edge. 250 | */ 251 | 252 | button, 253 | input { /* 1 */ 254 | overflow: visible; 255 | } 256 | 257 | /** 258 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 259 | * 1. Remove the inheritance of text transform in Firefox. 260 | */ 261 | 262 | button, 263 | select { /* 1 */ 264 | text-transform: none; 265 | } 266 | 267 | /** 268 | * 1. Prevent a WebKit bug where (2) destroys native 'audio' and 'video' 269 | * controls in Android 4. 270 | * 2. Correct the inability to style clickable types in iOS and Safari. 271 | */ 272 | 273 | button, 274 | html [type="button"], /* 1 */ 275 | [type="reset"], 276 | [type="submit"] { 277 | -webkit-appearance: button; /* 2 */ 278 | } 279 | 280 | /** 281 | * Remove the inner border and padding in Firefox. 282 | */ 283 | 284 | button::-moz-focus-inner, 285 | [type="button"]::-moz-focus-inner, 286 | [type="reset"]::-moz-focus-inner, 287 | [type="submit"]::-moz-focus-inner { 288 | border-style: none; 289 | padding: 0; 290 | } 291 | 292 | /** 293 | * Restore the focus styles unset by the previous rule. 294 | */ 295 | 296 | button:-moz-focusring, 297 | [type="button"]:-moz-focusring, 298 | [type="reset"]:-moz-focusring, 299 | [type="submit"]:-moz-focusring { 300 | outline: 1px dotted ButtonText; 301 | } 302 | 303 | /** 304 | * 1. Correct the text wrapping in Edge and IE. 305 | * 2. Correct the color inheritance from 'fieldset' elements in IE. 306 | * 3. Remove the padding so developers are not caught out when they zero out 307 | * 'fieldset' elements in all browsers. 308 | */ 309 | 310 | legend { 311 | box-sizing: border-box; /* 1 */ 312 | color: inherit; /* 2 */ 313 | display: table; /* 1 */ 314 | max-width: 100%; /* 1 */ 315 | padding: 0; /* 3 */ 316 | white-space: normal; /* 1 */ 317 | } 318 | 319 | /** 320 | * 1. Add the correct display in IE 9-. 321 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. 322 | */ 323 | 324 | progress { 325 | display: inline-block; /* 1 */ 326 | vertical-align: baseline; /* 2 */ 327 | } 328 | 329 | /** 330 | * Remove the default vertical scrollbar in IE. 331 | */ 332 | 333 | textarea { 334 | overflow: auto; 335 | } 336 | 337 | /** 338 | * 1. Add the correct box sizing in IE 10-. 339 | * 2. Remove the padding in IE 10-. 340 | */ 341 | 342 | [type="checkbox"], 343 | [type="radio"] { 344 | box-sizing: border-box; /* 1 */ 345 | padding: 0; /* 2 */ 346 | } 347 | 348 | /** 349 | * Correct the cursor style of increment and decrement buttons in Chrome. 350 | */ 351 | 352 | [type="number"]::-webkit-inner-spin-button, 353 | [type="number"]::-webkit-outer-spin-button { 354 | height: auto; 355 | } 356 | 357 | /** 358 | * 1. Correct the odd appearance in Chrome and Safari. 359 | * 2. Correct the outline style in Safari. 360 | */ 361 | 362 | [type="search"] { 363 | -webkit-appearance: textfield; /* 1 */ 364 | outline-offset: -2px; /* 2 */ 365 | } 366 | 367 | /** 368 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. 369 | */ 370 | 371 | [type="search"]::-webkit-search-cancel-button, 372 | [type="search"]::-webkit-search-decoration { 373 | -webkit-appearance: none; 374 | } 375 | 376 | /** 377 | * 1. Correct the inability to style clickable types in iOS and Safari. 378 | * 2. Change font properties to 'inherit' in Safari. 379 | */ 380 | 381 | ::-webkit-file-upload-button { 382 | -webkit-appearance: button; /* 1 */ 383 | font: inherit; /* 2 */ 384 | } 385 | 386 | /* Interactive 387 | ========================================================================== */ 388 | 389 | /* 390 | * Add the correct display in IE 9-. 391 | * 1. Add the correct display in Edge, IE, and Firefox. 392 | */ 393 | 394 | details, /* 1 */ 395 | menu { 396 | display: block; 397 | } 398 | 399 | /* 400 | * Add the correct display in all browsers. 401 | */ 402 | 403 | summary { 404 | display: list-item; 405 | } 406 | 407 | /* Scripting 408 | ========================================================================== */ 409 | 410 | /** 411 | * Add the correct display in IE 9-. 412 | */ 413 | 414 | canvas { 415 | display: inline-block; 416 | } 417 | 418 | /** 419 | * Add the correct display in IE. 420 | */ 421 | 422 | template { 423 | display: none; 424 | } 425 | 426 | /* Hidden 427 | ========================================================================== */ 428 | 429 | /** 430 | * Add the correct display in IE 10-. 431 | */ 432 | 433 | [hidden] { 434 | display: none; 435 | } 436 | 437 | * { 438 | box-sizing: border-box; 439 | } 440 | 441 | 442 | /* Box sizing 443 | ========================================================================== */ 444 | 445 | html { 446 | box-sizing: border-box; 447 | } 448 | 449 | * { 450 | &, 451 | &:before, 452 | &:after { 453 | box-sizing: inherit; 454 | } 455 | } 456 | 457 | /* Global 458 | ========================================================================== */ 459 | 460 | body { 461 | -webkit-font-smoothing: antialiased; 462 | -moz-osx-font-smoothing: grayscale; 463 | font-family: ${props => props.theme.typography.global.family}, sans-serif; 464 | margin: 0; 465 | padding: 0; 466 | background: ${props => props.theme.colors.neutral.percent00}; 467 | font-size: ${props => props.theme.typography.body.normal.fontSize}; 468 | line-height: ${props => props.theme.typography.body.normal.lineHeight}; 469 | } 470 | 471 | * { 472 | -webkit-tap-highlight-color: transparent; 473 | } 474 | 475 | 476 | h1, 477 | h2, 478 | h3, 479 | h4, 480 | h5, 481 | h6 { 482 | font-size: inherit; 483 | font-weight: 700; 484 | margin-top: 0; 485 | } 486 | 487 | p { 488 | margin: 0; 489 | margin-bottom: ${props => props.theme.spacing.md}; 490 | } 491 | 492 | a { 493 | transition: color .3s; 494 | 495 | &:hover { 496 | color: ${props => props.theme.colors.primary.dark}; 497 | } 498 | } 499 | ` 500 | 501 | export default GlobalStyle 502 | --------------------------------------------------------------------------------