From b0439c6ce14ff43e631747b0b5b8ac2f78846d5e Mon Sep 17 00:00:00 2001 From: Barry Gitarts Date: Tue, 5 Jun 2018 10:43:05 -0400 Subject: [PATCH] add additional custom ui components + complete name lookup style --- app/components/ens/nameLookup.js | 16 +- app/ui/components/Button/Button.js | 221 ++++++++++++++++++ app/ui/components/Button/README.md | 97 ++++++++ .../components/Button/assets/check-white.svg | 1 + app/ui/components/Button/assets/check.svg | 1 + .../components/Button/assets/cross-white.svg | 1 + app/ui/components/Button/assets/cross.svg | 1 + app/ui/components/Button/assets/index.js | 2 + app/ui/components/Button/index.js | 5 + app/ui/components/SafeLink.js | 8 + app/ui/components/index.js | 8 + app/ui/index.js | 9 +- app/ui/providers/PublicUrl/PublicUrl.js | 32 +++ app/ui/providers/PublicUrl/index.js | 2 + app/ui/providers/index.js | 4 + app/ui/utils/index.js | 5 + app/ui/utils/styles/index.js | 1 + app/ui/utils/url.js | 5 + 18 files changed, 413 insertions(+), 6 deletions(-) create mode 100644 app/ui/components/Button/Button.js create mode 100644 app/ui/components/Button/README.md create mode 100644 app/ui/components/Button/assets/check-white.svg create mode 100644 app/ui/components/Button/assets/check.svg create mode 100644 app/ui/components/Button/assets/cross-white.svg create mode 100644 app/ui/components/Button/assets/cross.svg create mode 100644 app/ui/components/Button/assets/index.js create mode 100644 app/ui/components/Button/index.js create mode 100644 app/ui/components/SafeLink.js create mode 100644 app/ui/components/index.js create mode 100644 app/ui/providers/PublicUrl/PublicUrl.js create mode 100644 app/ui/providers/PublicUrl/index.js create mode 100644 app/ui/providers/index.js create mode 100644 app/ui/utils/index.js create mode 100644 app/ui/utils/url.js diff --git a/app/components/ens/nameLookup.js b/app/components/ens/nameLookup.js index 542bbb1..7e5d2a5 100644 --- a/app/components/ens/nameLookup.js +++ b/app/components/ens/nameLookup.js @@ -1,13 +1,21 @@ import React, { Fragment } from 'react'; -import Field from '../../ui/components/Field' -import TextInput from '../../ui/components/TextInput' +import { Button, Field, TextInput, Card } from '../../ui/components' + +const cardStyle = { + width: '75%', + marginLeft: '15%', + padding: '30px' +} const NameLookup = () => ( -
+ -
+ + ) export default NameLookup; diff --git a/app/ui/components/Button/Button.js b/app/ui/components/Button/Button.js new file mode 100644 index 0000000..b475d5b --- /dev/null +++ b/app/ui/components/Button/Button.js @@ -0,0 +1,221 @@ +import styled, { css } from 'styled-components' +import SafeLink from '../SafeLink' +import theme from '../../theme' +import { font, unselectable } from '../../utils/styles' +import PublicUrl, { styledUrl } from '../../providers/PublicUrl' +import cross from './assets/cross.svg' +import check from './assets/check.svg' +import crossWhite from './assets/cross-white.svg' +import checkWhite from './assets/check-white.svg' + +const { + gradientStart, + gradientEnd, + gradientStartActive, + gradientEndActive, + gradientText, + contentBackground, + contentBorder, + contentBorderActive, + secondaryBackground, + textPrimary, + textSecondary, + disabled: disabledColor, + disabledText, +} = theme + +// Plain button = normal or strong +const plainButtonStyles = css` + position: relative; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0); + &:after { + content: ''; + opacity: 0; + position: absolute; + z-index: -1; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + + ${({ disabled }) => + disabled + ? '' + : css` + &:hover, + &:focus { + box-shadow: ${({ disabled }) => + disabled ? 'none' : '0 1px 1px rgba(0, 0, 0, 0.2)'}; + } + &:active { + transform: translateY(1px); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0); + &:after { + opacity: 1; + } + } + `}; +` + +const modeNormal = css` + ${plainButtonStyles}; + &:active { + color: ${textPrimary}; + } +` + +const modeSecondary = css` + ${plainButtonStyles}; + background: ${secondaryBackground}; + &:hover, + &:focus { + box-shadow: none; + } +` + +const modeStrong = css` + ${plainButtonStyles}; + ${font({ size: 'small', weight: 'bold' })}; + + ${({ disabled }) => + disabled + ? css` + color: ${disabledText}; + background-color: ${disabledColor}; + background-image: none; + ` + : css` + color: ${gradientText}; + background-color: transparent; + background-image: linear-gradient( + 130deg, + ${gradientStart}, + ${gradientEnd} + )}; + + &:after { + background-image: linear-gradient( + 130deg, + ${gradientStartActive}, + ${gradientEndActive} + ); + } + `}; +` + +const modeOutline = css` + background: transparent; + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid ${contentBorder}; + &:hover, + &:focus { + border-color: ${contentBorderActive}; + } + &:active { + color: ${textPrimary}; + border-color: ${textPrimary}; + } +` + +const modeText = css` + padding: 10px; + background: transparent; + &:active, + &:focus { + color: ${textPrimary}; + } +` + +const compactStyle = css` + padding: ${({ mode }) => (mode === 'outline' ? '4px 14px' : '5px 15px')}; +` + +const positiveStyle = css` + padding-left: 34px; + background: url(${styledUrl(check)}) no-repeat 12px calc(50% - 1px); + ${({ mode }) => { + if (mode !== 'strong') return '' + return css` + &, + &:active { + background-image: url(${styledUrl(checkWhite)}); + background-color: ${theme.positive}; + } + &:after { + background: none; + } + ` + }}; +` + +const negativeStyle = css` + padding-left: 30px; + background: url(${styledUrl(cross)}) no-repeat 10px calc(50% - 1px); + ${({ mode }) => { + if (mode !== 'strong') return '' + return css` + &, + &:active { + background-image: url(${styledUrl(crossWhite)}); + background-color: ${theme.negative}; + } + &:after { + background: none; + } + ` + }}; +` + +const StyledButton = styled.button.attrs({ type: 'button' })` + width: ${({ wide }) => (wide ? '100%' : 'auto')}; + padding: 10px 15px; + white-space: nowrap; + ${font({ size: 'small', weight: 'normal' })}; + color: ${textSecondary}; + background: ${contentBackground}; + border: 0; + border-radius: 3px; + outline: 0; + cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')}; + &, + &:after { + transition-property: all; + transition-duration: 100ms; + transition-timing-function: ease-in-out; + } + &::-moz-focus-inner { + border: 0; + } + + ${({ mode }) => { + if (mode === 'secondary') return modeSecondary + if (mode === 'strong') return modeStrong + if (mode === 'outline') return modeOutline + if (mode === 'text') return modeText + return modeNormal + }}; + + ${({ compact }) => (compact ? compactStyle : '')}; + + ${({ emphasis }) => { + if (emphasis === 'positive') return positiveStyle + if (emphasis === 'negative') return negativeStyle + return '' + }}; +` + +const Button = PublicUrl.hocWrap(StyledButton) +const Anchor = PublicUrl.hocWrap( + StyledButton.withComponent(SafeLink).extend` + ${unselectable}; + display: inline-block; + text-decoration: none; + ` +) + +Button.Anchor = Anchor + +export default Button diff --git a/app/ui/components/Button/README.md b/app/ui/components/Button/README.md new file mode 100644 index 0000000..2fe8617 --- /dev/null +++ b/app/ui/components/Button/README.md @@ -0,0 +1,97 @@ +# Button + +A simple Button component. + +## Usage + +```jsx +import { Button } from '@aragon/ui' + +const App = () => ( + +) +``` + +## Properties + +### `mode` + +- Type: `String` +- Values: `normal` (default), `secondary`, `outline`, `strong` or `text`. + +Set this property to the desired visual variant. + +#### Example: + +```jsx +const App = () => ( +
+ + +
+) +``` + +### `emphasis` + +- Type: `String` +- Values: `positive` or `negative`. + +Set this property to provide positive or negative visual cues. + +#### Example: + +```jsx +const App = () => ( +
+ + +
+) +``` + +### `compact` + +- Type: `Boolean` +- Default: `false` + +Set to true to obtain a button that contains less padding than normal buttons. + +#### Example: + +```jsx +const MyButton = () => ( + +) +``` + +### `wide` + +- Type: `Boolean` +- Default: `false` + +Set to true to obtain a button that expands horizontally. + +#### Example: + +```jsx +const MyButton = () => ( + +) +``` + +## Attached Components + +### `Anchor` + +An `` styled to be visually similar to Buttons, supporting the same properties. + +#### Example: + +```jsx +const LinkButton = () => ( + + Aragon + +) +``` diff --git a/app/ui/components/Button/assets/check-white.svg b/app/ui/components/Button/assets/check-white.svg new file mode 100644 index 0000000..6c1a3a7 --- /dev/null +++ b/app/ui/components/Button/assets/check-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/ui/components/Button/assets/check.svg b/app/ui/components/Button/assets/check.svg new file mode 100644 index 0000000..1dd408f --- /dev/null +++ b/app/ui/components/Button/assets/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/ui/components/Button/assets/cross-white.svg b/app/ui/components/Button/assets/cross-white.svg new file mode 100644 index 0000000..039d0b5 --- /dev/null +++ b/app/ui/components/Button/assets/cross-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/ui/components/Button/assets/cross.svg b/app/ui/components/Button/assets/cross.svg new file mode 100644 index 0000000..5f08878 --- /dev/null +++ b/app/ui/components/Button/assets/cross.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/ui/components/Button/assets/index.js b/app/ui/components/Button/assets/index.js new file mode 100644 index 0000000..98e3c34 --- /dev/null +++ b/app/ui/components/Button/assets/index.js @@ -0,0 +1,2 @@ +// @create-index + diff --git a/app/ui/components/Button/index.js b/app/ui/components/Button/index.js new file mode 100644 index 0000000..d4e7cd3 --- /dev/null +++ b/app/ui/components/Button/index.js @@ -0,0 +1,5 @@ +// @create-index + +export { default as Button } from './Button.js'; +export { default as assets } from './assets'; + diff --git a/app/ui/components/SafeLink.js b/app/ui/components/SafeLink.js new file mode 100644 index 0000000..25da85e --- /dev/null +++ b/app/ui/components/SafeLink.js @@ -0,0 +1,8 @@ +import styled from 'styled-components' + +const SafeLink = styled.a.attrs({ + // See https://mathiasbynens.github.io/rel-noopener + rel: 'noopener noreferrer', +})`` + +export default SafeLink diff --git a/app/ui/components/index.js b/app/ui/components/index.js new file mode 100644 index 0000000..1e7a4e9 --- /dev/null +++ b/app/ui/components/index.js @@ -0,0 +1,8 @@ +// @create-index + +export * from './Button'; +export { default as Card } from './Card.js'; +export { default as Field } from './Field.js'; +export { default as Text } from './Text.js'; +export { default as TextInput } from './TextInput.js'; + diff --git a/app/ui/index.js b/app/ui/index.js index ec8620e..24ff7ab 100644 --- a/app/ui/index.js +++ b/app/ui/index.js @@ -1,2 +1,7 @@ -export { default as Card } from './components/Card' -export { default as Field } from './components/Field.js' +// @create-index + +export { default as components } from './components'; +export { default as providers } from './providers'; +export { default as theme } from './theme'; +export { default as utils } from './utils'; + diff --git a/app/ui/providers/PublicUrl/PublicUrl.js b/app/ui/providers/PublicUrl/PublicUrl.js new file mode 100644 index 0000000..9e6c6fb --- /dev/null +++ b/app/ui/providers/PublicUrl/PublicUrl.js @@ -0,0 +1,32 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { prefixUrl } from '../../utils/url' + +const DEFAULT_URL = '' + +const { Provider, Consumer: PublicUrl } = React.createContext(DEFAULT_URL) + +const PublicUrlProvider = ({ url, children }) => { + return {children} +} +PublicUrlProvider.propTypes = { + url: PropTypes.string, + children: PropTypes.node, +} + +// HOC wrapper +const hocWrap = Component => props => ( + + {publicUrl => } + +) + +// styled-components utility for URLs +const styledUrl = url => ({ publicUrl }) => prefixUrl(url, publicUrl) + +PublicUrl.Provider = PublicUrlProvider +PublicUrl.hocWrap = hocWrap +PublicUrl.styledUrl = styledUrl + +export { PublicUrl, Provider, hocWrap, styledUrl } +export default PublicUrl diff --git a/app/ui/providers/PublicUrl/index.js b/app/ui/providers/PublicUrl/index.js new file mode 100644 index 0000000..e798b73 --- /dev/null +++ b/app/ui/providers/PublicUrl/index.js @@ -0,0 +1,2 @@ +export { default } from './PublicUrl' +export * from './PublicUrl' diff --git a/app/ui/providers/index.js b/app/ui/providers/index.js new file mode 100644 index 0000000..17dd339 --- /dev/null +++ b/app/ui/providers/index.js @@ -0,0 +1,4 @@ +// @create-index + +export { default as PublicUrl } from './PublicUrl'; + diff --git a/app/ui/utils/index.js b/app/ui/utils/index.js new file mode 100644 index 0000000..26ca5c0 --- /dev/null +++ b/app/ui/utils/index.js @@ -0,0 +1,5 @@ +// @create-index + +export { default as styles } from './styles'; +export { default as url } from './url.js'; + diff --git a/app/ui/utils/styles/index.js b/app/ui/utils/styles/index.js index 2136609..87a3784 100644 --- a/app/ui/utils/styles/index.js +++ b/app/ui/utils/styles/index.js @@ -1,3 +1,4 @@ +export * from './font' export const unselectable = () => ` -webkit-touch-callout: none; -webkit-user-select: none; diff --git a/app/ui/utils/url.js b/app/ui/utils/url.js new file mode 100644 index 0000000..232c630 --- /dev/null +++ b/app/ui/utils/url.js @@ -0,0 +1,5 @@ +// prefix helper +const prefixUrl = (url, publicUrl) => + url.startsWith('data:') ? url : publicUrl + url + +export { prefixUrl }