Skip to content

Commit

Permalink
feat: add pajamas color token
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Sep 30, 2020
1 parent 1316e10 commit 6a9e581
Show file tree
Hide file tree
Showing 14 changed files with 292 additions and 26 deletions.
46 changes: 45 additions & 1 deletion examples/stories/src/tutorial/design/tokens/colors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
LiquidColorPalette,
MorningstarColorPalette,
OPatternColorPalette,
PajamasColorPalette,
} from '@component-controls/design-tokens';

# Overview
Expand Down Expand Up @@ -1305,4 +1306,47 @@ import { OPatternColorPalette } from '@component-controls/design-tokens';
sass: '$weather-color',
},
}}
/>
/>

## PajamasColor

The [PajamasColor](/api/design-tokens-colors-pajamascolor--overview) component displays the color as a table row, expanding on hover with display of contrast and passing level.

Design inspired from GitLab's [Pajamas](https://design.gitlab.com/product-foundations/colors/).

```
import { PajamasColorPalette } from '@component-controls/design-tokens';
<PajamasColorPalette
palette={{
'$orange-50': '#fdf1dd',
'$orange-100': '#f5d9a8',
'$orange-200': '#e9be74',
'$orange-300': '#d99530',
'$orange-400': '#c17d10',
'$orange-500': '#ab6100',
'$orange-600': '#9e5400',
'$orange-700': '#8f4700',
'$orange-800': '#703800',
'$orange-900': '#5c2900',
'$orange-950': '#421f00',
}}
/>
```

