Skip to content

Commit

Permalink
feat(docs): improve colorselector
Browse files Browse the repository at this point in the history
add changing of entire colorgroups simultaneously
    - changing the basecolor will automatically change all shaded of
      that color
  • Loading branch information
Ilari Sinkkonen committed May 30, 2017
1 parent 579f135 commit 37e3092
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 24 deletions.
40 changes: 32 additions & 8 deletions docs/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ import {
Textarea,
Badge,
Icon,
defaultTheme,
withRipple,
createTheme,
} from 'react-components-kit';

import { getColorName, getColorData } from './utils';

const SECTION_SEPARATION = '42px';

const isNumeric = (n) => {
Expand Down Expand Up @@ -79,7 +81,7 @@ class App extends Component {
inputTwo: '',
selectInput: 'foo1',
textareaOne: '',
theme: { ...defaultTheme },
theme: createTheme(),
colorPanelOpen: false,
};
}
Expand All @@ -96,12 +98,34 @@ class App extends Component {
}

updateThemeColor(colorName, newColorValue) {
this.setState(prevState => ({
theme: {
...prevState.theme,
[colorName]: newColorValue,
},
}))
const { group, isBaseColor } = getColorData(colorName);
// base colors, e.g. primaryColor
if (isBaseColor) {
this.setState(prevState => ({
theme: {
...createTheme({
primary: prevState.theme.primaryColor,
secondary: prevState.theme.secondaryColor,
error: prevState.theme.errorColor,
success: prevState.theme.successColor,
warn: prevState.theme.warnColor,
grey: prevState.theme.grey,
[group]: newColorValue,
}),
infoColor: prevState.theme.infoColor,
textColorDark: prevState.theme.textColorDark,
textColorLight: prevState.theme.textColorLight,
}
}));
} else {
this.setState(prevState => ({
theme: {
...prevState.theme,
[colorName]: newColorValue,
},
}));
}

}

closeColorPanel() {
Expand Down
92 changes: 76 additions & 16 deletions docs/src/ThemeChanger.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
Text,
} from 'react-components-kit';

import { getColorData, getColorName } from './utils';

class ColorBox extends Component {
shouldComponentUpdate(nextProps) {
if ((nextProps.color !== this.props.color) ||
Expand Down Expand Up @@ -54,7 +56,7 @@ class ThemeChanger extends Component {

Object.entries(theme)
.filter(([colorName]) => colorName.indexOf('Base') === -1)
.map(([colorName, colorValue]) => { data[colorName] = colorValue; });
.forEach(([colorName, colorValue]) => { data[colorName] = colorValue; });

const json = JSON.stringify(data, null, 2);

Expand All @@ -69,25 +71,45 @@ class ThemeChanger extends Component {
render() {
const { theme } = this.props;

// Filter base colors since they are `Color` objects not color values
const colors = Object.entries(theme)
// Group colors by baseColor, and Filter 'Base' colors because
// they are Color objects
const baseColors = {};
const derivedColors = {};
const otherColors = [];
Object.entries(theme)
.filter(([colorName]) => colorName.indexOf('Base') === -1)
.sort((a, b) => {
const first = a[0].toLowerCase();
const second = b[0].toLowerCase();
return (first < second) ? -1 : (first > second) ? 1 : 0;
})
.forEach(([colorName, colorValue]) => {
const { group, lightness, isBaseColor } = getColorData(colorName);

if (group === 'text' || group === 'info') {
otherColors.push([colorName, colorValue]);
return;
}
if (isBaseColor) {
baseColors[group] = colorValue;
} else {
derivedColors[group] = {
...derivedColors[group],
[lightness]: colorValue,
}
}
});

const rank = color => [
'Darkest', 'Darker', 'Dark', 'Light', 'Lighter', 'Lightest'
].indexOf(color[0]);
const sortShades = shades => Object.entries(shades)
.sort((a, b) => rank(a) - rank(b));

return (
<ThemeChangerWrapper isOpen={this.props.isOpen}>
<ThemeChangerPanel isOpen={this.props.isOpen}>
<Layout align='center'>
<Layout column align='center'>
<Box flex='1'>
<Heading el='h2'>
{this.state.selected || 'Choose color to change'}
</Heading>
</Box>
<Padder />
<Box>
<Layout column align='center'>
<Box>
Expand All @@ -106,8 +128,44 @@ class ThemeChanger extends Component {
</Layout>

<LineSeparator horizontal />
<Layout row>
<Layout column w='48px'>
{Object.entries(baseColors).map(([group, value]) => {
const colorName = getColorName({ group, lightness: '' });
return (
<ColorBox
color={value}
label={colorName}
onClick={() => this.selectColorBox(colorName)}
selected={this.state.selected === colorName}
key={colorName}
/>
);
})}
</Layout>
<LineSeparator vertical />
<div>
{Object.entries(derivedColors).map(([group, shades]) =>
<Layout row>
{sortShades(shades).map(([lightness, value]) => {
const colorName = getColorName({ group, lightness });
return (
<ColorBox
color={value}
label={colorName}
onClick={() => this.selectColorBox(colorName)}
selected={this.state.selected === colorName}
key={colorName}
/>
);
})}
</Layout>
)}
</div>
</Layout>
<Padder vert='16px' />
<Colors>
{colors.map(([colorName, colorValue]) =>
{otherColors.map(([colorName, colorValue]) =>
<ColorBox
color={colorValue}
label={colorName}
Expand Down Expand Up @@ -150,7 +208,7 @@ const ThemeChangerWrapper = styled.div`
${props => !props.isOpen && 'pointer-events: none;'}
`;
const ThemeChangerPanel = styled.div`
width: 400px;
width: 420px;
height: 100vh;
position: fixed;
right: 0;
Expand All @@ -159,7 +217,7 @@ const ThemeChangerPanel = styled.div`
padding: 16px;
transition: transform 0.3s ease-in;
will-change: transform;
transform: translateX(${props => props.isOpen ? '0px' : '400px'});
transform: translateX(${props => props.isOpen ? '0px' : '420px'});
${props => props.isOpen && 'box-shadow: 0px 0px 12px rgba(0,0,0,0.5);'}
z-index: 999998;
`;
Expand All @@ -180,13 +238,15 @@ const Colors = styled.div`
display: flex;
flex-wrap: wrap;
`;

const ColorBoxWrapper = styled.div`
width: 40px;
height: 40px;
margin-bottom: 8px;
margin-right: 8px;
border: 3px solid white;
margin: 4px;
border: 1px solid black;
border-radius: 4px;
${props => props.selected && 'border-color: slategrey;'}
${props => props.selected && 'border-width: 3px;'}
background-color: ${props => props.color};
`;
const ColorPicker = styled.div`
Expand Down
30 changes: 30 additions & 0 deletions docs/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Colors are named like this: <group>Color<lightness>
* Lightness may be blank, and 'Color' will be omitted with grey shades, eg. greyLight
* Basecolors are all colors without a lightness, except for infoColor
*/

export const getColorData = colorName => {
if (colorName.indexOf('Color') === -1) {
return {
group: 'grey',
isBaseColor: colorName === 'grey',
lightness: colorName.slice(4),
};
}

const [group, lightness] = colorName.split('Color');

return {
group,
lightness,
colorName,
isBaseColor: lightness === '' && group !== 'info' && group !== 'text',
};
}

export const getColorName = colorData => {
const { group, lightness } = colorData;

return `${group}${group === 'grey' ? '' : 'Color'}${lightness}`;
}

0 comments on commit 37e3092

Please sign in to comment.