Skip to content

Commit 17a082b

Browse files
committed
feat: display semantic colors
1 parent 93c0a10 commit 17a082b

File tree

7 files changed

+471
-262
lines changed

7 files changed

+471
-262
lines changed

testing/src/App.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
import { theme } from '../../theme/src/main'
2-
import { ChakraBaseProvider, Box } from '@chakra-ui/react'
2+
import { Box, ChakraBaseProvider, Heading } from '@chakra-ui/react'
33

44
import { Buttons } from '@/views/Buttons'
55
import { Headings } from '@/views/Headings'
66
import { Colors } from '@/views/Colors'
7+
import { SemanticColors } from '@/views/SemanticColors'
78

89
function App() {
910
return (
1011
<ChakraBaseProvider theme={theme}>
12+
<Heading variant="h1">Colors</Heading>
1113
<Box p={8}>
1214
<Colors withText />
1315
</Box>
1416
<hr />
17+
<Heading variant="h1">Semantic Colors</Heading>
18+
<Box p={8}>
19+
<SemanticColors withText />
20+
</Box>
21+
<hr />
22+
<Heading variant="h1">Headings</Heading>
1523
<Box p={8}>
1624
<Headings />
1725
</Box>
1826
<hr />
27+
<Heading variant="h1">Buttons</Heading>
1928
<Box p={8}>
2029
<Buttons />
2130
</Box>

testing/src/views/SemanticColors.tsx

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { HStack, Heading, Text, VStack } from '@chakra-ui/react'
2+
import * as semanticColors from '@/../../theme/src/style-guide/semanticColors'
3+
import computedSemanticColors from '@/../../theme/src/style-guide/computedSemanticColors'
4+
import { ColorCategory, ColorsInCategories } from '@/../../theme/src/style-guide/types'
5+
import { neutrals } from '@/../../theme/src/foundations/colors'
6+
7+
const BORDER_WIDTH_IN_PIXEL = 1
8+
const BORDER_COLOR_LIGHT = neutrals['900']
9+
const BORDER_COLOR_DARK = neutrals.WHITE
10+
11+
export function SemanticColors({withText = false}: {withText?: boolean}) {
12+
const SIZE = 40
13+
14+
const columnStyle = {
15+
border: `1px solid ${neutrals['300']}`,
16+
borderRadius: 12,
17+
padding: 20
18+
}
19+
20+
return (
21+
<>
22+
<HStack alignItems="start" gap={withText ? 8 : 2}>
23+
{Object.entries(semanticColors as ColorsInCategories).map(([category, value]) => {
24+
return (
25+
<VStack alignItems="start" style={columnStyle} key={category + value}>
26+
<Heading variant="h2" marginBottom="4">{category}</Heading>
27+
28+
<VStack alignItems="start">
29+
{Object.entries(value).map(([colorName, colorValue]) => {
30+
const mappedColor = computedSemanticColors[category as ColorCategory][colorName]
31+
32+
// style for all types of semantic colors: text + a circle for light + a circle for dark with their values
33+
// the background of the circle is usually for the assigned color, and the border varies depending on whether it's light or dark theme
34+
// but for the 'border' key, it's the opposite: the border shows the assigned color, and the background corresponds to the light/dark theme
35+
const styles = {
36+
width: SIZE,
37+
height: SIZE,
38+
borderRadius: 999
39+
}
40+
const lightCircle = {
41+
...styles,
42+
backgroundColor: mappedColor.light,
43+
border: `${BORDER_WIDTH_IN_PIXEL}px solid ${BORDER_COLOR_LIGHT}`
44+
}
45+
const darkCircle = {
46+
...styles,
47+
backgroundColor: mappedColor.dark,
48+
border: `${BORDER_WIDTH_IN_PIXEL}px solid ${BORDER_COLOR_DARK}`
49+
}
50+
51+
const pillStyle = {
52+
display: 'flex',
53+
backgroundColor: 'red', // white be overridden
54+
border: `${BORDER_WIDTH_IN_PIXEL}px solid ${neutrals['200']}`,
55+
padding: 4,
56+
gap: 12,
57+
paddingRight: withText ? 16 : 4,
58+
borderRadius: 999,
59+
alignItems: 'center',
60+
width: 160
61+
}
62+
const lightPill = {
63+
...pillStyle,
64+
backgroundColor: neutrals.WHITE
65+
}
66+
const darkPill = {
67+
...pillStyle,
68+
backgroundColor: neutrals['900'],
69+
border: 'none'
70+
}
71+
72+
if (category === 'border') {
73+
lightCircle.backgroundColor = neutrals.WHITE
74+
lightCircle.border = `${BORDER_WIDTH_IN_PIXEL}px solid ${mappedColor.light}`
75+
darkCircle.backgroundColor = neutrals['900']
76+
darkCircle.border = `${BORDER_WIDTH_IN_PIXEL}px solid ${mappedColor.dark}`
77+
}
78+
79+
return (
80+
<HStack alignItems="center" gap={2} key={category + colorName}>
81+
{withText && (
82+
<Text fontFamily="monospace" minWidth="150" fontSize="small">
83+
{colorName}
84+
</Text>
85+
)}
86+
<HStack>
87+
<div style={lightPill}>
88+
<div style={lightCircle}>
89+
</div>
90+
{withText && (
91+
<Text color={neutrals['800']} fontSize="small">{colorValue.light}</Text>
92+
)}
93+
</div>
94+
</HStack>
95+
<HStack>
96+
<div style={darkPill}>
97+
<div style={darkCircle}>
98+
</div>
99+
{withText && (
100+
<Text color={neutrals.WHITE} fontSize="small">{colorValue.dark}</Text>
101+
)}
102+
</div>
103+
</HStack>
104+
</HStack>
105+
)
106+
})}
107+
</VStack>
108+
</VStack>
109+
)
110+
})}
111+
</HStack>
112+
</>
113+
)
114+
}

theme/src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { mode } from '@chakra-ui/theme-tools'
66
import { buttonTheme } from './components/button'
77
import { headingTheme } from './components/headings'
88

9-
import * as styleGuide from './style-guide'
9+
import semanticColors from './style-guide/computedSemanticColors'
1010

1111
export const fonts = {
1212
heading: "'Raleway', 'Roboto', 'Segoe UI', 'sans-serif'",
@@ -31,7 +31,7 @@ export const components = {
3131
export const theme = extendBaseTheme({
3232
fonts,
3333
colors: {
34-
...styleGuide
34+
...semanticColors
3535
},
3636
styles,
3737
components,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as allColors from '../foundations/colors'
2+
import * as semanticColors from './semanticColors'
3+
import { ColorCategory, ColorInCategory, ColorsInCategories, ThemedColors } from './types'
4+
5+
// path is a dot separated string e.g. 'neutrals.900'
6+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
7+
function _get(object: any, path: string, defaultValue: string | null = null): string | null {
8+
return path.split('.').reduce((results, key) => (results && results[key] ? results[key] : defaultValue), object)
9+
}
10+
11+
function translateCategory(category: ColorCategory): ColorInCategory {
12+
return Object.entries(semanticColors[category]).reduce((computedSemanticColors, [key, themedColors]) => ({
13+
...computedSemanticColors,
14+
[key]: {
15+
light: _get(allColors, (themedColors as ThemedColors).light || 'red.300', 'red.500'),
16+
dark: _get(allColors, (themedColors as ThemedColors).dark || 'red.300', 'red.500'),
17+
}
18+
}), {})
19+
}
20+
21+
const translatedCategories: ColorsInCategories = (Object.keys(semanticColors) as ColorCategory[]).reduce((translatedCategories, categoryName) => ({
22+
...translatedCategories,
23+
[categoryName]: translateCategory(categoryName)
24+
}), {} as ColorsInCategories)
25+
26+
export default translatedCategories

0 commit comments

Comments
 (0)