diff options
| -rw-r--r-- | .storybook/main.js | 1 | ||||
| -rw-r--r-- | .storybook/manager.js | 6 | ||||
| -rw-r--r-- | .storybook/overrides/docs-container.js | 36 | ||||
| -rw-r--r-- | .storybook/preview.js | 40 | ||||
| -rw-r--r-- | .storybook/themes/common.js | 8 | ||||
| -rw-r--r-- | .storybook/themes/dark.js | 37 | ||||
| -rw-r--r-- | .storybook/themes/light.js | 36 | ||||
| -rw-r--r-- | package.json | 3 | ||||
| -rw-r--r-- | src/styles/base/_base.scss | 16 | ||||
| -rw-r--r-- | yarn.lock | 14 |
10 files changed, 184 insertions, 13 deletions
diff --git a/.storybook/main.js b/.storybook/main.js index bedbd0e..477b09e 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -11,6 +11,7 @@ const storybookConfig = { '@storybook/addon-essentials', '@storybook/addon-interactions', 'storybook-addon-next', + 'storybook-dark-mode', ], framework: '@storybook/react', core: { diff --git a/.storybook/manager.js b/.storybook/manager.js new file mode 100644 index 0000000..945c246 --- /dev/null +++ b/.storybook/manager.js @@ -0,0 +1,6 @@ +import { addons } from '@storybook/addons'; +import light from './themes/light'; + +addons.setConfig({ + theme: light, +}); diff --git a/.storybook/overrides/docs-container.js b/.storybook/overrides/docs-container.js new file mode 100644 index 0000000..f539986 --- /dev/null +++ b/.storybook/overrides/docs-container.js @@ -0,0 +1,36 @@ +import { DocsContainer as BaseContainer } from '@storybook/addon-docs/blocks'; +import { useDarkMode } from 'storybook-dark-mode'; +import dark from '../themes/dark'; +import light from '../themes/light'; + +/** + * Custom Docs Container to support dark theme. + * + * @see https://github.com/hipstersmoothie/storybook-dark-mode/issues/127#issuecomment-1070524402 + */ +export const DocsContainer = ({ children, context }) => { + const isDark = useDarkMode(); + + return ( + <BaseContainer + context={{ + ...context, + storyById: (id) => { + const storyContext = context.storyById(id); + return { + ...storyContext, + parameters: { + ...storyContext?.parameters, + docs: { + ...storyContext?.parameters?.docs, + theme: isDark ? dark : light, + }, + }, + }; + }, + }} + > + {children} + </BaseContainer> + ); +}; diff --git a/.storybook/preview.js b/.storybook/preview.js index e30927b..9df7514 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,6 +1,12 @@ -import '@styles/globals.scss'; import * as NextImage from 'next/image'; +import { ThemeProvider, useTheme } from 'next-themes'; +import { useEffect } from 'react'; import { IntlProvider } from 'react-intl'; +import { useDarkMode } from 'storybook-dark-mode'; +import { DocsContainer } from './overrides/docs-container'; +import dark from './themes/dark'; +import light from './themes/light'; +import '@styles/globals.scss'; const OriginalNextImage = NextImage.default; @@ -27,12 +33,42 @@ export const parameters = { date: /Date$/, }, }, + darkMode: { + // Override the default dark theme + dark: { ...dark }, + // Override the default light theme + light: { ...light }, + stylePreview: true, + }, + docs: { + container: DocsContainer, + }, +}; + +// Create a component that listens for theme change. +export const ThemeWrapper = (props) => { + const { setTheme } = useTheme(); + const theme = useDarkMode() ? 'dark' : 'light'; + + useEffect(() => { + setTheme(theme); + }, [theme, setTheme]); + + return <>{props.children}</>; }; export const decorators = [ (Story) => ( <IntlProvider locale="en"> - <Story /> + <ThemeProvider + defaultTheme="system" + enableColorScheme={true} + enableSystem={true} + > + <ThemeWrapper> + <Story /> + </ThemeWrapper> + </ThemeProvider> </IntlProvider> ), ]; diff --git a/.storybook/themes/common.js b/.storybook/themes/common.js new file mode 100644 index 0000000..17619c2 --- /dev/null +++ b/.storybook/themes/common.js @@ -0,0 +1,8 @@ +export const brand = { + title: 'Design system', +}; + +export const fontFamilies = { + mono: '"Cousine", "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace', + primary: '"Inter", "Liberation Sans", Arial, sans-serif', +}; diff --git a/.storybook/themes/dark.js b/.storybook/themes/dark.js new file mode 100644 index 0000000..e23703b --- /dev/null +++ b/.storybook/themes/dark.js @@ -0,0 +1,37 @@ +import { create } from '@storybook/theming'; +import { brand, fontFamilies } from './common'; + +const colors = { + black: 'hsl(208, 25%, 11%)', + blackBright: 'hsl(208, 21%, 15%)', + blue: 'hsl(200, 50%, 68%)', + blueBright: 'hsl(200, 55%, 70%)', + grey: 'hsl(208, 10%, 70%)', + greyDark: 'hsl(208, 20%, 25%)', + greyDarker: 'hsl(208, 18%, 20%)', + white: 'hsl(208, 25%, 92%)', + whiteDark: 'hsl(206, 20%, 93%)', +}; + +export default create({ + base: 'dark', + brandTitle: brand.title, + colorPrimary: colors.blue, + colorSecondary: colors.blueBright, + appBg: colors.black, + appContentBg: colors.black, + appBorderColor: colors.greyDark, + appBorderRadius: 3, + fontBase: fontFamilies.primary, + fontCode: fontFamilies.mono, + textColor: colors.white, + textInverseColor: colors.black, + textMutedColor: colors.grey, + barTextColor: colors.white, + barSelectedColor: colors.blueBright, + barBg: colors.blackBright, + inputBg: colors.greyDarker, + inputBorder: colors.greyDark, + inputTextColor: colors.white, + inputBorderRadius: 0, +}); diff --git a/.storybook/themes/light.js b/.storybook/themes/light.js new file mode 100644 index 0000000..d445272 --- /dev/null +++ b/.storybook/themes/light.js @@ -0,0 +1,36 @@ +import { create } from '@storybook/theming'; +import { brand, fontFamilies } from './common'; + +const colors = { + black: 'hsl(207, 47%, 11%)', + blue: 'hsl(206, 75%, 31%)', + blueBright: 'hsl(206, 77%, 36%)', + grey: 'hsl(206, 15%, 80%)', + greyBright: 'hsl(206, 20%, 86%)', + greyDark: 'hsl(206, 30%, 30%)', + white: 'hsl(206, 15%, 97%)', + whiteDark: 'hsl(206, 20%, 93%)', +}; + +export default create({ + base: 'light', + brandTitle: brand.title, + colorPrimary: colors.blue, + colorSecondary: colors.blueBright, + appBg: colors.white, + appContentBg: colors.white, + appBorderColor: colors.grey, + appBorderRadius: 3, + fontBase: fontFamilies.primary, + fontCode: fontFamilies.mono, + textColor: colors.black, + textInverseColor: colors.white, + textMutedColor: colors.greyDark, + barTextColor: colors.black, + barSelectedColor: colors.blueBright, + barBg: colors.whiteDark, + inputBg: colors.greyBright, + inputBorder: colors.grey, + inputTextColor: colors.black, + inputBorderRadius: 0, +}); diff --git a/package.json b/package.json index 08f6140..447a372 100644 --- a/package.json +++ b/package.json @@ -65,10 +65,12 @@ "@storybook/addon-essentials": "^6.5.3", "@storybook/addon-interactions": "^6.5.3", "@storybook/addon-links": "^6.5.3", + "@storybook/addons": "^6.5.3", "@storybook/builder-webpack5": "^6.5.3", "@storybook/manager-webpack5": "^6.5.3", "@storybook/react": "^6.5.3", "@storybook/testing-library": "^0.0.11", + "@storybook/theming": "^6.5.3", "@svgr/webpack": "^6.2.1", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.1.1", @@ -93,6 +95,7 @@ "sass": "^1.50.0", "standard-version": "^9.3.2", "storybook-addon-next": "^1.6.2", + "storybook-dark-mode": "^1.1.0", "stylelint": "^14.7.0", "stylelint-config-standard": "^25.0.0", "stylelint-config-standard-scss": "^3.0.0", diff --git a/src/styles/base/_base.scss b/src/styles/base/_base.scss index 25ef393..1ec5494 100644 --- a/src/styles/base/_base.scss +++ b/src/styles/base/_base.scss @@ -70,14 +70,6 @@ body { flex-flow: column nowrap; min-height: 100vh; background: var(--color-bg); - border-top: max(0.4vw, fun.convert-px(6)) solid; - border-bottom: max(0.4vw, fun.convert-px(6)) solid; - border-image: radial-gradient( - ellipse at center, - var(--color-primary-lighter) 20%, - var(--color-primary) 100% - ) - 1; color: var(--color-fg); font-family: var(--font-family-primary); font-size: var(--font-size-md); @@ -89,4 +81,12 @@ body { display: flex; flex-flow: column nowrap; height: 100%; + border-top: max(0.4vw, fun.convert-px(6)) solid; + border-bottom: max(0.4vw, fun.convert-px(6)) solid; + border-image: radial-gradient( + ellipse at center, + var(--color-primary-lighter) 20%, + var(--color-primary) 100% + ) + 1; } @@ -2442,7 +2442,7 @@ global "^4.4.0" regenerator-runtime "^0.13.7" -"@storybook/addons@6.5.3": +"@storybook/addons@6.5.3", "@storybook/addons@^6.5.3": version "6.5.3" resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.5.3.tgz#43dd276417edf74be0c465b968d35795f8cd994d" integrity sha512-gzzkxZ7R4+EaEzIEBbTWmkA55JDEDQrDjg3nNY/SJklnRigYdStz41KSPx6HGkF2CaI5BYVd5vZCawYvG16gyg== @@ -3239,7 +3239,7 @@ resolve-from "^5.0.0" ts-dedent "^2.0.0" -"@storybook/theming@6.5.3": +"@storybook/theming@6.5.3", "@storybook/theming@^6.5.3": version "6.5.3" resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.5.3.tgz#a8df53df2812d49453a3410346123231e028c103" integrity sha512-2tM46jahAhKRUzCcoaqPoqs+4imXqbze0dCPZ0cdVnfs14jhMB1lAfGE+diodCCaUcXUu8r2c5dTPKqqM1lHqQ== @@ -7673,7 +7673,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: +fast-deep-equal@^3.0.0, fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -13914,6 +13914,14 @@ storybook-addon-next@^1.6.2: sass-loader "^12.4.0" semver "^7.3.5" +storybook-dark-mode@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/storybook-dark-mode/-/storybook-dark-mode-1.1.0.tgz#4aca307a9c09f1b95743da2db6b07c8eea99ed24" + integrity sha512-F+hG02zYGBzxGTUonA1XDV/CtMYm3OjF38Tu1CIUN+w+8hwUrwLcOtgtLLw6VjSrZdJ/ECK+tjXdKTV4oZqAXw== + dependencies: + fast-deep-equal "^3.0.0" + memoizerific "^1.11.3" + stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" |
