├── .gitignore ├── LICENSE ├── README.md ├── now.json ├── package.json ├── public ├── favicon.png ├── index.html └── meta.png ├── src ├── App │ ├── index.js │ └── style.js ├── Tile │ ├── index.js │ └── style.js ├── Tiles │ ├── index.js │ └── style.js ├── global-styles.js └── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Maximilian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Color Schemer](https://colors.styled-components.com) 2 | 3 | **[colors.styled-components.com](https://colors.styled-components.com)** 4 | 5 | [![The color schemer app](https://cloud.githubusercontent.com/assets/7525670/23553930/c8f83efc-001a-11e7-810a-7c7916dc1f29.png)](https://colors.styled-components.com) 6 | 7 | A demo React app built with [`💅 styled-components`](https://github.com/styled-components/styled-components) and [`✨ polished`](https://github.com/styled-components/polished). 8 | 9 | ## Structure 10 | 11 | Every component has a folder beneath the `src/` folder, with an `index.js` containing the component and a `style.js` containing the styled components used within that component. 12 | 13 | ```sh 14 | colors 15 | ├── App 16 | ├── Tile 17 | ├── Tiles 18 | ├── global-styles.js # The global styles 19 | └── index.js 20 | ``` 21 | 22 | ``` 23 | ┌───────────────────────────────────────────────────────────────────┐ 24 | │ │ 25 | │┌─────────────────────────────────────────────────────────────────┐│ 26 | ││ ││ 27 | ││ ││ 28 | ││ ││ 29 | ││ ││ 30 | ││ ││ 31 | │└─────────────────────────────────────────────────────────────────┘│ 32 | │┌─────────────────────────────────────────────────────────────────┐│ 33 | ││ ││ 34 | ││┌───────────┐┌───────────┐┌───────────┐┌───────────┐┌───────────┐││ 35 | │││ ││ ││ ││ ││ │││ 36 | │││ ││ ││ ││ ││ │││ 37 | │││ ││ ││ ││ ││ │││ 38 | ││└───────────┘└───────────┘└───────────┘└───────────┘└───────────┘││ 39 | │└─────────────────────────────────────────────────────────────────┘│ 40 | └───────────────────────────────────────────────────────────────────┘ 41 | ``` 42 | 43 | ## Calculation 44 | 45 | We take the entered color, convert it to HSL and render the same hue and saturation with lightness' of `0.1`, `0.3`, `0.5`, `0.7` and `0.9`. 46 | 47 | ## Running locally 48 | 49 | ```sh 50 | git clone https://github.com/styled-components/color-schemer 51 | cd color-schemer # Go to downloaded directory 52 | npm install # Install dependencies 53 | npm start # Start the development server 54 | ``` 55 | 56 | ## Uses 57 | 58 | - [`create-react-app`](https://github.com/facebookincubator/create-react-app) 59 | - [💅 `styled-components`](https://github.com/styled-components/styled-components) 60 | - [✨ `polished`](https://github.com/styled-components/polished) 61 | - [clipboard.js](https://clipboardjs.com/) 62 | - [`color-name`](https://npm.im/color-name) 63 | 64 | ## License 65 | 66 | Copyright (c) 2017 Maximilian Stoiber. Licensed under the MIT License, see the [LICENSE](LICENSE) file for more information. 67 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "name": "color-schemer", 4 | "builds": [ 5 | { "src": "package.json", "use": "@now/static-build" } 6 | ], 7 | "routes": [ 8 | {"src": "^/static/(.*)", "dest": "/static/$1"}, 9 | {"src": "^/favicon.ico", "dest": "/favicon.ico"}, 10 | {"src": "^/asset-manifest.json", "dest": "/asset-manifest.json"}, 11 | {"src": "^/manifest.json", "dest": "/manifest.json"}, 12 | {"src": "^/(.*)", "dest": "/index.html"} 13 | ] 14 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "colors", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "gh-pages": "^0.12.0", 7 | "lint-staged": "^3.3.1", 8 | "pre-commit": "^1.2.2", 9 | "prettier": "^0.20.0", 10 | "react-scripts": "2.1.1" 11 | }, 12 | "dependencies": { 13 | "clipboard": "^1.6.1", 14 | "color-name": "^1.1.4", 15 | "polished": "^2.3.1", 16 | "react": "^16.6.3", 17 | "react-dom": "^16.6.3", 18 | "styled-components": "^4.1.2" 19 | }, 20 | "scripts": { 21 | "start": "react-scripts start", 22 | "build": "react-scripts build", 23 | "test": "react-scripts test --env=jsdom", 24 | "eject": "react-scripts eject", 25 | "now-build": "react-scripts build && mv build dist", 26 | "lint:staged": "lint-staged" 27 | }, 28 | "lint-staged": { 29 | "*.js": [ 30 | "prettier --write --single-quote --trailing-comma es5", 31 | "git add" 32 | ] 33 | }, 34 | "pre-commit": "lint:staged", 35 | "browserslist": [ 36 | ">0.2%", 37 | "not dead", 38 | "not ie <= 11", 39 | "not op_mini all" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/styled-components/color-schemer/cbdbf006ea54b1402836dd5bb9cd77bf28d427ee/public/favicon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Color Schemer | Built with 💅 styled-components and ✨ polished 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /public/meta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/styled-components/color-schemer/cbdbf006ea54b1402836dd5bb9cd77bf28d427ee/public/meta.png -------------------------------------------------------------------------------- /src/App/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { invert } from 'polished'; 3 | import cssColors from 'color-name'; 4 | import GlobalStyles from '../global-styles'; 5 | import Tiles from '../Tiles'; 6 | 7 | import { BigTile, Input, Title, ForkBanner, Link, Wrapper } from './style'; 8 | 9 | const IS_HEX_WITHOUT_HASH = /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i; 10 | 11 | let inverted, color; 12 | class App extends Component { 13 | state = { 14 | color: '#65daa2', 15 | }; 16 | 17 | changeColor = evt => { 18 | this.setState({ 19 | color: evt.target.value, 20 | }); 21 | }; 22 | 23 | render() { 24 | try { 25 | // Handle color names (e.g. "red") 26 | let temp = cssColors[this.state.color]; 27 | if (temp) { 28 | temp = `rgb(${temp[0]}, ${temp[1]}, ${temp[2]})`; 29 | } else { 30 | temp = this.state.color; 31 | if (IS_HEX_WITHOUT_HASH.test(temp)) { 32 | temp = `#${temp}`; 33 | } 34 | } 35 | // This will throw if this.state.color is invalid, 36 | // leaving us with the old colors if somebody enters 37 | // an invalid color 38 | inverted = invert(temp); 39 | color = temp; 40 | } catch (err) {} 41 | return ( 42 | 43 | 44 | 45 | Color Schemer 46 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | ); 65 | } 66 | } 67 | 68 | export default App; 69 | -------------------------------------------------------------------------------- /src/App/style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const BigTile = styled.div` 4 | background: ${props => props.bg || '#6cc0e5'}; 5 | width: 100%; 6 | height: 50vh; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | `; 11 | 12 | export const Input = styled.input` 13 | background: transparent; 14 | border: none; 15 | color: ${props => props.color}; 16 | font-size: 24px; 17 | font-family: monaco,Consolas,Lucida Console,monospace; 18 | width: ${props => `${props.value.length * 16 || 96}px`}; 19 | text-align: center; 20 | border-bottom: 1px solid ${props => props.color}; 21 | 22 | &:focus, 23 | &:hover { 24 | outline: none; 25 | } 26 | `; 27 | 28 | export const Title = styled.h1` 29 | position: absolute; 30 | top: 0; 31 | color: ${props => props.color}; 32 | `; 33 | 34 | export const ForkBanner = styled.img` 35 | position: absolute; 36 | top: 0; 37 | right: 0; 38 | border: 'none'; 39 | `; 40 | 41 | export const Link = styled.a``; 42 | 43 | export const Wrapper = styled.div``; 44 | -------------------------------------------------------------------------------- /src/Tile/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { findDOMNode } from 'react-dom'; 3 | import { invert } from 'polished'; 4 | import Clipboard from 'clipboard'; 5 | import { Wrapper, Text } from './style'; 6 | 7 | class Tile extends React.Component { 8 | state = { 9 | text: this.props.color, 10 | }; 11 | 12 | // Set the text of the tile temporarily, reverting 13 | // back to the color after one second 14 | setText = text => { 15 | this.setState({ 16 | text: text, 17 | }); 18 | setTimeout( 19 | () => { 20 | this.setState({ 21 | text: this.props.color, 22 | }); 23 | }, 24 | 1000 25 | ); 26 | }; 27 | 28 | componentDidMount() { 29 | const clipboard = new Clipboard(findDOMNode(this.tile)); 30 | clipboard.on('success', () => { 31 | this.setText('Copied! 💯'); 32 | }); 33 | clipboard.on('error', function(e) { 34 | this.setText('Copying failed 😢'); 35 | }); 36 | } 37 | 38 | render() { 39 | const { color } = this.props; 40 | return ( 41 | this.tile = comp} 44 | data-clipboard-text={color} 45 | > 46 | {this.state.text} 47 | 48 | ); 49 | } 50 | } 51 | 52 | export default Tile; 53 | -------------------------------------------------------------------------------- /src/Tile/style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.button` 4 | background: ${props => props.bg}; 5 | height: 50vh; 6 | width: 20%; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | border: none; 11 | display: block; 12 | outline: none; 13 | cursor: pointer; 14 | 15 | @media screen and (max-aspect-ratio: 2/3) { 16 | width: 100%; 17 | height: 10vh; 18 | } 19 | `; 20 | 21 | export const Text = styled.p` 22 | font-size: 1.75em; 23 | color: ${props => props.color}; 24 | `; 25 | -------------------------------------------------------------------------------- /src/Tiles/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { setLightness } from 'polished'; 3 | 4 | import Tile from '../Tile'; 5 | import { Wrapper } from './style'; 6 | 7 | export default ({ color }) => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/Tiles/style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.div` 4 | display: flex; 5 | flex-direction: row; 6 | 7 | @media screen and (max-aspect-ratio: 2/3) { 8 | flex-direction: column; 9 | } 10 | `; 11 | -------------------------------------------------------------------------------- /src/global-styles.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | 3 | export default createGlobalStyle` 4 | html, 5 | #root, 6 | body { 7 | width: 100%; 8 | height: 100%; 9 | margin: 0; 10 | padding: 0; 11 | font-size: 16px; 12 | font-family: Andale Mono,AndaleMono,monospace; 13 | } 14 | 15 | @media screen and (min-aspect-ratio: 2/3) { 16 | overflow: hidden; 17 | } 18 | `; 19 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('root')); 6 | --------------------------------------------------------------------------------