Skip to content

Commit

Permalink
Document new functional color system (#225)
Browse files Browse the repository at this point in the history
* Replace docs

* Convert to TS

* Update theme context

* Add descriptions

* Add color theme picker

* Update color theme picker

* Add color scales

* Tweak styles

* Add content to homepage

* Wrap with `var()`

* Update scale variables heading

* Update docs/gatsby-config.js

* Replace colors_v2 with colors directory
  • Loading branch information
colebemis authored Sep 3, 2021
1 parent eaf6bb5 commit 0e84436
Show file tree
Hide file tree
Showing 15 changed files with 6,567 additions and 4,097 deletions.
121 changes: 121 additions & 0 deletions docs/content/colors.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
title: Colors
---

import colors from '../../dist/js/colors'
import deprecatedColors from '../../dist/deprecations/colors.json'
import filterObj from 'filter-obj'
import flatten from 'flat'
import {Box} from '@primer/components'
import {SwatchGrid} from '../src/components/swatch-grid'
import {ColorThemePicker} from '../src/components/color-theme-picker'
import {ColorScales} from '../src/components/color-scales'

## Themes

Preview color variables in any of the available themes:

<ColorThemePicker />

## Functional variables

### Foreground

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'fg')} />

### Canvas

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'canvas')} />

### Border

<SwatchGrid
names={Object.keys(flatten(colors.light)).filter(
key => key.split('.')[0] === 'border' && !Object.keys(deprecatedColors).includes(key)
)}
/>

### Shadow

<SwatchGrid
names={Object.keys(flatten(colors.light)).filter(
key => key.split('.')[0] === 'shadow' && !Object.keys(deprecatedColors).includes(key)
)}
/>

### Neutral

Use to highlight content without any added meaning.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'neutral')} />

### Accent

Use to draw attention to interactive elements.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'accent')} />

### Success

Use to expresses the completion or positive outcome of a task.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'success')} />

### Attention

Use to warn of pending tasks or highlight active content.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'attention')} />

### Severe

Use when there are more than 3 levels of states, for example in heatmaps.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'severe')} />

### Danger

Use to inform of error or another negative message.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'danger')} />

### Done

Completion color for productivity and code review workflows.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'done')} />

### Sponsors

Use for Sponsors-related interfaces.

<SwatchGrid names={Object.keys(flatten(colors.light)).filter(key => key.split('.')[0] === 'sponsors')} />

## Scale variables

<Note variant="warning">
Avoid referencing scale variables directly when building UI that needs to adapt to different color themes. Instead,
use the functional variables listed above. In rare cases, you may need to use scale variables to define custom
functional variables in your application.
</Note>

<ColorScales />

## Deprecated variables

<table>
<thead>
<tr>
<th>Deprecated variable</th>
<th>Replacement variable(s)</th>
</tr>
</thead>
<tbody>
{Object.entries(deprecatedColors).map(([key, value]) => (
<tr>
<td>{key}</td>
<td>{value}</td>
</tr>
))}
</tbody>
</table>
21 changes: 21 additions & 0 deletions docs/content/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Primer Primitives
---

import {HeroLayout} from '@primer/gatsby-theme-doctocat'

export default HeroLayout

## Install

```shell
npm install @primer/primitives
```

## Usage

