From 083646f3810a90b09a4cbb4c0e535edc874d1acf Mon Sep 17 00:00:00 2001 From: Penple03 Date: Wed, 7 Nov 2018 21:24:20 -0800 Subject: [PATCH 01/20] Begin work on moving to a CSS-in-JS model. --- demo/web/App.jsx | 122 ++++++++++++++++++++++++---------------------- lib/Animations.js | 49 +++++++++++++++++++ lib/Themes.js | 30 ++++++++++++ package.json | 4 +- web/Badge.jsx | 44 +++++++++++++++-- yarn.lock | 100 +++++++++++++++++++++++-------------- 6 files changed, 248 insertions(+), 101 deletions(-) create mode 100644 lib/Animations.js create mode 100644 lib/Themes.js diff --git a/demo/web/App.jsx b/demo/web/App.jsx index eb8487c..13b7762 100644 --- a/demo/web/App.jsx +++ b/demo/web/App.jsx @@ -4,6 +4,10 @@ import {HashRouter, Link, Route, Switch} from 'react-router-dom' import React from 'react' import { render } from 'react-dom' +import {ThemeProvider} from 'styled-components' + +import {light} from '../../lib/Themes' + import Github from './Github' import Home from './Home' import SASS from './SASS' @@ -41,66 +45,68 @@ class App extends React.Component { render () { return ( - -
- - Home - - - - SASS - Source Code - - Badge - Button - Card - Chart - Checkbox/Switch - Grid - Menu - Modal - Pagination - Panel - Progress - Radio - Select Input - Stepper - Tab - Table - Text Input - Tooltip - Typography - -
- - - - - - - - - - - - - - - - - - - - + + +
+ + Home + + + + SASS + Source Code + + Badge + Button + Card + Chart + Checkbox/Switch + Grid + Menu + Modal + Pagination + Panel + Progress + Radio + Select Input + Stepper + Tab + Table + Text Input + Tooltip + Typography + +
+ + + + + + + + + + + + + + + + + + + + - - - - + + + + +
+
-
-
- + + ) } } diff --git a/lib/Animations.js b/lib/Animations.js new file mode 100644 index 0000000..229b61e --- /dev/null +++ b/lib/Animations.js @@ -0,0 +1,49 @@ +import {keyframes, css} from 'styled-components' + +export const pulse = color => props => keyframes` + 0% { box-shadow: 0 0 0 0 rgba(${props.theme[color]}, 0.4); } + 70% { box-shadow: 0 0 0 10px rgba${props.theme[color]}, 0); } + 100% { box-shadow: 0 0 0 0 rgba(${props.theme[color]}, 0); } +` + +export const ripple = keyframes` + 0% { + opacity: 1; + transform: scale(0, 0); + } + 20% { + opacity: 1; + transform: scale(25, 25); + } + 100% { + opacity: 0; + transform: scale(40, 40); + } +` + +export const easeOutQuad = css`cubic-bezier(0.250, 0.460, 0.450, 0.940);` +export const bounce = css`cubic-bezier(0.175, 0.885, 0.32, 1.275);` + +const swiftEaseOutDuration = css`0.4s` +const swiftEaseOutTimingFunction = css`cubic-bezier(0.25, 0.8, 0.25, 1);` +export const swiftEaseOut = css`all ${swiftEaseOutDuration} ${swiftEaseOutTimingFunction};` + +const swiftEaseInDuration = css`0.3s;` +const swiftEaseInTimingFunction = css`cubic-bezier(0.55, 0, 0.55, 0.2);` +export const swiftEaseIn = css`all ${swiftEaseInDuration} ${swiftEaseInTimingFunction};` + +const swiftEaseInOutDuration = css`0.5s;` +const swiftEaseInOutTimingFunction = css`cubic-bezier(0.35, 0, 0.25, 1);` +export const swiftEaseInOut = css`all ${swiftEaseInOutDuration} ${swiftEaseInOutTimingFunction};` + +const swiftLinearDuration = css`0.08s;` +const swiftLinearTimingFunction = css`linear;` +export const swiftLinear = css`all ${swiftLinearDuration} ${swiftLinearTimingFunction};` + +const materialEnterDuration = css`0.3s;` +const materialEnterTimingFunction = css`cubic-bezier(0.0, 0.0, 0.2, 1);` +export const materialEnter = css`all ${materialEnterDuration} ${materialEnterTimingFunction};` + +const materialLeaveDuration = css`0.3s;` +const materialLeaveTimingFunction = css`cubic-bezier(0.4, 0.0, 1, 1);` +export const materialLeave = css`all ${materialLeaveDuration} ${materialLeaveTimingFunction};` diff --git a/lib/Themes.js b/lib/Themes.js new file mode 100644 index 0000000..1a0c2fc --- /dev/null +++ b/lib/Themes.js @@ -0,0 +1,30 @@ +const common = { + black: '#252525', + blue: '#294dea', + gray: '#959595', + green: '#9eff90', + lightGray: '#f7f7f7', + purple: '#bc92ff', + red: '#e34a4a', + white: '#ffffff', + yellow: '#fffb79', + + disabled: '#cccccc', + get primary () { return this.blue }, + secondary: '#7c7c7c', + tertiary: '#e9edfc', + + get alert () { return this.red }, + get info () { return this.blue }, + get success () { return this.green } +} + +export const light = Object.assign({}, common, { + bgColor: '#f7f7f7', + fgColor: common.black +}) + +export const dark = Object.assign({}, common, { + bgColor: common.black, + fgColor: common.white +}) diff --git a/package.json b/package.json index 7f2c5c7..9d215e2 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "must": "^0.13.4", "node-sass": "^4.9.2", "prop-types": "^15.6.2", - "react-native-sass-transformer": "^1.2.3", "react-native-scripts": "^1.14.0", "react-test-renderer": "^16.5.0", "sass-loader": "^7.0.3", @@ -90,7 +89,8 @@ "react-native": "^0.56.1", "react-router-dom": "^4.3.1", "react-stockcharts": "^0.7.7", - "react-syntax-highlighter": "^8.0.1" + "react-syntax-highlighter": "^8.0.1", + "styled-components": "^4.0.3" }, "standard": { "parser": "babel-eslint" diff --git a/web/Badge.jsx b/web/Badge.jsx index 6ed1cf0..224a73c 100644 --- a/web/Badge.jsx +++ b/web/Badge.jsx @@ -1,14 +1,48 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' +import styled, {css} from 'styled-components' +import {pulse, swiftEaseIn} from '../lib/Animations' + +const BadgeWrapper = styled.span` + position: relative; + z-index: 1; + ${props => props.primary ? css` + ${BadgeText} { + animation: ${pulse('primary')} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); + background-color: ${props => props.theme.primary}; + } + ` : ''} +` +const BadgeText = styled.span` + animation: ${pulse('default')} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); + background-color: ${props => props.theme.black}; + border-radius: 50%; + color: ${props => props.theme.white}; + font-size: 14px; + height: 24px; + position: absolute; + right: -8px; + text-align: center; + top: -100%; + transition: ${swiftEaseIn}; + width: 24px; + z-index: 2; + + span { + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + } +` const Badge = (props) => { - const [mods, {children, text, ...rest}] = pickRest(props, ['primary']) + const {children, text, ...rest} = props return ( - - {text} + + {text} {children} - + ) } diff --git a/yarn.lock b/yarn.lock index eab92b9..34e08f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -82,6 +82,12 @@ dependencies: "@babel/types" "7.0.0-beta.47" +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + dependencies: + "@babel/types" "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor@7.0.0-beta.47": version "7.0.0-beta.47" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.0.0-beta.47.tgz#d5917c29ee3d68abc2c72f604bc043f6e056e907" @@ -670,6 +676,24 @@ lodash "^4.17.5" to-fast-properties "^2.0.0" +"@babel/types@^7.0.0": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.5.tgz#12fe64e91a431234b7017b4227a78cc0eec4e081" + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@emotion/is-prop-valid@^0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.6.8.tgz#68ad02831da41213a2089d2cab4e8ac8b30cbd85" + dependencies: + "@emotion/memoize" "^0.6.6" + +"@emotion/memoize@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b" + "@expo/bunyan@1.8.10", "@expo/bunyan@^1.8.10": version "1.8.10" resolved "https://registry.yarnpkg.com/@expo/bunyan/-/bunyan-1.8.10.tgz#7d19354a6bce85aae5fea0e973569d3f0142533e" @@ -1160,10 +1184,6 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -app-root-path@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a" - append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -1652,6 +1672,13 @@ babel-plugin-react-transform@^3.0.0: dependencies: lodash "^4.6.1" +"babel-plugin-styled-components@>= 1": + version "1.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.8.0.tgz#9dd054c8e86825203449a852a5746f29f2dab857" + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + lodash "^4.17.10" + babel-plugin-syntax-async-functions@^6.5.0, babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -3265,10 +3292,6 @@ css-loader@^1.0.0: postcss-value-parser "^3.3.0" source-list-map "^2.0.0" -css-mediaquery@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" - css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -3286,15 +3309,7 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.1" regexpu-core "^1.0.0" -css-to-react-native-transform@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/css-to-react-native-transform/-/css-to-react-native-transform-1.7.0.tgz#1e12deb806644be88583ac3751fad68b0e321437" - dependencies: - css "^2.2.3" - css-mediaquery "^0.1.2" - css-to-react-native "^2.2.1" - -css-to-react-native@^2.2.1: +css-to-react-native@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.2.2.tgz#c077d0f7bf3e6c915a539e7325821c9dd01f9965" dependencies: @@ -3306,15 +3321,6 @@ css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" -css@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - dependencies: - inherits "^2.0.3" - source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" - cssesc@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" @@ -7229,6 +7235,10 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +memoize-one@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.0.3.tgz#cdfdd942853f1a1b4c71c5336b8c49da0bf0273c" + memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -8632,7 +8642,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -8867,6 +8877,10 @@ react-is@^16.5.0: version "16.5.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.5.0.tgz#2ec7c192709698591efe13722fab3ef56144ba55" +react-is@^16.6.0: + version "16.6.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.1.tgz#f77b1c3d901be300abe8d58645b7a59e794e5982" + react-native-branch@2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/react-native-branch/-/react-native-branch-2.2.5.tgz#4074dd63b4973e6397d9ce50e97b57c77a518e9d" @@ -8896,14 +8910,6 @@ react-native-safe-module@^1.1.0: dependencies: dedent "^0.6.0" -react-native-sass-transformer@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/react-native-sass-transformer/-/react-native-sass-transformer-1.2.3.tgz#b7d5227f851e32928322e5c762faded7275ca28b" - dependencies: - app-root-path "^2.1.0" - css-to-react-native-transform "^1.7.0" - semver "^5.5.0" - react-native-scripts@^1.14.0: version "1.14.0" resolved "https://registry.yarnpkg.com/react-native-scripts/-/react-native-scripts-1.14.0.tgz#1c0a71ea2194a3889055c54458e32730f5cd1ccc" @@ -10027,7 +10033,7 @@ source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: +source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: @@ -10343,6 +10349,28 @@ style-loader@^0.21.0: loader-utils "^1.1.0" schema-utils "^0.4.5" +styled-components@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.0.3.tgz#6c1a95a93857aa613fdfc26ad40899217100d8c3" + dependencies: + "@emotion/is-prop-valid" "^0.6.8" + babel-plugin-styled-components ">= 1" + css-to-react-native "^2.2.2" + memoize-one "^4.0.0" + prop-types "^15.5.4" + react-is "^16.6.0" + stylis "^3.5.0" + stylis-rule-sheet "^0.0.10" + supports-color "^5.5.0" + +stylis-rule-sheet@^0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" + +stylis@^3.5.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.3.tgz#99fdc46afba6af4deff570825994181a5e6ce546" + superagent-proxy@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/superagent-proxy/-/superagent-proxy-1.0.3.tgz#acfa776672f11c24a90ad575e855def8be44f741" From 27a4ff2024d93f660265691e6d5f5e71f9d2502a Mon Sep 17 00:00:00 2001 From: Penple03 Date: Wed, 7 Nov 2018 23:00:52 -0800 Subject: [PATCH 02/20] Finish porting buttons to CSS-in-JS. --- .babelrc | 4 ++ lib/Animations.js | 7 +-- lib/Themes.js | 28 +++++++++++- package.json | 2 + web/Badge.jsx | 2 +- web/Button.jsx | 108 ++++++++++++++++++++++++++++++++++++++++++--- web/IconButton.jsx | 105 +++++++++++++++++++++++++++++++++++-------- yarn.lock | 18 +++++++- 8 files changed, 244 insertions(+), 30 deletions(-) diff --git a/.babelrc b/.babelrc index a79602b..e9c7bd9 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,9 @@ { "plugins": [ + ["babel-plugin-styled-components", { + "minify": false, + "displayName": true + }], "transform-class-properties", "transform-object-rest-spread", "transform-rebem-jsx" diff --git a/lib/Animations.js b/lib/Animations.js index 229b61e..ebe1aff 100644 --- a/lib/Animations.js +++ b/lib/Animations.js @@ -1,9 +1,10 @@ import {keyframes, css} from 'styled-components' +import {rgba} from 'polished' export const pulse = color => props => keyframes` - 0% { box-shadow: 0 0 0 0 rgba(${props.theme[color]}, 0.4); } - 70% { box-shadow: 0 0 0 10px rgba${props.theme[color]}, 0); } - 100% { box-shadow: 0 0 0 0 rgba(${props.theme[color]}, 0); } + 0% { box-shadow: 0 0 0 0 ${rgba(props.theme[color], 0.4)}; } + 70% { box-shadow: 0 0 0 10px ${rgba(props.theme[color], 0)}; } + 100% { box-shadow: 0 0 0 0 ${rgba(props.theme[color], 0)}; } ` export const ripple = keyframes` diff --git a/lib/Themes.js b/lib/Themes.js index 1a0c2fc..d21895c 100644 --- a/lib/Themes.js +++ b/lib/Themes.js @@ -1,4 +1,8 @@ const common = { + // Border + borderRadius: '5px', + + // Colors black: '#252525', blue: '#294dea', gray: '#959595', @@ -9,6 +13,7 @@ const common = { white: '#ffffff', yellow: '#fffb79', + // Color Codes disabled: '#cccccc', get primary () { return this.blue }, secondary: '#7c7c7c', @@ -16,7 +21,28 @@ const common = { get alert () { return this.red }, get info () { return this.blue }, - get success () { return this.green } + get success () { return this.green }, + + // Card + cardPadding: '32px', + + // Drawer + drawerWidth: '290px', + + // Font + fontPrimary: "'Roboto', sans-serif", + fontSecondary: "'Poppins', sans-serif", + + // Grid + gridGutter: '10px', + + // Input + + // Modal + modalPadding: '32px', + + // Panel + panelPadding: '32px' } export const light = Object.assign({}, common, { diff --git a/package.json b/package.json index 9d215e2..5ffdcd4 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "babel-core": "^6.26.3", "babel-eslint": "^8.2.6", "babel-loader": "^7.1.5", + "babel-plugin-styled-components": "^1.8.0", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-rebem-jsx": "^0.3.3", @@ -83,6 +84,7 @@ "d3-format": "^1.3.0", "d3-time-format": "^2.1.1", "expo": "^29.0.0", + "polished": "^2.3.0", "react": "^16.4.1", "react-chartkick": "^0.3.0", "react-dom": "^16.4.1", diff --git a/web/Badge.jsx b/web/Badge.jsx index 224a73c..8d56dd7 100644 --- a/web/Badge.jsx +++ b/web/Badge.jsx @@ -14,7 +14,7 @@ const BadgeWrapper = styled.span` ` : ''} ` const BadgeText = styled.span` - animation: ${pulse('default')} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); + animation: ${pulse('black')} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); background-color: ${props => props.theme.black}; border-radius: 50%; color: ${props => props.theme.white}; diff --git a/web/Button.jsx b/web/Button.jsx index b7f1919..6f882e2 100644 --- a/web/Button.jsx +++ b/web/Button.jsx @@ -1,11 +1,109 @@ -import React from 'react' -import {pickRest} from '../lib/utils' import PropTypes from 'prop-types' +import styled, {css} from 'styled-components' +import {ripple} from '../lib/Animations' +import {lighten, darken} from 'polished' +import React from 'react' + +/* eslint-disable indent */ +const StyledButton = styled.button` + border-radius: ${props => props.theme.borderRadius}; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + color: ${props => props.theme.white}; + cursor: pointer; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + font-weight: 500; + height: 35px; + line-height: 19px; + letter-spacing: normal; + margin: 0 5px; + overflow: hidden; + padding: 8px 16px; + position: relative; + text-align: center; + + background-color: ${props => props.theme[props.color]} + background-position: center; + border: none; + + ${props => props.large ? css` + height: 51px; + padding: 16px 24px; + ` : ''} + + ::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 5px; + height: 5px; + background: rgba(255, 255, 255, .5); + opacity: 0; + border-radius: 100%; + transform: scale(1, 1) translate(-50%); + transform-origin: 50% 50%; + visibility: hidden; + } + + :focus::after { + visibility: visible; + } + + :focus:not(:active)::after { + animation: ${ripple} 2s ease-out; + } + + :hover { + background-color: ${props => lighten(0.1, props.theme[props.color])} + } + + ${props => props.outline ? css` + background: transparent; + border: 1px solid ${props => props.theme[props.color]}; + box-shadow: none; + color: ${props => props.theme[props.color]}; + + :active { + background-color: ${props => darken(0.25, lighten(props.p, props.theme[props.color]))}; + } + + :hover, :focus { + background-color: ${props => lighten(props.p, props.theme[props.color])}; + } + ` : ''} + + ${props => props.text ? css` + background: transparent; + box-shadow: none; + color: ${props => props.theme[props.color]}; + + :active { + background-color: ${props => darken(0.25, lighten(props.p, props.theme[props.color]))}; + } + + :hover, :focus { + background-color: ${props => lighten(props.p, props.theme[props.color])}; + } + ` : ''} +` +/* eslint-enable indent */ const Button = props => { - const [ mods, {children, as, block, ...rest} ] = pickRest(props, ['large', 'primary', 'secondary', 'disabled', 'outline', 'text']) - const As = as - return {children} + const {primary, secondary, disabled, children, ...rest} = props + let color = 'black' + let p = 0.6 + if (primary) { + color = 'primary' + p = 0.4 + } else if (secondary) { + color = 'secondary' + p = 0.35 + } else if (disabled) { + color = 'disabled' + p = 0.1 + } + return {children} } Button.defaultProps = { diff --git a/web/IconButton.jsx b/web/IconButton.jsx index f8ce3cf..e245634 100644 --- a/web/IconButton.jsx +++ b/web/IconButton.jsx @@ -1,30 +1,97 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' +import styled from 'styled-components' +import {ripple} from '../lib/Animations' +import {lighten, darken} from 'polished' import Icon from './Icon' -export default class IconButton extends React.Component { - static defaultProps = { - as: 'button' +/* eslint-disable indent */ +const StyledIconButton = styled.button` + border-radius: 50%; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + color: ${props => props.theme[props.color]}; + cursor: pointer; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + font-weight: 500; + height: 44px; + width: 44px; + line-height: 19px; + letter-spacing: normal; + margin: 0 10px; + overflow: hidden; + padding: 0; + position: relative; + text-align: center; + + background: transparent; + background-position: center; + border: 1px solid transparent; + box-shadow: none; + + ::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 5px; + height: 5px; + background: rgba(255, 255, 255, .5); + opacity: 0; + border-radius: 100%; + transform: scale(1, 1) translate(-50%); + transform-origin: 50% 50%; + visibility: hidden; + } + + :focus::after { + visibility: visible; + } + + :focus:not(:active)::after { + animation: ${ripple} 2s ease-out; + } + + :hover { + background-color: ${props => lighten(0.1, props.theme[props.color])} + } + + :active { + background-color: ${props => darken(0.25, lighten(props.p, props.theme[props.color]))}; } - static propTypes = { - as: PropTypes.string.isRequired, - icon: PropTypes.bool, - k: PropTypes.string.isRequired, - primary: PropTypes.bool, - secondary: PropTypes.bool, - disabled: PropTypes.bool + :hover, :focus { + background-color: ${props => lighten(props.p, props.theme[props.color])}; + border: 1px solid ${props => lighten(props.p, props.theme[props.color])}; } +` +/* eslint-enable indent */ - render () { - const [ mods, {children, as, icon, k, ...rest} ] = pickRest(this.props, ['primary', 'secondary', 'disabled']) - const As = as - return ( - - {children} - - ) +const IconButton = props => { + const {primary, secondary, disabled, children, k, ...rest} = props + let color = 'black' + let p = 0.6 + if (primary) { + color = 'primary' + p = 0.4 + } else if (secondary) { + color = 'secondary' + p = 0.35 + } else if (disabled) { + color = 'disabled' + p = 0.1 } + return {children} } + +IconButton.propTypes = { + as: PropTypes.string.isRequired, + icon: PropTypes.bool, + k: PropTypes.string.isRequired, + primary: PropTypes.bool, + secondary: PropTypes.bool, + disabled: PropTypes.bool +} + +export default IconButton diff --git a/yarn.lock b/yarn.lock index 34e08f1..e0d77a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -580,6 +580,12 @@ pirates "^3.0.1" source-map-support "^0.4.2" +"@babel/runtime@^7.0.0": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.5.tgz#4170907641cf1f61508f563ece3725150cc6fe39" + dependencies: + regenerator-runtime "^0.12.0" + "@babel/template@7.0.0-beta.44": version "7.0.0-beta.44" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" @@ -1672,7 +1678,7 @@ babel-plugin-react-transform@^3.0.0: dependencies: lodash "^4.6.1" -"babel-plugin-styled-components@>= 1": +"babel-plugin-styled-components@>= 1", babel-plugin-styled-components@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.8.0.tgz#9dd054c8e86825203449a852a5746f29f2dab857" dependencies: @@ -8489,6 +8495,12 @@ pn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" +polished@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/polished/-/polished-2.3.0.tgz#66c8b66bc666e95d9d12d760dac9df758aed8f8e" + dependencies: + "@babel/runtime" "^7.0.0" + portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" @@ -9278,6 +9290,10 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" From 68aafa1391742f63e543e746681e075ef84f1699 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 17 Nov 2018 01:32:10 -0800 Subject: [PATCH 03/20] Port card to cssinjs --- sass/_badge.scss | 37 ---------------- sass/_button.scss | 88 -------------------------------------- sass/_card.scss | 78 ---------------------------------- sass/_library.scss | 3 -- web/Card.jsx | 103 +++++++++++++++++++++++++++++++++++++-------- 5 files changed, 86 insertions(+), 223 deletions(-) delete mode 100644 sass/_badge.scss delete mode 100644 sass/_button.scss delete mode 100644 sass/_card.scss diff --git a/sass/_badge.scss b/sass/_badge.scss deleted file mode 100644 index 6e72a26..0000000 --- a/sass/_badge.scss +++ /dev/null @@ -1,37 +0,0 @@ - -.badge { - position: relative; - z-index: 1; - - $self: &; - - &--primary { - #{$self}__text { - animation: pulse-primary 1.25s infinite cubic-bezier(0.66, 0, 0, 1); - background-color: $primary; - } - } - - &__text { - animation: pulse-default 1.25s infinite cubic-bezier(0.66, 0, 0, 1); - background-color: $black; - border-radius: 50%; - color: $white; - font-size: 14px; - height: 24px; - position: absolute; - right: -8px; - text-align: center; - top: -100%; - transition: $animation-badge; - width: 24px; - z-index: 2; - - span { - left: 50%; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - } - } -} diff --git a/sass/_button.scss b/sass/_button.scss deleted file mode 100644 index 65279b8..0000000 --- a/sass/_button.scss +++ /dev/null @@ -1,88 +0,0 @@ - -.button { - border-radius: $border-radius; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: $white; - cursor: pointer; - font-family: $font-primary; - font-size: 14px; - font-weight: 500; - height: 35px; - line-height: 19px; - letter-spacing: normal; - margin: 0 5px; - overflow: hidden; - padding: 8px 16px; - position: relative; - text-align: center; - - @include button-default($black); - - &--icon { - @include button-icon($black, 60%); - border-radius: 50%; - color: $black; - height: 44px; - margin: 0 10px; - padding: 0; - text-align: center; - width: 44px; - } - &--large { - height: 51px; - padding: 16px 24px; - } - &--outline { @include button-outline($black, 60%); } - &--text { @include button-text($black, 60%); } - - $self: &; - - &--primary { - background-color: $primary; - border: 1px solid $primary; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: $white; - - @include button-default($primary); - - &#{$self}--icon { @include button-icon($primary, 40%); } - &#{$self}--outline { @include button-outline($primary, 40%); } - &#{$self}--text { @include button-text($primary, 40%); } - } - - &--secondary { - background-color: $secondary; - border: 1px solid $secondary; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: $white; - - @include button-default($secondary); - - &#{$self}--icon { @include button-icon($secondary, 35%); } - &#{$self}--outline { @include button-outline($secondary, 35%); } - &#{$self}--text { @include button-text($secondary, 35%); } - } - - &--disabled { - background-color: $disabled; - border: 1px solid $disabled; - box-shadow: none; - color: lighten($disabled, 10%); - cursor: not-allowed; - - @include button-default($disabled); - - &#{$self}--icon { - @include button-icon($disabled, 10%); - cursor: not-allowed; - } - &#{$self}--outline { - @include button-outline($disabled, 10%); - cursor: not-allowed; - } - &#{$self}--text { - @include button-text($disabled, 10%); - cursor: not-allowed; - } - } -} diff --git a/sass/_card.scss b/sass/_card.scss deleted file mode 100644 index 5816454..0000000 --- a/sass/_card.scss +++ /dev/null @@ -1,78 +0,0 @@ - -.card { - background-color: $white; - border-bottom: 10px; - border-radius: $border-radius; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - transition: $animation-card; - - $self: &; - - &:hover { - box-shadow: 0 0 13px 0 rgba(0, 0, 0, 0.2); - } - - &--image { - overflow: hidden; - - #{$self}__title { - border: 0; - color: $white; - margin: 0; - padding: 0; - - &__text { - bottom: $card-padding; - left: $card-padding; - position: absolute; - } - } - - img { - border-top-left-radius: $border-radius; - border-top-right-radius: $border-radius; - height: min-content; - } - } - - &__actions { - padding: 0 $card-padding $card-padding $card-padding; - position: relative; - - .row div:first { - margin-left: 0; - padding-left: 0; - } - - button { margin: 0 $grid-gutter 0 0; } - } - - &__body { - padding: $card-padding; - - &--nopadding { padding: 0; } - } - - &__title { - border-bottom: 1px solid rgba(0, 0, 0, 0.2); - font-family: $font-secondary; - font-size: 24px; - font-weight: bold; - padding: $card-padding; - position: relative; - - i { - color: $red; - font-size: 24px; - position: absolute; - right: $card-padding; - top: 50%; - transform: translateY(-50%); - } - - img { - border-top-left-radius: $border-radius; - border-top-right-radius: $border-radius; - } - } -} diff --git a/sass/_library.scss b/sass/_library.scss index c19e78d..35fb02c 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -1,9 +1,6 @@ @import 'mixin'; @import 'animation'; -@import 'badge'; -@import 'button'; -@import 'card'; @import 'chart'; @import 'checkbox'; @import 'code'; diff --git a/web/Card.jsx b/web/Card.jsx index 706bfba..37e9dcb 100644 --- a/web/Card.jsx +++ b/web/Card.jsx @@ -1,14 +1,52 @@ import PropTypes from 'prop-types' import React from 'react' +import styled, { css } from 'styled-components' + +import { swiftEaseIn } from '../lib/Animations' import Icon from './Icon' +const CardWrapper = styled.div` + background-color: ${props => props.theme.white}; + border-bottom: 10px; + border-radius: ${props => props.theme.borderRadius}; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + transition: ${swiftEaseIn}; + + :hover { + box-shadow: 0 0 13px 0 rgba(0, 0, 0, 0.2); + } + + ${props => props.image ? css` + overflow: hidden; + + ${CardTitle} { + border: 0; + color: ${props => props.theme.white}; + margin: 0; + padding: 0; + + ${CardText} { + bottom: ${props => props.theme.cardPadding}; + left: ${props => props.theme.cardPadding}; + position: absolute; + } + } + + img { + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + height: min-content; + } + ` : ''} +` + // Card export const Card = ({children, image, ...rest}) => ( -
+ {!!image && } {children} -
+ ) Card.propTypes = { @@ -17,35 +55,66 @@ Card.propTypes = { } // Actions -export const CardActions = ({children, ...rest}) => ( -
- {children} -
-) +export const CardActions = styled.div` + padding: 0 ${props => props.theme.cardPadding} ${props => props.theme.cardPadding} ${props => props.theme.cardPadding}; + position: relative; + + .row div:first { + margin-left: 0; + padding-left: 0; + } + + button { margin: 0 ${props => props.theme.gridGutter} 0 0; } +` CardActions.propTypes = { children: PropTypes.any.isRequired } // Body -export const CardBody = ({children, nopadding, ...rest}) => ( -
- {children} -
-) +export const CardBody = styled.div` + padding: ${props => props.theme.cardPadding}; + + ${props => props.nopadding ? 'padding: 0;' : ''} +` CardBody.propTypes = { children: PropTypes.any.isRequired, nopadding: PropTypes.bool } +const CardTitleWrapper = styled.div` + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + font-family: ${props => props.theme.fontSecondary}; + font-size: 24px; + font-weight: bold; + padding: ${props => props.theme.cardPadding}; + position: relative; + + i { + color: $red; + font-size: 24px; + position: absolute; + right: ${props => props.theme.cardPadding}; + top: 50%; + transform: translateY(-50%); + } + + img { + border-top-left-radius: ${props => props.theme.borderRadius}; + border-top-right-radius: ${props => props.theme.borderRadius}; + } +` +const CardText = styled.span`` + +// styled() factory here to use on line 23 // Title -export const CardTitle = ({icon, title, ...rest}) => ( -
- {title} +export const CardTitle = styled(({icon, title, ...rest}) => ( + + {title} {icon && } -
-) + +))`` CardTitle.propTypes = { icon: PropTypes.string, From 8fea0cdfbec90078f90db4a284e97420ce9247a9 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 17 Nov 2018 10:27:47 -0800 Subject: [PATCH 04/20] Port checkbox to cssinjs. --- demo/web/Section/CheckboxDemo.jsx | 16 ++--- sass/_checkbox.scss | 100 ------------------------------ sass/_library.scss | 1 - web/Checkbox.jsx | 78 ++++++++++++++++++++--- 4 files changed, 79 insertions(+), 116 deletions(-) delete mode 100644 sass/_checkbox.scss diff --git a/demo/web/Section/CheckboxDemo.jsx b/demo/web/Section/CheckboxDemo.jsx index 46cb46b..385b054 100644 --- a/demo/web/Section/CheckboxDemo.jsx +++ b/demo/web/Section/CheckboxDemo.jsx @@ -6,9 +6,9 @@ import Source from '../../../web/Source' const CheckboxDemo = () => (

Checkboxes

- - - + + +
@@ -23,8 +23,8 @@ const CheckboxDemo = () => ( `} />
- - + +

Code Example

@@ -38,9 +38,9 @@ const CheckboxDemo = () => ( `} />

Switches

- - - + + +

Code Example

props.theme[props.color]}; + border-radius: 50%; + margin: 0 5px; + color: ${props => props.theme.white}; + text-align: center; + vertical-align: top; + + ${props => props.disabled ? 'cursor: not-allowed;' : ''} + + ${props => props.checked && !props.switch ? css` + animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); + border: 0; + background-color: ${props => props.theme.black}; + + ${props => props.color ? css` + animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); + background-color: ${props => props.theme[props.color]}; + ` : ''} + ${props => props.color == 'disabled' ? 'background-color: #C8C8C8;' : ''} + + ::after { + content: ${props => props.indeterminate ? '"\\2015"' : '"\\2713"'}; + } + ` : ''} + + ${props => props.switch ? css` + background-color: #D8D8D8; + width: 48px; + border-radius: 12px; + border: none; + + ::after { + content: ""; + display: block; + width: 24px; + height: 24px; + border-radius: 50%; + background-color: ${props => props.theme.white}; + transition: ${swiftEaseOut}; + box-sizing: content-box; + ${props => props.checked ? css` + animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); + background-color: ${props => props.theme.black}; + transform: translate(24px); + ${props => props.color ? css` + animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); + background-color: ${props => props.theme[props.color]}; + ` : ''} + ` : ''} + ${props => props.disabled ? css` + ::after { + animation: none; + background-color: #C8C8C8; + } + ` : ''} + } + ` : ''} +` export default class Checkbox extends React.Component { static defaultProps = { @@ -10,9 +76,7 @@ export default class Checkbox extends React.Component { static propTypes = { as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - primary: PropTypes.bool, - secondary: PropTypes.bool, - red: PropTypes.bool, + color: PropTypes.oneOf('primary', 'secondary', 'red'), disabled: PropTypes.bool, indeterminate: PropTypes.bool, defaultChecked: PropTypes.bool, @@ -55,9 +119,9 @@ export default class Checkbox extends React.Component { } render () { - const [mods, { children, as, checked, onChange, value, ...rest }] = pickRest(this.props, ['primary', 'secondary', 'red', 'disabled', 'indeterminate', 'switch']) - mods.checked = this.isControlled() ? checked : this.state.checked - const As = as - return + const { checked, color, ...rest } = this.props + const realChecked = this.isControlled() ? checked : this.state.checked + const realColor = this.props.disabled ? 'disabled' : color + return } } From f817a9a6e40ca8bd3d60494b6862e73d3671f20f Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 17 Nov 2018 11:30:33 -0800 Subject: [PATCH 05/20] Port Radio to cssinjs --- demo/web/Section/RadioDemo.jsx | 6 ++--- web/Checkbox.jsx | 24 +++++++++--------- web/Radio.jsx | 45 ++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/demo/web/Section/RadioDemo.jsx b/demo/web/Section/RadioDemo.jsx index 7aa3978..a4c3245 100644 --- a/demo/web/Section/RadioDemo.jsx +++ b/demo/web/Section/RadioDemo.jsx @@ -20,10 +20,10 @@ export default class RadioDemo extends React.Component { return (

Radio Buttons

- + - - + +

Code Example

props.disabled ? 'cursor: not-allowed;' : ''} + ${props => props.disabled ? css` + border-color: #C8C8C8; + cursor: not-allowed; + ` : ''} ${props => props.checked && !props.switch ? css` animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); @@ -27,7 +30,7 @@ const CheckboxWrapper = styled.span` animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); background-color: ${props => props.theme[props.color]}; ` : ''} - ${props => props.color == 'disabled' ? 'background-color: #C8C8C8;' : ''} + ${props => props.disabled ? 'background-color: #C8C8C8;' : ''} ::after { content: ${props => props.indeterminate ? '"\\2015"' : '"\\2713"'}; @@ -59,10 +62,8 @@ const CheckboxWrapper = styled.span` ` : ''} ` : ''} ${props => props.disabled ? css` - ::after { - animation: none; - background-color: #C8C8C8; - } + animation: none; + background-color: #C8C8C8; ` : ''} } ` : ''} @@ -70,13 +71,13 @@ const CheckboxWrapper = styled.span` export default class Checkbox extends React.Component { static defaultProps = { - as: 'span', - defaultChecked: false + defaultChecked: false, + color: 'black' } static propTypes = { as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - color: PropTypes.oneOf('primary', 'secondary', 'red'), + color: PropTypes.oneOf('black', 'primary', 'secondary', 'red'), disabled: PropTypes.bool, indeterminate: PropTypes.bool, defaultChecked: PropTypes.bool, @@ -119,9 +120,8 @@ export default class Checkbox extends React.Component { } render () { - const { checked, color, ...rest } = this.props + const { checked, ...rest } = this.props const realChecked = this.isControlled() ? checked : this.state.checked - const realColor = this.props.disabled ? 'disabled' : color - return + return } } diff --git a/web/Radio.jsx b/web/Radio.jsx index 8ec5804..ef66eb8 100644 --- a/web/Radio.jsx +++ b/web/Radio.jsx @@ -1,10 +1,46 @@ import PropTypes from 'prop-types' import React from 'react' import {pickRest} from '../lib/utils' +import styled, { css } from 'styled-components' + +import { pulse, swiftEaseOut } from '../lib/Animations' + +const RadioWrapper = styled.span` + display: inline-block; + height: 24px; + width: 24px; + border: 1px solid ${props => props.theme[props.color]}; + border-radius: 50%; + margin: 0 5px; + text-align: center; + vertical-align: top; + + ${props => props.disabled ? 'cursor: not-allowed;' : ''} + + ${props => props.checked ? css` + ::after { + animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); + content: ""; + border-radius: 50%; + display: block; + margin: 4px; + height: 14px; + width: 14px; + background-color: ${props => props.theme.black}; + + ${props => props.color ? css` + animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); + background-color: ${props => props.theme[props.color]}; + `: ''} + ${props => props.disabled ? css` + background-color: #C8C8C8; + ` : ''} + } + ` : ''} +` export default class Radio extends React.Component { static defaultProps = { - as: 'span', defaultChecked: false } @@ -54,9 +90,8 @@ export default class Radio extends React.Component { } render () { - const [mods, {children, as, checked, onChange, value, ...rest}] = pickRest(this.props, ['primary', 'secondary', 'red', 'disabled', 'radio']) - mods.checked = this.isControlled() ? checked : this.state.checked - const As = as - return + const { checked, ...rest } = this.props + const realChecked = this.isControlled() ? checked : this.state.checked + return } } From 78a55b3cc37d2e18907cdbcfc4b7e5485d44783a Mon Sep 17 00:00:00 2001 From: Penple03 Date: Tue, 20 Nov 2018 23:19:33 -0800 Subject: [PATCH 06/20] Port Code element. --- sass/_code.scss | 7 ------- sass/_library.scss | 1 - web/Button.jsx | 6 +++--- web/Code.jsx | 11 ++++++++--- web/Col.jsx | 1 + 5 files changed, 12 insertions(+), 14 deletions(-) delete mode 100644 sass/_code.scss diff --git a/sass/_code.scss b/sass/_code.scss deleted file mode 100644 index 495ff19..0000000 --- a/sass/_code.scss +++ /dev/null @@ -1,7 +0,0 @@ - -.code { - background-color: lighten($gray, 30%); - color: $black; - font-family: $font-secondary; - padding: 20px; -} diff --git a/sass/_library.scss b/sass/_library.scss index 820a62a..12eeb76 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -2,7 +2,6 @@ @import 'mixin'; @import 'animation'; @import 'chart'; -@import 'code'; @import 'drawer'; @import 'grid'; @import 'input'; diff --git a/web/Button.jsx b/web/Button.jsx index 6f882e2..085d8ee 100644 --- a/web/Button.jsx +++ b/web/Button.jsx @@ -22,7 +22,7 @@ const StyledButton = styled.button` position: relative; text-align: center; - background-color: ${props => props.theme[props.color]} + background-color: ${props => props.theme[props.color]}; background-position: center; border: none; @@ -89,7 +89,7 @@ const StyledButton = styled.button` ` /* eslint-enable indent */ -const Button = props => { +const Button = styled(props => { const {primary, secondary, disabled, children, ...rest} = props let color = 'black' let p = 0.6 @@ -104,7 +104,7 @@ const Button = props => { p = 0.1 } return {children} -} +}) Button.defaultProps = { as: 'button' diff --git a/web/Code.jsx b/web/Code.jsx index 8e18ccc..519fccf 100644 --- a/web/Code.jsx +++ b/web/Code.jsx @@ -1,9 +1,14 @@ import PropTypes from 'prop-types' import React from 'react' +import styled from 'styled-components' +import {lighten} from 'polished' -const Code = ({children}) => ( -
{children}
-) +const Code = styled.pre` + background-color: ${props => lighten(0.3, props.theme.gray)}; + color: ${props => props.theme.black}; + font-family: ${props => props.theme.fontSecondary}; + padding: 20px; +` Code.propTypes = { children: PropTypes.node.isRequired diff --git a/web/Col.jsx b/web/Col.jsx index f2e7e9c..bb5bb45 100644 --- a/web/Col.jsx +++ b/web/Col.jsx @@ -1,6 +1,7 @@ import PropTypes from 'prop-types' import React from 'react' +// this can stay, we're probally not going to do our own grid system const Col = ({children, lg, md, sm, xs, ...props}) => { let classes = `col-xs-${xs}` if (props.className) { From fd1d0756b6b08554d83a357aa5c3a92578b6b284 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Tue, 20 Nov 2018 23:34:25 -0800 Subject: [PATCH 07/20] Port Panel. --- sass/_library.scss | 1 - sass/_panel.scss | 74 -------------------------------------- web/Panel.jsx | 89 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 80 insertions(+), 84 deletions(-) delete mode 100644 sass/_panel.scss diff --git a/sass/_library.scss b/sass/_library.scss index 12eeb76..238f3f4 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -9,7 +9,6 @@ @import 'modal'; @import 'navbar'; @import 'pagination'; -@import 'panel'; @import 'progressbar'; @import 'radio'; @import 'reset'; diff --git a/sass/_panel.scss b/sass/_panel.scss deleted file mode 100644 index e6c5ad8..0000000 --- a/sass/_panel.scss +++ /dev/null @@ -1,74 +0,0 @@ - -.panel { - background-color: $white; - border-radius: 10px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - overflow: hidden; - padding: $panel-padding $panel-padding 0 $panel-padding; - transition: $animation-panel-close; - - $self: &; - - &:hover { - box-shadow: 0 0 13px 0 rgba(0, 0, 0, 0.2); - } - - &--open { - padding-bottom: $panel-padding; - transition: $animation-panel-open; - - #{$self}__arrow i { - transform: rotate(-180deg); - } - - #{$self}__content { - max-height: 100vh; - transition: $animation-panel-open; - } - } - - &__arrow { - cursor: pointer; - position: absolute; - right: 32px; - top: 6px; - i { transition: $animation-panel-arrow; } - } - - &__content { - color: $secondary; - display: block; - font-family: $font-primary; - font-size: 14px; - margin: 0; - max-height: 0; - overflow: hidden; - padding: 0; - transition: $animation-panel-close; - width: 100%; - } - - &__header { - padding-bottom: $panel-padding; - position: relative; - - &__subtitle { - color: $secondary; - font-family: $font-primary; - font-size: 14px; - height: 19px; - left: 50%; - line-height: 19px; - position: absolute; - top: 5px; - } - - &__title { - font-family: $font-primary; - font-size: 20px; - font-weight: bold; - height: 26px; - line-height: 26px; - } - } -} diff --git a/web/Panel.jsx b/web/Panel.jsx index 99836c3..797cc3e 100644 --- a/web/Panel.jsx +++ b/web/Panel.jsx @@ -1,8 +1,79 @@ import PropTypes from 'prop-types' import React from 'react' +import styled, {css} from 'styled-components' + +import {swiftEaseIn, swiftEaseOut} from '../lib/Animations' import Icon from '../web/Icon' +const PanelWrapper = styled.div` + background-color: ${props => props.theme.white}; + border-radius: 10px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + overflow: hidden; + padding: ${props => props.theme.panelPadding} ${props => props.theme.panelPadding} 0 ${props => props.theme.panelPadding}; + transition: ${swiftEaseOut}; + + ${props => props.open ? css` + padding-bottom: ${props => props.theme.panelPadding}; + transition: ${swiftEaseIn}; + + ${PanelArrow} i { + transform: rotate(-180deg); + } + + ${PanelContent} { + max-height: 100vh; + transition: ${swiftEaseIn}; + } + ` : ''} +` + +const PanelHeader = styled.div` + padding-bottom: ${props => props.theme.panelPadding}; + position: relative; +` + +const PanelHeaderTitle = styled.div` + font-family: ${props => props.theme.fontPrimary}; + font-size: 20px; + font-weight: bold; + height: 26px; + line-height: 26px; +` + +const PanelHeaderSubtitle = styled.div` + color: ${props => props.theme.secondary}; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 19px; + left: 50%; + line-height: 19px; + position: absolute; + top: 5px; +` + +const PanelArrow = styled.div` + cursor: pointer; + position: absolute; + right: 32px; + top: 6px; + i { transition: ${swiftEaseIn}; } +` + +const PanelContent = styled.div` +color: ${props => props.theme.secondary}; + display: block; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + margin: 0; + max-height: 0; + overflow: hidden; + padding: 0; + transition: ${swiftEaseOut}; + width: 100%; +` + export default class Panel extends React.Component { static propTypes = { children: PropTypes.any.isRequired @@ -18,16 +89,16 @@ export default class Panel extends React.Component { const open = this.state.open const {children, subtitle, title, ...rest} = this.props return ( -
-
-
{title}
-
{subtitle}
-
+ + + {title} + {subtitle} + -
-
-
{children}
-
+ + + {children} + ) } } From ea3595208931bcd35c21629a0dbe13bd46b25e72 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Tue, 20 Nov 2018 23:44:10 -0800 Subject: [PATCH 08/20] Port ProgressBar, fix misc errors. --- lib/Animations.js | 2 ++ sass/_library.scss | 1 - web/Button.jsx | 6 +----- web/Checkbox.jsx | 2 +- web/IconButton.jsx | 1 - web/ProgressBar.jsx | 17 ++++++++++++++++- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/Animations.js b/lib/Animations.js index ebe1aff..9fcfe3c 100644 --- a/lib/Animations.js +++ b/lib/Animations.js @@ -48,3 +48,5 @@ export const materialEnter = css`all ${materialEnterDuration} ${materialEnterTim const materialLeaveDuration = css`0.3s;` const materialLeaveTimingFunction = css`cubic-bezier(0.4, 0.0, 1, 1);` export const materialLeave = css`all ${materialLeaveDuration} ${materialLeaveTimingFunction};` + +export const animationProgressbar = css`all 1s ${swiftEaseInTimingFunction} .1s;` diff --git a/sass/_library.scss b/sass/_library.scss index 238f3f4..b0afa72 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -9,7 +9,6 @@ @import 'modal'; @import 'navbar'; @import 'pagination'; -@import 'progressbar'; @import 'radio'; @import 'reset'; @import 'stepper'; diff --git a/web/Button.jsx b/web/Button.jsx index 085d8ee..5e01b1a 100644 --- a/web/Button.jsx +++ b/web/Button.jsx @@ -104,11 +104,7 @@ const Button = styled(props => { p = 0.1 } return {children} -}) - -Button.defaultProps = { - as: 'button' -} +})`` Button.propTypes = { as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), diff --git a/web/Checkbox.jsx b/web/Checkbox.jsx index 75dd891..bfd8283 100644 --- a/web/Checkbox.jsx +++ b/web/Checkbox.jsx @@ -77,7 +77,7 @@ export default class Checkbox extends React.Component { static propTypes = { as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - color: PropTypes.oneOf('black', 'primary', 'secondary', 'red'), + color: PropTypes.oneOf(['black', 'primary', 'secondary', 'red']), disabled: PropTypes.bool, indeterminate: PropTypes.bool, defaultChecked: PropTypes.bool, diff --git a/web/IconButton.jsx b/web/IconButton.jsx index e245634..d56ef0e 100644 --- a/web/IconButton.jsx +++ b/web/IconButton.jsx @@ -86,7 +86,6 @@ const IconButton = props => { } IconButton.propTypes = { - as: PropTypes.string.isRequired, icon: PropTypes.bool, k: PropTypes.string.isRequired, primary: PropTypes.bool, diff --git a/web/ProgressBar.jsx b/web/ProgressBar.jsx index e0b0474..50579fa 100644 --- a/web/ProgressBar.jsx +++ b/web/ProgressBar.jsx @@ -1,8 +1,23 @@ import PropTypes from 'prop-types' import React from 'react' +import styled from 'styled-components' +import {animationProgressbar} from '../lib/Animations' + +const ProgressBarWrapper = styled.div` + animation: all 1s ${animationProgressbar} .1s; + background-color: ${props => props.theme.primary}; + box-shadow: 0 0 10px ${props => props.theme.primary}; + display: block; + height: 4px; + left: 0; + position: fixed; + top: 0; + width: 0; + z-index: 100; +` const ProgressBar = ({v, ...rest}) => ( -
+ ) ProgressBar.propTypes = { From 8417022350b31133f769ef74ef9a92c6db757726 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Tue, 20 Nov 2018 23:57:36 -0800 Subject: [PATCH 09/20] Port table. --- sass/_library.scss | 1 - sass/_table.scss | 74 --------------------------------- web/Checkbox.jsx | 3 +- web/Table.jsx | 100 ++++++++++++++++++++++++++++++++++++--------- 4 files changed, 82 insertions(+), 96 deletions(-) delete mode 100644 sass/_table.scss diff --git a/sass/_library.scss b/sass/_library.scss index b0afa72..67405cb 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -13,7 +13,6 @@ @import 'reset'; @import 'stepper'; @import 'tab'; -@import 'table'; @import 'text'; @import 'tooltip'; @import 'util'; diff --git a/sass/_table.scss b/sass/_table.scss deleted file mode 100644 index 0e2fec7..0000000 --- a/sass/_table.scss +++ /dev/null @@ -1,74 +0,0 @@ - -.table { - margin: 0; - padding: 0; - width: 100%; - - $self: &; - - &__head { - #{$self}__cell { - color: $secondary; - cursor: pointer; - font-size: 14px; - height: 70px; - line-height: 19px; - - i { margin-left: 7px; } - } - - #{$self}__row, #{$self}__row:hover { - background: transparent !important; - } - } - - &__cell { - color: #252525; - font-size: 16px; - line-height: 21px; - padding: 7px; - - input[type="checkbox"] { - border-radius: 2px; - display: none; - - &:hover::before { - text-shadow: 0px 0px 1px $primary; - } - - &::before { - color: $secondary; - cursor: pointer; - display: inline-block; - text-align: center; - text-shadow: 0px 0px 1px $light-gray; - transition: color .3s ease; - } - - &:checked + label::before { - color: $primary; - } - - & + label::before { - content: "\2610"; - font-size: 18px; - } - - &:checked + label::before { content: "\2611"; } - } - } - - &__row { - height: 50px; - padding: 0 32px; - transition: $animation-table; - - &:hover { - background-color: rgba(41, 77, 234, 0.1) !important; - } - - &:nth-child(odd) { - background-color: rgba(124, 124, 124, 0.1); - } - } -} diff --git a/web/Checkbox.jsx b/web/Checkbox.jsx index bfd8283..2c51cba 100644 --- a/web/Checkbox.jsx +++ b/web/Checkbox.jsx @@ -1,6 +1,5 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' import styled, { css } from 'styled-components' import { pulse, swiftEaseOut } from '../lib/Animations' @@ -122,6 +121,6 @@ export default class Checkbox extends React.Component { render () { const { checked, ...rest } = this.props const realChecked = this.isControlled() ? checked : this.state.checked - return + return } } diff --git a/web/Table.jsx b/web/Table.jsx index 488d1a3..bee55be 100644 --- a/web/Table.jsx +++ b/web/Table.jsx @@ -1,25 +1,87 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' +import styled from 'styled-components' import Checkbox from './Checkbox' import Icon from './Icon' +import { swiftEaseIn } from '../lib/Animations' -export const TableBody = ({children, ...rest}) => ( - {children} -) +const TableWrapper = styled.table` + margin: 0; + padding: 0; + width: 100%; +` -export const TableCell = ({children, ...rest}) => ( - {children} -) +// Empty? +export const TableBody = styled.tbody` -export const TableHead = ({children, ...rest}) => ( - {children} -) +` -export const TableRow = ({children, ...rest}) => ( - {children} -) +export const TableCell = styled.td` + color: #252525; + font-size: 16px; + line-height: 21px; + padding: 7px; + + input[type="checkbox"] { + border-radius: 2px; + display: none; + + :hover::before { + text-shadow: 0px 0px 1px ${props => props.theme.primary}; + } + + ::before { + color: ${props => props.theme.secondary}; + cursor: pointer; + display: inline-block; + text-align: center; + text-shadow: 0px 0px 1px ${props => props.theme.lightGray}; + transition: color .3s ease; + } + + &:checked + label::before { + color: ${props => props.theme.primary}; + } + + & + label::before { + content: "\\2610"; + font-size: 18px; + } + + &:checked + label::before { content: "\\2611"; } + } +` + +export const TableRow = styled.tr` + height: 50px; + padding: 0 32px; + transition: ${swiftEaseIn}; + + &:hover { + background-color: rgba(41, 77, 234, 0.1) !important; + } + + &:nth-child(odd) { + background-color: rgba(124, 124, 124, 0.1); + } +` + +export const TableHead = styled.thead` + ${TableCell} { + color: ${props => props.theme.secondary}; + cursor: pointer; + font-size: 14px; + height: 70px; + line-height: 19px; + + i { margin-left: 7px; } + } + + ${TableRow}, ${TableRow}:hover { + background: transparent !important; + } +` export class Table extends React.Component { static propTypes = { @@ -37,17 +99,17 @@ export class Table extends React.Component { } render () { - const [mods, {children, column, columns, onSelect, onSort, row, rows, ...rest}] = pickRest(this.props, ['descending', 'selectable', 'sortable']) - const cols = mods.selectable ? [{key: '__select', text: ''}, ...columns] : [...columns] + const {children, column, columns, onSelect, onSort, row, rows, ...rest} = this.props + const cols = this.props.selectable ? [{key: '__select', text: ''}, ...columns] : [...columns] return ( - + {cols.map(c => ( onSort(c.key) : null}> - {c.text}{(mods.sortable && column === c.key) && - + {c.text}{(this.props.sortable && column === c.key) && + } ))} @@ -69,7 +131,7 @@ export class Table extends React.Component { ) })} -
+ ) } } From 3d860a06c2846577129ca3bcccfdb99ba13bbbcf Mon Sep 17 00:00:00 2001 From: Penple03 Date: Wed, 21 Nov 2018 00:04:43 -0800 Subject: [PATCH 10/20] Port Chart. --- sass/_chart.scss | 52 ------------------------------ sass/_library.scss | 1 - web/Chart.jsx | 80 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 66 deletions(-) delete mode 100644 sass/_chart.scss diff --git a/sass/_chart.scss b/sass/_chart.scss deleted file mode 100644 index f8fa4bb..0000000 --- a/sass/_chart.scss +++ /dev/null @@ -1,52 +0,0 @@ - -.chart { - background-color: $black; - border-radius: 10px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: $white; - - &__body { - padding: 0 24px 24px 24px; - text-align: center; - } - - &__head { - display: flex; - flex-direction: row; - padding: 32px 24px; - - * { display: inline-block; } - - &__flex { flex: 1; } - - &__links { - a { - color: $secondary; - cursor: pointer; - font-size: 14px; - font-weight: 500; - line-height: 19px; - margin-right: 56px; - - &:last-child { margin-right: 0; } - - &.active { color: $white; } - } - } - - &__subtitle { - font-size: 14px; - line-height: 19px; - padding-top: 11px; - } - - &__title { - font-family: $font-secondary; - font-size: 24px; - font-weight: bold; - letter-spacing: -1px; - line-height: 35px; - margin-right: 10px; - } - } -} diff --git a/sass/_library.scss b/sass/_library.scss index 67405cb..2fd9640 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -1,7 +1,6 @@ @import 'mixin'; @import 'animation'; -@import 'chart'; @import 'drawer'; @import 'grid'; @import 'input'; diff --git a/web/Chart.jsx b/web/Chart.jsx index 33cd3ea..5750d4a 100644 --- a/web/Chart.jsx +++ b/web/Chart.jsx @@ -2,31 +2,85 @@ import Chart from 'chart.js' import PropTypes from 'prop-types' import React from 'react' import ReactChartKick, {LineChart} from 'react-chartkick' -import {pickRest} from '../lib/utils' +import styled from 'styled-components' ReactChartKick.addAdapter(Chart) +const ChartWrapper = styled.div` + background-color: ${props => props.theme.black}; + border-radius: 10px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + color: ${props => props.theme.white}; +` + +const ChartHead = styled.div` + display: flex; + flex-direction: row; + padding: 32px 24px; + + * { display: inline-block; } +` + +const ChartHeadTitle = styled.div` + font-family: ${props => props.theme.fontSecondary}; + font-size: 24px; + font-weight: bold; + letter-spacing: -1px; + line-height: 35px; + margin-right: 10px; +` + +const ChartHeadSubtitle = styled.div` + font-size: 14px; + line-height: 19px; + padding-top: 11px; +` + +const ChartHeadFlex = styled.div` + flex: 1; +` + +const ChartHeadLinks = styled.div` + a { + color: ${props => props.theme.secondary}; + cursor: pointer; + font-size: 14px; + font-weight: 500; + line-height: 19px; + margin-right: 56px; + + &:last-child { margin-right: 0; } + + &.active { color: ${props => props.theme.white}; } + } +` + +const ChartBody = styled.div` + padding: 0 24px 24px 24px; + text-align: center; +` + export const ChartLine = (props) => { - const [mods, {data, links, subtitle, title, ...rest}] = pickRest(props, []) + const {data, links, subtitle, title, ...rest} = props return ( -
-
-
{title}
- {!!subtitle &&
{subtitle}
} -
+ + + {title} + {!!subtitle && {subtitle}} + {Array.isArray(links) && -
+ {links.map(l => ( {l.text} ))} -
+ } -
-
+ + -
-
+ + ) } From ea16addd9f8b2688eefadc0318a3d72a9aeea1c2 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Wed, 21 Nov 2018 00:35:14 -0800 Subject: [PATCH 11/20] Port tooltip. --- demo/web/Section/TooltipDemo.jsx | 4 +- sass/_library.scss | 1 - sass/_tooltip.scss | 114 ------------------------------- web/Tooltip.jsx | 106 ++++++++++++++++++++++++++-- 4 files changed, 102 insertions(+), 123 deletions(-) delete mode 100644 sass/_tooltip.scss diff --git a/demo/web/Section/TooltipDemo.jsx b/demo/web/Section/TooltipDemo.jsx index e0a66a9..e066f88 100644 --- a/demo/web/Section/TooltipDemo.jsx +++ b/demo/web/Section/TooltipDemo.jsx @@ -9,8 +9,8 @@ const TooltipDemo = () => (

Tooltips

- - + +

Code Example

props.color ? props.theme[props.color] : props.theme.secondary}; + border-radius: ${props => props.theme.borderRadius}; + color: ${props => props.theme.white}; + display: inline-block; + font-size: 9px; + line-height: 11px; + opacity: 0; + padding: 5px ${props => props.theme.gridGutter}; + position: absolute; + text-align: center; + transition: ${swiftEaseIn}; + visibility: hidden; + width: max-content; + z-index: 1; + + ::after { + border-style: solid; + border-width: 5px; + content: " "; + position: absolute; + } + + ${props => props.bottom ? css` + left: 50%; + top: 105%; + transform: translateX(-50%); + + ::after { + border-color: transparent transparent ${props => props.color ? props.theme[props.color] : props.theme.secondary} transparent; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + } + ` : ''} + + ${props => props.left ? css` + top: 50%; + right: 105%; + transform: translateY(-50%); + + ::after { + border-color: transparent transparent transparent ${props => props.color ? props.theme[props.color] : props.theme.secondary}; + left: 100%; + top: 50%; + transform: translateY(-50%); + } + ` : ''} + + ${props => props.right ? css` + left: 105%; + top: 50%; + transform: translateY(-50%); + + ::after { + border-color: transparent ${props => props.color ? props.theme[props.color] : props.theme.secondary} transparent transparent; + right: 100%; + top: 50%; + transform: translateY(-50%); + } + ` : ''} + + ${props => props.top ? css` + bottom: 105%; + left: 50%; + transform: translateX(-50%); + + ::after { + border-color: ${props => props.color ? props.theme[props.color] : props.theme.secondary} transparent transparent transparent; + left: 50%; + top: 100%; + transform: translateX(-50%); + } +` : ''} +` + +const TooltipWrapper = styled.div` + display: inline-block; + position: relative; + + :hover ${TooltipContent} { + opacity: 1; + visibility: visible; + } + + ${Button} { + margin: 5px; + } +` const Tooltip = (props) => { - const [ mods, {children, content, ...rest} ] = pickRest(props, ['bottom', 'left', 'primary', 'right', 'top', 'urgent']) + const {children, content, ...rest} = props return ( -
- {content} + + {content} {children} -
+ ) } @@ -20,7 +114,7 @@ Tooltip.propTypes = { primary: PropTypes.bool, right: PropTypes.bool, top: PropTypes.bool, - urgent: PropTypes.bool + color: PropTypes.string } export default Tooltip From 4f54c80d183acdf8bb3cc593d5108a20ee31ee35 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Fri, 23 Nov 2018 02:53:42 -0800 Subject: [PATCH 12/20] Port Menu. --- lib/Animations.js | 2 ++ sass/_library.scss | 1 - sass/_radio.scss | 50 ------------------------------ web/Menu.jsx | 77 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 67 insertions(+), 63 deletions(-) delete mode 100644 sass/_radio.scss diff --git a/lib/Animations.js b/lib/Animations.js index 9fcfe3c..c5535ff 100644 --- a/lib/Animations.js +++ b/lib/Animations.js @@ -50,3 +50,5 @@ const materialLeaveTimingFunction = css`cubic-bezier(0.4, 0.0, 1, 1);` export const materialLeave = css`all ${materialLeaveDuration} ${materialLeaveTimingFunction};` export const animationProgressbar = css`all 1s ${swiftEaseInTimingFunction} .1s;` + +export const animationSelectItem = css`opacity .15s ${swiftEaseInTimingFunction} .4s;` diff --git a/sass/_library.scss b/sass/_library.scss index 40ef8b3..5f74cc7 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -8,7 +8,6 @@ @import 'modal'; @import 'navbar'; @import 'pagination'; -@import 'radio'; @import 'reset'; @import 'stepper'; @import 'tab'; diff --git a/sass/_radio.scss b/sass/_radio.scss deleted file mode 100644 index 0f34f4c..0000000 --- a/sass/_radio.scss +++ /dev/null @@ -1,50 +0,0 @@ -.radio { - display: inline-block; - height: 24px; - width: 24px; - border: 1px solid $black; - border-radius: 50%; - margin: 0 5px; - color: $white; - text-align: center; - vertical-align: top; - - &--primary { border-color: $primary; } - &--secondary { border-color: $secondary; } - &--red { border-color: $red; } - &--disabled { - border-color: #C8C8C8; - cursor: not-allowed; - } - - $self: &; - - &--checked { - &::after { - animation: pulse-default 1.25s cubic-bezier(0.66, 0, 0, 1); - content: ""; - border-radius: 50%; - display: block; - margin: 4px; - height: 14px; - width: 14px; - background-color: $black; - } - - &#{$self}--primary::after { - animation: pulse-primary 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: $primary; - } - &#{$self}--secondary::after { - animation: pulse-secondary 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: $secondary; - } - &#{$self}--red::after { - animation: pulse-red 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: $red; - } - &#{$self}--disabled::after { - background-color: #C8C8C8; - } - } -} diff --git a/web/Menu.jsx b/web/Menu.jsx index d713fb8..543f159 100644 --- a/web/Menu.jsx +++ b/web/Menu.jsx @@ -1,6 +1,64 @@ import PropTypes from 'prop-types' import React from 'react' -import {kill, pickRest} from '../lib/utils' +import {kill} from '../lib/utils' +import styled, {css} from 'styled-components' +import {swiftEaseInOut, animationSelectItem} from '../lib/Animations' + +const MenuWrapper = styled.div` + display: inline-block; + position: relative; + + ${props => props.open ? css` + ${MenuItems} { + max-height: 230px; + transition: ${swiftEaseInOut}; + } + ${MenuItem} { + opacity: 1; + transition: ${animationSelectItem}; + } + ` : ''} +` + +const MenuItems = styled.div` + background-color: ${props => props.theme.white}; + border-radius: 5px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + display: block; + left: 50%; + margin: 0; + max-height: 0; + overflow-x: hidden; + overflow-y: auto; + padding: 0; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: max-content; + z-index: 5; +` + +export const MenuItem = styled.div` + cursor: pointer; + font-family: ${props => props.theme.fontPrimary}; + font-size: 16px; + height: 39px; + line-height: 19px; + margin: 0; + opacity: 0; + overflow: hidden; + padding: 10px 11px; + position: relative; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; + + :hover { background-color: rgba(124, 124, 124, 0.1); } + + ${props => props.active ? 'background-color: rgba(124, 124, 124, 0.2);' : ''} + + i { margin-right: 12px; } +` export class Menu extends React.Component { static propTypes = { @@ -26,24 +84,19 @@ export class Menu extends React.Component { } render () { - const [mods, {children, component, ...rest}] = pickRest(this.props, ['open']) - if (this.state.isOpen) mods.open = true + const {open, children, component, ...rest} = this.props + let realOpen = open + if (this.state.isOpen) realOpen = true return ( -
+ {React.cloneElement(component, {onClick: this.handleOpen})} -
{children}
-
+ {children} + ) } } -export const MenuItem = ({children, ...rest}) => ( -
- {children} -
-) - MenuItem.propTypes = { children: PropTypes.any.isRequired, onClick: PropTypes.func.isRequired From 6e247e92c1034d7ffd4d29d44a9a58368bfaeafd Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 24 Nov 2018 00:48:19 -0800 Subject: [PATCH 13/20] Port Modal. --- lib/Animations.js | 2 + sass/_library.scss | 1 - sass/_modal.scss | 99 ------------------------------------- web/Modal.jsx | 119 +++++++++++++++++++++++++++++++++++++-------- 4 files changed, 101 insertions(+), 120 deletions(-) delete mode 100644 sass/_modal.scss diff --git a/lib/Animations.js b/lib/Animations.js index c5535ff..09f73db 100644 --- a/lib/Animations.js +++ b/lib/Animations.js @@ -52,3 +52,5 @@ export const materialLeave = css`all ${materialLeaveDuration} ${materialLeaveTim export const animationProgressbar = css`all 1s ${swiftEaseInTimingFunction} .1s;` export const animationSelectItem = css`opacity .15s ${swiftEaseInTimingFunction} .4s;` + +export const animationModalContainer = css`all ${swiftEaseInOutDuration} ${swiftEaseInOutTimingFunction} .1s;` diff --git a/sass/_library.scss b/sass/_library.scss index 5f74cc7..8f6cf3c 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -5,7 +5,6 @@ @import 'grid'; @import 'input'; @import 'menu'; -@import 'modal'; @import 'navbar'; @import 'pagination'; @import 'reset'; diff --git a/sass/_modal.scss b/sass/_modal.scss deleted file mode 100644 index 6a7b7b5..0000000 --- a/sass/_modal.scss +++ /dev/null @@ -1,99 +0,0 @@ - -.modal { - background: transparent; - bottom: 0; - left: 0; - margin: 0; - opacity: 0; - padding: 0; - position: fixed; - right: 0; - top: 0; - transform: scale(0, 0); - z-index: 10; - - $self: &; - - &--open { - opacity: 1; - transform: scale(1, 1); - - #{$self}__container { - opacity: 1; - transition: $animation-modal-container; - } - } - - &--overlay { - background-color: rgba(0, 0, 0, 0.5); - transition: $animation-modal-overlay; - } - - &__actions { - margin: 0; - padding-top: 42px; - text-align: right; - - .button, button { margin: 0; } - - .button:first-child, button:first-child { margin-right: 20px; } - } - - &__container { - background-color: $white; - border-radius: 5px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - left: 50%; - margin: 0; - opacity: 0; - padding: $modal-padding; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - } - - &__content { - margin: 0; - padding: 0; - - * { - margin: 0; - padding: 0; - } - } - - &__title { - font-family: $font-secondary; - font-size: 20px; - font-weight: bold; - height: 28px; - letter-spacing: -1px; - line-height: 30px; - margin-bottom: 17px; - - * { - margin: 0; - padding: 0; - } - } - - @media screen { - @media only screen and (max-width: 768px) { - &--open { - height: 100%; - width: 100%; - - #{$self}__container { - bottom: 0; - height: 100%; - left: 0; - right: 0; - top: 0; - transform: none; - transition: $animation-modal-overlay; - width: 100%; - } - } - } - } -} diff --git a/web/Modal.jsx b/web/Modal.jsx index a2265d8..093acc4 100644 --- a/web/Modal.jsx +++ b/web/Modal.jsx @@ -1,16 +1,78 @@ import PropTypes from 'prop-types' import React from 'react' import {pickRest} from '../lib/utils' +import styled, {css} from 'styled-components' +import { animationModalContainer } from '../lib/Animations' + +const ModalWrapper = styled.div` + background: transparent; + bottom: 0; + left: 0; + margin: 0; + opacity: 0; + padding: 0; + position: fixed; + right: 0; + top: 0; + transform: scale(0, 0); + z-index: 10; + + ${props => props.open ? css` + opacity: 1; + transform: scale(1, 1); + + ${ModalContainer} { + opacity: 1; + transition: ${animationModalContainer}; + } + + @media screen { + @media only screen and (max-width: 768px) { + height: 100%; + width: 100%; + + ${ModalContainer} { + bottom: 0; + height: 100%; + left: 0; + right: 0; + top: 0; + transform: none; + transition: $animation-modal-overlay; + width: 100%; + } + } + } + ` : ''} + + ${props => props.overlay ? css` + background-color: rgba(0, 0, 0, 0.5); + transition: none; + ` : ''} +` + +const ModalContainer = styled.div` + background-color: ${props => props.theme.white}; + border-radius: 5px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + left: 50%; + margin: 0; + opacity: 0; + padding: ${props => props.theme.modalPadding}; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); +` // Modal export const Modal = (props) => { - const [mods, {children, onCancel, ...rest}] = pickRest(props, ['open', 'overlay']) + const {children, onCancel, ...rest} = props return ( -
-
+ + {children} -
-
+ + ) } @@ -22,33 +84,50 @@ Modal.propTypes = { } // Actions -export const ModalActions = ({children, ...rest}) => ( -
- {children} -
-) +export const ModalActions = styled.div` + margin: 0; + padding-top: 42px; + text-align: right; + + .button, button { margin: 0; } + + .button:first-child, button:first-child { margin-right: 20px; } +` ModalActions.propTypes = { children: PropTypes.any.isRequired } // Content -export const ModalContent = ({children, ...rest}) => ( -
- {children} -
-) +export const ModalContent = styled.div` + margin: 0; + padding: 0; + + * { + margin: 0; + padding: 0; + } +` ModalContent.propTypes = { children: PropTypes.any.isRequired } // Title -export const ModalTitle = ({children, ...rest}) => ( -
- {children} -
-) +export const ModalTitle = styled.div` + font-family: ${props => props.theme.fontSecondary}; + font-size: 20px; + font-weight: bold; + height: 28px; + letter-spacing: -1px; + line-height: 30px; + margin-bottom: 17px; + + * { + margin: 0; + padding: 0; + } +` ModalTitle.propTypes = { children: PropTypes.any.isRequired From 892bd9b89504cb4e9185b35f03a9077b039509a6 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 24 Nov 2018 00:56:41 -0800 Subject: [PATCH 14/20] Port Pagination. --- sass/_library.scss | 1 - sass/_pagination.scss | 59 ------------------------------- web/IconButton.jsx | 4 +-- web/Pagination.jsx | 80 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 72 insertions(+), 72 deletions(-) delete mode 100644 sass/_pagination.scss diff --git a/sass/_library.scss b/sass/_library.scss index 8f6cf3c..b59eca9 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -6,7 +6,6 @@ @import 'input'; @import 'menu'; @import 'navbar'; -@import 'pagination'; @import 'reset'; @import 'stepper'; @import 'tab'; diff --git a/sass/_pagination.scss b/sass/_pagination.scss deleted file mode 100644 index 9b9adbe..0000000 --- a/sass/_pagination.scss +++ /dev/null @@ -1,59 +0,0 @@ - -.pagination { - color: $secondary; - display: block; - font-size: 14px; - line-height: 19px; - - &__count { - display: inline-block; - margin-right: 20px; - } - - &__label { - display: inline-block; - margin-right: 20px; - } - - &__page { - display: inline-block; - - &__label { - display: inline-block; - padding: 0 10px; - } - - .button--icon { - border: 0; - color: $secondary; - display: inline-block; - font-size: 14px; - margin: 0 4px; - padding: 0; - width: 16px; - - &:active, &:focus, &:hover { - background: transparent; - } - } - } - - &__size { - display: inline-block; - margin-right: 20px; - - select { - background-color: transparent; - border: 0; - border-bottom: 1px solid $secondary; - color: $secondary; - min-width: 43px; - width: 43px; - } - - .input__options { - min-width: 60px; - width: 60px; - } - } -} diff --git a/web/IconButton.jsx b/web/IconButton.jsx index d56ef0e..f65fb82 100644 --- a/web/IconButton.jsx +++ b/web/IconButton.jsx @@ -68,7 +68,7 @@ const StyledIconButton = styled.button` ` /* eslint-enable indent */ -const IconButton = props => { +const IconButton = styled(props => { const {primary, secondary, disabled, children, k, ...rest} = props let color = 'black' let p = 0.6 @@ -83,7 +83,7 @@ const IconButton = props => { p = 0.1 } return {children} -} +})`` IconButton.propTypes = { icon: PropTypes.bool, diff --git a/web/Pagination.jsx b/web/Pagination.jsx index 80df33d..8073c9b 100644 --- a/web/Pagination.jsx +++ b/web/Pagination.jsx @@ -1,9 +1,69 @@ import PropTypes from 'prop-types' import React from 'react' +import styled from 'styled-components' import IconButton from './IconButton' import SelectInput from './SelectInput' +const PaginationWrapper = styled.div` + color: ${props => props.theme.secondary}; + display: block; + font-size: 14px; + line-height: 19px; +` + +const PaginationLabel = styled.div` + display: inline-block; + margin-right: 20px; +` + +const PaginationSize = styled.div` + display: inline-block; + margin-right: 20px; + + select { + background-color: transparent; + border: 0; + border-bottom: 1px solid $secondary; + color: $secondary; + min-width: 43px; + width: 43px; + } + + .input__options { + min-width: 60px; + width: 60px; + } +` + +const PaginationCount = styled.div` + display: inline-block; + margin-right: 20px; +` + +const PaginationPage = styled.div` + display: inline-block; + + ${IconButton} { + border: 0; + color: ${props => props.theme.secondary}; + display: inline-block; + font-size: 14px; + margin: 0 4px; + padding: 0; + width: 16px; + + &:active, &:focus, &:hover { + background: transparent; + } + } +` + +const PaginationPageLabel = styled.div` + display: inline-block; + padding: 0 10px; +` + export default class Pagination extends React.Component { static defaultProps = { label: 'Items', @@ -27,27 +87,27 @@ export default class Pagination extends React.Component { render () { return ( -
-
{this.props.label}:
-
+ + {this.props.label}: + ({text: s.toString(), value: s}))} value={this.props.size} /> -
-
+ + {((this.props.page - 1) * this.props.size) + 1}-{this.props.page * this.props.size} of {this.props.total} -
-
+ + this.handlePage(1)} /> this.handlePage(this.props.page - 1)} /> - Page {this.props.page} + Page {this.props.page} this.handlePage(this.props.page + 1)} /> this.handlePage(Math.ceil(this.props.total / this.props.size))} /> -
-
+ + ) } } From 7e7fe096bc2f8b5093111306e6704a72833c0beb Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 24 Nov 2018 01:18:12 -0800 Subject: [PATCH 15/20] Port Stepper. --- lib/Animations.js | 2 + sass/_library.scss | 1 - sass/_stepper.scss | 69 ---------------------------------- web/Stepper.jsx | 92 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 83 insertions(+), 81 deletions(-) delete mode 100644 sass/_stepper.scss diff --git a/lib/Animations.js b/lib/Animations.js index 09f73db..746d3a1 100644 --- a/lib/Animations.js +++ b/lib/Animations.js @@ -54,3 +54,5 @@ export const animationProgressbar = css`all 1s ${swiftEaseInTimingFunction} .1s; export const animationSelectItem = css`opacity .15s ${swiftEaseInTimingFunction} .4s;` export const animationModalContainer = css`all ${swiftEaseInOutDuration} ${swiftEaseInOutTimingFunction} .1s;` + +export const animationStepper = css`background-color ${swiftEaseInDuration} ${swiftEaseInTimingFunction} 0s;` diff --git a/sass/_library.scss b/sass/_library.scss index b59eca9..82e5177 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -7,7 +7,6 @@ @import 'menu'; @import 'navbar'; @import 'reset'; -@import 'stepper'; @import 'tab'; @import 'text'; @import 'util'; diff --git a/sass/_stepper.scss b/sass/_stepper.scss deleted file mode 100644 index 32cf599..0000000 --- a/sass/_stepper.scss +++ /dev/null @@ -1,69 +0,0 @@ - -.stepper { - &__content { - padding: 32px; - } - - &__steps { - - } - - &__step { - color: $secondary; - display: inline-block; - font-size: 14px; - line-height: 19px; - - $self: &; - - &--active { - #{$self}__indicator { - background-color: $primary; - color: $white; - } - } - - &--complete { - #{$self}__indicator { - background-color: $black; - color: $secondary; - } - } - - &__bar { - border-top: 1px solid $secondary; - display: inline-block; - height: 5px; - margin-right: 21px; - margin-top: -2px; - min-width: 100px; - width: 100px; - } - - &__indicator { - background-color: $black; - border-radius: 50%; - color: $white; - display: inline-block; - font-size: 16px; - height: 35px; - line-height: 21px; - margin-right: 9px; - margin-bottom: -12px; - overflow: hidden; - position: relative; - transition: $animation-stepper; - width: 35px; - - i, span { - font-size: 16px; - left: 50%; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - } - } - - &__title { margin-right: 40px; } - } -} diff --git a/web/Stepper.jsx b/web/Stepper.jsx index 2fe1640..759dd88 100644 --- a/web/Stepper.jsx +++ b/web/Stepper.jsx @@ -1,8 +1,9 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' +import styled, {css} from 'styled-components' import Icon from './Icon' +import { animationStepper } from '../lib/Animations' // Step export const Step = () => null @@ -13,6 +14,75 @@ Step.propTypes = { title: PropTypes.string.isRequired } +const StepperWrapper = styled.div` +` + +const StepperSteps = styled.div` +` + +const StepperContent = styled.div` + padding: 32px; +` + +const StepperStep = styled.div` + color: ${props => props.theme.secondary}; + display: inline-block; + font-size: 14px; + line-height: 19px; + + ${props => props.active ? css` + ${StepperIndicator} { + background-color: ${props => props.theme.primary}; + color: ${props => props.theme.white}; + } + ` : ''} + + ${props => props.complete ? css` + ${StepperIndicator} { + background-color: ${props => props.theme.black}; + color: ${props => props.theme.secondary}; + } + ` : ''} +` + +const StepperIndicator = styled.span` + background-color: ${props => props.theme.black}; + border-radius: 50%; + color: ${props => props.theme.white}; + display: inline-block; + font-size: 16px; + height: 35px; + line-height: 21px; + margin-right: 9px; + margin-bottom: -12px; + overflow: hidden; + position: relative; + transition: ${animationStepper}; + width: 35px; + + i, span { + font-size: 16px; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + } +` + +const StepperBar = styled.div` + border-top: 1px solid ${props => props.theme.secondary}; + display: inline-block; + height: 5px; + margin-right: 21px; + margin-top: -2px; + min-width: 100px; + width: 100px; +` + +const StepperTitle = styled.span` + margin-right: 40px; +` + // Stepper export class Stepper extends React.Component { static propTypes = { @@ -22,7 +92,7 @@ export class Stepper extends React.Component { } render () { - const [mods, {children, ...rest}] = pickRest(this.props, ['vertical']) + const {children, ...rest} = this.props const childArray = Array.isArray(children) ? children : [children] let content = null @@ -31,19 +101,19 @@ export class Stepper extends React.Component { const complete = i < this.props.index if (active) content = s.props.children return ( -
- {active || complete ? : {i}} - {s.props.title} - {i !== (childArray.length - 1) &&
} -
+ + {active || complete ? : {i}} + {s.props.title} + {i !== (childArray.length - 1) && } + ) }) return ( -
-
{steps}
-
{content}
-
+ + {steps} + {content} + ) } } From 74de2ed4cb0580d56ab561d23fb5f0f6c3cda8f1 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sun, 25 Nov 2018 02:33:42 -0800 Subject: [PATCH 16/20] Port Tab. --- sass/_library.scss | 1 - sass/_tab.scss | 79 ----------------------------------- web/Tab.jsx | 101 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 86 insertions(+), 95 deletions(-) delete mode 100644 sass/_tab.scss diff --git a/sass/_library.scss b/sass/_library.scss index 82e5177..a72eec9 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -7,6 +7,5 @@ @import 'menu'; @import 'navbar'; @import 'reset'; -@import 'tab'; @import 'text'; @import 'util'; diff --git a/sass/_tab.scss b/sass/_tab.scss deleted file mode 100644 index 584411e..0000000 --- a/sass/_tab.scss +++ /dev/null @@ -1,79 +0,0 @@ - -.tabs { - display: block; - margin: 0; - padding: 0; - position: relative; - text-align: center; - - &__bar { - background-color: $primary; - height: 1px; - position: absolute; - top: 50px; - transition: left .2s ease; - -webkit-transition: left .2s ease; - } - - &__clear { clear: both; } - - &__content { - background-color: $white; - border-radius: 5px; - box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); - margin-top: 5px; - padding: 32px; - text-align: left; - width: 100%; - } - - &__list { - background-color: $white; - border-radius: 5px; - box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); - position: relative; - - &__items { - position: absolute; - left: 50%; - transform: translateX(-50%); - } - } -} - -.tab { - display: inline-block; - - $self: &; - - &--active { - #{$self}__title { font-weight: bold; } - } - - &--disabled { - #{$self}__content { display: none; } - - #{$self}__icon, #{$self}__title { - color: $secondary; - cursor: not-allowed; - } - } - - &__icon { - cursor: pointer; - font-size: 24px; - height: 70px; - padding: 23px 63px; - - &:hover { font-weight: bold; } - } - - &__title { - cursor: pointer; - font-size: 16px; - line-height: 21px; - padding: 15px 42px; - - &:hover { font-weight: bold; } - } -} diff --git a/web/Tab.jsx b/web/Tab.jsx index 12ff1b9..7bb322b 100644 --- a/web/Tab.jsx +++ b/web/Tab.jsx @@ -2,15 +2,42 @@ import PropTypes from 'prop-types' import React from 'react' import {kill, pickRest} from '../lib/utils' import Icon from './Icon' +import styled, {css} from 'styled-components' + +const TabWrapper = styled.div` + display: inline-block; + + ${props => props.active ? css` + ${TabTitle} { font-weight: bold; } + ` : ''} +` + +const TabTitle = styled.div` + cursor: pointer; + font-size: 16px; + line-height: 21px; + padding: 15px 42px; + + :hover { font-weight: bold; } +` + +const TabIcon = styled.div` + cursor: pointer; + font-size: 24px; + height: 70px; + padding: 23px 63px; + + &:hover { font-weight: bold; } +` // Tab export const Tab = (props) => { - const [mods, {children, icon, index, onClick, title, ...rest}] = pickRest(props, ['active', 'disabled']) + const {children, icon, index, onClick, title, ...rest} = props return ( -
- {!!title &&
{title}
} - {!!icon &&
} -
+ + {!!title && {title}} + {!!icon && } + ) } @@ -23,6 +50,50 @@ Tab.propTypes = { title: PropTypes.string } +const TabsWrapper = styled.div` + display: block; + margin: 0; + padding: 0; + position: relative; + text-align: center; +` + +const TabsBar = styled.div` + background-color: ${props => props.theme.primary}; + height: 1px; + position: absolute; + top: 50px; + transition: left .2s ease; + -webkit-transition: left .2s ease; +` + +const TabsContent = styled.div` + background-color: ${props => props.theme.white}; + border-radius: 5px; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); + margin-top: 5px; + padding: 32px; + text-align: left; + width: 100%; +` + +const TabsList = styled.div` + background-color: ${props => props.theme.white}; + border-radius: 5px; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); + position: relative; +` + +const TabsListItems = styled.span` + /* position: absolute; + left: 50%; + transform: translateX(-50%); */ +` // none of this was ever working, what? + +const TabsClear = styled.div` + clear: both; +` + // Tabs export class Tabs extends React.Component { static propTypes = { @@ -70,7 +141,7 @@ export class Tabs extends React.Component { } render () { - const [mods, {children, ...rest}] = pickRest(this.props, []) + const {children, ...rest} = this.props // Clone tabs and add props let content = null let hasIcon = false @@ -92,16 +163,16 @@ export class Tabs extends React.Component { } return ( -
-
- { this.tabs = i }}> + + + { this.tabs = i }}> {tabs} -
- -
-
{content}
-
-
+ +
+
+ {content} + +
) } } From fd290de9c40d4412faebd93fac83ea4c814ca2c8 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sun, 25 Nov 2018 02:43:54 -0800 Subject: [PATCH 17/20] Port Navbar. --- sass/_library.scss | 1 - sass/_navbar.scss | 87 ------------------------------------- web/Navbar.jsx | 104 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 93 insertions(+), 99 deletions(-) delete mode 100644 sass/_navbar.scss diff --git a/sass/_library.scss b/sass/_library.scss index a72eec9..3c65ebc 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -5,7 +5,6 @@ @import 'grid'; @import 'input'; @import 'menu'; -@import 'navbar'; @import 'reset'; @import 'text'; @import 'util'; diff --git a/sass/_navbar.scss b/sass/_navbar.scss deleted file mode 100644 index d316706..0000000 --- a/sass/_navbar.scss +++ /dev/null @@ -1,87 +0,0 @@ - -.navbar { - background-color: $white; - min-height: 90px; - left: 0; - position: fixed; - top: 0; - width: 100%; - z-index: 5; - - $self: &; - - &__links { - min-height: 90px; - left: 121px; - margin: 0; - padding: 0; - } - - &__link { - cursor: pointer; - display: inline-block; - height: 90px; - padding: 33px 24px; - position: relative; - - &:hover { - a { - color: $primary; - transition: $animation-navbar; - } - } - - &--active { - a { color: $primary !important; } - - i { color: $primary !important; } - } - - a { - color: $black; - cursor: pointer; - font-family: $font-primary; - font-size: 16px; - text-decoration: none; - width: max-content; - width: -moz-max-content; - width: -ms-max-content; - width: -o-max-content; - width: -webkit-max-content; - } - - i { - color: $black; - font-size: 22px; - margin-right: 10px; - } - } - - &__menu { - cursor: pointer; - font-size: 30px; - left: 32px; - margin: 0; - position: absolute; - top: 32px; - } - - @media only screen and (max-width: 768px) { - &:hover { - #{$self}__links { - display: block; - margin-bottom: 24px; - } - - #{$self}__link { - display: block; - height: 50px; - padding: 33px 24px; - } - } - - &__links { - display: none; - } - } -} diff --git a/web/Navbar.jsx b/web/Navbar.jsx index d216884..c940f40 100644 --- a/web/Navbar.jsx +++ b/web/Navbar.jsx @@ -1,19 +1,101 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' +import styled, {css} from 'styled-components' +import {swiftEaseIn} from '../lib/Animations' import Icon from './Icon' +const NavbarMenu = styled.div` + cursor: pointer; + font-size: 30px; + left: 32px; + margin: 0; + position: absolute; + top: 32px; +` + +const NavbarLinks = styled.div` + min-height: 90px; + left: 121px; + margin: 0; + padding: 0; +` + +const NavbarLinkWrapper = styled.div` + cursor: pointer; + display: inline-block; + height: 90px; + padding: 33px 24px; + position: relative; + + :hover { + a { + color: ${props => props.theme.primary}; + transition: ${swiftEaseIn}; + } + } + + ${props => props.active ? css` + a { color: ${props => props.theme.primary} !important; } + + i { color: ${props => props.theme.primary} !important; } + ` : ''} + + a { + color: ${props => props.theme.black}; + cursor: pointer; + font-family: ${props => props.theme.fontPrimary}; + font-size: 16px; + text-decoration: none; + width: max-content; + } + + i { + color: ${props => props.theme.black}; + font-size: 22px; + margin-right: 10px; + } +` + +const NavbarWrapper = styled.div` + background-color: ${props => props.theme.white}; + min-height: 90px; + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index: 5; + + @media only screen and (max-width: 768px) { + :hover { + ${NavbarLinks} { + display: block; + margin-bottom: 24px; + } + + ${NavbarLinkWrapper} { + display: block; + height: 50px; + padding: 33px 24px; + } + } + + ${NavbarLinks} { + display: none; + } + } +` + // Navbar export const Navbar = ({children, onDrawer, ...rest}) => ( -
+ {!!onDrawer && -
+ -
+ } -
{children}
-
+ {children} + ) Navbar.propTypes = { @@ -40,20 +122,20 @@ export class NavbarLink extends React.Component { } render () { - const [ mods, {as, children, k, to, ...rest} ] = pickRest(this.props, ['active']) + const {active, as, children, k, to, ...rest} = this.props if (as === 'Link') { rest.to = to } else { rest.href = to } - - if (window.location.hash === to) mods.active = true + let realActive = active + if (window.location.hash === to) realActive = true const As = as return ( -
+ {!!k && }{children} -
+ ) } } From becf9cce9835884b7ac08bd37b72b2fa85222d94 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Tue, 27 Nov 2018 18:11:19 -0800 Subject: [PATCH 18/20] Port Inputs --- sass/_input.scss | 199 -------------------------------------------- sass/_library.scss | 1 - web/SelectInput.jsx | 162 ++++++++++++++++++++++++++++++++---- web/TextInput.jsx | 116 +++++++++++++++++++++++--- 4 files changed, 250 insertions(+), 228 deletions(-) delete mode 100644 sass/_input.scss diff --git a/sass/_input.scss b/sass/_input.scss deleted file mode 100644 index e8861eb..0000000 --- a/sass/_input.scss +++ /dev/null @@ -1,199 +0,0 @@ - -.input { - font-family: $font-primary; - font-size: 14px; - height: 55px; - padding-top: 18px; - position: relative; - - $self: &; - - input, select, textarea { - background: transparent; - border: 0; - color: $black; - line-height: 16px; - outline: none; - padding: 4px 0; - } - - select { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - border: 0 !important; - color: $black; - text-indent: 0.1px; - text-overflow: ''; - - &::-ms-expand { - display: none; - } - - option { - border: 0; - color: $black; - max-height: 0; - } - } - - &--active { - #{$self}__label { - color: $secondary; - font-family: $font-primary; - font-size: 12px; - height: 11px; - line-height: 11px; - top: 0; - } - - #{$self}__arrow { color: $black; } - } - - &--error { - #{$self}__label { color: $red !important; } - - #{$self}__component { border-color: $red !important; } - } - - &--focus { - #{$self}__bar:after, #{$self}__bar:before { - width: 50%; - } - - &:not(#{$self}--native) { - select#{$self}__component { - display: none; - } - - #{$self}__options { - max-height: 230px; - transition: $animation-select; - - &__item { - opacity: 1; - transition: $animation-select-item; - } - } - } - } - - &--native { - select { - font-family: $font-primary; - font-size: 14px; - - option { - cursor: pointer; - display: block !important; - height: 27px; - line-height: 19px; - min-width: 108px; - padding: 6px 11px; - width: 100%; - - &:active { background-color: rgba(124, 124, 124, 0.2); } - - &:hover { background-color: rgba(124, 124, 124, 0.1); } - } - } - } - - &__arrow { - color: $secondary; - float: right; - height: 5px; - position: absolute; - right: 0; - top: 19px; - width: 10px; - } - - &__bar { - display: block; - position: relative; - - &:after, &:before { - content: ''; - height: 1px; - width: 0; - bottom: 1px; - position: absolute; - background: $primary; - transition: 0.2s ease all; - } - - &:after { - right: 50%; - } - - &:before { - left: 50%; - } - } - - &__component { - border-color: transparent; - border-bottom: 1px solid #f2f2f2; - font-family: $font-primary; - font-size: 14px; - min-width: 108px; - width: 100%; - } - - &__label { - color: $secondary; - cursor: text; - font-family: $font-primary; - font-size: 14px; - height: 16px; - line-height: 16px; - min-width: 108px; - position: absolute; - top: 18px; - transition: $animation-label; - } - - &__message { - color: $secondary; - font-size: 9px; - height: 11px; - line-height: 11px; - margin-top: 6px; - } - - &__options { - background-color: $white; - border-radius: 5px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - display: block; - left: 50%; - max-height: 0; - min-width: 108px; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - width: 100%; - z-index: 4; - - @include scrollbar; - - &__item { - cursor: pointer; - font-family: $font-primary; - font-size: 14px; - height: 27px; - line-height: 19px; - min-width: 108px; - opacity: 0; - padding: 6px 11px; - width: 100%; - - &:hover { background-color: rgba(124, 124, 124, 0.1); } - - &--active { background-color: rgba(124, 124, 124, 0.2); } - } - } -} diff --git a/sass/_library.scss b/sass/_library.scss index 3c65ebc..620bb76 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -3,7 +3,6 @@ @import 'animation'; @import 'drawer'; @import 'grid'; -@import 'input'; @import 'menu'; @import 'reset'; @import 'text'; diff --git a/web/SelectInput.jsx b/web/SelectInput.jsx index c9619d2..fb9025d 100644 --- a/web/SelectInput.jsx +++ b/web/SelectInput.jsx @@ -1,8 +1,136 @@ import PropTypes from 'prop-types' import React from 'react' -import {kill, pickRest} from '../lib/utils' +import {kill} from '../lib/utils' +import styled, {css} from 'styled-components' import Icon from './Icon' +import { swiftEaseIn, swiftEaseInOut, animationSelectItem } from '../lib/Animations' + +const SelectInputWrapper = styled.div` + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 55px; + padding-top: 18px; + position: relative; + + ${props => props.active ? css` + ${SelectInputLabel} { + color: ${props => props.theme.secondary}; + font-family: ${props => props.theme.fontPrimary}; + font-size: 12px; + height: 11px; + line-height: 11px; + top: 0; + } + + ${SelectInputArrow} { color: ${props => props.theme.black}; } + ` : ''} + + ${props => props.focus && !props.native ? css` + ${SelectInputComponent} { + display: none; + } + + ${SelectInputOptions} { + max-height: 230px; + transition: ${swiftEaseInOut}; + + ${SelectInputItem} { + opacity: 1; + transition: ${animationSelectItem}; + } + } + ` : ''} +` + +const SelectInputLabel = styled.label` + color: ${props => props.theme.secondary}; + cursor: text; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 16px; + line-height: 16px; + min-width: 108px; + position: absolute; + top: 18px; + transition: ${swiftEaseIn}; +` + +const SelectInputArrow = styled.label` + color: ${props => props.theme.secondary}; + float: right; + height: 5px; + position: absolute; + right: 0; + top: 19px; + width: 10px; +` + +const SelectInputComponent = styled.select` + background: transparent; + border: 0; + color: ${props => props.theme.black}; + line-height: 16px; + outline: none; + padding: 4px 0; + appearance: none; + border: 0 !important; + color: ${props => props.theme.black}; + text-indent: 0.1px; + text-overflow: ''; + + ::-ms-expand { + display: none; + } + + option { + border: 0; + color: ${props => props.theme.black}; + max-height: 0; + } + + border-color: transparent; + border-bottom: 1px solid #f2f2f2; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + min-width: 108px; + width: 100%; +` + +const SelectInputOptions = styled.div` + background-color: ${props => props.theme.white}; + border-radius: 5px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + display: block; + left: 50%; + max-height: 0; + min-width: 108px; + overflow-x: hidden; + overflow-y: auto; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 100%; + z-index: 4; +` + +const SelectInputItem = styled.div` + cursor: pointer; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 27px; + line-height: 19px; + min-width: 108px; + opacity: 0; + padding: 6px 11px; + width: 100%; + + :hover { background-color: rgba(124, 124, 124, 0.1); } + + ${props => props.active ? css` + background-color: rgba(124, 124, 124, 0.2); + ` : ''} +` export default class SelectInput extends React.Component { static defaultProps = { @@ -67,10 +195,12 @@ export default class SelectInput extends React.Component { } render () { - const [mods, {defaultValue, label, message, name, notempty, options, value, ...rest}] = pickRest(this.props, ['error', 'native']) + const {defaultValue, label, message, name, notempty, options, value, ...rest} = this.props - if (this.state.isFocus) mods.focus = true - if (mods.focus || !!this.state.value) mods.active = true + let focus = false + if (this.state.isFocus) focus = true + let active = focus + if (this.state.value) active = true const inputProps = { autoComplete: 'off', @@ -84,27 +214,27 @@ export default class SelectInput extends React.Component { const adjustedOptions = notempty ? options : [{text: '', value: ''}, ...options] return ( -
+ {!!label && - + } -
- - {!mods.native && -
+ + {!this.props.native && + {adjustedOptions.map((o, i) => ( -
this.handleSelect(ev, o)}> + this.handleSelect(ev, o)}> {o.text} -
+ ))} -
+ } {!!message &&
{message}
} -
+ ) } } diff --git a/web/TextInput.jsx b/web/TextInput.jsx index b02d72e..fc3583c 100644 --- a/web/TextInput.jsx +++ b/web/TextInput.jsx @@ -1,6 +1,97 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' +import styled, {css} from 'styled-components' +import { swiftEaseIn } from '../lib/Animations' + +const TextInputWrapper = styled.div` + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 55px; + padding-top: 18px; + position: relative; + + ${props => props.active ? css` + ${TextInputLabel} { + color: ${props => props.theme.secondary}; + font-family: ${props => props.theme.fontPrimary}; + font-size: 12px; + height: 11px; + line-height: 11px; + top: 0; + } + ` : ''} + + ${props => props.focus ? css` + ${TextInputBar}:after, ${TextInputBar}:before { + width: 50%; + } + ` : ''} + + ${props => props.error ? css` + ${TextInputLabel} { color: ${props => props.theme.red} !important; } + + ${TextInputInput} { border-color: ${props => props.theme.red} !important; } + ` : ''} +` + +const TextInputLabel = styled.label` + color: ${props => props.theme.secondary}; + cursor: text; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 16px; + line-height: 16px; + min-width: 108px; + position: absolute; + top: 18px; + transition: ${swiftEaseIn}; +` + +const TextInputInput = styled.input` + background: transparent; + border: 0; + color: ${props => props.theme.black}; + line-height: 16px; + outline: none; + padding: 4px 0; + border-color: transparent; + border-bottom: 1px solid #f2f2f2; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + min-width: 108px; + width: 100%; +` + +const TextInputBar = styled.div` + display: block; + position: relative; + + &:after, &:before { + content: ''; + height: 1px; + width: 0; + bottom: 1px; + position: absolute; + background: ${props => props.theme.primary}; + transition: 0.2s ease all; + } + + :after { + right: 50%; + } + + :before { + left: 50%; + } +` + +const TextInputMessage = styled.div` + color: ${props => props.theme.secondary}; + font-size: 9px; + height: 11px; + line-height: 11px; + margin-top: 6px; +` export default class TextInput extends React.Component { static defaultProps = { @@ -34,11 +125,12 @@ export default class TextInput extends React.Component { handleFocus = isFocus => this.setState({isFocus}) render () { - const [mods, {as, defaultValue, label, message, ...rest}] = pickRest(this.props, ['error']) - const As = as + const {defaultValue, label, message, ...rest} = this.props - if (this.state.isFocus) mods.focus = true - if (mods.focus || !!this.state.value) mods.active = true + let focus = false + if (this.state.isFocus) focus = true + let active = focus + if (this.state.value) active = true const inputProps = { autoComplete: 'off', @@ -51,16 +143,16 @@ export default class TextInput extends React.Component { } return ( -
+ {!!label && - + } - -
- {!!message &&
{message}
} -
+ + + {!!message && {message}} +
) } } From ea8f50b0fad3db287362039c1a321d0d7df5bfba Mon Sep 17 00:00:00 2001 From: Penple03 Date: Tue, 27 Nov 2018 19:48:04 -0800 Subject: [PATCH 19/20] Port Drawer --- sass/_drawer.scss | 91 ---------------------------------- sass/_library.scss | 1 - web/Drawer.jsx | 119 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 104 insertions(+), 107 deletions(-) delete mode 100644 sass/_drawer.scss diff --git a/sass/_drawer.scss b/sass/_drawer.scss deleted file mode 100644 index ca3490d..0000000 --- a/sass/_drawer.scss +++ /dev/null @@ -1,91 +0,0 @@ - -.drawer { - background-color: transparent; - bottom: 0; - display: block; - left: -100%; - position: fixed; - top: 0; - transition: $animation-drawer; - z-index: 6; - - &--open { - background-color: rgba(0, 0, 0, 0.5); - left: 0; - right: 0; - } - - &__menu { - background-color: $white; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - height: 100%; - left: 0; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - top: 0; - width: $drawer-width; - z-index: 7; - - &__divider { - border: 1px solid rgba(0, 0, 0, 0.2); - height: 1px; - } - - &__header { - border-bottom: 1px solid rgba(0, 0, 0, 0.2); - padding: 20px; - } - - &__link { - cursor: pointer; - position: relative; - - &:active { - background-color: darken(#f2f2f2, 25%); - } - - &:focus, &:hover { - background-color: #f2f2f2; - } - - a { - color: $secondary; - display: block; - font-family: $font-primary; - font-size: 14px; - height: 60px; - line-height: 19px; - padding-left: 84px; - padding-top: 22px; - text-decoration: none; - width: 100%; - } - - i { - font-size: 24px; - left: 32px; - position: absolute; - top: 50%; - transform: translateY(-50%); - } - } - - &__title { - color: $black; - font-family: $font-secondary; - font-size: 24px; - font-weight: bold; - height: 33px; - letter-spacing: -1px; - line-height: 35px; - } - - &__subtitle { - color: $black; - font-family: $font-primary; - font-size: 14px; - line-height: 19px; - } - } -} diff --git a/sass/_library.scss b/sass/_library.scss index 620bb76..23b0c32 100644 --- a/sass/_library.scss +++ b/sass/_library.scss @@ -1,7 +1,6 @@ @import 'mixin'; @import 'animation'; -@import 'drawer'; @import 'grid'; @import 'menu'; @import 'reset'; diff --git a/web/Drawer.jsx b/web/Drawer.jsx index 4c0243c..d419b71 100644 --- a/web/Drawer.jsx +++ b/web/Drawer.jsx @@ -1,18 +1,50 @@ import PropTypes from 'prop-types' import React from 'react' import {pickRest} from '../lib/utils' +import styled, {css} from 'styled-components' import Icon from './Icon' +import { swiftEaseOut } from '../lib/Animations' + +const DrawerWrapper = styled.div` + background-color: transparent; + bottom: 0; + display: block; + left: -100%; + position: fixed; + top: 0; + transition: ${swiftEaseOut}; + z-index: 6; + + ${props => props.open ? css` + background-color: rgba(0, 0, 0, 0.5); + left: 0; + right: 0; + ` : ''} +` + +const DrawerMenu = styled.div` + background-color: ${props => props.theme.white}; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); + height: 100%; + left: 0; + overflow-x: hidden; + overflow-y: auto; + position: absolute; + top: 0; + width: ${props => props.theme.drawerWidth}; + z-index: 7; +` // Drawer export const Drawer = (props) => { - const [mods, {children, onDrawer, ...rest}] = pickRest(props, ['open']) + const {children, onDrawer, ...rest} = props return ( -
-
+ + {children} -
-
+ + ) } @@ -23,16 +55,39 @@ Drawer.propTypes = { } // Divider -export const DrawerDivider = () => ( -
-) +export const DrawerDivider = styled.div` + border: 1px solid rgba(0, 0, 0, 0.2); + height: 1px; +` + +const DrawerHeaderWrapper = styled.div` + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + padding: 20px; +` + +const DrawerHeaderTitle = styled.div` + color: ${props => props.theme.black}; + font-family: ${props => props.theme.fontSecondary}; + font-size: 24px; + font-weight: bold; + height: 33px; + letter-spacing: -1px; + line-height: 35px; +` + +const DrawerHeaderSubtitle = styled.div` + color: ${props => props.theme.black}; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + line-height: 19px; +` // Header export const DrawerHeader = ({subtitle, title, ...rest}) => ( -
- {!!title &&
{title}
} - {!!subtitle &&
{subtitle}
} -
+ + {!!title && {title}} + {!!subtitle && {subtitle}} + ) DrawerHeader.propTypes = { @@ -40,13 +95,47 @@ DrawerHeader.propTypes = { title: PropTypes.string } +const DrawerLinkWrapper = styled.div` + cursor: pointer; + position: relative; + + &:active { + background-color: darken(#f2f2f2, 25%); + } + + &:focus, &:hover { + background-color: #f2f2f2; + } + + a { + color: ${props => props.theme.secondary}; + display: block; + font-family: ${props => props.theme.fontPrimary}; + font-size: 14px; + height: 60px; + line-height: 19px; + padding-left: 84px; + padding-top: 22px; + text-decoration: none; + width: 100%; + } + + i { + font-size: 24px; + left: 32px; + position: absolute; + top: 50%; + transform: translateY(-50%); + } +` + // Link export const DrawerLink = (props) => { - const [mods, {children, k, ...rest}] = pickRest(props, ['active']) + const {children, k, ...rest} = props return ( -
+ {!!k && }{children} -
+ ) } From c3a726e12253228d91766157f816e396aeed0368 Mon Sep 17 00:00:00 2001 From: Penple03 Date: Sat, 8 Dec 2018 13:27:58 -0800 Subject: [PATCH 20/20] heavy refactor --- demo/web/App.jsx | 4 +- demo/web/Section/BadgeDemo.jsx | 4 +- demo/web/Section/ButtonDemo.jsx | 24 ++++++------ demo/web/Section/TooltipDemo.jsx | 2 +- lib/Animations.js | 8 ++-- lib/Theme.js | 62 +++++++++++++++++++++++++++++ lib/Themes.js | 56 -------------------------- lib/utils.js | 14 ++++++- package.json | 3 +- web/Badge.jsx | 38 ++++++++++-------- web/Button.jsx | 67 ++++++++++++++++++-------------- web/Card.jsx | 33 ++++++++-------- web/Chart.jsx | 11 +++--- web/Checkbox.jsx | 47 ++++++++++------------ web/Code.jsx | 8 ++-- web/Drawer.jsx | 18 ++++----- web/IconButton.jsx | 56 ++++++++++++++------------ web/Menu.jsx | 5 ++- web/Modal.jsx | 3 +- web/Navbar.jsx | 15 +++---- web/Pagination.jsx | 7 ++-- web/Panel.jsx | 19 ++++----- web/ProgressBar.jsx | 5 ++- web/Radio.jsx | 26 ++++++------- web/SelectInput.jsx | 28 ++++++------- web/Stepper.jsx | 18 +++++---- web/Tab.jsx | 10 +++-- web/Table.jsx | 11 +++--- web/TextInput.jsx | 27 ++++++------- web/Tooltip.jsx | 30 +++++++++----- webpack.config.js | 3 +- yarn.lock | 4 ++ 32 files changed, 364 insertions(+), 302 deletions(-) create mode 100644 lib/Theme.js delete mode 100644 lib/Themes.js diff --git a/demo/web/App.jsx b/demo/web/App.jsx index 13b7762..62b704d 100644 --- a/demo/web/App.jsx +++ b/demo/web/App.jsx @@ -6,8 +6,6 @@ import { render } from 'react-dom' import {ThemeProvider} from 'styled-components' -import {light} from '../../lib/Themes' - import Github from './Github' import Home from './Home' import SASS from './SASS' @@ -45,7 +43,7 @@ class App extends React.Component { render () { return ( - +
diff --git a/demo/web/Section/BadgeDemo.jsx b/demo/web/Section/BadgeDemo.jsx index 360faab..32030d6 100644 --- a/demo/web/Section/BadgeDemo.jsx +++ b/demo/web/Section/BadgeDemo.jsx @@ -8,9 +8,9 @@ import Source from '../../../web/Source' const ButtonDemo = () => (

Badges

- + - +

Code Example

(

Buttons

- - + +

Code Example

(

Large Buttons

- - + +

Code Example

(

Outlined Buttons

- - + +

Code Example

(

Large Outline Buttons

- - + +

Code Example

(

Text Buttons

- - + +

Code Example

(

Icon Buttons

- - + +

Code Example

(

Tooltips

- +

Code Example

props => keyframes` - 0% { box-shadow: 0 0 0 0 ${rgba(props.theme[color], 0.4)}; } - 70% { box-shadow: 0 0 0 10px ${rgba(props.theme[color], 0)}; } - 100% { box-shadow: 0 0 0 0 ${rgba(props.theme[color], 0)}; } +export const pulse = color => keyframes` + 0% { box-shadow: 0 0 0 0 ${rgba(color, 0.4)}; } + 70% { box-shadow: 0 0 0 10px ${rgba(color, 0)}; } + 100% { box-shadow: 0 0 0 0 ${rgba(color, 0)}; } ` export const ripple = keyframes` diff --git a/lib/Theme.js b/lib/Theme.js new file mode 100644 index 0000000..02c3e38 --- /dev/null +++ b/lib/Theme.js @@ -0,0 +1,62 @@ +import theme from 'styled-theming' + +// Border +export const borderRadius = '5px' + +// Colors +export const black = '#252525' +export const blue = '#294dea' +export const gray = '#959595' +export const green = '#9eff90' +export const lightGray = '#f7f7f7' +export const purple = '#bc92ff' +export const red = '#e34a4a' +export const white = '#ffffff' +export const yellow = '#fffb79' + +// Color Codes +export const disabled = theme('mode', { + light: '#cccccc' +}) +export const primary = theme('mode', { + light: blue +}) +export const secondary = theme('mode', { + light: '#7c7c7c' +}) +export const tertiary = theme('mode', { + light: '#e9edfc' +}) + +export const alert = theme('mode', { + light: red +}) + +export const info = theme('mode', { + light: blue +}) + +export const success = theme('mode', { + light: green +}) + +// Card +export const cardPadding = '32px' + +// Drawer +export const drawerWidth = '290px' + +// Font +export const fontPrimary = "'Roboto', sans-serif" +export const fontSecondary = "'Poppins', sans-serif" + +// Grid +export const gridGutter = '10px' + +// Input + +// Modal +export const modalPadding = '32px' + +// Panel +export const panelPadding = '32px' diff --git a/lib/Themes.js b/lib/Themes.js deleted file mode 100644 index d21895c..0000000 --- a/lib/Themes.js +++ /dev/null @@ -1,56 +0,0 @@ -const common = { - // Border - borderRadius: '5px', - - // Colors - black: '#252525', - blue: '#294dea', - gray: '#959595', - green: '#9eff90', - lightGray: '#f7f7f7', - purple: '#bc92ff', - red: '#e34a4a', - white: '#ffffff', - yellow: '#fffb79', - - // Color Codes - disabled: '#cccccc', - get primary () { return this.blue }, - secondary: '#7c7c7c', - tertiary: '#e9edfc', - - get alert () { return this.red }, - get info () { return this.blue }, - get success () { return this.green }, - - // Card - cardPadding: '32px', - - // Drawer - drawerWidth: '290px', - - // Font - fontPrimary: "'Roboto', sans-serif", - fontSecondary: "'Poppins', sans-serif", - - // Grid - gridGutter: '10px', - - // Input - - // Modal - modalPadding: '32px', - - // Panel - panelPadding: '32px' -} - -export const light = Object.assign({}, common, { - bgColor: '#f7f7f7', - fgColor: common.black -}) - -export const dark = Object.assign({}, common, { - bgColor: common.black, - fgColor: common.white -}) diff --git a/lib/utils.js b/lib/utils.js index 991b893..cc5096c 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -22,4 +22,16 @@ export function pickRest (object, pick) { return [picked, rest] } -export default {kill, pickRest} +export function splitProps (map) { + return function (props) { + const out = {} + for (const key in map) { + for (const prop of map[key]) { + if (props[prop]) { + out[key] = prop + } + } + } + return out + } +} diff --git a/package.json b/package.json index 5ffdcd4..76ec2ca 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,8 @@ "react-router-dom": "^4.3.1", "react-stockcharts": "^0.7.7", "react-syntax-highlighter": "^8.0.1", - "styled-components": "^4.0.3" + "styled-components": "^4.0.3", + "styled-theming": "^2.2.0" }, "standard": { "parser": "babel-eslint" diff --git a/web/Badge.jsx b/web/Badge.jsx index 8d56dd7..c976112 100644 --- a/web/Badge.jsx +++ b/web/Badge.jsx @@ -1,23 +1,19 @@ import PropTypes from 'prop-types' import React from 'react' -import styled, {css} from 'styled-components' +import styled from 'styled-components' import {pulse, swiftEaseIn} from '../lib/Animations' +import { primary, white, black } from '../lib/Theme' +import theme from 'styled-theming' + +const color = theme.variants('mode', 'color', { + default: {light: black}, + primary: {light: primary} +}) -const BadgeWrapper = styled.span` - position: relative; - z-index: 1; - ${props => props.primary ? css` - ${BadgeText} { - animation: ${pulse('primary')} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); - background-color: ${props => props.theme.primary}; - } - ` : ''} -` const BadgeText = styled.span` - animation: ${pulse('black')} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); - background-color: ${props => props.theme.black}; + background-color: ${black}; border-radius: 50%; - color: ${props => props.theme.white}; + color: ${white}; font-size: 14px; height: 24px; position: absolute; @@ -36,6 +32,15 @@ const BadgeText = styled.span` } ` +const BadgeWrapper = styled.span` + position: relative; + z-index: 1; + ${BadgeText} { + animation: ${props => pulse(color(props))} 1.25s infinite cubic-bezier(0.66, 0, 0, 1); + background-color: ${color}; + } +` + const Badge = (props) => { const {children, text, ...rest} = props return ( @@ -47,12 +52,13 @@ const Badge = (props) => { } Badge.defaultProps = { - text: '!' + text: '!', + color: 'default' } Badge.propTypes = { children: PropTypes.any.isRequired, - primary: PropTypes.bool, + color: PropTypes.oneOf(['default', 'primary']), text: PropTypes.string.isRequired } diff --git a/web/Button.jsx b/web/Button.jsx index 5e01b1a..f293d6f 100644 --- a/web/Button.jsx +++ b/web/Button.jsx @@ -3,14 +3,30 @@ import styled, {css} from 'styled-components' import {ripple} from '../lib/Animations' import {lighten, darken} from 'polished' import React from 'react' +import { fontPrimary, white, borderRadius, black, primary, secondary, disabled } from '../lib/Theme' +import theme from 'styled-theming' + +const color = theme.variants('mode', 'color', { + default: {light: black}, + primary: {light: primary}, + secondary: {light: secondary}, + disabled: {light: disabled} +}) + +const lightenedColor = theme.variants('mode', 'color', { + default: {light: lighten(0.6, black)}, + primary: {light: props => lighten(0.4, primary(props))}, + secondary: {light: props => lighten(0.35, secondary(props))}, + disabled: {light: props => lighten(0.1, disabled(props))} +}) /* eslint-disable indent */ -const StyledButton = styled.button` - border-radius: ${props => props.theme.borderRadius}; +const ButtonWrapper = styled.button` + border-radius: ${borderRadius}; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: ${props => props.theme.white}; + color: ${white}; cursor: pointer; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; font-weight: 500; height: 35px; @@ -22,7 +38,7 @@ const StyledButton = styled.button` position: relative; text-align: center; - background-color: ${props => props.theme[props.color]}; + background-color: ${color}; background-position: center; border: none; @@ -55,62 +71,53 @@ const StyledButton = styled.button` } :hover { - background-color: ${props => lighten(0.1, props.theme[props.color])} + background-color: ${props => lighten(0.1, color(props))}; } ${props => props.outline ? css` background: transparent; - border: 1px solid ${props => props.theme[props.color]}; + border: 1px solid ${color}; box-shadow: none; - color: ${props => props.theme[props.color]}; + color: ${color}; :active { - background-color: ${props => darken(0.25, lighten(props.p, props.theme[props.color]))}; + background-color: ${props => darken(0.25, lightenedColor(props))}; } :hover, :focus { - background-color: ${props => lighten(props.p, props.theme[props.color])}; + background-color: ${lightenedColor}; } ` : ''} ${props => props.text ? css` background: transparent; box-shadow: none; - color: ${props => props.theme[props.color]}; + color: ${color}; :active { - background-color: ${props => darken(0.25, lighten(props.p, props.theme[props.color]))}; + background-color: ${props => darken(0.25, lightenedColor(props))}; } :hover, :focus { - background-color: ${props => lighten(props.p, props.theme[props.color])}; + background-color: ${lightenedColor}; } ` : ''} ` /* eslint-enable indent */ const Button = styled(props => { - const {primary, secondary, disabled, children, ...rest} = props - let color = 'black' - let p = 0.6 - if (primary) { - color = 'primary' - p = 0.4 - } else if (secondary) { - color = 'secondary' - p = 0.35 - } else if (disabled) { - color = 'disabled' - p = 0.1 - } - return {children} + const {disabled, children, color, ...rest} = props + return {children} })`` +Button.defaultProps = { + color: 'default' +} + Button.propTypes = { - as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), large: PropTypes.bool, - primary: PropTypes.bool, - secondary: PropTypes.bool, + as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + color: PropTypes.oneOf(['default', 'primary', 'secondary']), disabled: PropTypes.bool, outline: PropTypes.bool, text: PropTypes.bool diff --git a/web/Card.jsx b/web/Card.jsx index 37e9dcb..47cadb5 100644 --- a/web/Card.jsx +++ b/web/Card.jsx @@ -5,11 +5,12 @@ import styled, { css } from 'styled-components' import { swiftEaseIn } from '../lib/Animations' import Icon from './Icon' +import { white, borderRadius, cardPadding, gridGutter, fontSecondary, red } from '../lib/Theme' const CardWrapper = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; border-bottom: 10px; - border-radius: ${props => props.theme.borderRadius}; + border-radius: ${borderRadius}; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); transition: ${swiftEaseIn}; @@ -22,20 +23,20 @@ const CardWrapper = styled.div` ${CardTitle} { border: 0; - color: ${props => props.theme.white}; + color: ${white}; margin: 0; padding: 0; ${CardText} { - bottom: ${props => props.theme.cardPadding}; - left: ${props => props.theme.cardPadding}; + bottom: ${cardPadding}; + left: ${cardPadding}; position: absolute; } } img { - border-top-left-radius: $border-radius; - border-top-right-radius: $border-radius; + border-top-left-radius: ${borderRadius}; + border-top-right-radius: ${borderRadius}; height: min-content; } ` : ''} @@ -56,7 +57,7 @@ Card.propTypes = { // Actions export const CardActions = styled.div` - padding: 0 ${props => props.theme.cardPadding} ${props => props.theme.cardPadding} ${props => props.theme.cardPadding}; + padding: 0 ${cardPadding} ${cardPadding} ${cardPadding}; position: relative; .row div:first { @@ -64,7 +65,7 @@ export const CardActions = styled.div` padding-left: 0; } - button { margin: 0 ${props => props.theme.gridGutter} 0 0; } + button { margin: 0 ${gridGutter} 0 0; } ` CardActions.propTypes = { @@ -73,7 +74,7 @@ CardActions.propTypes = { // Body export const CardBody = styled.div` - padding: ${props => props.theme.cardPadding}; + padding: ${cardPadding}; ${props => props.nopadding ? 'padding: 0;' : ''} ` @@ -85,24 +86,24 @@ CardBody.propTypes = { const CardTitleWrapper = styled.div` border-bottom: 1px solid rgba(0, 0, 0, 0.2); - font-family: ${props => props.theme.fontSecondary}; + font-family: ${fontSecondary}; font-size: 24px; font-weight: bold; - padding: ${props => props.theme.cardPadding}; + padding: ${cardPadding}; position: relative; i { - color: $red; + color: ${red}; font-size: 24px; position: absolute; - right: ${props => props.theme.cardPadding}; + right: ${cardPadding}; top: 50%; transform: translateY(-50%); } img { - border-top-left-radius: ${props => props.theme.borderRadius}; - border-top-right-radius: ${props => props.theme.borderRadius}; + border-top-left-radius: ${borderRadius}; + border-top-right-radius: ${borderRadius}; } ` const CardText = styled.span`` diff --git a/web/Chart.jsx b/web/Chart.jsx index 5750d4a..ab53717 100644 --- a/web/Chart.jsx +++ b/web/Chart.jsx @@ -3,14 +3,15 @@ import PropTypes from 'prop-types' import React from 'react' import ReactChartKick, {LineChart} from 'react-chartkick' import styled from 'styled-components' +import { black, white, fontSecondary, secondary } from '../lib/Theme' ReactChartKick.addAdapter(Chart) const ChartWrapper = styled.div` - background-color: ${props => props.theme.black}; + background-color: ${black}; border-radius: 10px; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: ${props => props.theme.white}; + color: ${white}; ` const ChartHead = styled.div` @@ -22,7 +23,7 @@ const ChartHead = styled.div` ` const ChartHeadTitle = styled.div` - font-family: ${props => props.theme.fontSecondary}; + font-family: ${fontSecondary}; font-size: 24px; font-weight: bold; letter-spacing: -1px; @@ -42,7 +43,7 @@ const ChartHeadFlex = styled.div` const ChartHeadLinks = styled.div` a { - color: ${props => props.theme.secondary}; + color: ${secondary}; cursor: pointer; font-size: 14px; font-weight: 500; @@ -51,7 +52,7 @@ const ChartHeadLinks = styled.div` &:last-child { margin-right: 0; } - &.active { color: ${props => props.theme.white}; } + &.active { color: ${white}; } } ` diff --git a/web/Checkbox.jsx b/web/Checkbox.jsx index 2c51cba..a368276 100644 --- a/web/Checkbox.jsx +++ b/web/Checkbox.jsx @@ -1,35 +1,38 @@ import PropTypes from 'prop-types' import React from 'react' import styled, { css } from 'styled-components' +import theme from 'styled-theming' import { pulse, swiftEaseOut } from '../lib/Animations' +import { black, primary, secondary, white, red } from '../lib/Theme' + +const color = theme.variants('mode', 'color', { + default: {light: black}, + primary: {light: primary}, + secondary: {light: secondary}, + disabled: {light: '#C8C8C8'}, + red: {light: red} +}) const CheckboxWrapper = styled.span` display: inline-block; height: 24px; width: 24px; - border: 1px solid ${props => props.theme[props.color]}; + border: 1px solid ${color}; border-radius: 50%; margin: 0 5px; - color: ${props => props.theme.white}; + color: ${white}; text-align: center; vertical-align: top; ${props => props.disabled ? css` - border-color: #C8C8C8; cursor: not-allowed; ` : ''} ${props => props.checked && !props.switch ? css` - animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); + animation: ${props => pulse(color(props))} 1.25s cubic-bezier(0.66, 0, 0, 1); border: 0; - background-color: ${props => props.theme.black}; - - ${props => props.color ? css` - animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: ${props => props.theme[props.color]}; - ` : ''} - ${props => props.disabled ? 'background-color: #C8C8C8;' : ''} + background-color: ${color}; ::after { content: ${props => props.indeterminate ? '"\\2015"' : '"\\2713"'}; @@ -48,21 +51,13 @@ const CheckboxWrapper = styled.span` width: 24px; height: 24px; border-radius: 50%; - background-color: ${props => props.theme.white}; + background-color: ${white}; transition: ${swiftEaseOut}; box-sizing: content-box; ${props => props.checked ? css` - animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: ${props => props.theme.black}; + animation: ${props => pulse(color(props))} 1.25s cubic-bezier(0.66, 0, 0, 1); + background-color: ${color}; transform: translate(24px); - ${props => props.color ? css` - animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: ${props => props.theme[props.color]}; - ` : ''} - ` : ''} - ${props => props.disabled ? css` - animation: none; - background-color: #C8C8C8; ` : ''} } ` : ''} @@ -71,12 +66,12 @@ const CheckboxWrapper = styled.span` export default class Checkbox extends React.Component { static defaultProps = { defaultChecked: false, - color: 'black' + color: 'default' } static propTypes = { as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - color: PropTypes.oneOf(['black', 'primary', 'secondary', 'red']), + color: PropTypes.oneOf(['default', 'primary', 'secondary', 'red']), disabled: PropTypes.bool, indeterminate: PropTypes.bool, defaultChecked: PropTypes.bool, @@ -119,8 +114,8 @@ export default class Checkbox extends React.Component { } render () { - const { checked, ...rest } = this.props + const { checked, color, ...rest } = this.props const realChecked = this.isControlled() ? checked : this.state.checked - return + return } } diff --git a/web/Code.jsx b/web/Code.jsx index 519fccf..774e189 100644 --- a/web/Code.jsx +++ b/web/Code.jsx @@ -1,12 +1,12 @@ import PropTypes from 'prop-types' -import React from 'react' import styled from 'styled-components' import {lighten} from 'polished' +import { black, gray, fontSecondary } from '../lib/Theme' const Code = styled.pre` - background-color: ${props => lighten(0.3, props.theme.gray)}; - color: ${props => props.theme.black}; - font-family: ${props => props.theme.fontSecondary}; + background-color: ${props => lighten(0.3, gray(props))}; + color: ${black}; + font-family: ${fontSecondary}; padding: 20px; ` diff --git a/web/Drawer.jsx b/web/Drawer.jsx index d419b71..949d490 100644 --- a/web/Drawer.jsx +++ b/web/Drawer.jsx @@ -1,10 +1,10 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' import styled, {css} from 'styled-components' import Icon from './Icon' import { swiftEaseOut } from '../lib/Animations' +import { white, drawerWidth, fontSecondary, fontPrimary, secondary, black } from '../lib/Theme' const DrawerWrapper = styled.div` background-color: transparent; @@ -24,7 +24,7 @@ const DrawerWrapper = styled.div` ` const DrawerMenu = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); height: 100%; left: 0; @@ -32,7 +32,7 @@ const DrawerMenu = styled.div` overflow-y: auto; position: absolute; top: 0; - width: ${props => props.theme.drawerWidth}; + width: ${drawerWidth}; z-index: 7; ` @@ -66,8 +66,8 @@ const DrawerHeaderWrapper = styled.div` ` const DrawerHeaderTitle = styled.div` - color: ${props => props.theme.black}; - font-family: ${props => props.theme.fontSecondary}; + color: ${black}; + font-family: ${fontSecondary}; font-size: 24px; font-weight: bold; height: 33px; @@ -76,8 +76,8 @@ const DrawerHeaderTitle = styled.div` ` const DrawerHeaderSubtitle = styled.div` - color: ${props => props.theme.black}; - font-family: ${props => props.theme.fontPrimary}; + color: ${black}; + font-family: ${fontPrimary}; font-size: 14px; line-height: 19px; ` @@ -108,9 +108,9 @@ const DrawerLinkWrapper = styled.div` } a { - color: ${props => props.theme.secondary}; + color: ${secondary}; display: block; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; height: 60px; line-height: 19px; diff --git a/web/IconButton.jsx b/web/IconButton.jsx index f65fb82..db6993e 100644 --- a/web/IconButton.jsx +++ b/web/IconButton.jsx @@ -3,16 +3,32 @@ import React from 'react' import styled from 'styled-components' import {ripple} from '../lib/Animations' import {lighten, darken} from 'polished' +import theme from 'styled-theming' +import { black, primary, secondary, disabled, fontPrimary } from '../lib/Theme' import Icon from './Icon' +const color = theme.variants('mode', 'color', { + default: {light: black}, + primary: {light: primary}, + secondary: {light: secondary}, + disabled: {light: disabled} +}) + +const lightenedColor = theme.variants('mode', 'color', { + default: {light: lighten(0.6, black)}, + primary: {light: props => lighten(0.4, primary(props))}, + secondary: {light: props => lighten(0.35, secondary(props))}, + disabled: {light: props => lighten(0.1, disabled(props))} +}) + /* eslint-disable indent */ -const StyledIconButton = styled.button` +const IconButtonWrapper = styled.button` border-radius: 50%; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); - color: ${props => props.theme[props.color]}; + color: ${color}; cursor: pointer; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; font-weight: 500; height: 44px; @@ -54,43 +70,33 @@ const StyledIconButton = styled.button` } :hover { - background-color: ${props => lighten(0.1, props.theme[props.color])} + background-color: ${props => lighten(0.1, color(props))}; } :active { - background-color: ${props => darken(0.25, lighten(props.p, props.theme[props.color]))}; + background-color: ${props => darken(0.25, lightenedColor(props))}; } :hover, :focus { - background-color: ${props => lighten(props.p, props.theme[props.color])}; - border: 1px solid ${props => lighten(props.p, props.theme[props.color])}; + background-color: ${lightenedColor}; + border: 1px solid ${lightenedColor}; } ` /* eslint-enable indent */ const IconButton = styled(props => { - const {primary, secondary, disabled, children, k, ...rest} = props - let color = 'black' - let p = 0.6 - if (primary) { - color = 'primary' - p = 0.4 - } else if (secondary) { - color = 'secondary' - p = 0.35 - } else if (disabled) { - color = 'disabled' - p = 0.1 - } - return {children} + const {disabled, color, children, k, ...rest} = props + return {children} })`` +IconButton.defaultProps = { + color: 'default' +} + IconButton.propTypes = { icon: PropTypes.bool, - k: PropTypes.string.isRequired, - primary: PropTypes.bool, - secondary: PropTypes.bool, - disabled: PropTypes.bool + color: PropTypes.oneOf(['default', 'primary', 'secondary']), + k: PropTypes.string.isRequired } export default IconButton diff --git a/web/Menu.jsx b/web/Menu.jsx index 543f159..cb633de 100644 --- a/web/Menu.jsx +++ b/web/Menu.jsx @@ -3,6 +3,7 @@ import React from 'react' import {kill} from '../lib/utils' import styled, {css} from 'styled-components' import {swiftEaseInOut, animationSelectItem} from '../lib/Animations' +import { white, fontPrimary } from '../lib/Theme' const MenuWrapper = styled.div` display: inline-block; @@ -21,7 +22,7 @@ const MenuWrapper = styled.div` ` const MenuItems = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; border-radius: 5px; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); display: block; @@ -40,7 +41,7 @@ const MenuItems = styled.div` export const MenuItem = styled.div` cursor: pointer; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 16px; height: 39px; line-height: 19px; diff --git a/web/Modal.jsx b/web/Modal.jsx index 093acc4..419d703 100644 --- a/web/Modal.jsx +++ b/web/Modal.jsx @@ -1,6 +1,5 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' import styled, {css} from 'styled-components' import { animationModalContainer } from '../lib/Animations' @@ -38,7 +37,7 @@ const ModalWrapper = styled.div` right: 0; top: 0; transform: none; - transition: $animation-modal-overlay; + transition: none; width: 100%; } } diff --git a/web/Navbar.jsx b/web/Navbar.jsx index c940f40..5db3a3a 100644 --- a/web/Navbar.jsx +++ b/web/Navbar.jsx @@ -4,6 +4,7 @@ import styled, {css} from 'styled-components' import {swiftEaseIn} from '../lib/Animations' import Icon from './Icon' +import { primary, black, fontPrimary, white } from '../lib/Theme' const NavbarMenu = styled.div` cursor: pointer; @@ -30,35 +31,35 @@ const NavbarLinkWrapper = styled.div` :hover { a { - color: ${props => props.theme.primary}; + color: ${primary}; transition: ${swiftEaseIn}; } } ${props => props.active ? css` - a { color: ${props => props.theme.primary} !important; } + a { color: ${primary} !important; } - i { color: ${props => props.theme.primary} !important; } + i { color: ${primary} !important; } ` : ''} a { - color: ${props => props.theme.black}; + color: ${black}; cursor: pointer; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 16px; text-decoration: none; width: max-content; } i { - color: ${props => props.theme.black}; + color: ${black}; font-size: 22px; margin-right: 10px; } ` const NavbarWrapper = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; min-height: 90px; left: 0; position: fixed; diff --git a/web/Pagination.jsx b/web/Pagination.jsx index 8073c9b..57df2b3 100644 --- a/web/Pagination.jsx +++ b/web/Pagination.jsx @@ -4,6 +4,7 @@ import styled from 'styled-components' import IconButton from './IconButton' import SelectInput from './SelectInput' +import { secondary } from '../lib/Theme' const PaginationWrapper = styled.div` color: ${props => props.theme.secondary}; @@ -24,8 +25,8 @@ const PaginationSize = styled.div` select { background-color: transparent; border: 0; - border-bottom: 1px solid $secondary; - color: $secondary; + border-bottom: 1px solid ${secondary}; + color: ${secondary}; min-width: 43px; width: 43px; } @@ -46,7 +47,7 @@ const PaginationPage = styled.div` ${IconButton} { border: 0; - color: ${props => props.theme.secondary}; + color: ${secondary}; display: inline-block; font-size: 14px; margin: 0 4px; diff --git a/web/Panel.jsx b/web/Panel.jsx index 797cc3e..1a3e77b 100644 --- a/web/Panel.jsx +++ b/web/Panel.jsx @@ -5,17 +5,18 @@ import styled, {css} from 'styled-components' import {swiftEaseIn, swiftEaseOut} from '../lib/Animations' import Icon from '../web/Icon' +import { white, panelPadding, fontPrimary, secondary } from '../lib/Theme' const PanelWrapper = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; border-radius: 10px; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); overflow: hidden; - padding: ${props => props.theme.panelPadding} ${props => props.theme.panelPadding} 0 ${props => props.theme.panelPadding}; + padding: ${panelPadding} ${panelPadding} 0 ${panelPadding}; transition: ${swiftEaseOut}; ${props => props.open ? css` - padding-bottom: ${props => props.theme.panelPadding}; + padding-bottom: ${panelPadding}; transition: ${swiftEaseIn}; ${PanelArrow} i { @@ -30,12 +31,12 @@ const PanelWrapper = styled.div` ` const PanelHeader = styled.div` - padding-bottom: ${props => props.theme.panelPadding}; + padding-bottom: ${panelPadding}; position: relative; ` const PanelHeaderTitle = styled.div` - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 20px; font-weight: bold; height: 26px; @@ -43,8 +44,8 @@ const PanelHeaderTitle = styled.div` ` const PanelHeaderSubtitle = styled.div` - color: ${props => props.theme.secondary}; - font-family: ${props => props.theme.fontPrimary}; + color: ${secondary}; + font-family: ${fontPrimary}; font-size: 14px; height: 19px; left: 50%; @@ -62,9 +63,9 @@ const PanelArrow = styled.div` ` const PanelContent = styled.div` -color: ${props => props.theme.secondary}; + color: ${secondary}; display: block; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; margin: 0; max-height: 0; diff --git a/web/ProgressBar.jsx b/web/ProgressBar.jsx index 50579fa..277175a 100644 --- a/web/ProgressBar.jsx +++ b/web/ProgressBar.jsx @@ -2,11 +2,12 @@ import PropTypes from 'prop-types' import React from 'react' import styled from 'styled-components' import {animationProgressbar} from '../lib/Animations' +import { primary } from '../lib/Theme' const ProgressBarWrapper = styled.div` animation: all 1s ${animationProgressbar} .1s; - background-color: ${props => props.theme.primary}; - box-shadow: 0 0 10px ${props => props.theme.primary}; + background-color: ${primary}; + box-shadow: 0 0 10px ${primary}; display: block; height: 4px; left: 0; diff --git a/web/Radio.jsx b/web/Radio.jsx index ef66eb8..d38482c 100644 --- a/web/Radio.jsx +++ b/web/Radio.jsx @@ -1,15 +1,23 @@ import PropTypes from 'prop-types' import React from 'react' -import {pickRest} from '../lib/utils' import styled, { css } from 'styled-components' +import theme from 'styled-theming' -import { pulse, swiftEaseOut } from '../lib/Animations' +import { pulse } from '../lib/Animations' +import { black, primary, secondary } from '../lib/Theme' + +const color = theme.variants('mode', 'color', { + default: {light: black}, + primary: {light: primary}, + secondary: {light: secondary}, + disabled: {light: '#C8C8C8'} +}) const RadioWrapper = styled.span` display: inline-block; height: 24px; width: 24px; - border: 1px solid ${props => props.theme[props.color]}; + border: 1px solid ${color}; border-radius: 50%; margin: 0 5px; text-align: center; @@ -19,22 +27,14 @@ const RadioWrapper = styled.span` ${props => props.checked ? css` ::after { - animation: ${pulse('black')} 1.25s cubic-bezier(0.66, 0, 0, 1); + animation: ${props => pulse(color(props))} 1.25s cubic-bezier(0.66, 0, 0, 1); content: ""; border-radius: 50%; display: block; margin: 4px; height: 14px; width: 14px; - background-color: ${props => props.theme.black}; - - ${props => props.color ? css` - animation: ${pulse(props.color)} 1.25s cubic-bezier(0.66, 0, 0, 1); - background-color: ${props => props.theme[props.color]}; - `: ''} - ${props => props.disabled ? css` - background-color: #C8C8C8; - ` : ''} + background-color: ${color}; } ` : ''} ` diff --git a/web/SelectInput.jsx b/web/SelectInput.jsx index fb9025d..8401e26 100644 --- a/web/SelectInput.jsx +++ b/web/SelectInput.jsx @@ -5,9 +5,11 @@ import styled, {css} from 'styled-components' import Icon from './Icon' import { swiftEaseIn, swiftEaseInOut, animationSelectItem } from '../lib/Animations' +import { fontPrimary, secondary, white } from '../lib/Theme' +import { black } from 'kleur' const SelectInputWrapper = styled.div` - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; height: 55px; padding-top: 18px; @@ -15,15 +17,15 @@ const SelectInputWrapper = styled.div` ${props => props.active ? css` ${SelectInputLabel} { - color: ${props => props.theme.secondary}; - font-family: ${props => props.theme.fontPrimary}; + color: ${secondary}; + font-family: ${fontPrimary}; font-size: 12px; height: 11px; line-height: 11px; top: 0; } - ${SelectInputArrow} { color: ${props => props.theme.black}; } + ${SelectInputArrow} { color: ${black}; } ` : ''} ${props => props.focus && !props.native ? css` @@ -44,9 +46,9 @@ const SelectInputWrapper = styled.div` ` const SelectInputLabel = styled.label` - color: ${props => props.theme.secondary}; + color: ${secondary}; cursor: text; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; height: 16px; line-height: 16px; @@ -57,7 +59,7 @@ const SelectInputLabel = styled.label` ` const SelectInputArrow = styled.label` - color: ${props => props.theme.secondary}; + color: ${secondary}; float: right; height: 5px; position: absolute; @@ -69,13 +71,13 @@ const SelectInputArrow = styled.label` const SelectInputComponent = styled.select` background: transparent; border: 0; - color: ${props => props.theme.black}; + color: ${black}; line-height: 16px; outline: none; padding: 4px 0; appearance: none; border: 0 !important; - color: ${props => props.theme.black}; + color: ${black}; text-indent: 0.1px; text-overflow: ''; @@ -85,20 +87,20 @@ const SelectInputComponent = styled.select` option { border: 0; - color: ${props => props.theme.black}; + color: ${black}; max-height: 0; } border-color: transparent; border-bottom: 1px solid #f2f2f2; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; min-width: 108px; width: 100%; ` const SelectInputOptions = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; border-radius: 5px; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.25); display: block; @@ -116,7 +118,7 @@ const SelectInputOptions = styled.div` const SelectInputItem = styled.div` cursor: pointer; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; height: 27px; line-height: 19px; diff --git a/web/Stepper.jsx b/web/Stepper.jsx index 759dd88..d1b4141 100644 --- a/web/Stepper.jsx +++ b/web/Stepper.jsx @@ -4,6 +4,8 @@ import styled, {css} from 'styled-components' import Icon from './Icon' import { animationStepper } from '../lib/Animations' +import { secondary, white, primary } from '../lib/Theme' +import { black } from 'kleur' // Step export const Step = () => null @@ -25,30 +27,30 @@ const StepperContent = styled.div` ` const StepperStep = styled.div` - color: ${props => props.theme.secondary}; + color: ${secondary}; display: inline-block; font-size: 14px; line-height: 19px; ${props => props.active ? css` ${StepperIndicator} { - background-color: ${props => props.theme.primary}; - color: ${props => props.theme.white}; + background-color: ${primary}; + color: ${white}; } ` : ''} ${props => props.complete ? css` ${StepperIndicator} { - background-color: ${props => props.theme.black}; - color: ${props => props.theme.secondary}; + background-color: ${black}; + color: ${secondary}; } ` : ''} ` const StepperIndicator = styled.span` - background-color: ${props => props.theme.black}; + background-color: ${black}; border-radius: 50%; - color: ${props => props.theme.white}; + color: ${white}; display: inline-block; font-size: 16px; height: 35px; @@ -70,7 +72,7 @@ const StepperIndicator = styled.span` ` const StepperBar = styled.div` - border-top: 1px solid ${props => props.theme.secondary}; + border-top: 1px solid ${secondary}; display: inline-block; height: 5px; margin-right: 21px; diff --git a/web/Tab.jsx b/web/Tab.jsx index 7bb322b..a72dd7d 100644 --- a/web/Tab.jsx +++ b/web/Tab.jsx @@ -1,8 +1,10 @@ import PropTypes from 'prop-types' import React from 'react' -import {kill, pickRest} from '../lib/utils' +import {kill} from '../lib/utils' import Icon from './Icon' import styled, {css} from 'styled-components' +import { primary } from '../lib/Theme' +import { white } from 'kleur' const TabWrapper = styled.div` display: inline-block; @@ -59,7 +61,7 @@ const TabsWrapper = styled.div` ` const TabsBar = styled.div` - background-color: ${props => props.theme.primary}; + background-color: ${primary}; height: 1px; position: absolute; top: 50px; @@ -68,7 +70,7 @@ const TabsBar = styled.div` ` const TabsContent = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; border-radius: 5px; box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); margin-top: 5px; @@ -78,7 +80,7 @@ const TabsContent = styled.div` ` const TabsList = styled.div` - background-color: ${props => props.theme.white}; + background-color: ${white}; border-radius: 5px; box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.25); position: relative; diff --git a/web/Table.jsx b/web/Table.jsx index bee55be..70894fb 100644 --- a/web/Table.jsx +++ b/web/Table.jsx @@ -5,6 +5,7 @@ import styled from 'styled-components' import Checkbox from './Checkbox' import Icon from './Icon' import { swiftEaseIn } from '../lib/Animations' +import { primary, secondary, lightGray } from '../lib/Theme' const TableWrapper = styled.table` margin: 0; @@ -28,20 +29,20 @@ export const TableCell = styled.td` display: none; :hover::before { - text-shadow: 0px 0px 1px ${props => props.theme.primary}; + text-shadow: 0px 0px 1px ${primary}; } ::before { - color: ${props => props.theme.secondary}; + color: ${secondary}; cursor: pointer; display: inline-block; text-align: center; - text-shadow: 0px 0px 1px ${props => props.theme.lightGray}; + text-shadow: 0px 0px 1px ${lightGray}; transition: color .3s ease; } &:checked + label::before { - color: ${props => props.theme.primary}; + color: ${primary}; } & + label::before { @@ -69,7 +70,7 @@ export const TableRow = styled.tr` export const TableHead = styled.thead` ${TableCell} { - color: ${props => props.theme.secondary}; + color: ${secondary}; cursor: pointer; font-size: 14px; height: 70px; diff --git a/web/TextInput.jsx b/web/TextInput.jsx index fc3583c..826511c 100644 --- a/web/TextInput.jsx +++ b/web/TextInput.jsx @@ -2,9 +2,10 @@ import PropTypes from 'prop-types' import React from 'react' import styled, {css} from 'styled-components' import { swiftEaseIn } from '../lib/Animations' +import { secondary, fontPrimary, red, black, primary } from '../lib/Theme' const TextInputWrapper = styled.div` - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; height: 55px; padding-top: 18px; @@ -12,8 +13,8 @@ const TextInputWrapper = styled.div` ${props => props.active ? css` ${TextInputLabel} { - color: ${props => props.theme.secondary}; - font-family: ${props => props.theme.fontPrimary}; + color: ${secondary}; + font-family: ${fontPrimary}; font-size: 12px; height: 11px; line-height: 11px; @@ -28,16 +29,16 @@ const TextInputWrapper = styled.div` ` : ''} ${props => props.error ? css` - ${TextInputLabel} { color: ${props => props.theme.red} !important; } + ${TextInputLabel} { color: ${red} !important; } - ${TextInputInput} { border-color: ${props => props.theme.red} !important; } + /* ${TextInputInput} { border-color: ${red} !important; } */ ` : ''} ` const TextInputLabel = styled.label` - color: ${props => props.theme.secondary}; + color: ${secondary}; cursor: text; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; height: 16px; line-height: 16px; @@ -50,13 +51,13 @@ const TextInputLabel = styled.label` const TextInputInput = styled.input` background: transparent; border: 0; - color: ${props => props.theme.black}; + color: ${black}; line-height: 16px; outline: none; padding: 4px 0; border-color: transparent; border-bottom: 1px solid #f2f2f2; - font-family: ${props => props.theme.fontPrimary}; + font-family: ${fontPrimary}; font-size: 14px; min-width: 108px; width: 100%; @@ -72,7 +73,7 @@ const TextInputBar = styled.div` width: 0; bottom: 1px; position: absolute; - background: ${props => props.theme.primary}; + background: ${primary}; transition: 0.2s ease all; } @@ -86,7 +87,7 @@ const TextInputBar = styled.div` ` const TextInputMessage = styled.div` - color: ${props => props.theme.secondary}; + color: ${secondary}; font-size: 9px; height: 11px; line-height: 11px; @@ -125,7 +126,7 @@ export default class TextInput extends React.Component { handleFocus = isFocus => this.setState({isFocus}) render () { - const {defaultValue, label, message, ...rest} = this.props + const {defaultValue, label, message, error, ...rest} = this.props let focus = false if (this.state.isFocus) focus = true @@ -143,7 +144,7 @@ export default class TextInput extends React.Component { } return ( - + {!!label && {label} diff --git a/web/Tooltip.jsx b/web/Tooltip.jsx index 8b325c7..f85ced4 100644 --- a/web/Tooltip.jsx +++ b/web/Tooltip.jsx @@ -4,17 +4,25 @@ import styled, {css} from 'styled-components' import Button from './Button' import { swiftEaseIn } from '../lib/Animations' +import { alert, secondary, primary, borderRadius, white, gridGutter } from '../lib/Theme' +import theme from 'styled-theming' + +const color = theme.variants('mode', 'color', { + default: {light: secondary}, + primary: {light: primary}, + alert: {light: alert} +}) // TODO: Change the padding here to calculate based on gridGutter/2 instead of hardcoded const TooltipContent = styled.div` - background-color: ${props => props.color ? props.theme[props.color] : props.theme.secondary}; - border-radius: ${props => props.theme.borderRadius}; - color: ${props => props.theme.white}; + background-color: ${color}; + border-radius: ${borderRadius}; + color: ${white}; display: inline-block; font-size: 9px; line-height: 11px; opacity: 0; - padding: 5px ${props => props.theme.gridGutter}; + padding: 5px ${gridGutter}; position: absolute; text-align: center; transition: ${swiftEaseIn}; @@ -35,7 +43,7 @@ const TooltipContent = styled.div` transform: translateX(-50%); ::after { - border-color: transparent transparent ${props => props.color ? props.theme[props.color] : props.theme.secondary} transparent; + border-color: transparent transparent ${color} transparent; bottom: 100%; left: 50%; transform: translateX(-50%); @@ -48,7 +56,7 @@ const TooltipContent = styled.div` transform: translateY(-50%); ::after { - border-color: transparent transparent transparent ${props => props.color ? props.theme[props.color] : props.theme.secondary}; + border-color: transparent transparent transparent ${color}; left: 100%; top: 50%; transform: translateY(-50%); @@ -61,7 +69,7 @@ const TooltipContent = styled.div` transform: translateY(-50%); ::after { - border-color: transparent ${props => props.color ? props.theme[props.color] : props.theme.secondary} transparent transparent; + border-color: transparent ${color} transparent transparent; right: 100%; top: 50%; transform: translateY(-50%); @@ -74,7 +82,7 @@ const TooltipContent = styled.div` transform: translateX(-50%); ::after { - border-color: ${props => props.color ? props.theme[props.color] : props.theme.secondary} transparent transparent transparent; + border-color: ${color} transparent transparent transparent; left: 50%; top: 100%; transform: translateX(-50%); @@ -106,6 +114,10 @@ const Tooltip = (props) => { ) } +Tooltip.defaultProps = { + color: 'default' +} + Tooltip.propTypes = { bottom: PropTypes.bool, children: PropTypes.any.isRequired, @@ -114,7 +126,7 @@ Tooltip.propTypes = { primary: PropTypes.bool, right: PropTypes.bool, top: PropTypes.bool, - color: PropTypes.string + color: PropTypes.oneOf(['default', 'primary', 'alert']) } export default Tooltip diff --git a/webpack.config.js b/webpack.config.js index e0714f7..7c9ecd1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,7 +7,8 @@ module.exports = { contentBase: path.join(__dirname, 'dist'), compress: true, port: 8080, - hot: true + hot: true, + overlay: true }, entry: path.join(__dirname, 'demo/web', 'App.jsx'), mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', diff --git a/yarn.lock b/yarn.lock index e0d77a3..41464af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10379,6 +10379,10 @@ styled-components@^4.0.3: stylis-rule-sheet "^0.0.10" supports-color "^5.5.0" +styled-theming@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/styled-theming/-/styled-theming-2.2.0.tgz#3084e43d40eaab4bc11ebafd3de04e3622fee37e" + stylis-rule-sheet@^0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"