From 840cd4364a179a344b848b067276da1217c31c3e Mon Sep 17 00:00:00 2001 From: Davide Bizzi Date: Tue, 17 Dec 2024 17:35:40 +0100 Subject: [PATCH] feat: enhance Storybook setup with custom DocsContainer and global styles for theme colors --- .storybook/preview.tsx | 11 ++ src/stories/shared/globalStyle.ts | 12 ++ src/stories/theme/colors.mdx | 25 ++++ src/stories/theme/colors.stories.tsx | 117 ----------------- src/stories/theme/palette.mdx | 13 ++ src/stories/theme/palette.stories.tsx | 171 ------------------------- src/stories/theme/paletteComponent.tsx | 39 ++++++ 7 files changed, 100 insertions(+), 288 deletions(-) create mode 100644 src/stories/theme/colors.mdx delete mode 100644 src/stories/theme/colors.stories.tsx create mode 100644 src/stories/theme/palette.mdx delete mode 100644 src/stories/theme/palette.stories.tsx create mode 100644 src/stories/theme/paletteComponent.tsx diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 68f31170..b7e09dc4 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,3 +1,4 @@ +import { DocsContainer } from "@storybook/blocks"; import { ThemeProvider } from "@zendeskgarden/react-theming"; import React from "react"; import { GlobalStyle } from "../src/stories/shared/globalStyle"; @@ -12,6 +13,14 @@ export const decorators = [ ), ]; +const CustomDocsContainer = ({ children, context }) => { + return ( + + + {children} + + ); +}; export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, controls: { @@ -22,6 +31,8 @@ export const parameters = { }, docs: { inlineStories: true, + + container: CustomDocsContainer, }, options: { storySort: { diff --git a/src/stories/shared/globalStyle.ts b/src/stories/shared/globalStyle.ts index 5e079997..2e24455b 100644 --- a/src/stories/shared/globalStyle.ts +++ b/src/stories/shared/globalStyle.ts @@ -3,6 +3,7 @@ import { createGlobalStyle } from "styled-components"; import "@zendeskgarden/css-bedrock"; //This package provides a mostly reasonable CSS reset layered on top of modern-normalize. import { theme } from "../theme"; +import { getColor } from "../theme/utils"; const GlobalStyle = createGlobalStyle` ::-webkit-scrollbar-track:hover { @@ -25,6 +26,17 @@ const GlobalStyle = createGlobalStyle` border-radius: 25px; } + :root { + --zd-palette-primary: ${getColor(theme.colors.primaryHue, 600)}; + --zd-palette-danger: ${getColor(theme.colors.dangerHue, 600)}; + --zd-palette-warning: ${getColor(theme.colors.warningHue, 600)}; + --zd-palette-success: ${getColor(theme.colors.successHue, 600)}; + --zd-palette-neutral: ${getColor(theme.colors.neutralHue, 600)}; + --zd-palette-info: ${getColor(theme.colors.infoHue, 600)}; + --zd-palette-chrome: ${getColor(theme.colors.chromeHue, 600)}; + --zd-palette-accent: ${getColor(theme.colors.accentHue, 600)}; + } + /* This stuff is for Firefox */ * { scrollbar-color: ${theme.palette.blue["200"]} #FFFFFF; diff --git a/src/stories/theme/colors.mdx b/src/stories/theme/colors.mdx new file mode 100644 index 00000000..234d3c3a --- /dev/null +++ b/src/stories/theme/colors.mdx @@ -0,0 +1,25 @@ +import { + ColorItem, + ColorPalette, + DocsContainer, + Meta, +} from "@storybook/blocks"; +import { colors } from "./colors"; +import { palette } from "./palette"; + + + + + {Object.keys(palette).map((k) => { + return ( + <> + + + ); + })} + diff --git a/src/stories/theme/colors.stories.tsx b/src/stories/theme/colors.stories.tsx deleted file mode 100644 index 3a8af0e6..00000000 --- a/src/stories/theme/colors.stories.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { StoryFn } from "@storybook/react"; -import { MD } from "@zendeskgarden/react-typography"; -import { HTMLAttributes } from "react"; -import { styled } from "styled-components"; -import { theme } from "."; - -const ColorsLayout = styled.div` - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-gap: ${(p) => p.theme.space.xl} ${(p) => p.theme.space.lg}; - max-width: 768px; -`; - -const Ul = styled.ul` - border-radius: ${(p) => p.theme.borderRadii.lg}; - overflow: hidden; - height: fit-content; -`; -const Li = styled.li<{ hex: string }>` - border: 1px solid #00000045; - background-color: ${({ hex }) => hex}; - color: ${({ hex }) => getTextColor(hex)}; - padding: ${(p) => p.theme.space.sm}; -`; - -const ColorSpec = styled(MD)<{ color: string }>` - color: ${({ color }) => color}; - display: flex; - justify-content: space-between; - align-items: center; -`; - -interface ColorProps extends HTMLAttributes {} - -const isHex = (color: string) => { - return color.startsWith("#") && (color.length === 7 || color.length === 4); -}; - -const getTextColor = (hex: string) => { - if (hex.indexOf("#") === 0) { - hex = hex.slice(1); - } - // convert 3-digit hex to 6-digits. - if (hex.length === 3) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - if (hex.length !== 6) { - throw new Error("Invalid HEX color."); - } - var r = parseInt(hex.slice(0, 2), 16), - g = parseInt(hex.slice(2, 4), 16), - b = parseInt(hex.slice(4, 6), 16); - - // https://stackoverflow.com/a/3943023/112731 - return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? "#000000" : "#FFFFFF"; -}; - -const getPaletteColor = (color: string) => { - if (color.startsWith("#")) { - return color; - } - if (color in theme.palette) { - const c = theme.palette[color as keyof typeof theme.palette]; - if (typeof c !== "string" && "600" in c) return c[600]; - } - return null; -}; - -const Template: StoryFn = (props) => { - return ( -
- - {Object.entries(theme.colors).map(([name, value], i) => { - let hex = value; - let textName = value; - if (!isHex(value)) { - const paletteColor = getPaletteColor(value); - if (!paletteColor) return null; - hex = paletteColor; - textName = `${value}600 - ${hex.toUpperCase()}`; - } - if (!hex) return null; - return ( - <> -
    -
  • - - {name} - {textName} - -
  • -
- - ); - })} -
-
- ); -}; - -export const Default = Template.bind({}); -Default.args = {}; - -export default { - title: "Theme/Colors", - argTypes: { - cards: { - table: { - disable: true, - }, - }, - }, - parameters: { - // Sets a delay for the component's stories - chromatic: { delay: 300 }, - }, -}; diff --git a/src/stories/theme/palette.mdx b/src/stories/theme/palette.mdx new file mode 100644 index 00000000..59878552 --- /dev/null +++ b/src/stories/theme/palette.mdx @@ -0,0 +1,13 @@ +import { + ColorItem, + ColorPalette, + DocsContainer, + Meta, + Story, +} from "@storybook/blocks"; +import { colors } from "./colors"; + +import PaletteComponent from "./paletteComponent"; + + + diff --git a/src/stories/theme/palette.stories.tsx b/src/stories/theme/palette.stories.tsx deleted file mode 100644 index bca7e619..00000000 --- a/src/stories/theme/palette.stories.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { StoryFn } from "@storybook/react"; -import { LG, MD } from "@zendeskgarden/react-typography"; -import { HTMLAttributes } from "react"; -import styled from "styled-components"; -import { theme } from "."; - -interface Variant { - name: string; - hex: string; -} - -interface PaletteProps extends HTMLAttributes { - palette: Array<{ - title: string; - variants: Array; - }>; -} - -const Section = styled.section` - margin-bottom: ${(p) => p.theme.space.xl}; - .sectionTitle { - margin-bottom: ${(p) => p.theme.space.md}; - } -`; -const Ul = styled.ul` - border-radius: ${(p) => p.theme.borderRadii.lg}; - overflow: hidden; - height: fit-content; -`; - -const Li = styled.li<{ hex: string }>` - background-color: ${({ hex }) => hex}; - color: ${({ hex }) => getTextColor(hex)}; - padding: ${(p) => p.theme.space.sm}; -`; - -const ColorsLayout = styled.div` - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-gap: ${(p) => p.theme.space.xl} ${(p) => p.theme.space.lg}; - max-width: 768px; -`; - -const ColorSpec = styled(MD)<{ color: string }>` - color: ${({ color }) => color}; - display: flex; - justify-content: space-between; - align-items: center; -`; - -const Template: StoryFn = (props) => { - return ( -
-
-
- Reference: -
-

- - Design principles{" "} - - https://garden.zendesk.com/design/color (accessed 28 apr 2023) - - -

-

- - Palette:{" "} - - https://garden.zendesk.com/components/palette (accessed 28 apr - 2023) - - -

-
-
-
- Palette -
- - {props.palette.map((color, i) => ( -
    - {color.variants.map(({ name, hex }) => ( -
  • - - - {color.title} - {name !== color.title && `-${name}`} - - {hex.toUpperCase()} - -
  • - ))} -
- ))} -
-
-
- ); -}; - -const palette = Object.keys(theme.palette).map((key) => { - let color = theme.palette[key as keyof typeof theme.palette]; - let colorsVariants: Array = []; - if (typeof color === "object") { - Object.keys(color).map((variants) => { - let variant = color[variants as keyof typeof color]; - return colorsVariants.push({ - name: variants, - hex: variant, - }); - }); - } else { - colorsVariants[0] = { - name: key, - hex: color, - }; - } - - return { - title: key, - variants: colorsVariants, - }; -}); - -export const Default = Template.bind({}); -Default.args = { - palette, -}; - -const getTextColor = (hex: string) => { - if (hex.indexOf("#") === 0) { - hex = hex.slice(1); - } - // convert 3-digit hex to 6-digits. - if (hex.length === 3) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - if (hex.length !== 6) { - throw new Error("Invalid HEX color."); - } - var r = parseInt(hex.slice(0, 2), 16), - g = parseInt(hex.slice(2, 4), 16), - b = parseInt(hex.slice(4, 6), 16); - - // https://stackoverflow.com/a/3943023/112731 - return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? "#000000" : "#FFFFFF"; -}; - -export default { - title: "Theme/Palette", - argTypes: { - cards: { - table: { - disable: true, - }, - }, - }, - parameters: { - // Sets a delay for the component's stories - chromatic: { delay: 300 }, - }, -}; diff --git a/src/stories/theme/paletteComponent.tsx b/src/stories/theme/paletteComponent.tsx new file mode 100644 index 00000000..30e83637 --- /dev/null +++ b/src/stories/theme/paletteComponent.tsx @@ -0,0 +1,39 @@ +import { ColorItem, ColorPalette } from "@storybook/addon-docs"; +import { useEffect, useState } from "react"; +import { colors } from "./colors"; + +const PaletteComponent = () => { + const [colorValues, setColorValues] = useState>({}); + useEffect(() => { + const colorValues = Object.keys(colors) + .filter((k) => k.endsWith("Hue")) + .reduce( + (acc, k) => { + const name = k.replace("Hue", ""); + const color = getComputedStyle(document.documentElement) + .getPropertyValue("--zd-palette-" + name) + .trim(); + acc[name] = color; + return acc; + }, + {} as Record, + ); + setColorValues(colorValues); + }, [document.documentElement, colors]); + return ( + + {Object.entries(colorValues).map(([name, color]) => { + return ( + + ); + })} + + ); +}; + +export default PaletteComponent;