<PajamasColorPalette
palette={{
'$orange-50': '#fdf1dd',
'$orange-100': '#f5d9a8',
'$orange-200': '#e9be74',
'$orange-300': '#d99530',
'$orange-400': '#c17d10',
'$orange-500': '#ab6100',
'$orange-600': '#9e5400',
'$orange-700': '#8f4700',
'$orange-800': '#703800',
'$orange-900': '#5c2900',
'$orange-950': '#421f00',
}}
/>
1 change: 1 addition & 0 deletions ui/design-tokens/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"theme-ui": "^0.4.0-rc.1"
},
"devDependencies": {
"@component-controls/core": "^1.25.0",
"@component-controls/jest-snapshots": "^1.25.1",
"@component-controls/ts-markdown-docs": "^1.21.0",
"@types/tinycolor2": "^1.4.2",
Expand Down
4 changes: 2 additions & 2 deletions ui/design-tokens/src/Colors/Alta/AltaColor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const AltaColor: FC<ColorBlockProps> = ({ name, color }) => {
bg: colorValue,
width: 64,
height: 64,
border: (t: Theme) => ` 1px solid ${t.colors?.shadow}`,
border: (t: Theme) => `1px solid ${t.colors?.shadow}`,
}}
/>
</CopyContainer>
Expand All @@ -46,7 +46,7 @@ export const AltaColor: FC<ColorBlockProps> = ({ name, color }) => {
<div
sx={{
fontWeight: 'bold',
borderBottom: (t: Theme) => ` 1px solid ${t.colors?.shadow}`,
borderBottom: (t: Theme) => `1px solid ${t.colors?.shadow}`,
pb: 1,
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const AntdVertColor: FC<ColorBlockProps> = ({ name, color, hover }) => {
);

return (
<div sx={{ display: 'flex', flex: '1', width: 250 }}>
<div sx={{ display: 'flex', flex: '1' }}>
<CopyContainer value={hex} name={name} sx={{ width: '100%' }}>
<div
{...onMouseEvents}
Expand Down
29 changes: 17 additions & 12 deletions ui/design-tokens/src/Colors/CometColor/CometColor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { FC } from 'react';
import { jsx, SxStyleProp } from 'theme-ui';
import tinycolor from 'tinycolor2';
import { CopyContainer } from '@component-controls/components';
import { colorToStr, mostReadable } from '../utils';
import { ColorBlockProps, ColorValue, colorContrast } from '../../types';
import { colorToStr, mostReadable, contrastGrade } from '../utils';
import { ColorBlockProps, ColorValue } from '../../types';
import { FlexContainerProps, FlexContainer } from '../../components';

/**
Expand All @@ -29,16 +29,21 @@ export const CometColor: FC<ColorBlockProps> = ({ name, color }) => {
color: 'black',
fontSize: 1,
};
if (contrast >= colorContrast.AAA.ratio) {
accessibilityTest = <div sx={{ ...testProps, bg: 'gray' }}>AAA</div>;
} else if (contrast >= colorContrast.small.ratio) {
accessibilityTest = <div sx={{ ...testProps, bg: 'gray' }}>AA</div>;
} else if (contrast >= colorContrast.large.ratio) {
accessibilityTest = <div sx={{ ...testProps, bg: '#e6c719' }}>AA18</div>;
} else {
accessibilityTest = (
<div sx={{ ...testProps, bg: '##b42818', color: 'white' }}>DNP</div>
);
const grade = contrastGrade(contrast);
switch (grade) {
case 'AAA':
accessibilityTest = <div sx={{ ...testProps, bg: 'gray' }}>AAA</div>;
break;
case 'AA':
accessibilityTest = <div sx={{ ...testProps, bg: 'gray' }}>AA</div>;
break;
case 'AA':
accessibilityTest = <div sx={{ ...testProps, bg: '#e6c719' }}>AA18</div>;
break;
default:
accessibilityTest = (
<div sx={{ ...testProps, bg: '##b42818', color: 'white' }}>DNP</div>
);
}
return (
<div sx={{ display: 'flex', flex: '1' }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const HelpScoutColor: FC<ColorBlockProps> = ({ name, color }) => {
const textColor = mostReadable(hex);

return (
<div sx={{ display: 'flex', flex: '1', width: 250 }}>
<div sx={{ display: 'flex', flex: '1' }}>
<CopyContainer value={hex} name={name} sx={{ width: '100%' }}>
<div
sx={{
Expand Down
8 changes: 4 additions & 4 deletions ui/design-tokens/src/Colors/LightningColor/LightningColor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ const BaseLightningColor: FC<LightningColorProps> = ({
bg: 'background',
'& > td ': {
py: 3,
borderTop: (t: Theme) => ` 1px solid ${t.colors?.shadow}`,
borderBottom: (t: Theme) => ` 1px solid ${t.colors?.shadow}`,
borderTop: (t: Theme) => `1px solid ${t.colors?.shadow}`,
borderBottom: (t: Theme) => `1px solid ${t.colors?.shadow}`,
},
}}
>
Expand Down Expand Up @@ -122,8 +122,8 @@ export const LightningColorPalette: FC<Optional<
textAlign: 'left',
fontSize: 0,
bg: 'gray',
borderTop: (t: Theme) => ` 1px solid ${t.colors?.shadow}`,
borderBottom: (t: Theme) => ` 1px solid ${t.colors?.shadow}`,
borderTop: (t: Theme) => `1px solid ${t.colors?.shadow}`,
borderBottom: (t: Theme) => `1px solid ${t.colors?.shadow}`,
},
}}
columns={[
Expand Down
36 changes: 36 additions & 0 deletions ui/design-tokens/src/Colors/PajamasColor/PajamasColor.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { ControlTypes } from '@component-controls/core';
import { PajamasColor, PajamasColorPalette } from './PajamasColor';
import { ColorProps } from '../../types';

export default {
title: 'Design Tokens/Colors/PajamasColor',
component: PajamasColor,
};

export const overview = ({ name, color }: ColorProps) => (
<PajamasColor name={name} color={color} />
);

overview.controls = {
name: '$blue-50',
color: { type: ControlTypes.COLOR, value: '#e9f3fc' },
};

export const palette = () => (
<PajamasColorPalette
palette={{
'$orange-50': '#fdf1dd',
'$orange-100': '#f5d9a8',
'$orange-200': '#e9be74',
'$orange-300': '#d99530',
'$orange-400': '#c17d10',
'$orange-500': '#ab6100',
'$orange-600': '#9e5400',
'$orange-700': '#8f4700',
'$orange-800': '#703800',
'$orange-900': '#5c2900',
'$orange-950': '#421f00',
}}
/>
);
165 changes: 165 additions & 0 deletions ui/design-tokens/src/Colors/PajamasColor/PajamasColor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/** @jsx jsx */
import { FC, useState, useMemo } from 'react';
import { jsx } from 'theme-ui';
import tinycolor from 'tinycolor2';
import { CopyContainer } from '@component-controls/components';
import { colorToStr, mostReadable, contrastGrade } from '../utils';
import { ColorBlockProps } from '../../types';
import { FlexContainerProps, FlexContainer } from '../../components';

/**
* Color item displaying the color as a table row, expanding on hover with display of contrast and passing level.
* Design inspired from GitLab's [Pajamas](https://design.gitlab.com/product-foundations/colors/).
*/

export const PajamasColor: FC<ColorBlockProps> = ({ name, color, hover }) => {
const [hoverMe, setHoverMe] = useState(false);
const colorValue = typeof color === 'string' ? color : color.value;
const { hex } = colorToStr(colorValue);
const textColor = mostReadable(hex);
const onMouseEvents = useMemo(
() => ({
onMouseOver: () => setHoverMe(true),
onMouseLeave: () => setHoverMe(false),
}),
[],
);
const contrastWhite = tinycolor.readability(hex, '#ffffff');
const contrastGradeWhite = contrastGrade(contrastWhite);
const contrastBlack = tinycolor.readability(hex, '#000000');
const contrastGradeBlack = contrastGrade(contrastBlack);
return (
<div sx={{ display: 'flex', flex: '1' }}>
<div
{...onMouseEvents}
sx={{
display: 'flex',
flexDirection: 'column',
fontSize: 0,
transition: 'all .2s',
width: '100%',
border: `1px solid ${colorValue}`,
}}
>
<CopyContainer value={hex} name={name}>
<div
sx={{
minWidth: '100%',
display: 'flex',
flexDirection: 'row',
bg: colorValue,
color: textColor,
height: 35,
alignItems: 'center',
justifyContent: 'space-between',
fontSize: 0,
transition: 'all .2s',
mr: hoverMe ? -3 : 0,
px: 3,
}}
>
<div
sx={{
fontWeight: hoverMe ? 'bold' : 'normal',
}}
>
{name || hex}
</div>
<div
sx={{
...(hover || hoverMe ? {} : { visibility: 'hidden', width: 0 }),
}}
>
{hex}
</div>
</div>
</CopyContainer>
{hoverMe && (
<div
sx={{
bg: 'background',
color: 'text',
display: 'flex',
flexDirection: 'column',
px: 3,
py: 4,
fontSize: 1,
}}
>
<div sx={{ fontWeight: 'bold' }}>
Passing level and contrast ratio
</div>
<div
sx={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
}}
>
<div
sx={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
mr: 3,
}}
>
<div sx={{ bg: colorValue, color: 'black', px: 1, mr: 2 }}>
Text
</div>
<div
sx={{
px: 1,
border: `1px solid ${colorValue}`,
color: contrastGradeBlack === 'F' ? '#c91c00' : 'text',
}}
>
{`${contrastGradeBlack} (${contrastBlack.toFixed(1)})`}
</div>
</div>
<div
sx={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
}}
>
<div sx={{ bg: colorValue, color: 'white', px: 1 }}>Text</div>
<div
sx={{
px: 1,
border: `1px solid ${colorValue}`,
color: contrastGradeWhite === 'F' ? '#c91c00' : 'text',
}}
>
{`${contrastGradeWhite} (${contrastWhite.toFixed(1)})`}
</div>
</div>
</div>
</div>
)}
</div>
</div>
);
};

/**
*
* palette displayed with PajamasColor items
* using a css flex display direction column
*/
export const PajamasColorPalette: FC<Omit<
FlexContainerProps,
'children' | 'direction'
>> = props => (
<FlexContainer direction="column" sx={{ width: 360 }} {...props}>
{({ name, value, hover }) => (
<PajamasColor
key={`color_item_${name}}`}
name={name}
color={value}
hover={hover}
/>
)}
</FlexContainer>
);
1 change: 1 addition & 0 deletions ui/design-tokens/src/Colors/PajamasColor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './PajamasColor';
1 change: 1 addition & 0 deletions ui/design-tokens/src/Colors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './LightningColor';
export * from './LiquidColor';
export * from './MorningstarColor';
export * from './OPatternColor';
export * from './PajamasColor';
14 changes: 13 additions & 1 deletion ui/design-tokens/src/Colors/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import tinycolor from 'tinycolor2';

import { colorContrast, ContrastGrades } from '../types';
/**
* convert color
*/
Expand All @@ -18,3 +18,15 @@ export const colorToStr = (

export const mostReadable = (color: string) =>
tinycolor.mostReadable(color, ['#000000', '#ffffff']).toString('hex');

export const contrastGrade = (contrast: number): ContrastGrades => {
if (contrast >= colorContrast.AAA.ratio) {
return 'AAA';
} else if (contrast >= colorContrast.small.ratio) {
return 'AA';
} else if (contrast >= colorContrast.large.ratio) {
return 'AA+';
} else {
return 'F';
}
};
Loading

0 comments on commit 6a9e581

Please sign in to comment.