diff --git a/.storybook/main.js b/.storybook/main.js
index 23cae2d8..75bbfec7 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -1,6 +1,12 @@
module.exports = {
stories: ['../client/**/*.stories.(jsx|mdx)'],
- addons: ['@storybook/addon-actions', '@storybook/addon-docs', '@storybook/addon-knobs', '@storybook/addon-links'],
+ addons: [
+ '@storybook/addon-actions',
+ '@storybook/addon-docs',
+ '@storybook/addon-knobs',
+ '@storybook/addon-links',
+ 'storybook-addon-theme-playground/dist/register'
+ ],
webpackFinal: async config => {
// do mutation to the config
diff --git a/.storybook/preview.js b/.storybook/preview.js
new file mode 100644
index 00000000..e63fad69
--- /dev/null
+++ b/.storybook/preview.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import { addDecorator, addParameters } from '@storybook/react';
+import { withKnobs } from "@storybook/addon-knobs";
+import { withThemePlayground } from 'storybook-addon-theme-playground';
+import { ThemeProvider } from "styled-components";
+
+import theme, { Theme } from '../client/theme';
+
+addDecorator(withKnobs);
+
+const themeConfigs = Object.values(Theme).map(
+ name => {
+ return { name, theme: theme[name] };
+ }
+);
+
+addDecorator(withThemePlayground({
+ theme: themeConfigs,
+ provider: ThemeProvider
+}));
+
+// addDecorator(storyFn => {storyFn()});
diff --git a/client/components/Button/index.js b/client/components/Button/index.js
index 89e9d3b7..ea7afd36 100644
--- a/client/components/Button/index.js
+++ b/client/components/Button/index.js
@@ -1,12 +1,28 @@
import React from "react";
import PropTypes from "prop-types";
import styled from 'styled-components';
+import { remSize, prop } from '../../theme';
const StyledButton = styled.button`
+ background-color: ${prop('buttonColorBackground')};
+ color: ${prop('buttonColor')};
+ cursor: pointer;
+ border: 2px solid ${prop('buttonBorderColor')};
+ border-radius: 2px;
+ padding: ${remSize(8)} ${remSize(25)};
+ line-height: 1;
margin: 0;
- padding: 0;
- border: none;
- background: none;
+
+ &:hover:not(:disabled) {
+ color: ${prop('buttonHoverColor')};
+ background-color: ${prop('buttonHoverColorBackground')};
+ }
+
+ &:disabled {
+ color: ${prop('buttonDisabledColor')};
+ background-color: ${prop('buttonDisabledColorBackground')};
+ cursor: not-allowed;
+ }
`;
/**
@@ -24,7 +40,7 @@ Button.propTypes = {
/**
If the button can be clicked or not
*/
- disabled: PropTypes.boolean,
+ disabled: PropTypes.bool,
/*
* An ARIA Label used for accessibility
*/
diff --git a/client/index.jsx b/client/index.jsx
index 09f6eba0..140ef596 100644
--- a/client/index.jsx
+++ b/client/index.jsx
@@ -3,8 +3,11 @@ import { render } from 'react-dom';
import { hot } from 'react-hot-loader/root';
import { Provider } from 'react-redux';
import { Router, browserHistory } from 'react-router';
+import { ThemeProvider } from 'styled-components';
+
import configureStore from './store';
import routes from './routes';
+import theme, { Theme } from './theme';
require('./styles/main.scss');
@@ -16,10 +19,14 @@ const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);
+const currentTheme = Theme.light;
+
const App = () => (
-
-
-
+
+
+
+
+
);
const HotApp = hot(App);
diff --git a/client/theme.js b/client/theme.js
new file mode 100644
index 00000000..1d90e8fc
--- /dev/null
+++ b/client/theme.js
@@ -0,0 +1,54 @@
+export const Theme = {
+ contrast: 'contrast',
+ dark: 'dark',
+ light: 'light',
+};
+
+export const colors = {
+ p5pink: '#ed225d',
+ yellow: '#f5dc23',
+};
+
+export const common = {
+ baseFontSize: 12
+};
+
+export const remSize = size => `${size / common.baseFontSize}rem`;
+
+export const prop = key => props => props.theme[key];
+
+export default {
+ [Theme.light]: {
+ colors,
+ ...common,
+ primaryTextColor: '#333',
+
+ buttonColor: '#f10046',
+ buttonColorBackground: '#fff',
+ buttonBorderColor: '#b5b5b5',
+ buttonHoverColor: '#fff',
+ buttonHoverColorBackground: colors.p5pink,
+ },
+ [Theme.dark]: {
+ colors,
+ ...common,
+ primaryTextColor: '#FFF',
+
+ buttonColor: '#f10046',
+ buttonColorBackground: '#fff',
+ buttonBorderColor: '#b5b5b5',
+ buttonHoverColor: '#fff',
+ buttonHoverColorBackground: colors.p5pink,
+ },
+ [Theme.contrast]: {
+ colors,
+ ...common,
+ primaryTextColor: '#F5DC23',
+
+ buttonColor: '#333',
+ buttonColorBackground: colors.yellow,
+ buttonBorderColor: '#b5b5b5',
+ buttonHoverColor: '#333',
+ buttonHoverColorBackground: '#fff',
+ },
+};
diff --git a/package-lock.json b/package-lock.json
index 5dceb528..66ae17b9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27914,6 +27914,15 @@
"integrity": "sha512-tWEpK0snS2RPUq1i3R6OahfJNjWCQYNxq0+by1amCSuw0mXtymJpzmZIeYpA1UAa+7B0grCpNYIbDcd7AgTbFg==",
"dev": true
},
+ "storybook-addon-theme-playground": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/storybook-addon-theme-playground/-/storybook-addon-theme-playground-1.2.0.tgz",
+ "integrity": "sha512-9eAgRhTdAqSPQfHPSBxk8ttvZ7fH0tI++/1xvZpyrJwDnSoWrpVlSNVIk748bH9mq6aCyUCi92KzJOhSy+nPxQ==",
+ "dev": true,
+ "requires": {
+ "react-color": "^2.17.3"
+ }
+ },
"storybook-chromatic": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/storybook-chromatic/-/storybook-chromatic-2.2.2.tgz",
@@ -28563,6 +28572,11 @@
}
}
},
+ "styled-theming": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/styled-theming/-/styled-theming-2.2.0.tgz",
+ "integrity": "sha1-MITkPUDqq0vBHrr9PeBONiL+434="
+ },
"stylehacks": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
diff --git a/package.json b/package.json
index 3e584e4d..b8195517 100644
--- a/package.json
+++ b/package.json
@@ -93,6 +93,7 @@
"react-test-renderer": "^16.6.0",
"rimraf": "^2.6.3",
"sass-loader": "^6.0.7",
+ "storybook-addon-theme-playground": "^1.2.0",
"style-loader": "^1.0.0",
"terser-webpack-plugin": "^1.4.1",
"webpack-cli": "^3.3.7",
@@ -185,6 +186,7 @@
"slugify": "^1.3.4",
"srcdoc-polyfill": "^0.2.0",
"styled-components": "^5.0.0",
+ "styled-theming": "^2.2.0",
"url": "^0.11.0",
"webpack": "^4.39.2",
"webpack-dev-middleware": "^2.0.6",