summaryrefslogtreecommitdiffstats
path: root/.storybook
diff options
context:
space:
mode:
Diffstat (limited to '.storybook')
-rw-r--r--.storybook/main.js55
-rw-r--r--.storybook/manager.js6
-rw-r--r--.storybook/overrides/docs-container.js36
-rw-r--r--.storybook/preview.js74
-rw-r--r--.storybook/themes/common.js8
-rw-r--r--.storybook/themes/dark.js37
-rw-r--r--.storybook/themes/light.js36
7 files changed, 252 insertions, 0 deletions
diff --git a/.storybook/main.js b/.storybook/main.js
new file mode 100644
index 0000000..477b09e
--- /dev/null
+++ b/.storybook/main.js
@@ -0,0 +1,55 @@
+const path = require('path');
+
+/**
+ * @typedef {import('webpack').Configuration} WebpackConfig
+ */
+
+const storybookConfig = {
+ stories: ['../src/**/*.stories.@(md|mdx|js|jsx|ts|tsx)'],
+ addons: [
+ '@storybook/addon-links',
+ '@storybook/addon-essentials',
+ '@storybook/addon-interactions',
+ 'storybook-addon-next',
+ 'storybook-dark-mode',
+ ],
+ framework: '@storybook/react',
+ core: {
+ builder: 'webpack5',
+ },
+ staticDirs: ['../public'],
+ /**
+ * @param {WebpackConfig} config
+ * @return {Promise<WebpackConfig>}
+ */
+ webpackFinal: async (config) => {
+ // Use SVGR for SVG files. See: https://medium.com/@derek_19900/config-storybook-4-to-use-svgr-webpack-plugin-22cb1152f004
+ const rules = config.module.rules;
+ const fileLoaderRule = rules.find((rule) => rule.test.test('.svg'));
+ fileLoaderRule.exclude = /\.svg$/;
+ rules.push({
+ test: /\.svg$/,
+ use: [{ loader: '@svgr/webpack', options: { dimensions: false } }],
+ });
+
+ /** @type {import('next').NextConfig} */
+ const nextConfig = require('../next.config');
+
+ // Set modules aliases.
+ config.resolve.alias = {
+ ...config.resolve.alias,
+ '@i18n': path.resolve(__dirname, '../src/i18n'),
+ '@assets': path.resolve(__dirname, '../src/assets'),
+ '@components': path.resolve(__dirname, '../src/components'),
+ '@content': path.resolve(__dirname, '../src/content'),
+ '@pages': path.resolve(__dirname, '../src/pages'),
+ '@services': path.resolve(__dirname, '../src/services'),
+ '@styles': path.resolve(__dirname, '../src/styles'),
+ '@utils': path.resolve(__dirname, '../src/utils'),
+ };
+
+ return { ...config, ...nextConfig.webpack };
+ },
+};
+
+module.exports = storybookConfig;
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
new file mode 100644
index 0000000..9df7514
--- /dev/null
+++ b/.storybook/preview.js
@@ -0,0 +1,74 @@
+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;
+
+Object.defineProperty(NextImage, 'default', {
+ configurable: true,
+ value: (props) =>
+ typeof props.src === 'string' ? (
+ <OriginalNextImage {...props} unoptimized blurDataURL={props.src} />
+ ) : (
+ <OriginalNextImage {...props} unoptimized />
+ ),
+});
+
+Object.defineProperty(NextImage, '__esModule', {
+ configurable: true,
+ value: true,
+});
+
+export const parameters = {
+ actions: { argTypesRegex: '^on[A-Z].*' },
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ 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">
+ <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,
+});