Primitive data is served in several formats from the [`dist/`](https://unpkg.com/browse/@primer/primitives/dist/) folder:

- `dist/scss` contains [SCSS](https://sass-lang.com/) files that define CSS variables to be imported into other SCSS files
- `dist/json` contains JSON files for each set of primitives
- `dist/js` contains CommonJS-style JavaScript modules for each set of primitives, as well as an index file that loads all of the primitives for all primitive types. The JavaScript modules also include TypeScript typings files for use in TypeScript projects.
13 changes: 9 additions & 4 deletions docs/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
module.exports = {
siteMetadata: {
title: 'Primer Primitives',
shortName: 'Primitives',
description: 'Color, spacing, and typography primitives for the Primer Design System',
imageUrl: 'https://user-images.githubusercontent.com/10384315/53922681-2f6d3100-402a-11e9-9719-5d1811c8110a.png'
},
pathPrefix: '/primitives',
plugins: [
'gatsby-plugin-styled-components',
'gatsby-plugin-react-helmet',
{
resolve: 'gatsby-plugin-manifest',
resolve: '@primer/gatsby-theme-doctocat',
options: {
icon: require.resolve('./src/images/favicon.png')
defaultBranch: 'main',
repoRootPath: '..'
}
}
]
Expand Down
38 changes: 8 additions & 30 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "docs",
"private": true,
"version": "0.1.0",
"repository": "primer/primitives",
"scripts": {
"setup": "cd ..; yarn; yarn build",
"prebuild": "yarn setup",
Expand All @@ -16,39 +17,16 @@
},
"prettier": "@github/prettier-config",
"dependencies": {
"@primer/components": "^20.0.0",
"@primer/octicons-react": "^11.0.0",
"@types/chroma-js": "^2.1.3",
"@types/flat": "^5.0.1",
"@types/lodash.flatmap": "^4.5.6",
"@types/lodash.groupby": "^4.6.6",
"@types/lodash.kebabcase": "^4.1.6",
"@types/lodash.merge": "^4.6.6",
"@types/react-helmet": "^6.1.0",
"@types/react-table": "^7.0.29",
"babel-plugin-styled-components": "^1.11.1",
"chroma-js": "^2.1.1",
"@github/prettier-config": "^0.0.4",
"@primer/gatsby-theme-doctocat": "^1.7.0",
"color2k": "^1.2.4",
"filter-obj": "^2.0.2",
"flat": "^5.0.2",
"fuse.js": "^6.4.1",
"gatsby": "^2.24.66",
"gatsby-plugin-manifest": "^2.4.34",
"gatsby-plugin-react-helmet": "^3.3.13",
"gatsby-plugin-styled-components": "^3.3.12",
"lodash.debounce": "^4.0.8",
"lodash.flatmap": "^4.5.0",
"lodash.groupby": "^4.6.0",
"lodash.kebabcase": "^4.1.1",
"lodash.merge": "^4.6.2",
"lodash.get": "^4.4.2",
"prettier": "2.1.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "^6.1.0",
"react-table": "^7.6.3",
"sentence-case": "^3.0.3",
"styled-components": "^5.2.0",
"worker-loader": "^3.0.3"
},
"devDependencies": {
"@github/prettier-config": "^0.0.4",
"prettier": "2.1.2"
"sentence-case": "^3.0.4"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {BaseStyles} from '@primer/components'
import SkipLink from '@primer/gatsby-theme-doctocat/src/components/skip-link'
import React from 'react'
import {ColorThemeProvider} from '../../../components/color-theme-context'

// Shadowing this file to wrap the page in our custom ColorThemeProvider.

function wrapPageElement({element}) {
return (
<ColorThemeProvider>
<BaseStyles>
<SkipLink />
{element}
</BaseStyles>
</ColorThemeProvider>
)
}

export default wrapPageElement
2 changes: 2 additions & 0 deletions docs/src/@primer/gatsby-theme-doctocat/nav.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- title: Colors
url: /colors
66 changes: 66 additions & 0 deletions docs/src/components/color-scales.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import colors from '../../../dist/js/colors'
import React from 'react'
import {useColorTheme} from './color-theme-context'
import {Box, Text} from '@primer/components'
import {readableColor} from 'color2k'

export function ColorScales() {
const [colorTheme] = useColorTheme()
return (
<Box
sx={{
display: 'grid',
gridGap: 3,
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
p: 3,
bg: colors[colorTheme].canvas.default,
boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.1)',
borderRadius: 2
}}
>
{Object.entries(colors[colorTheme].scale).map(([scaleName, scale]) => {
return (
<Box sx={{overflow: 'hidden', borderRadius: 1}}>
{Array.isArray(scale) ? (
scale.map((color, index) => {
return (
<Box
sx={{
color: readableColor(color),
bg: color,
p: 2,
display: 'flex',
justifyContent: 'space-between',
fontFamily: 'mono',
fontSize: 1
}}
>
<Text>
scale.{scaleName}.{index}
</Text>
<Text>{color}</Text>
</Box>
)
})
) : (
<Box
sx={{
color: readableColor(scale),
bg: scale,
p: 2,
display: 'flex',
justifyContent: 'space-between',
fontFamily: 'mono',
fontSize: 1
}}
>
<Text>scale.{scaleName}</Text>
<Text>{scale}</Text>
</Box>
)}
</Box>
)
})}
</Box>
)
}
15 changes: 15 additions & 0 deletions docs/src/components/color-theme-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import colors from '../../../dist/js/colors'

const ColorThemeContext = React.createContext<
[keyof typeof colors, React.Dispatch<React.SetStateAction<keyof typeof colors>>]
>(['light', () => {}])

export function ColorThemeProvider({children}) {
const [colorTheme, setColorTheme] = React.useState<keyof typeof colors>('light')
return <ColorThemeContext.Provider value={[colorTheme, setColorTheme]}>{children}</ColorThemeContext.Provider>
}

export function useColorTheme() {
return React.useContext(ColorThemeContext)
}
68 changes: 68 additions & 0 deletions docs/src/components/color-theme-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {Box} from '@primer/components'
import React from 'react'
import {sentenceCase} from 'sentence-case'
import colors from '../../../dist/js/colors'
import {useColorTheme} from './color-theme-context'

export function ColorThemePicker() {
const [colorTheme, setColorTheme] = useColorTheme()
return (
<Box sx={{display: 'grid', gridGap: 3, gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))'}}>
{Object.keys(colors).map(key => (
<Box
as="label"
key={key}
sx={{
border: '1px solid',
borderColor: key === colorTheme ? 'blue.5' : 'border.gray',
borderRadius: 2,
overflow: 'hidden'
}}
>
<ColorThemePreview colorTheme={key} />
<Box sx={{p: 2}}>
<input
type="radio"
id={key}
name="drone"
value={key}
checked={colorTheme === key}
onChange={event => setColorTheme(event.target.value as keyof typeof colors)}
/>
<Box as="span" sx={{ml: 1}}>
{sentenceCase(key)}
</Box>
</Box>
</Box>
))}
</Box>
)
}

function ColorThemePreview({colorTheme}) {
return (
<Box
sx={{
color: colors[colorTheme].fg.default,
bg: colors[colorTheme].canvas.default,
display: 'flex',
p: 3,
borderBottom: '1px solid',
borderColor: 'border.gray',
justifyContent: 'center'
}}
>
{['neutral', 'accent', 'success', 'attention', 'severe', 'danger', 'done', 'sponsors'].map(role => (
<Box
sx={{
width: 20,
height: 20,
bg: colors[colorTheme][role].emphasis,
margin: '2px',
borderRadius: 999
}}
/>
))}
</Box>
)
}
Loading

1 comment on commit 0e84436

@vercel
Copy link

@vercel vercel bot commented on 0e84436 Sep 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.