From b5198a8b354666ec389a424e7daa038dae407311 Mon Sep 17 00:00:00 2001 From: Jake Laderman Date: Fri, 5 Jul 2024 08:39:45 -0700 Subject: [PATCH] feat: light mode updates (#619) --- src/components/Card.tsx | 36 +-------- src/components/Chip.tsx | 67 +++++++--------- src/components/SubTab.tsx | 5 +- src/components/Table.tsx | 18 ++--- src/theme/boxShadows.ts | 5 -- src/theme/colors-base.ts | 24 +++--- src/theme/colors-semantic-dark.ts | 32 ++++---- src/theme/colors-semantic-light.ts | 120 ++++++++++++++--------------- 8 files changed, 126 insertions(+), 181 deletions(-) diff --git a/src/components/Card.tsx b/src/components/Card.tsx index e9d05bbc..eb32e70f 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -133,34 +133,6 @@ export const getFillToLightBgC = memoize( }) ) -const getLightModeBorderMapper = memoize( - (theme: DefaultTheme): Record, string> => ({ - info: theme.colors['border-info'], - success: theme.colors['border-success'], - warning: theme.colors['border-warning'], - danger: theme.colors['border-danger-light'], - critical: theme.colors['border-danger'], - }) -) - -const getBorderColor = ({ - theme, - fillLevel, - severity = 'neutral', -}: { - theme: DefaultTheme - fillLevel: CardFillLevel - severity?: CardSeverity -}) => { - const fillLevelToLightBorderColor = getLightModeBorderMapper(theme) - - if (theme.mode === 'dark' || severity === 'neutral') { - return theme.colors[fillToNeutralBorderC[fillLevel]] - } - - return fillLevelToLightBorderColor[severity] -} - const getBgColor = ({ theme, fillLevel, @@ -197,15 +169,11 @@ const CardSC = styled(Div)<{ disabled, }) => ({ ...theme.partials.reset.button, - border: `1px solid ${getBorderColor({ - theme, - fillLevel, - severity, - })}`, + border: `1px solid ${theme.colors[fillToNeutralBorderC[fillLevel]]}`, borderRadius: theme.borderRadiuses[cornerSize], backgroundColor: selected ? theme.colors[fillToNeutralSelectedBgC[fillLevel]] - : getBgColor({ theme, fillLevel, severity }), + : getBgColor({ theme, fillLevel }), '&:focus, &:focus-visible': { outline: 'none', }, diff --git a/src/components/Chip.tsx b/src/components/Chip.tsx index 8848b274..029d4d06 100644 --- a/src/components/Chip.tsx +++ b/src/components/Chip.tsx @@ -11,15 +11,12 @@ import styled, { useTheme, } from 'styled-components' -import chroma from 'chroma-js' - import { type SEVERITIES } from '../types' import { Spinner } from './Spinner' import Card, { type BaseCardProps, type CardFillLevel, - getFillToLightBgC, useDecideFillLevel, } from './Card' import CloseIcon from './icons/CloseIcon' @@ -84,9 +81,7 @@ const ChipCardSC = styled(Card)<{ $condensed?: boolean }>(({ $size, $severity, $truncateWidth, $truncateEdge, $condensed, theme }) => { const textColor = - theme.mode === 'light' - ? theme.colors['text-light'] - : theme.colors[severityToColor[$severity]] || theme.colors.text + theme.colors[severityToColor[$severity]] || theme.colors.text return { '&&': { @@ -136,43 +131,35 @@ const ChipCardSC = styled(Card)<{ }) const CloseButtonSC = styled.button<{ - $severity: ChipSeverity $fillLevel: CardFillLevel -}>(({ theme, $fillLevel, $severity }) => { - const lightBg = chroma(getFillToLightBgC(theme)[$severity][$fillLevel]) - const lightBgHover = `${lightBg.alpha(lightBg.alpha() + 0.15)}` - - return { - ...theme.partials.reset.button, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - borderRadius: theme.borderRadiuses.medium, - padding: theme.spacing.xsmall - theme.spacing.xxsmall, - margin: -(theme.spacing.xsmall - theme.spacing.xxsmall), - '.closeIcon': { - color: theme.colors['text-light'], - }, - '&:focus-visible': { - ...theme.partials.focus.outline, - }, - '&:not(:disabled)': { - '&:focus-visible, &:hover, [data-clickable=true]:hover > &': { - backgroundColor: - theme.mode === 'light' && $severity !== 'neutral' - ? lightBgHover - : theme.colors[ - `fill-${ - $fillLevel === 3 ? 'three' : $fillLevel === 2 ? 'two' : 'one' - }-hover` - ], - '.closeIcon': { - color: theme.colors.text, - }, +}>(({ theme, $fillLevel }) => ({ + ...theme.partials.reset.button, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + borderRadius: theme.borderRadiuses.medium, + padding: theme.spacing.xsmall - theme.spacing.xxsmall, + margin: -(theme.spacing.xsmall - theme.spacing.xxsmall), + '.closeIcon': { + color: theme.colors['text-light'], + }, + '&:focus-visible': { + ...theme.partials.focus.outline, + }, + '&:not(:disabled)': { + '&:focus-visible, &:hover, [data-clickable=true]:hover > &': { + backgroundColor: + theme.colors[ + `fill-${ + $fillLevel === 3 ? 'three' : $fillLevel === 2 ? 'two' : 'one' + }-hover` + ], + '.closeIcon': { + color: theme.colors.text, }, }, - } -}) + }, +})) function ChipRef( { diff --git a/src/components/SubTab.tsx b/src/components/SubTab.tsx index ccf56d26..e02ba520 100644 --- a/src/components/SubTab.tsx +++ b/src/components/SubTab.tsx @@ -48,6 +48,8 @@ const SubTabBase = styled.div<{ ? theme.colors[parentFillLevelToActiveBG[parentFillLevel]] : 'transparent', borderRadius: theme.borderRadiuses.medium, + outline: active ? theme.borders.default : undefined, + outlineOffset: '-1px', // inset outline instead of border so layout isn't affected focusVisible: { zIndex: theme.zIndexes.base + 1, ...theme.partials.focus.default, @@ -62,8 +64,7 @@ const SubTabBase = styled.div<{ ? theme.colors[parentFillLevelToHoverBG[parentFillLevel]] : undefined, }, - transition: - 'background-color 150ms ease, border-color 150ms ease, color 150ms ease', + transition: 'background-color 150ms ease, color 150ms ease', '.codeTabInner': {}, })) diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 6025870e..8970461f 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -158,10 +158,10 @@ const Tr = styled.tr<{ }) => ({ display: 'contents', backgroundColor: selected - ? theme.colors['fill-one-selected'] + ? theme.colors['fill-zero-hover'] : raised || (selectable && !selected) - ? theme.colors['fill-one-hover'] - : theme.colors['fill-one'], + ? theme.colors['fill-zero-selected'] + : theme.colors['fill-zero'], ...(clickable && { cursor: 'pointer', @@ -169,9 +169,9 @@ const Tr = styled.tr<{ '&:hover': { backgroundColor: selectable ? selected - ? theme.colors['fill-one-selected'] - : theme.colors['fill-one-hover'] - : theme.colors['fill-one-selected'], + ? theme.colors['fill-zero-hover'] + : theme.colors['fill-zero-selected'] + : theme.colors['fill-zero-hover'], }, }), }) @@ -196,9 +196,9 @@ const Th = styled.th<{ alignItems: 'center', display: hideHeader ? 'none' : 'flex', position: 'relative', - backgroundColor: theme.colors['fill-two'], + backgroundColor: theme.colors['fill-one'], zIndex: 4, - borderBottom: theme.borders['fill-three'], + borderBottom: theme.borders.default, color: theme.colors.text, height: 48, minHeight: 48, @@ -222,7 +222,7 @@ const Th = styled.th<{ bottom: 0, width: 10000, backgroundColor: theme.colors['fill-two'], - borderBottom: hideHeader ? 'none' : theme.borders['fill-three'], + borderBottom: hideHeader ? 'none' : theme.borders.default, }, }, '&:first-child': { diff --git a/src/theme/boxShadows.ts b/src/theme/boxShadows.ts index 5ad6620e..badaac86 100644 --- a/src/theme/boxShadows.ts +++ b/src/theme/boxShadows.ts @@ -1,9 +1,6 @@ import chroma from 'chroma-js' import { type CSSProperties } from 'react' -import { borderWidths } from './borders' - -import { semanticColorCssVars } from './colors' import { semanticColorsDark } from './colors-semantic-dark' import { semanticColorsLight } from './colors-semantic-light' @@ -48,6 +45,4 @@ export const getBoxShadows = ({ mode }: { mode: 'dark' | 'light' }) => ].join(','), modalPurple: `0px 10px 40px 0px ${shadowLPurple.alpha(0.25)}`, }), - // Deprecated in favor of focus outlines - focused: `0px 0px 0px ${borderWidths.focus}px ${semanticColorCssVars['border-outline-focused']}`, }) as const satisfies Record diff --git a/src/theme/colors-base.ts b/src/theme/colors-base.ts index 4829e25c..fe586700 100644 --- a/src/theme/colors-base.ts +++ b/src/theme/colors-base.ts @@ -16,11 +16,15 @@ export const grey = { 600: '#5D626F', 500: '#747B8B', 400: '#A1A5B0', - 350: '#A9AFBC', - 300: '#B2B7C3', - 200: '#C5C9D3', - 100: '#DFE2E7', - 50: '#EBEFF0', + 350: '#A8AEBC', + 300: '#AEB3C0', + 200: '#C5C9D2', + 175: '#CCCFD6', + 150: '#D4D6DC', + 125: '#DDDFE3', + 100: '#E3E4E7', + 75: '#EBEDEE', + 50: '#EEF0F1', 25: '#F9FAFA', } as const satisfies Record @@ -75,11 +79,11 @@ export const yellow = { 950: '#242000', 900: '#3D2F00', 850: '#574500', - 800: '#756200', - 700: '#A88C00', - 600: '#D6BA00', - 500: '#FFE500', - 400: '#FFEB33', + 800: '#855800', + 700: '#A86D00', + 600: '#E09600', + 500: '#F5AF00', + 400: '#FFCF33', 300: '#FFF170', 200: '#FFF59E', 100: '#FFF9C2', diff --git a/src/theme/colors-semantic-dark.ts b/src/theme/colors-semantic-dark.ts index cfe7d182..9fd75e2d 100644 --- a/src/theme/colors-semantic-dark.ts +++ b/src/theme/colors-semantic-dark.ts @@ -1,4 +1,3 @@ -import chroma from 'chroma-js' import { type CSSProperties } from 'styled-components' import { blue, green, grey, purple, red, yellow } from './colors-base' @@ -10,20 +9,21 @@ export const semanticColorsDark = { // // fill-zero 'fill-zero': grey[900], - 'fill-zero-hover': grey[875], - 'fill-zero-selected': grey[825], + 'fill-zero-hover': grey[850], + 'fill-zero-selected': grey[875], // fill-one 'fill-one': grey[850], - 'fill-one-hover': grey[825], - 'fill-one-selected': grey[775], + 'fill-one-hover': grey[800], + 'fill-one-selected': grey[825], // fill-two 'fill-two': grey[800], - 'fill-two-hover': grey[775], - 'fill-two-selected': grey[725], + 'fill-two-hover': grey[750], + 'fill-two-selected': grey[775], // fill-three 'fill-three': grey[750], - 'fill-three-hover': grey[725], - 'fill-three-selected': grey[675], + 'fill-three-hover': grey[700], + 'fill-three-selected': grey[725], + // primary 'fill-primary': purple[400], 'fill-primary-hover': purple[350], @@ -45,9 +45,11 @@ export const semanticColorsDark = { 'action-link-inline-hover': blue[100], 'action-link-inline-visited': purple[300], 'action-link-inline-visited-hover': purple[200], - 'action-input-hover': `${chroma('#E9ECF0').alpha(0.04)}`, + // input + 'action-input-hover': '#E9ECF00A', // always-white 'action-always-white': grey[50], + 'action-on-filled-bg': grey[25], // Border // @@ -63,7 +65,7 @@ export const semanticColorsDark = { 'border-success': green[300], 'border-warning': yellow[200], 'border-danger': red[300], - 'border-danger-light': red[300], + 'border-danger-light': red[200], 'border-outline-focused': blue[300], // Text @@ -83,6 +85,7 @@ export const semanticColorsDark = { 'text-danger': red[400], 'text-danger-light': red[200], 'text-always-white': grey[50], + 'text-on-filled-bg': grey[50], // Icon // @@ -133,11 +136,4 @@ export const semanticColorsDark = { semanticYellow: '#FFF9C2', semanticRedLight: '#F599A8', semanticRedDark: '#E95374', - - // Deprecated (Remove after all 'error' colors converted to 'danger' in app) - // - 'border-error': red[300], - 'text-error': red[400], - 'text-error-light': red[200], - 'icon-error': red[200], } as const satisfies Record diff --git a/src/theme/colors-semantic-light.ts b/src/theme/colors-semantic-light.ts index 2cab0cf9..5711d08c 100644 --- a/src/theme/colors-semantic-light.ts +++ b/src/theme/colors-semantic-light.ts @@ -1,7 +1,6 @@ -import chroma from 'chroma-js' import { type CSSProperties } from 'styled-components' -import { blue, green, grey, purple, red } from './colors-base' +import { blue, green, grey, purple, red, yellow } from './colors-base' import { colorsCloudShellLight } from './colors-cloudshell-light' import { colorsCodeBlockLight } from './colors-codeblock-light' import { semanticColorsDark } from './colors-semantic-dark' @@ -10,21 +9,21 @@ export const semanticColorsLight = { // Fill // // fill-zero - 'fill-zero': '#F3F5F6', - 'fill-zero-hover': '#F5F5F5', - 'fill-zero-selected': '#E5E6E7', + 'fill-zero': '#FFFFFF', + 'fill-zero-hover': grey[50], + 'fill-zero-selected': grey[25], // fill-one - 'fill-one': '#F9FAFB', - 'fill-one-hover': '#F3F5F7', - 'fill-one-selected': '#EEF0F2', + 'fill-one': grey[25], + 'fill-one-hover': grey[75], + 'fill-one-selected': grey[50], // fill-two - 'fill-two': '#F5F5F5', - 'fill-two-hover': '#EBEDEE', - 'fill-two-selected': '#E6E8E9', + 'fill-two': grey[50], + 'fill-two-hover': grey[100], + 'fill-two-selected': grey[75], // fill-three - 'fill-three': '#E2E3E8', - 'fill-three-hover': '#D6D6D8', - 'fill-three-selected': '#D3D3D3', + 'fill-three': grey[75], + 'fill-three-hover': grey[125], + 'fill-three-selected': grey[100], // primary 'fill-primary': purple[400], 'fill-primary-hover': purple[350], @@ -32,8 +31,8 @@ export const semanticColorsLight = { // Action // // primary - 'action-primary': purple[400], - 'action-primary-hover': purple[350], + 'action-primary': purple[350], + 'action-primary-hover': purple[300], 'action-primary-disabled': grey[100], // link 'action-link-inactive': grey[300], @@ -43,65 +42,75 @@ export const semanticColorsLight = { 'action-link-active-hover': grey[50], 'action-link-active-disabled': grey[200], // link-inline - 'action-link-inline': '#539AC3', + 'action-link-inline': blue[700], 'action-link-inline-hover': blue[600], - 'action-link-inline-visited': purple[300], - 'action-link-inline-visited-hover': purple[200], + 'action-link-inline-visited': purple[500], + 'action-link-inline-visited-hover': purple[350], // input - 'action-input-hover': `${chroma('#C3C3C4').alpha(0.1)}`, // text color w/ alpha + 'action-input-hover': 'C3C3C419', // always white 'action-always-white': semanticColorsDark['action-always-white'], + 'action-on-filled-bg': grey[25], // Border // - border: '#DFE2E7', - 'border-fill-two': '#C5C9D3', - 'border-fill-three': grey[400], - 'border-selected': grey[600], - 'border-input': '#C6CBD7', - 'border-disabled': grey[100], - 'border-primary': purple[400], - 'border-secondary': blue[400], - 'border-info': blue[300], + border: grey[75], + 'border-fill-two': grey[100], + 'border-fill-three': grey[125], + 'border-selected': grey[800], + 'border-input': grey[100], + 'border-disabled': grey[75], + 'border-primary': purple[500], + 'border-secondary': blue[700], + 'border-info': blue[600], 'border-success': green[700], - 'border-warning': '#C3B853', - 'border-danger': '#ED4578', - 'border-danger-light': '#F599A8', - 'border-outline-focused': blue[400], + 'border-warning': yellow[700], + 'border-danger': red[600], + 'border-danger-light': red[600], + 'border-outline-focused': blue[500], // Text // - text: grey[950], + text: grey[800], 'text-light': grey[600], - 'text-xlight': '#8B8F97', - 'text-long-form': grey[300], + 'text-xlight': grey[500], + 'text-long-form': grey[700], 'text-disabled': grey[200], - 'text-input-disabled': grey[200], - 'text-primary-accent': '#38B6FF', - 'text-primary-disabled': grey[400], - 'text-success': green[700], - 'text-success-light': green[600], - 'text-warning': '#FF9900', - 'text-warning-light': '#DCBC40', - 'text-danger': '#E54064', - 'text-danger-light': red[300], + 'text-input-disabled': grey[400], + 'text-primary-accent': blue[600], + 'text-primary-disabled': grey[500], + 'text-success': green[800], + 'text-success-light': green[700], + 'text-warning': yellow[800], + 'text-warning-light': yellow[700], + 'text-danger': red[700], + 'text-danger-light': red[600], 'text-always-white': semanticColorsDark['text-always-white'], + 'text-on-filled-bg': grey[950], // Icon // - 'icon-default': grey[600], - 'icon-light': grey[500], + 'icon-default': grey[900], + 'icon-light': grey[700], 'icon-xlight': grey[400], 'icon-disabled': grey[100], 'icon-primary': purple[300], 'icon-secondary': blue[400], 'icon-info': blue[350], 'icon-success': green[700], - 'icon-warning': '#FF9900', + 'icon-warning': yellow[600], 'icon-danger': red[300], 'icon-danger-critical': '#ED4578', 'icon-always-white': semanticColorsDark['icon-always-white'], + // Graph + // + 'graph-blue': blue[500], + 'graph-lilac': '#BE5EEB', + 'graph-green': green[500], + 'graph-purple': purple[350], + 'graph-red': red[400], + // Marketing // 'marketing-white': '#000000', @@ -127,21 +136,6 @@ export const semanticColorsLight = { semanticYellow: '#C3B853', semanticRedLight: '#F599A8', semanticRedDark: '#E95374', - - // Graph - // - 'graph-blue': blue[500], - 'graph-lilac': '#BE5EEB', - 'graph-green': green[500], - 'graph-purple': purple[350], - 'graph-red': red[400], - - // Deprecated (Remove after all 'error' colors converted to 'danger' in app) - // - 'border-error': red[300], - 'text-error': 'blue', - 'text-error-light': 'blue', - 'icon-error': 'blue', } as const satisfies Record< keyof typeof semanticColorsDark, CSSProperties['color']