Browse Source

feat(ui): New Colors page in Storybook (#29889)

* feat(ui): New Colors page in Storybook
Vu Luong 3 years ago
parent
commit
24e1478962

+ 1 - 1
.storybook/preview.tsx

@@ -134,7 +134,7 @@ addParameters({
         'Getting Started',
         'Changelog',
         'Core',
-        ['Overview'],
+        ['Overview', 'Colors', 'Typography'],
         'Assets',
         ['Logo', 'Icons', 'Platforms'],
         'Components',

+ 6 - 2
docs-ui/components/sample.tsx

@@ -17,11 +17,15 @@ type Props = {
    * components in both modes.
    */
   showThemeSwitcher?: boolean;
-  /** Remove the outer border and padding */
+  /**
+   * Remove the outer border and padding
+   */
   noBorder?: boolean;
 };
 
-/** Expose the selected theme to children of <Sample /> */
+/**
+ * Expose the selected theme to children of <Sample />
+ */
 export const SampleThemeContext = createContext<ThemeName>('light');
 
 const Sample = ({children, showThemeSwitcher = false, noBorder = false}: Props) => {

+ 1 - 0
docs-ui/images/colors-link-preview.svg

@@ -0,0 +1 @@
+<svg width="600" height="300" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path fill="#FAF9FB" d="M0 0h600v300H0z"/><circle cx="100" cy="300" r="100" fill="#33BF9E"/><path fill="#6C5FC7" d="M250 118h125v125H250z"/><path d="M-28.383 182.701c23.632 15.505 34.441 9.161 32.428-19.031-2.014-28.192 8.796-34.536 32.428-19.032 23.632 15.505 34.44 9.161 32.427-19.031-2.013-28.192 8.796-34.536 32.428-19.032 23.632 15.505 34.441 9.161 32.428-19.031-2.013-28.192 8.796-34.536 32.428-19.032 23.632 15.505 34.441 9.161 32.428-19.031-2.014-28.192 8.795-34.536 32.427-19.032 23.632 15.505 34.442 9.161 32.428-19.031-2.013-28.192 8.796-34.536 32.428-19.032" stroke="#F5B000" stroke-width="13" stroke-linecap="round"/><ellipse cx="487.418" cy="123.159" rx="47.5" ry="120" transform="rotate(141.013 487.418 123.159)" fill="#F55459"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h600v300H0z"/></clipPath></defs></svg>

+ 22 - 0
docs-ui/stories/changelog/changelog.stories.mdx

@@ -6,6 +6,28 @@ This is where you can find all of the latest updates to Sentry's design and comp
 
 ---
 
+<p className="small">Nov 9, 2021</p>
+
+## New Colors page
+
+We've added a new page covering our color system. Highlights include the meaning of accent colors and accessibility concerns.
+
+<DocsLinks
+  links={[
+    {
+      img: {
+        src: require('docs-ui/images/colors-link-preview.svg'),
+        alt: 'Various shapes in Sentry colors',
+      },
+      title: 'Colors',
+      kind: 'Core/Colors',
+      story: 'Page',
+    },
+  ]}
+/>
+
+---
+
 <p className="small">Sep 22, 2021</p>
 
 ## New Typography page

File diff suppressed because it is too large
+ 3 - 0
docs-ui/stories/core/colors/accent-contrast-do.svg


File diff suppressed because it is too large
+ 3 - 0
docs-ui/stories/core/colors/accent-contrast-dont.svg


+ 71 - 0
docs-ui/stories/core/colors/colorSwatch.tsx

@@ -0,0 +1,71 @@
+import styled from '@emotion/styled';
+import * as Color from 'color';
+
+import space from 'app/styles/space';
+
+type Props = {
+  theme: 'light' | 'dark';
+  colors: [
+    {
+      name: string;
+      darkValue: string;
+      lightValue: string;
+    }
+  ];
+};
+
+const ColorSwatch = ({colors, theme}: Props) => {
+  return (
+    <Wrap>
+      {colors.map(color => {
+        const colorValue = theme === 'light' ? color.lightValue : color.darkValue;
+        let labelColor = 'gray500';
+        /**
+         * Use a white label if the color is dark or if
+         * the background is dark and the color is semi-transparent
+         */
+        if (
+          (Color(colorValue).alpha() > 0.5 && Color(colorValue).isDark()) ||
+          (Color(colorValue).alpha() <= 0.5 && theme === 'dark')
+        ) {
+          labelColor = 'white';
+        }
+
+        return (
+          <ColorWrap key={color.name} value={colorValue}>
+            <ColorName color={labelColor}>{color.name}</ColorName>
+            <ColorValue color={labelColor}>{colorValue}</ColorValue>
+          </ColorWrap>
+        );
+      })}
+    </Wrap>
+  );
+};
+
+export default ColorSwatch;
+
+const Wrap = styled('div')`
+  border-radius: ${p => p.theme.borderRadius};
+  overflow: hidden;
+`;
+
+const ColorWrap = styled('div')<{value: string}>`
+  background: ${p => p.value};
+  padding: ${space(2)} ${space(2)};
+`;
+
+const Label = styled('p')<{color: boolean}>`
+  margin-bottom: 0;
+  white-space: nowrap;
+  && {
+    color: ${p => p.theme[p.color]};
+  }
+`;
+
+const ColorName = styled(Label)`
+  font-weight: bold;
+`;
+
+const ColorValue = styled(Label)`
+  opacity: 0.8;
+`;

+ 0 - 101
docs-ui/stories/core/colors/colors.stories.js

@@ -1,101 +0,0 @@
-import {Fragment} from 'react';
-import styled from '@emotion/styled';
-
-import theme, {aliases} from 'app/utils/theme';
-
-export default {
-  title: 'Core/Color',
-};
-
-const DESCRIPTIONS = {
-  textColor: 'Primary text color',
-  subText: 'Text that should not have as much emphasis',
-  bodyBackground: 'Background for the main content area of a page?',
-  background: 'Primary background color',
-  backgroundSecondary:
-    'Secondary background color used as a slight contrast against primary background',
-  headerBackground: 'Background for the header of a page',
-  border: 'Primary border color',
-  success: 'A color that denotes a "success", or something good',
-  error: 'A color that denotes an error, or something that is wrong',
-  disabled:
-    'A color that indicates something is disabled where user can not interact or use it in the usual manner (implies that there is an "enabled" state)',
-  active: 'Indicates that something is "active" or "selected"',
-  linkColor: 'Link color indicates that something is clickable',
-  secondaryButton: '...',
-  sidebarGradient: 'Gradient for sidebar',
-  formPlaceholder: 'Form placeholder text color',
-  formText: 'Default form text color',
-  rowBackground: ' ',
-  chartLineColor:
-    'Color of lines that flow across the background of the chart to indicate axes levels',
-  chartLabel: 'Color for chart label text',
-};
-
-export const Default = () => {
-  const colorsToDisplay = Object.entries(theme).filter(([_name, val]) => {
-    return typeof val === 'string' && val.match(/^\#[0-9a-fA-F]{6}$/);
-  });
-
-  return (
-    <Fragment>
-      <h2>Aliases</h2>
-
-      <p>
-        These are the color aliases you should be using (if possible) instead of using the
-        direct colors.
-      </p>
-
-      <Aliases>
-        {Object.keys(aliases).map(alias => (
-          <Fragment key={alias}>
-            <Swatch color={aliases[alias]}>{alias}</Swatch>
-            <div>{DESCRIPTIONS[alias] || 'No description available'}</div>
-          </Fragment>
-        ))}
-      </Aliases>
-
-      <h2>All Colors</h2>
-      <Swatches>
-        {colorsToDisplay.map(([name, color]) => (
-          <Swatch key={name} color={color}>
-            {name}
-          </Swatch>
-        ))}
-      </Swatches>
-    </Fragment>
-  );
-};
-Default.storyName = 'Color';
-
-const Swatches = styled('div')`
-  display: grid;
-  grid-template-columns: repeat(auto-fill, 80px);
-  grid-gap: 16px;
-`;
-
-const Swatch = styled('div')`
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  background-color: ${p => p.color};
-  color: ${p =>
-    /[0-8]{1}/.test(p.color) ? p.theme.backgroundSecondary : p.theme.gray500};
-  font-size: ${p => p.theme.fontSizeSmall};
-  height: 80px;
-  text-align: center;
-  word-break: break-all;
-  line-height: 1.4em;
-`;
-
-const Aliases = styled('div')`
-  display: grid;
-  align-items: center;
-  grid-template-columns: max-content auto;
-  grid-gap: 16px;
-  margin-bottom: 30px;
-  ${Swatch} {
-    height: auto;
-    padding: 8px;
-  }
-`;

+ 115 - 0
docs-ui/stories/core/colors/colors.stories.mdx

@@ -0,0 +1,115 @@
+import {NeutralTable, AccentTable} from './tables';
+
+<Meta title="Core/Colors" />
+
+# Colors
+
+Sentry has a flexible, tiered color system that adapts to both light and dark mode. Our color palette consists of neutral grays and 6 accent colors.
+
+---
+
+## Grays
+
+There are 5 shades of gray, ranging from Gray 500 (darkest) to Gray 100 (lightest).
+
+**Gray 300 and above** are accessible foreground colors that conform to [WCAG standards](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html). Use them as text and icon colors.
+
+Here are the recommended use cases:
+
+- **Gray 500:** headings, button labels, tags/badges, and alerts.
+- **Gray 400:** body text, input values & labels.
+- **Gray 300:** input placeholders, inactive/disabled inputs and buttons, chart labels, supplemental and non-essential text
+- **Gray 200:** borders around large elements (cards, panels, dialogs, tables).
+- **Gray 100:** dividers and borders around small elements (buttons, form inputs).
+
+<NeutralTable />
+
+---
+
+## Accent colors
+
+Accent colors help shift the user's focus to certain interactive and high-priority elements, like links, buttons, and warning banners.
+
+### Hues
+
+There are 6 hues to choose from. Each has specific connotations:
+
+- **Purple:** brand, current/active/focus state, or new information.
+- **Blue:** hyperlink.
+- **Green:** success, resolution, approval, availability, or creation.
+- **Yellow:** warning, missing, or impeded progress.
+- **Red:** fatal error, deletion, or removal.
+- **Pink:** new feature or promotion.
+
+### Levels
+
+Each hue comes in 4 levels: 400 (dark), 300 (full opacity), 200 (medium opacity), and 100 (low opacity).
+
+- **The 400 level** is a darkened version of 300. It is useful for hover/active states in already accentuated elements. For example, a button could have a background of Purple 300 in normal state and Purple 400 on hover.
+- **The 300 level** has full opacity and serves well as text and icon colors (with the exception of Yellow 300, which does not meet [WCAG's contrast standards](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html)).
+- **The 200 level** has medium opacity, useful for borders and dividers.
+- **The 100 level** has very low opacity, useful as background fills.
+
+<AccentTable />
+
+---
+
+## Accessibility
+
+When it comes to using color, there are two main accessibility concerns: readability and separation.
+
+### Readability
+
+[WCAG](https://www.w3.org/TR/WCAG21/) requires that normal text elements have a contrast ratio of at least 4.5:1 against the background. For large text (at least 16px in size AND in medium/bold weight), the required ratio is lower, at 3:1. This is to ensure a comfortable reading experience in different lighting conditions. [Use this tool](https://webaim.org/resources/contrastchecker/) to confirm text contrast ratios.
+
+In Sentry's color palette, only Gray 300 and above satisfy the contrast requirement for normal text. This applies to both light and dark mode.
+
+Accent colors in the 300 series, except for Yellow 300, satisfy the contrast requirement for large text.
+
+<DoDont
+  doBox={{
+    img: {src: require('./contrast-do.svg'), alt: 'Text in Gray 300, 400, and 500'},
+    text: 'Use Gray 300 and above for normal text',
+  }}
+  dontBox={{
+    img: {src: require('./contrast-dont.svg'), alt: 'Text in Gray 100 and 200'},
+    text: "Use Gray 100 or 200 for normal text, as they don't have the required the contrast levels",
+  }}
+/>
+
+<DoDont
+  doBox={{
+    img: {
+      src: require('./accent-contrast-do.svg'),
+      alt: 'Text in Green 300',
+    },
+    text: 'Use accent colors in the 300 series (except for Yellow 300) for large text, if needed',
+  }}
+  dontBox={{
+    img: {src: require('./accent-contrast-dont.svg'), alt: 'Text in Green 100 and 200'},
+    text: 'Use accent colors in the 100 or 200 series for any text',
+  }}
+/>
+
+### Separation
+
+Color can be an effective way to visually separate elements in the user interface. However, not all users see color in the same way. Some are color-blind and cannot reliably differentiate one color from another. Some have color filters on their screens, like Night Shift in MacOS. Others are in bright environments with high levels of glare, reducing their ability to see color clearly.
+
+As such, color is an unreliable way to separate elements. Whenever possible, provide additional visual cues like icons, text labels, line type (solid, dashed, dotted),… to further reinforce the separation.
+
+<DoDont
+  doBox={{
+    img: {
+      src: require('./differentiation-do.svg'),
+      alt: 'Solid, dashed, and dotted lines in different colors',
+    },
+    text: 'Provide additional visual encoding (e.g. line type) besides color to differentiate elements',
+  }}
+  dontBox={{
+    img: {
+      src: require('./differentiation-dont.svg'),
+      alt: 'Solid lines in different colors',
+    },
+    text: 'Use color as the only way to differentiate elements',
+  }}
+/>

File diff suppressed because it is too large
+ 3 - 0
docs-ui/stories/core/colors/contrast-do.svg


Some files were not shown because too many files changed in this diff