├── README.md
└── colors-app
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── App.js
├── App.test.js
├── ColorBox.js
├── ColorPickerForm.js
├── DraggableColorBox.js
├── DraggableColorList.js
├── MiniPalette.js
├── Navbar.js
├── NewPaletteForm.js
├── Page.js
├── Palette.js
├── PaletteFooter.js
├── PaletteFormNav.js
├── PaletteList.js
├── PaletteMetaForm.js
├── SingleColorPalette.js
├── colorHelpers.js
├── constants.js
├── index.css
├── index.js
├── logo.svg
├── seedColors.js
├── serviceWorker.js
└── styles
│ ├── ColorBoxStyles.js
│ ├── ColorPickerFormStyles.js
│ ├── DraggableColorBoxStyles.js
│ ├── MiniPaletteStyles.js
│ ├── NavbarStyles.js
│ ├── NewPaletteFormStyles.js
│ ├── Page.css
│ ├── PaletteFooterStyles.js
│ ├── PaletteFormNavStyles.js
│ ├── PaletteListStyles.js
│ ├── PaletteStyles.js
│ ├── bg.svg
│ └── sizes.js
└── yarn.lock
/README.md:
--------------------------------------------------------------------------------
1 | # React Colors Project
2 |
3 | - A clone of websites like [Flat UI Colors](https://flatuicolors.com/) and [Material UI Colors](http://materialuicolors.co/?utm_source=launchers).
4 | - One of the projects for my Modern React Bootcamp course.
5 | - Each video has its own corresponding commit that you can follow along with.
6 |
7 | 
8 | 
9 |
10 | 
11 | 
12 |
13 |
--------------------------------------------------------------------------------
/colors-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 | .DS_Store
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/colors-app/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/colors-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "colors-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^3.9.2",
7 | "@material-ui/icons": "^3.0.2",
8 | "@material-ui/styles": "^3.0.0-alpha.10",
9 | "chroma-js": "^2.0.3",
10 | "emoji-mart": "^2.10.0",
11 | "rc-slider": "^8.6.6",
12 | "react": "^16.8.4",
13 | "react-color": "^2.17.0",
14 | "react-copy-to-clipboard": "^5.0.1",
15 | "react-dom": "^16.8.4",
16 | "react-material-ui-form-validator": "^2.0.7",
17 | "react-router-dom": "^4.3.1",
18 | "react-router-transition": "^1.3.0",
19 | "react-scripts": "2.1.8",
20 | "react-sortable-hoc": "^1.7.1",
21 | "react-transition-group": "^2.6.1"
22 | },
23 | "scripts": {
24 | "start": "react-scripts start",
25 | "build": "react-scripts build",
26 | "test": "react-scripts test",
27 | "eject": "react-scripts eject"
28 | },
29 | "eslintConfig": {
30 | "extends": "react-app"
31 | },
32 | "browserslist": [
33 | ">0.2%",
34 | "not dead",
35 | "not ie <= 11",
36 | "not op_mini all"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/colors-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Colt/react-colors/c358775e0e23e32f47085df1fefc34e38ab0b6be/colors-app/public/favicon.ico
--------------------------------------------------------------------------------
/colors-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
14 |
15 |
19 |
20 |
29 | React App
30 |
31 |
32 | You need to enable JavaScript to run this app.
33 |
34 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/colors-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/colors-app/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Route, Switch } from "react-router-dom";
3 | import { TransitionGroup, CSSTransition } from "react-transition-group";
4 | import Palette from "./Palette";
5 | import PaletteList from "./PaletteList";
6 | import SingleColorPalette from "./SingleColorPalette";
7 | import Page from "./Page";
8 | import NewPaletteForm from "./NewPaletteForm";
9 | import seedColors from "./seedColors";
10 | import { generatePalette } from "./colorHelpers";
11 |
12 | class App extends Component {
13 | constructor(props) {
14 | super(props);
15 | const savedPalettes = JSON.parse(window.localStorage.getItem("palettes"));
16 | this.state = { palettes: savedPalettes || seedColors };
17 | this.savePalette = this.savePalette.bind(this);
18 | this.findPalette = this.findPalette.bind(this);
19 | this.deletePalette = this.deletePalette.bind(this);
20 | }
21 | findPalette(id) {
22 | return this.state.palettes.find(function(palette) {
23 | return palette.id === id;
24 | });
25 | }
26 | deletePalette(id) {
27 | this.setState(
28 | st => ({ palettes: st.palettes.filter(palette => palette.id !== id) }),
29 | this.syncLocalStorage
30 | );
31 | }
32 | savePalette(newPalette) {
33 | this.setState(
34 | { palettes: [...this.state.palettes, newPalette] },
35 | this.syncLocalStorage
36 | );
37 | }
38 | syncLocalStorage() {
39 | //save palettes to local storage
40 | window.localStorage.setItem(
41 | "palettes",
42 | JSON.stringify(this.state.palettes)
43 | );
44 | }
45 | render() {
46 | return (
47 | (
49 |
50 |
51 |
52 | (
56 |
57 |
62 |
63 | )}
64 | />
65 | (
69 |
70 |
76 |
77 | )}
78 | />
79 | (
83 |
84 |
89 |
90 | )}
91 | />
92 | (
96 |
97 |
102 |
103 | )}
104 | />
105 | (
107 |
108 |
113 |
114 | )}
115 | />
116 |
117 |
118 |
119 | )}
120 | />
121 | );
122 | }
123 | }
124 |
125 | export default App;
126 |
--------------------------------------------------------------------------------
/colors-app/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render( , div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/colors-app/src/ColorBox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { CopyToClipboard } from "react-copy-to-clipboard";
3 | import { Link } from "react-router-dom";
4 | import classNames from "classnames";
5 | import { withStyles } from "@material-ui/styles";
6 | import styles from "./styles/ColorBoxStyles";
7 |
8 | class ColorBox extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = { copied: false };
12 | this.changeCopyState = this.changeCopyState.bind(this);
13 | }
14 | changeCopyState() {
15 | this.setState({ copied: true }, () => {
16 | setTimeout(() => this.setState({ copied: false }), 1500);
17 | });
18 | }
19 |
20 | render() {
21 | const {
22 | name,
23 | background,
24 | moreUrl,
25 | showingFullPalette,
26 | classes
27 | } = this.props;
28 |
29 | const { copied } = this.state;
30 | return (
31 |
32 |
33 |
39 |
40 |
45 |
copied!
46 |
{background}
47 |
48 |
49 |
50 | {name}
51 |
52 |
Copy
53 |
54 | {showingFullPalette && (
55 |
e.stopPropagation()}>
56 |
MORE
57 |
58 | )}
59 |
60 |
61 | );
62 | }
63 | }
64 | export default withStyles(styles)(ColorBox);
65 |
--------------------------------------------------------------------------------
/colors-app/src/ColorPickerForm.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Button from "@material-ui/core/Button";
3 | import { ValidatorForm, TextValidator } from "react-material-ui-form-validator";
4 | import { ChromePicker } from "react-color";
5 | import { withStyles } from "@material-ui/core/styles";
6 | import styles from "./styles/ColorPickerFormStyles";
7 |
8 | class ColorPickerForm extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = { currentColor: "teal", newColorName: "" };
12 | this.updateCurrentColor = this.updateCurrentColor.bind(this);
13 | this.handleChange = this.handleChange.bind(this);
14 | this.handleSubmit = this.handleSubmit.bind(this);
15 | }
16 | componentDidMount() {
17 | ValidatorForm.addValidationRule("isColorNameUnique", value =>
18 | this.props.colors.every(
19 | ({ name }) => name.toLowerCase() !== value.toLowerCase()
20 | )
21 | );
22 | ValidatorForm.addValidationRule("isColorUnique", value =>
23 | this.props.colors.every(({ color }) => color !== this.state.currentColor)
24 | );
25 | }
26 | updateCurrentColor(newColor) {
27 | this.setState({ currentColor: newColor.hex });
28 | }
29 | handleChange(evt) {
30 | this.setState({
31 | [evt.target.name]: evt.target.value
32 | });
33 | }
34 | handleSubmit() {
35 | const newColor = {
36 | color: this.state.currentColor,
37 | name: this.state.newColorName
38 | };
39 | this.props.addNewColor(newColor);
40 | this.setState({ newColorName: "" });
41 | }
42 |
43 | render() {
44 | const { paletteIsFull, classes } = this.props;
45 | const { currentColor, newColorName } = this.state;
46 | return (
47 |
48 |
53 |
58 |
73 |
83 | {paletteIsFull ? "Palette Full" : "Add Color"}
84 |
85 |
86 |
87 | );
88 | }
89 | }
90 | export default withStyles(styles)(ColorPickerForm);
91 |
--------------------------------------------------------------------------------
/colors-app/src/DraggableColorBox.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { SortableElement } from "react-sortable-hoc";
3 | import { withStyles } from "@material-ui/styles";
4 | import DeleteIcon from "@material-ui/icons/Delete";
5 | import styles from "./styles/DraggableColorBoxStyles";
6 |
7 | const DraggableColorBox = SortableElement(props => {
8 | const { classes, handleClick, name, color } = props;
9 | return (
10 |
11 |
12 | {name}
13 |
14 |
15 |
16 | );
17 | });
18 | export default withStyles(styles)(DraggableColorBox);
19 |
--------------------------------------------------------------------------------
/colors-app/src/DraggableColorList.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import DraggableColorBox from "./DraggableColorBox";
3 | import { SortableContainer } from "react-sortable-hoc";
4 |
5 | const DraggableColorList = SortableContainer(({ colors, removeColor }) => {
6 | return (
7 |
8 | {colors.map((color, i) => (
9 | removeColor(color.name)}
15 | />
16 | ))}
17 |
18 | );
19 | });
20 | export default DraggableColorList;
21 |
--------------------------------------------------------------------------------
/colors-app/src/MiniPalette.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 | import { withStyles } from "@material-ui/styles";
3 | import styles from "./styles/MiniPaletteStyles";
4 | import DeleteIcon from "@material-ui/icons/Delete";
5 |
6 | class MiniPalette extends PureComponent {
7 | constructor(props) {
8 | super(props);
9 | this.deletePalette = this.deletePalette.bind(this);
10 | this.handleClick = this.handleClick.bind(this);
11 | }
12 | deletePalette(e) {
13 | e.stopPropagation();
14 | this.props.openDialog(this.props.id);
15 | }
16 | handleClick() {
17 | this.props.goToPalette(this.props.id);
18 | }
19 | render() {
20 | const { classes, paletteName, emoji, colors } = this.props;
21 |
22 | const miniColorBoxes = colors.map(color => (
23 |
28 | ));
29 | return (
30 |
31 |
36 |
37 |
{miniColorBoxes}
38 |
39 | {paletteName} {emoji}
40 |
41 |
42 | );
43 | }
44 | }
45 |
46 | export default withStyles(styles)(MiniPalette);
47 |
--------------------------------------------------------------------------------
/colors-app/src/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Link } from "react-router-dom";
3 | import { withStyles } from "@material-ui/styles";
4 | import Select from "@material-ui/core/Select";
5 | import MenuItem from "@material-ui/core/MenuItem";
6 | import Snackbar from "@material-ui/core/Snackbar";
7 | import IconButton from "@material-ui/core/IconButton";
8 | import CloseIcon from "@material-ui/icons/Close";
9 | import Slider from "rc-slider";
10 | import "rc-slider/assets/index.css";
11 | import styles from "./styles/NavbarStyles";
12 |
13 | class Navbar extends Component {
14 | constructor(props) {
15 | super(props);
16 | this.state = { format: "hex", open: false };
17 | this.handleFormatChange = this.handleFormatChange.bind(this);
18 | this.closeSnackbar = this.closeSnackbar.bind(this);
19 | }
20 | handleFormatChange(e) {
21 | this.setState({ format: e.target.value, open: true });
22 | this.props.handleChange(e.target.value);
23 | }
24 | closeSnackbar() {
25 | this.setState({ open: false });
26 | }
27 | render() {
28 | const { level, changeLevel, showingAllColors, classes } = this.props;
29 | const { format } = this.state;
30 | return (
31 |
32 |
33 | reactcolorpicker
34 |
35 | {showingAllColors && (
36 |
37 |
Level: {level}
38 |
39 |
46 |
47 |
48 | )}
49 |
50 |
51 | HEX - #ffffff
52 | RGB - rgb(255,255,255)
53 | RGBA - rgba(255,255,255, 1.0)
54 |
55 |
56 |
62 | Format Changed To {format.toUpperCase()}
63 |
64 | }
65 | ContentProps={{
66 | "aria-describedby": "message-id"
67 | }}
68 | onClose={this.closeSnackbar}
69 | action={[
70 |
76 |
77 |
78 | ]}
79 | />
80 |
81 | );
82 | }
83 | }
84 | export default withStyles(styles)(Navbar);
85 |
--------------------------------------------------------------------------------
/colors-app/src/NewPaletteForm.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import classNames from "classnames";
3 | import { withStyles } from "@material-ui/core/styles";
4 | import PaletteFormNav from "./PaletteFormNav";
5 | import ColorPickerForm from "./ColorPickerForm";
6 | import Drawer from "@material-ui/core/Drawer";
7 | import Typography from "@material-ui/core/Typography";
8 | import Divider from "@material-ui/core/Divider";
9 | import IconButton from "@material-ui/core/IconButton";
10 | import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
11 | import Button from "@material-ui/core/Button";
12 | import DraggableColorList from "./DraggableColorList";
13 | import { arrayMove } from "react-sortable-hoc";
14 | import styles from "./styles/NewPaletteFormStyles";
15 | import seedColors from "./seedColors";
16 |
17 | class NewPaletteForm extends Component {
18 | static defaultProps = {
19 | maxColors: 20
20 | };
21 | constructor(props) {
22 | super(props);
23 | this.state = {
24 | open: true,
25 | colors: seedColors[0].colors
26 | };
27 | this.addNewColor = this.addNewColor.bind(this);
28 | this.handleChange = this.handleChange.bind(this);
29 | this.handleSubmit = this.handleSubmit.bind(this);
30 | this.removeColor = this.removeColor.bind(this);
31 | this.clearColors = this.clearColors.bind(this);
32 | this.addRandomColor = this.addRandomColor.bind(this);
33 | }
34 |
35 | handleDrawerOpen = () => {
36 | this.setState({ open: true });
37 | };
38 |
39 | handleDrawerClose = () => {
40 | this.setState({ open: false });
41 | };
42 |
43 | addNewColor(newColor) {
44 | this.setState({
45 | colors: [...this.state.colors, newColor],
46 | newColorName: ""
47 | });
48 | }
49 | handleChange(evt) {
50 | this.setState({
51 | [evt.target.name]: evt.target.value
52 | });
53 | }
54 | clearColors() {
55 | this.setState({ colors: [] });
56 | }
57 | addRandomColor() {
58 | const allColors = this.props.palettes.map(p => p.colors).flat();
59 | let rand;
60 | let randomColor;
61 | let isDuplicateColor = true;
62 | while (isDuplicateColor) {
63 | rand = Math.floor(Math.random() * allColors.length);
64 | randomColor = allColors[rand];
65 | isDuplicateColor = this.state.colors.some(
66 | color => color.name === randomColor.name
67 | );
68 | }
69 | this.setState({ colors: [...this.state.colors, randomColor] });
70 | }
71 | handleSubmit(newPalette) {
72 | newPalette.id = newPalette.paletteName.toLowerCase().replace(/ /g, "-");
73 | newPalette.colors = this.state.colors;
74 | this.props.savePalette(newPalette);
75 | this.props.history.push("/");
76 | }
77 | removeColor(colorName) {
78 | this.setState({
79 | colors: this.state.colors.filter(color => color.name !== colorName)
80 | });
81 | }
82 | onSortEnd = ({ oldIndex, newIndex }) => {
83 | this.setState(({ colors }) => ({
84 | colors: arrayMove(colors, oldIndex, newIndex)
85 | }));
86 | };
87 |
88 | render() {
89 | const { classes, maxColors, palettes } = this.props;
90 | const { open, colors } = this.state;
91 | const paletteIsFull = colors.length >= maxColors;
92 |
93 | return (
94 |
95 |
101 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | Design Your Palette
119 |
120 |
121 |
127 | Clear Palette
128 |
129 |
136 | Random Color
137 |
138 |
139 |
144 |
145 |
146 |
151 |
152 |
159 |
160 |
161 | );
162 | }
163 | }
164 | export default withStyles(styles, { withTheme: true })(NewPaletteForm);
165 |
--------------------------------------------------------------------------------
/colors-app/src/Page.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./styles/Page.css";
3 |
4 | function Page({ children }) {
5 | return ;
6 | }
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/colors-app/src/Palette.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import ColorBox from "./ColorBox";
3 | import Navbar from "./Navbar";
4 | import PaletteFooter from "./PaletteFooter";
5 | import { withStyles } from "@material-ui/styles";
6 | import styles from "./styles/PaletteStyles";
7 |
8 | class Palette extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = { level: 500, format: "hex" };
12 | this.changeLevel = this.changeLevel.bind(this);
13 | this.changeFormat = this.changeFormat.bind(this);
14 | }
15 | changeLevel(level) {
16 | this.setState({ level });
17 | }
18 | changeFormat(val) {
19 | this.setState({ format: val });
20 | }
21 | render() {
22 | const { colors, paletteName, emoji, id } = this.props.palette;
23 | const { classes } = this.props;
24 | const { level, format } = this.state;
25 | const colorBoxes = colors[level].map(color => (
26 |
33 | ));
34 | return (
35 |
36 |
42 |
{colorBoxes}
43 |
44 |
45 | );
46 | }
47 | }
48 | export default withStyles(styles)(Palette);
49 |
--------------------------------------------------------------------------------
/colors-app/src/PaletteFooter.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withStyles } from "@material-ui/styles";
3 | import styles from "./styles/PaletteFooterStyles";
4 |
5 | function PaletteFooter(props) {
6 | const { paletteName, emoji, classes } = props;
7 | return (
8 |
9 | {paletteName}
10 | {emoji}
11 |
12 | );
13 | }
14 | export default withStyles(styles)(PaletteFooter);
15 |
--------------------------------------------------------------------------------
/colors-app/src/PaletteFormNav.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { withStyles } from "@material-ui/core/styles";
3 | import PaletteMetaForm from "./PaletteMetaForm";
4 | import { Link } from "react-router-dom";
5 | import classNames from "classnames";
6 | import CssBaseline from "@material-ui/core/CssBaseline";
7 | import AppBar from "@material-ui/core/AppBar";
8 | import Toolbar from "@material-ui/core/Toolbar";
9 | import Typography from "@material-ui/core/Typography";
10 | import IconButton from "@material-ui/core/IconButton";
11 | import AddToPhotosIcon from "@material-ui/icons/AddToPhotos";
12 | import Button from "@material-ui/core/Button";
13 | import styles from "./styles/PaletteFormNavStyles";
14 |
15 | class PaletteFormNav extends Component {
16 | constructor(props) {
17 | super(props);
18 | this.state = { newPaletteName: "", formShowing: false };
19 | this.handleChange = this.handleChange.bind(this);
20 | this.showForm = this.showForm.bind(this);
21 | this.hideForm = this.hideForm.bind(this);
22 | }
23 |
24 | handleChange(evt) {
25 | this.setState({
26 | [evt.target.name]: evt.target.value
27 | });
28 | }
29 | showForm() {
30 | this.setState({ formShowing: true });
31 | }
32 | hideForm() {
33 | this.setState({ formShowing: false });
34 | }
35 | render() {
36 | const {
37 | classes,
38 | open,
39 | palettes,
40 | handleSubmit,
41 | handleDrawerOpen
42 | } = this.props;
43 | const { formShowing } = this.state;
44 | return (
45 |
46 |
47 |
54 |
55 |
63 |
64 |
65 |
66 | Create A Palette
67 |
68 |
69 |
70 |
71 |
76 | Go Back
77 |
78 |
79 |
85 | Save
86 |
87 |
88 |
89 | {formShowing && (
90 |
95 | )}
96 |
97 | );
98 | }
99 | }
100 | export default withStyles(styles, { withTheme: true })(PaletteFormNav);
101 |
--------------------------------------------------------------------------------
/colors-app/src/PaletteList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Link } from "react-router-dom";
3 | import { CSSTransition, TransitionGroup } from "react-transition-group";
4 | import Dialog from "@material-ui/core/Dialog";
5 | import List from "@material-ui/core/List";
6 | import ListItem from "@material-ui/core/ListItem";
7 | import ListItemAvatar from "@material-ui/core/ListItemAvatar";
8 | import Avatar from "@material-ui/core/Avatar";
9 | import ListItemText from "@material-ui/core/ListItemText";
10 | import CheckIcon from "@material-ui/icons/Check";
11 | import CloseIcon from "@material-ui/icons/Close";
12 | import DialogTitle from "@material-ui/core/DialogTitle";
13 | import { withStyles } from "@material-ui/styles";
14 | import MiniPalette from "./MiniPalette";
15 | import blue from "@material-ui/core/colors/blue";
16 | import red from "@material-ui/core/colors/red";
17 | import styles from "./styles/PaletteListStyles";
18 |
19 | class PaletteList extends Component {
20 | constructor(props) {
21 | super(props);
22 | this.state = {
23 | openDeleteDialog: false,
24 | deletingId: ""
25 | };
26 | this.openDialog = this.openDialog.bind(this);
27 | this.closeDialog = this.closeDialog.bind(this);
28 | this.handleDelete = this.handleDelete.bind(this);
29 | this.goToPalette = this.goToPalette.bind(this);
30 | }
31 | openDialog(id) {
32 | this.setState({ openDeleteDialog: true, deletingId: id });
33 | }
34 | closeDialog() {
35 | this.setState({ openDeleteDialog: false, deletingId: "" });
36 | }
37 | goToPalette(id) {
38 | this.props.history.push(`/palette/${id}`);
39 | }
40 | handleDelete() {
41 | this.props.deletePalette(this.state.deletingId);
42 | this.closeDialog();
43 | }
44 | render() {
45 | const { palettes, classes } = this.props;
46 | const { openDeleteDialog } = this.state;
47 | return (
48 |
49 |
50 |
51 | React Colors
52 | Create Palette
53 |
54 |
55 | {palettes.map(palette => (
56 |
57 |
64 |
65 | ))}
66 |
67 |
68 |
73 |
74 | Delete This Palette?
75 |
76 |
77 |
78 |
79 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | );
99 | }
100 | }
101 | export default withStyles(styles)(PaletteList);
102 |
--------------------------------------------------------------------------------
/colors-app/src/PaletteMetaForm.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Button from "@material-ui/core/Button";
3 | import Dialog from "@material-ui/core/Dialog";
4 | import DialogActions from "@material-ui/core/DialogActions";
5 | import DialogContent from "@material-ui/core/DialogContent";
6 | import DialogContentText from "@material-ui/core/DialogContentText";
7 | import DialogTitle from "@material-ui/core/DialogTitle";
8 | import { ValidatorForm, TextValidator } from "react-material-ui-form-validator";
9 | import { Picker } from "emoji-mart";
10 | import "emoji-mart/css/emoji-mart.css";
11 |
12 | class PaletteMetaForm extends Component {
13 | constructor(props) {
14 | super(props);
15 | this.state = {
16 | stage: "form",
17 | newPaletteName: ""
18 | };
19 | this.handleChange = this.handleChange.bind(this);
20 | this.showEmojiPicker = this.showEmojiPicker.bind(this);
21 | this.savePalette = this.savePalette.bind(this);
22 | }
23 | componentDidMount() {
24 | ValidatorForm.addValidationRule("isPaletteNameUnique", value =>
25 | this.props.palettes.every(
26 | ({ paletteName }) => paletteName.toLowerCase() !== value.toLowerCase()
27 | )
28 | );
29 | }
30 | handleChange(evt) {
31 | this.setState({
32 | [evt.target.name]: evt.target.value
33 | });
34 | }
35 | showEmojiPicker() {
36 | this.setState({ stage: "emoji" });
37 | }
38 | savePalette(emoji) {
39 | const newPalette = {
40 | paletteName: this.state.newPaletteName,
41 | emoji: emoji.native
42 | };
43 | this.props.handleSubmit(newPalette);
44 | this.setState({ stage: "" });
45 | }
46 | handleClickOpen = () => {
47 | this.setState({ open: true });
48 | };
49 |
50 | handleClose = () => {
51 | this.setState({ open: false });
52 | };
53 |
54 | render() {
55 | const { newPaletteName, stage } = this.state;
56 | const { hideForm } = this.props;
57 |
58 | return (
59 |
60 |
61 |
62 | Choose a Palette Emoji
63 |
64 |
65 |
66 |
71 |
72 | Choose a Palette Name
73 |
74 |
75 |
76 |
77 | Please enter a name for your new beautiful palette. Make sure
78 | it's unique!
79 |
80 |
81 |
91 |
92 |
93 |
94 | Cancel
95 |
96 |
97 | Save Palette
98 |
99 |
100 |
101 |
102 |
103 | );
104 | }
105 | }
106 | export default PaletteMetaForm;
107 |
--------------------------------------------------------------------------------
/colors-app/src/SingleColorPalette.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Link } from "react-router-dom";
3 | import { withStyles } from "@material-ui/styles";
4 | import Navbar from "./Navbar";
5 | import ColorBox from "./ColorBox";
6 | import PaletteFooter from "./PaletteFooter";
7 | import styles from "./styles/PaletteStyles";
8 |
9 | class SingleColorPalette extends Component {
10 | constructor(props) {
11 | super(props);
12 | this._shades = this.gatherShades(this.props.palette, this.props.colorId);
13 | this.state = { format: "hex" };
14 | this.changeFormat = this.changeFormat.bind(this);
15 | }
16 | gatherShades(palette, colorToFilterBy) {
17 | let shades = [];
18 | let allColors = palette.colors;
19 |
20 | for (let key in allColors) {
21 | shades = shades.concat(
22 | allColors[key].filter(color => color.id === colorToFilterBy)
23 | );
24 | }
25 | return shades.slice(1);
26 | }
27 | changeFormat(val) {
28 | this.setState({ format: val });
29 | }
30 | render() {
31 | const { format } = this.state;
32 | const { paletteName, emoji, id } = this.props.palette;
33 | const { classes } = this.props;
34 | const colorBoxes = this._shades.map(color => (
35 |
41 | ));
42 | return (
43 |
44 |
45 |
46 | {colorBoxes}
47 |
48 | GO BACK
49 |
50 |
51 |
52 |
53 | );
54 | }
55 | }
56 | export default withStyles(styles)(SingleColorPalette);
57 |
--------------------------------------------------------------------------------
/colors-app/src/colorHelpers.js:
--------------------------------------------------------------------------------
1 | import chroma from "chroma-js";
2 | const levels = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
3 |
4 | function generatePalette(starterPalette) {
5 | let newPalette = {
6 | paletteName: starterPalette.paletteName,
7 | id: starterPalette.id,
8 | emoji: starterPalette.emoji,
9 | colors: {}
10 | };
11 | for (let level of levels) {
12 | newPalette.colors[level] = [];
13 | }
14 | for (let color of starterPalette.colors) {
15 | let scale = getScale(color.color, 10).reverse();
16 | for (let i in scale) {
17 | newPalette.colors[levels[i]].push({
18 | name: `${color.name} ${levels[i]}`,
19 | id: color.name.toLowerCase().replace(/ /g, "-"),
20 | hex: scale[i],
21 | rgb: chroma(scale[i]).css(),
22 | rgba: chroma(scale[i])
23 | .css()
24 | .replace("rgb", "rgba")
25 | .replace(")", ",1.0)")
26 | });
27 | }
28 | }
29 | return newPalette;
30 | }
31 | function getRange(hexColor) {
32 | const end = "#fff";
33 | return [
34 | chroma(hexColor)
35 | .darken(1.4)
36 | .hex(),
37 | hexColor,
38 | end
39 | ];
40 | }
41 |
42 | function getScale(hexColor, numberOfColors) {
43 | return chroma
44 | .scale(getRange(hexColor))
45 | .mode("lab")
46 | .colors(numberOfColors);
47 | }
48 |
49 | export { generatePalette };
50 |
--------------------------------------------------------------------------------
/colors-app/src/constants.js:
--------------------------------------------------------------------------------
1 | export const DRAWER_WIDTH = 400;
2 |
--------------------------------------------------------------------------------
/colors-app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/colors-app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import { BrowserRouter } from "react-router-dom";
4 | import "./index.css";
5 | import App from "./App";
6 | import * as serviceWorker from "./serviceWorker";
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById("root")
13 | );
14 |
15 | // If you want your app to work offline and load faster, you can change
16 | // unregister() to register() below. Note this comes with some pitfalls.
17 | // Learn more about service workers: https://bit.ly/CRA-PWA
18 | serviceWorker.unregister();
19 |
--------------------------------------------------------------------------------
/colors-app/src/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/colors-app/src/seedColors.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | paletteName: "Material UI Colors",
4 | id: "material-ui-colors",
5 | emoji: "🎨",
6 | colors: [
7 | { name: "red", color: "#F44336" },
8 | { name: "pink", color: "#E91E63" },
9 | { name: "purple", color: "#9C27B0" },
10 | { name: "deeppurple", color: "#673AB7" },
11 | { name: "indigo", color: "#3F51B5" },
12 | { name: "blue", color: "#2196F3" },
13 | { name: "lightblue", color: "#03A9F4" },
14 | { name: "cyan", color: "#00BCD4" },
15 | { name: "teal", color: "#009688" },
16 | { name: "green", color: "#4CAF50" },
17 | { name: "lightgreen", color: "#8BC34A" },
18 | { name: "lime", color: "#CDDC39" },
19 | { name: "yellow", color: "#FFEB3B" },
20 | { name: "amber", color: "#FFC107" },
21 | { name: "orange", color: "#FF9800" },
22 | { name: "deeporange", color: "#FF5722" },
23 | { name: "brown", color: "#795548" },
24 | { name: "grey", color: "#9E9E9E" },
25 | { name: "bluegrey", color: "#607D8B" }
26 | ]
27 | },
28 | {
29 | paletteName: "Flat UI Colors v1",
30 | id: "flat-ui-colors-v1",
31 | emoji: "🤙",
32 | colors: [
33 | { name: "Turquoise", color: "#1abc9c" },
34 | { name: "Emerald", color: "#2ecc71" },
35 | { name: "PeterRiver", color: "#3498db" },
36 | { name: "Amethyst", color: "#9b59b6" },
37 | { name: "WetAsphalt", color: "#34495e" },
38 | { name: "GreenSea", color: "#16a085" },
39 | { name: "Nephritis", color: "#27ae60" },
40 | { name: "BelizeHole", color: "#2980b9" },
41 | { name: "Wisteria", color: "#8e44ad" },
42 | { name: "MidnightBlue", color: "#2c3e50" },
43 | { name: "SunFlower", color: "#f1c40f" },
44 | { name: "Carrot", color: "#e67e22" },
45 | { name: "Alizarin", color: "#e74c3c" },
46 | { name: "Clouds", color: "#ecf0f1" },
47 | { name: "Concrete", color: "#95a5a6" },
48 | { name: "Orange", color: "#f39c12" },
49 | { name: "Pumpkin", color: "#d35400" },
50 | { name: "Pomegranate", color: "#c0392b" },
51 | { name: "Silver", color: "#bdc3c7" },
52 | { name: "Asbestos", color: "#7f8c8d" }
53 | ]
54 | },
55 | {
56 | paletteName: "Flat UI Colors Dutch",
57 | id: "flat-ui-colors-dutch",
58 | emoji: "🇳🇱",
59 | colors: [
60 | { name: "Sunflower", color: "#FFC312" },
61 | { name: "Energos", color: "#C4E538" },
62 | { name: "BlueMartina", color: "#12CBC4" },
63 | { name: "LavenderRose", color: "#FDA7DF" },
64 | { name: "BaraRose", color: "#ED4C67" },
65 | { name: "RadiantYellow", color: "#F79F1F" },
66 | { name: "AndroidGreen", color: "#A3CB38" },
67 | { name: "MediterraneanSea", color: "#1289A7" },
68 | { name: "LavenderTea", color: "#D980FA" },
69 | { name: "VerryBerry", color: "#B53471" },
70 | { name: "PuffinsBill", color: "#EE5A24" },
71 | { name: "PixelatedGrass", color: "#009432" },
72 | { name: "MerchantMarineBlue", color: "#0652DD" },
73 | { name: "ForgottenPurple", color: "#9980FA" },
74 | { name: "HollyHock", color: "#833471" },
75 | { name: "RedPigment", color: "#EA2027" },
76 | { name: "TurkishAqua", color: "#006266" },
77 | { name: "20000LeaguesUnderTheSea", color: "#1B1464" },
78 | { name: "CircumorbitalRing", color: "#5758BB" },
79 | { name: "MagentaPurple", color: "#6F1E51" }
80 | ]
81 | },
82 | {
83 | paletteName: "Flat UI Colors American",
84 | id: "flat-ui-colors-american",
85 | emoji: "🇺🇸",
86 | colors: [
87 | { name: "LightGreenishBlue", color: "#55efc4" },
88 | { name: "FadedPoster", color: "#81ecec" },
89 | { name: "GreenDarnerTail", color: "#74b9ff" },
90 | { name: "ShyMoment", color: "#a29bfe" },
91 | { name: "CityLights", color: "#dfe6e9" },
92 | { name: "MintLeaf", color: "#00b894" },
93 | { name: "RobinsEggBlue", color: "#00cec9" },
94 | { name: "ElectronBlue", color: "#0984e3" },
95 | { name: "ExodusFruit", color: "#6c5ce7" },
96 | { name: "SoothingBreeze", color: "#b2bec3" },
97 | { name: "SourLemon", color: "#ffeaa7" },
98 | { name: "FirstDate", color: "#fab1a0" },
99 | { name: "PinkGlamour", color: "#ff7675" },
100 | { name: "Pico8Pink", color: "#fd79a8" },
101 | { name: "AmericanRiver", color: "#636e72" },
102 | { name: "BrightYarrow", color: "#fdcb6e" },
103 | { name: "OrangeVille", color: "#e17055" },
104 | { name: "Chi-Gong", color: "#d63031" },
105 | { name: "PrunusAvium", color: "#e84393" },
106 | { name: "DraculaOrchid", color: "#2d3436" }
107 | ]
108 | },
109 | {
110 | paletteName: "Flat UI Colors Aussie",
111 | id: "flat-ui-colors-aussie",
112 | emoji: "🇦🇺",
113 | colors: [
114 | { name: "Beekeeper", color: "#f6e58d" },
115 | { name: "SpicedNectarine", color: "#ffbe76" },
116 | { name: "PinkGlamour", color: "#ff7979" },
117 | { name: "JuneBud", color: "#badc58" },
118 | { name: "CoastalBreeze", color: "#dff9fb" },
119 | { name: "Turbo", color: "#f9ca24" },
120 | { name: "QuinceJelly", color: "#f0932b" },
121 | { name: "CarminePink", color: "#eb4d4b" },
122 | { name: "PureApple", color: "#6ab04c" },
123 | { name: "HintOfIcePack", color: "#c7ecee" },
124 | { name: "MiddleBlue", color: "#7ed6df" },
125 | { name: "Heliotrope", color: "#e056fd" },
126 | { name: "ExodusFruit", color: "#686de0" },
127 | { name: "DeepKoamaru", color: "#30336b" },
128 | { name: "SoaringEagle", color: "#95afc0" },
129 | { name: "GreenlandGreen", color: "#22a6b3" },
130 | { name: "SteelPink", color: "#be2edd" },
131 | { name: "Blurple", color: "#4834d4" },
132 | { name: "DeepCove", color: "#130f40" },
133 | { name: "WizardGrey", color: "#535c68" }
134 | ]
135 | },
136 | {
137 | paletteName: "Flat UI Colors British",
138 | id: "flat-ui-colors-british",
139 | emoji: "🇬🇧",
140 | colors: [
141 | { name: "ProtossPylon", color: "#00a8ff" },
142 | { name: "Periwinkle", color: "#9c88ff" },
143 | { name: "Rise-N-Shine", color: "#fbc531" },
144 | { name: "DownloadProgress", color: "#4cd137" },
145 | { name: "Seabrook", color: "#487eb0" },
146 | { name: "VanaDylBlue", color: "#0097e6" },
147 | { name: "MattPurple", color: "#8c7ae6" },
148 | { name: "NanohanachaGold", color: "#e1b12c" },
149 | { name: "SkirretGreen", color: "#44bd32" },
150 | { name: "Naval", color: "#40739e" },
151 | { name: "NasturcianFlower", color: "#e84118" },
152 | { name: "LynxWhite", color: "#f5f6fa" },
153 | { name: "BlueberrySoda", color: "#7f8fa6" },
154 | { name: "MazarineBlue", color: "#273c75" },
155 | { name: "BlueNights", color: "#353b48" },
156 | { name: "HarleyOrange", color: "#c23616" },
157 | { name: "HintOfPensive", color: "#dcdde1" },
158 | { name: "ChainGangGrey", color: "#718093" },
159 | { name: "PicoVoid", color: "#192a56" },
160 | { name: "ElectroMagnetic", color: "#2f3640" }
161 | ]
162 | },
163 | {
164 | paletteName: "Flat UI Colors Spanish",
165 | id: "flat-ui-colors-spanish",
166 | emoji: "🇪🇸",
167 | colors: [
168 | { name: "JacksonsPurple", color: "#40407a" },
169 | { name: "C64Purple", color: "#706fd3" },
170 | { name: "SwanWhite", color: "#f7f1e3" },
171 | { name: "SummerSky", color: "#34ace0" },
172 | { name: "CelestialGreen", color: "#33d9b2" },
173 | { name: "LuckyPoint", color: "#2c2c54" },
174 | { name: "Liberty", color: "#474787" },
175 | { name: "HotStone", color: "#aaa69d" },
176 | { name: "DevilBlue", color: "#227093" },
177 | { name: "PalmSpringsSplash", color: "#218c74" },
178 | { name: "FlourescentRed", color: "#ff5252" },
179 | { name: "SyntheticPumpkin", color: "#ff793f" },
180 | { name: "CrocodileTooth", color: "#d1ccc0" },
181 | { name: "MandarinSorbet", color: "#ffb142" },
182 | { name: "SpicedButterNut", color: "#ffda79" },
183 | { name: "EyeOfNewt", color: "#b33939" },
184 | { name: "ChileanFire", color: "#cd6133" },
185 | { name: "GreyPorcelain", color: "#84817a" },
186 | { name: "AlamedaOchre", color: "#cc8e35" },
187 | { name: "Desert", color: "#ccae62" }
188 | ]
189 | },
190 | {
191 | paletteName: "Flat UI Colors Indian",
192 | id: "flat-ui-colors-indian",
193 | emoji: "🇮🇳",
194 | colors: [
195 | { name: "OrchidOrange", color: "#FEA47F" },
196 | { name: "SpiroDiscoBall", color: "#25CCF7" },
197 | { name: "HoneyGlow", color: "#EAB543" },
198 | { name: "SweetGarden", color: "#55E6C1" },
199 | { name: "FallingStar", color: "#CAD3C8" },
200 | { name: "RichGardenia", color: "#F97F51" },
201 | { name: "ClearChill", color: "#1B9CFC" },
202 | { name: "WhitePepper", color: "#F8EFBA" },
203 | { name: "Keppel", color: "#58B19F" },
204 | { name: "ShipsOfficer", color: "#2C3A47" },
205 | { name: "FieryFuchsia", color: "#B33771" },
206 | { name: "BlueBell", color: "#3B3B98" },
207 | { name: "GeorgiaPeach", color: "#FD7272" },
208 | { name: "OasisStream", color: "#9AECDB" },
209 | { name: "BrightUbe", color: "#D6A2E8" },
210 | { name: "MagentaPurple", color: "#6D214F" },
211 | { name: "EndingNavyBlue", color: "#182C61" },
212 | { name: "SasquatchSocks", color: "#FC427B" },
213 | { name: "PineGlade", color: "#BDC581" },
214 | { name: "HighlighterLavender", color: "#82589F" }
215 | ]
216 | },
217 | {
218 | paletteName: "Flat UI Colors French",
219 | id: "flat-ui-colors-french",
220 | emoji: "🇫🇷",
221 | colors: [
222 | { name: "FlatFlesh", color: "#fad390" },
223 | { name: "MelonMelody", color: "#f8c291" },
224 | { name: "Livid", color: "#6a89cc" },
225 | { name: "Spray", color: "#82ccdd" },
226 | { name: "ParadiseGreen", color: "#b8e994" },
227 | { name: "SquashBlossom", color: "#f6b93b" },
228 | { name: "MandarinRed", color: "#e55039" },
229 | { name: "AzraqBlue", color: "#4a69bd" },
230 | { name: "Dupain", color: "#60a3bc" },
231 | { name: "AuroraGreen", color: "#78e08f" },
232 | { name: "IcelandPoppy", color: "#fa983a" },
233 | { name: "TomatoRed", color: "#eb2f06" },
234 | { name: "YueGuangBlue", color: "#1e3799" },
235 | { name: "GoodSamaritan", color: "#3c6382" },
236 | { name: "Waterfall", color: "#38ada9" },
237 | { name: "CarrotOrange", color: "#e58e26" },
238 | { name: "JalapenoRed", color: "#b71540" },
239 | { name: "DarkSapphire", color: "#0c2461" },
240 | { name: "ForestBlues", color: "#0a3d62" },
241 | { name: "ReefEncounter", color: "#079992" }
242 | ]
243 | }
244 | ];
245 |
--------------------------------------------------------------------------------
/colors-app/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/colors-app/src/styles/ColorBoxStyles.js:
--------------------------------------------------------------------------------
1 | import chroma from "chroma-js";
2 | import sizes from "./sizes";
3 | export default {
4 | ColorBox: {
5 | width: "20%",
6 | height: props => (props.showingFullPalette ? "25%" : "50%"),
7 | margin: "0 auto",
8 | display: "inline-block",
9 | position: "relative",
10 | cursor: "pointer",
11 | marginBottom: "-3.5px",
12 | "&:hover button": {
13 | opacity: 1
14 | },
15 | [sizes.down("lg")]: {
16 | width: "25%",
17 | height: props => (props.showingFullPalette ? "20%" : "33.3333%")
18 | },
19 | [sizes.down("md")]: {
20 | width: "50%",
21 | height: props => (props.showingFullPalette ? "10%" : "20%")
22 | },
23 | [sizes.down("xs")]: {
24 | width: "100%",
25 | height: props => (props.showingFullPalette ? "5%" : "10%")
26 | }
27 | },
28 | copyText: {
29 | color: props =>
30 | chroma(props.background).luminance() >= 0.7 ? "black" : "white"
31 | },
32 | colorName: {
33 | color: props =>
34 | chroma(props.background).luminance() <= 0.08 ? "white" : "black"
35 | },
36 | seeMore: {
37 | color: props =>
38 | chroma(props.background).luminance() >= 0.7 ? "rgba(0,0,0,0.6)" : "white",
39 | background: "rgba(255, 255, 255, 0.3)",
40 | position: "absolute",
41 | border: "none",
42 | right: "0px",
43 | bottom: "0px",
44 | width: "60px",
45 | height: "30px",
46 | textAlign: "center",
47 | lineHeight: "30px",
48 | textTransform: "uppercase"
49 | },
50 | copyButton: {
51 | color: props =>
52 | chroma(props.background).luminance() >= 0.7 ? "rgba(0,0,0,0.6)" : "white",
53 | width: "100px",
54 | height: "30px",
55 | position: "absolute",
56 | display: "inline-block",
57 | top: "50%",
58 | left: "50%",
59 | marginLeft: "-50px",
60 | marginTop: "-15px",
61 | textAlign: "center",
62 | outline: "none",
63 | background: "rgba(255, 255, 255, 0.3)",
64 | fontSize: "1rem",
65 | lineHeight: "30px",
66 | textTransform: "uppercase",
67 | border: "none",
68 | textDecoration: "none",
69 | opacity: 0
70 | },
71 | boxContent: {
72 | position: "absolute",
73 | width: "100%",
74 | left: "0px",
75 | bottom: "0px",
76 | padding: "10px",
77 | color: "black",
78 | letterSpacing: "1px",
79 | textTransform: "uppercase",
80 | fontSize: "12px"
81 | },
82 | copyOverlay: {
83 | opacity: "0",
84 | zIndex: "0",
85 | width: "100%",
86 | height: "100%",
87 | transition: "transform 0.6s ease-in-out",
88 | transform: "scale(0.1)"
89 | },
90 | showOverlay: {
91 | opacity: "1",
92 | transform: "scale(50)",
93 | zIndex: "10",
94 | position: "absolute"
95 | },
96 | copyMessage: {
97 | position: "fixed",
98 | left: "0",
99 | right: "0",
100 | top: "0",
101 | bottom: "0",
102 | display: "flex",
103 | alignItems: "center",
104 | justifyContent: "center",
105 | flexDirection: "column",
106 | fontSize: "4rem",
107 | transform: "scale(0.1)",
108 | opacity: "0",
109 | color: "white",
110 | "& h1": {
111 | fontWeight: "400",
112 | textShadow: "1px 2px black",
113 | background: "rgba(255, 255, 255, 0.2)",
114 | width: "100%",
115 | textAlign: "center",
116 | marginBottom: "0",
117 | padding: "1rem",
118 | textTransform: "uppercase",
119 | [sizes.down("xs")]: {
120 | fontSize: "6rem"
121 | }
122 | },
123 | "& p": {
124 | fontSize: "2rem",
125 | fontWeight: "100"
126 | }
127 | },
128 | showMessage: {
129 | opacity: "1",
130 | transform: "scale(1)",
131 | zIndex: "25",
132 | transition: "all 0.4s ease-in-out",
133 | transitionDelay: "0.3s"
134 | }
135 | };
136 |
--------------------------------------------------------------------------------
/colors-app/src/styles/ColorPickerFormStyles.js:
--------------------------------------------------------------------------------
1 | const styles = {
2 | picker: {
3 | width: "100% !important",
4 | marginTop: "2rem"
5 | },
6 | addColor: {
7 | width: "100%",
8 | padding: "1rem",
9 | marginTop: "1rem",
10 | fontSize: "2rem"
11 | },
12 | colorNameInput: {
13 | width: "100%",
14 | height: "70px"
15 | }
16 | };
17 |
18 | export default styles;
19 |
--------------------------------------------------------------------------------
/colors-app/src/styles/DraggableColorBoxStyles.js:
--------------------------------------------------------------------------------
1 | import sizes from "./sizes";
2 | import chroma from "chroma-js";
3 |
4 | const styles = {
5 | root: {
6 | width: "20%",
7 | height: "25%",
8 | margin: "0 auto",
9 | display: "inline-block",
10 | position: "relative",
11 | cursor: "pointer",
12 | marginBottom: "-3.5px",
13 | "&:hover svg": {
14 | color: "white",
15 | transform: "scale(1.5)"
16 | },
17 | [sizes.down("lg")]: {
18 | width: "25%",
19 | height: "20%"
20 | },
21 | [sizes.down("md")]: {
22 | width: "50%",
23 | height: "10%"
24 | },
25 | [sizes.down("sm")]: {
26 | width: "100%",
27 | height: "5%"
28 | }
29 | },
30 | boxContent: {
31 | position: "absolute",
32 | width: "100%",
33 | left: "0px",
34 | bottom: "0px",
35 | padding: "10px",
36 | color: props =>
37 | chroma(props.color).luminance() <= 0.08
38 | ? "rgba(255,255,255,0.8)"
39 | : "rgba(0,0,0,0.6)",
40 | letterSpacing: "1px",
41 | textTransform: "uppercase",
42 | fontSize: "12px",
43 | display: "flex",
44 | justifyContent: "space-between"
45 | },
46 | deleteIcon: {
47 | transition: "all 0.3s ease-in-out"
48 | }
49 | };
50 |
51 | export default styles;
52 |
--------------------------------------------------------------------------------
/colors-app/src/styles/MiniPaletteStyles.js:
--------------------------------------------------------------------------------
1 | export default {
2 | root: {
3 | backgroundColor: "white",
4 | border: "1px solid black",
5 | borderRadius: "5px",
6 | padding: "0.5rem",
7 | position: "relative",
8 | overflow: "hidden",
9 | cursor: "pointer",
10 | "&:hover svg": {
11 | opacity: 1
12 | }
13 | },
14 | colors: {
15 | backgroundColor: "#dae1e4",
16 | height: "150px",
17 | width: "100%",
18 | borderRadius: "5px",
19 | overflow: "hidden"
20 | },
21 | title: {
22 | display: "flex",
23 | justifyContent: "space-between",
24 | alignItems: "center",
25 | margin: "0",
26 | color: "black",
27 | paddingTop: "0.5rem",
28 | fontSize: "1rem",
29 | position: "relative"
30 | },
31 | emoji: {
32 | marginLeft: "0.5rem",
33 | fontSize: "1.5rem"
34 | },
35 | miniColor: {
36 | height: "25%",
37 | width: "20%",
38 | display: "inline-block",
39 | margin: "0 auto",
40 | position: "relative",
41 | marginBottom: "-3.5px"
42 | },
43 | deleteIcon: {
44 | color: "white",
45 | backgroundColor: "#eb3d30",
46 | width: "20px",
47 | height: "20px",
48 | position: "absolute",
49 | right: "0px",
50 | top: "0px",
51 | padding: "10px",
52 | zIndex: 10,
53 | opacity: 0
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/colors-app/src/styles/NavbarStyles.js:
--------------------------------------------------------------------------------
1 | import sizes from "./sizes";
2 |
3 | export default {
4 | Navbar: {
5 | display: "flex",
6 | alignItems: "center",
7 | justifyContent: "flex-start",
8 | height: "6vh"
9 | },
10 | logo: {
11 | marginRight: "15px",
12 | padding: "0 13px",
13 | fontSize: "22px",
14 | backgroundColor: "#eceff1",
15 | fontFamily: "Roboto",
16 | height: "100%",
17 | display: "flex",
18 | alignItems: "center",
19 | "& a": {
20 | textDecoration: "none",
21 | color: "black"
22 | },
23 | [sizes.down("xs")]: {
24 | display: "none"
25 | }
26 | },
27 | slider: {
28 | width: "340px",
29 | margin: "0 10px",
30 | display: "inline-block",
31 | "& .rc-slider-track": {
32 | backgroundColor: "transparent"
33 | },
34 | "& .rc-slider-rail": {
35 | height: "8px"
36 | },
37 | "& .rc-slider-handle, .rc-slider-handle:active, .rc-slider-handle:focus,.rc-slider-handle:hover": {
38 | backgroundColor: "green",
39 | outline: "none",
40 | border: "2px solid green",
41 | boxShadow: "none",
42 | width: "13px",
43 | height: "13px",
44 | marginLeft: "-7px",
45 | marginTop: "-3px"
46 | },
47 | [sizes.down("sm")]: {
48 | width: "150px"
49 | }
50 | },
51 | selectContainer: {
52 | marginLeft: "auto",
53 | marginRight: "1rem"
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/colors-app/src/styles/NewPaletteFormStyles.js:
--------------------------------------------------------------------------------
1 | import { DRAWER_WIDTH } from "../constants";
2 | const drawerWidth = DRAWER_WIDTH;
3 |
4 | const styles = theme => ({
5 | root: {
6 | display: "flex"
7 | },
8 | drawer: {
9 | width: drawerWidth,
10 | flexShrink: 0,
11 | height: "100vh"
12 | },
13 | drawerPaper: {
14 | width: drawerWidth,
15 | display: "flex",
16 | alignItems: "center"
17 | },
18 | drawerHeader: {
19 | display: "flex",
20 | alignItems: "center",
21 | width: "100%",
22 | padding: "0 8px",
23 | ...theme.mixins.toolbar,
24 | justifyContent: "flex-end"
25 | },
26 | content: {
27 | flexGrow: 1,
28 | height: "calc(100vh - 64px)",
29 | padding: 0,
30 | transition: theme.transitions.create("margin", {
31 | easing: theme.transitions.easing.sharp,
32 | duration: theme.transitions.duration.leavingScreen
33 | }),
34 | marginLeft: -drawerWidth
35 | },
36 | contentShift: {
37 | transition: theme.transitions.create("margin", {
38 | easing: theme.transitions.easing.easeOut,
39 | duration: theme.transitions.duration.enteringScreen
40 | }),
41 | marginLeft: 0
42 | },
43 | container: {
44 | width: "90%",
45 | height: "100%",
46 | display: "flex",
47 | flexDirection: "column",
48 | justifyContent: "center",
49 | alignItems: "center"
50 | },
51 | buttons: {
52 | width: "100%"
53 | },
54 | button: {
55 | width: "50%"
56 | }
57 | });
58 |
59 | export default styles;
60 |
--------------------------------------------------------------------------------
/colors-app/src/styles/Page.css:
--------------------------------------------------------------------------------
1 | .page {
2 | height: 100vh;
3 | position: fixed;
4 | width: 100%;
5 | top: 0;
6 | transition: opacity 0.5s ease-in-out;
7 | }
8 | .page-enter {
9 | opacity: 0;
10 | }
11 | .page-enter-active {
12 | opacity: 1;
13 | }
14 | .page-exit-active {
15 | opacity: 0;
16 | }
17 |
--------------------------------------------------------------------------------
/colors-app/src/styles/PaletteFooterStyles.js:
--------------------------------------------------------------------------------
1 | export default {
2 | PaletteFooter: {
3 | backgroundColor: "white",
4 | height: "5vh",
5 | display: "flex",
6 | justifyContent: "flex-end",
7 | alignItems: "center",
8 | fontWeight: "bold"
9 | },
10 | emoji: {
11 | fontSize: "1.5rem",
12 | margin: "0 1rem"
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/colors-app/src/styles/PaletteFormNavStyles.js:
--------------------------------------------------------------------------------
1 | import { DRAWER_WIDTH } from "../constants";
2 | import sizes from "./sizes";
3 |
4 | const drawerWidth = DRAWER_WIDTH;
5 | const styles = theme => ({
6 | root: {
7 | display: "flex"
8 | },
9 | hide: {
10 | display: "none"
11 | },
12 | appBar: {
13 | transition: theme.transitions.create(["margin", "width"], {
14 | easing: theme.transitions.easing.sharp,
15 | duration: theme.transitions.duration.leavingScreen
16 | }),
17 | flexDirection: "row",
18 | justifyContent: "space-between",
19 | alignItems: "center",
20 | height: "64px"
21 | },
22 | appBarShift: {
23 | width: `calc(100% - ${drawerWidth}px)`,
24 | marginLeft: drawerWidth,
25 | transition: theme.transitions.create(["margin", "width"], {
26 | easing: theme.transitions.easing.easeOut,
27 | duration: theme.transitions.duration.enteringScreen
28 | })
29 | },
30 | menuButton: {
31 | marginLeft: 12,
32 | marginRight: 20
33 | },
34 | navBtns: {
35 | marginRight: "1rem",
36 | "& a": {
37 | textDecoration: "none"
38 | },
39 | [sizes.down("xs")]: {
40 | marginRight: "0.5rem"
41 | }
42 | },
43 | button: {
44 | margin: "0 0.5rem",
45 | [sizes.down("xs")]: {
46 | margin: "0 0.2rem",
47 | padding: "0.3rem"
48 | }
49 | }
50 | });
51 |
52 | export default styles;
53 |
--------------------------------------------------------------------------------
/colors-app/src/styles/PaletteListStyles.js:
--------------------------------------------------------------------------------
1 | import sizes from "./sizes";
2 | import bg from "./bg.svg";
3 | export default {
4 | "@global": {
5 | ".fade-exit": {
6 | opacity: 1
7 | },
8 | ".fade-exit-active": {
9 | opacity: 0,
10 | transition: "opacity 500ms ease-out"
11 | }
12 | },
13 | root: {
14 | height: "100vh",
15 | display: "flex",
16 | alignItems: "flex-start",
17 | justifyContent: "center",
18 | /* background by SVGBackgrounds.com */
19 | backgroundColor: "#394bad",
20 | backgroundImage: `url(${bg})`,
21 | overflow: "scroll"
22 | },
23 | heading: {
24 | fontSize: "2rem"
25 | },
26 | container: {
27 | width: "50%",
28 | display: "flex",
29 | alignItems: "flex-start",
30 | flexDirection: "column",
31 | flexWrap: "wrap",
32 | [sizes.down("xl")]: {
33 | width: "80%"
34 | },
35 | [sizes.down("xs")]: {
36 | width: "75%"
37 | }
38 | },
39 | nav: {
40 | display: "flex",
41 | width: "100%",
42 | justifyContent: "space-between",
43 | alignItems: "center",
44 | color: "white",
45 | "& a": {
46 | color: "white"
47 | }
48 | },
49 | palettes: {
50 | boxSizing: "border-box",
51 | width: "100%",
52 | display: "grid",
53 | gridTemplateColumns: "repeat(3, 30%)",
54 | gridGap: "2.5rem",
55 | [sizes.down("md")]: {
56 | gridTemplateColumns: "repeat(2, 50%)"
57 | },
58 | [sizes.down("xs")]: {
59 | gridTemplateColumns: "repeat(1, 100%)",
60 | gridGap: "1.4rem"
61 | }
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/colors-app/src/styles/PaletteStyles.js:
--------------------------------------------------------------------------------
1 | import sizes from "./sizes";
2 | export default {
3 | Palette: {
4 | height: "100vh",
5 | display: "flex",
6 | flexDirection: "column"
7 | },
8 | colors: {
9 | height: "90%"
10 | },
11 | goBack: {
12 | width: "20%",
13 | height: "50%",
14 | margin: "0 auto",
15 | display: "inline-block",
16 | position: "relative",
17 | cursor: "pointer",
18 | marginBottom: "-3.5px",
19 | opacity: 1,
20 | backgroundColor: "black",
21 | "& a": {
22 | color: "white",
23 | width: "100px",
24 | height: "30px",
25 | position: "absolute",
26 | display: "inline-block",
27 | top: "50%",
28 | left: "50%",
29 | marginLeft: "-50px",
30 | marginTop: "-15px",
31 | textAlign: "center",
32 | outline: "none",
33 | background: "rgba(255, 255, 255, 0.3)",
34 | fontSize: "1rem",
35 | lineHeight: "30px",
36 | textTransform: "uppercase",
37 | border: "none",
38 | textDecoration: "none"
39 | },
40 | [sizes.down("lg")]: {
41 | width: "25%",
42 | height: "33.3333%"
43 | },
44 | [sizes.down("md")]: {
45 | width: "50%",
46 | height: "20%"
47 | },
48 | [sizes.down("xs")]: {
49 | width: "100%",
50 | height: "10%"
51 | }
52 | }
53 | };
54 |
--------------------------------------------------------------------------------
/colors-app/src/styles/bg.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/colors-app/src/styles/sizes.js:
--------------------------------------------------------------------------------
1 | export default {
2 | up() {},
3 | down(size) {
4 | const sizes = {
5 | xs: "575.98px",
6 | sm: "767.98px",
7 | md: "991.98px",
8 | lg: "1199.98px",
9 | xl: "1600px"
10 | };
11 | return `@media (max-width: ${sizes[size]})`;
12 | }
13 | };
14 |
--------------------------------------------------------------------------------