✨(react) add themes switching in Storybook
We want to be able to visualize easily themes directly inside Storybook. This was not a trivial task as there is no centralized logic to handle Doc / Stories / Manager at the same time.
This commit is contained in:
@@ -1,40 +0,0 @@
|
||||
import { addons } from "@storybook/manager-api";
|
||||
import { create } from "@storybook/theming";
|
||||
import { defaultTokens } from "@openfun/cunningham-tokens";
|
||||
|
||||
const COLORS = defaultTokens.theme.colors;
|
||||
|
||||
const theme = create({
|
||||
base: "light",
|
||||
brandUrl: "https://github.com/openfun/cunningham",
|
||||
brandImage: "logo-cunningham.svg",
|
||||
brandTitle: "Cunningham",
|
||||
brandTarget: "_self",
|
||||
|
||||
//
|
||||
colorPrimary: COLORS["primary-400"],
|
||||
colorSecondary: COLORS["primary-400"],
|
||||
|
||||
// UI
|
||||
appBg: COLORS["greyscale-100"],
|
||||
appContentBg: COLORS["greyscale-000"],
|
||||
appBorderColor: COLORS["greyscale-300"],
|
||||
appBorderRadius: 4,
|
||||
|
||||
// Text colors
|
||||
textColor: COLORS["greyscale-900"],
|
||||
textInverseColor: COLORS["greyscale-000"],
|
||||
|
||||
// Toolbar default and active colors
|
||||
barTextColor: COLORS["greyscale-500"],
|
||||
barSelectedColor: COLORS["greyscale-900"],
|
||||
barBg: COLORS["greyscale-000"],
|
||||
|
||||
// Form colors
|
||||
inputBg: COLORS["greyscale-000"],
|
||||
inputBorder: COLORS["greyscale-300"],
|
||||
inputTextColor: COLORS["greyscale-800"],
|
||||
inputBorderRadius: 2,
|
||||
});
|
||||
|
||||
addons.setConfig({ theme });
|
||||
34
packages/react/.storybook/manager.tsx
Normal file
34
packages/react/.storybook/manager.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { addons, types, useStorybookApi } from '@storybook/manager-api';
|
||||
import { getThemeFromGlobals, themes } from './themes';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useGlobals } from '@storybook/api';
|
||||
|
||||
addons.setConfig({ theme: themes.default });
|
||||
|
||||
/**
|
||||
* This add-on is just here to apply the theme to the Storybook manager ( the top-most frame
|
||||
* containing sidebar, toolbar, etc ) when the theme is switched.
|
||||
*
|
||||
* The reason why we needed to add this add-on is that add-ons are the only place from where you can
|
||||
* dynamically change the current theme of the manager.
|
||||
*/
|
||||
addons.register('theme-synchronizer', () => {
|
||||
addons.add('theme-synchronizer/main', {
|
||||
title: 'Theme synchronizer',
|
||||
//👇 Sets the type of UI element in Storybook
|
||||
type: types.TOOL,
|
||||
//👇 Shows the Toolbar UI element if either the Canvas or Docs tab is active
|
||||
match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
|
||||
render: ({ active }) => {
|
||||
const api = useStorybookApi();
|
||||
const [globals, updateGlobals] = useGlobals();
|
||||
const theme = getThemeFromGlobals(globals);
|
||||
useEffect(() => {
|
||||
api.setOptions({
|
||||
theme: themes[theme]
|
||||
})
|
||||
}, [theme]);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,17 @@
|
||||
pre * {
|
||||
font-family: ui-monospace,Menlo,Monaco,"Roboto Mono","Oxygen Mono","Ubuntu Monospace","Source Code Pro","Droid Sans Mono","Courier New",monospace;
|
||||
}
|
||||
|
||||
.cunningham-theme--dark {
|
||||
.docblock-source {
|
||||
background-color: var(--c--theme--colors--greyscale-100);
|
||||
}
|
||||
|
||||
.prismjs {
|
||||
background-color: var(--c--theme--colors--greyscale-100) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.global = window;
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import "../src/icons.scss";
|
||||
import "../src/index.scss";
|
||||
import "../src/fonts.scss";
|
||||
import { Preview } from "@storybook/react";
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
storySort: (a, b) => {
|
||||
const roots = ["Getting Started", "Components"];
|
||||
const gettingStartedOrder = [
|
||||
"Installation",
|
||||
"Customization",
|
||||
"Colors",
|
||||
"Spacings",
|
||||
"Typography",
|
||||
];
|
||||
|
||||
const aParts = a.title.split("/");
|
||||
const bParts = b.title.split("/");
|
||||
if (aParts[0] !== bParts[0]) {
|
||||
return roots.indexOf(aParts[0]) - roots.indexOf(bParts[0]);
|
||||
}
|
||||
if (aParts[1] !== bParts[1]) {
|
||||
if (aParts[0] === "Getting Started") {
|
||||
return (
|
||||
gettingStartedOrder.indexOf(aParts[1]) -
|
||||
gettingStartedOrder.indexOf(bParts[1])
|
||||
);
|
||||
}
|
||||
return aParts[1].localeCompare(bParts[1]);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
76
packages/react/.storybook/preview.tsx
Normal file
76
packages/react/.storybook/preview.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import '../src/icons.scss';
|
||||
import '../src/index.scss';
|
||||
import '../src/fonts.scss';
|
||||
import { Preview } from '@storybook/react';
|
||||
import { DocsContainer } from '@storybook/blocks';
|
||||
|
||||
import { CunninghamProvider } from ':/components/Provider';
|
||||
import { BACKGROUND_COLOR_TO_THEME, getThemeFromGlobals, themes } from './themes';
|
||||
|
||||
export const DocsWithTheme = (props, context) => {
|
||||
const theme = getThemeFromGlobals(props.context.store.globals.globals);
|
||||
return <CunninghamProvider theme={theme}>
|
||||
<DocsContainer {...props} theme={themes[theme]} />
|
||||
</CunninghamProvider>;
|
||||
};
|
||||
|
||||
const preview: Preview = {
|
||||
decorators: [
|
||||
(Story, context) => (
|
||||
<CunninghamProvider theme={getThemeFromGlobals(context.globals)}>
|
||||
<Story />
|
||||
</CunninghamProvider>
|
||||
),
|
||||
],
|
||||
parameters: {
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
backgrounds: {
|
||||
default: null,
|
||||
values: Object.entries(BACKGROUND_COLOR_TO_THEME).map(value => ({
|
||||
name: value[1],
|
||||
value: value[0],
|
||||
})),
|
||||
},
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
docs: {
|
||||
container: DocsWithTheme,
|
||||
},
|
||||
options: {
|
||||
storySort: (a, b) => {
|
||||
const roots = ['Getting Started', 'Components'];
|
||||
const gettingStartedOrder = [
|
||||
'Installation',
|
||||
'First steps',
|
||||
'Customization',
|
||||
'Theming',
|
||||
'Colors',
|
||||
'Spacings',
|
||||
'Typography',
|
||||
];
|
||||
|
||||
const aParts = a.title.split('/');
|
||||
const bParts = b.title.split('/');
|
||||
if (aParts[0] !== bParts[0]) {
|
||||
return roots.indexOf(aParts[0]) - roots.indexOf(bParts[0]);
|
||||
}
|
||||
if (aParts[1] !== bParts[1]) {
|
||||
if (aParts[0] === 'Getting Started') {
|
||||
return (
|
||||
gettingStartedOrder.indexOf(aParts[1]) -
|
||||
gettingStartedOrder.indexOf(bParts[1])
|
||||
);
|
||||
}
|
||||
return aParts[1].localeCompare(bParts[1]);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
61
packages/react/.storybook/themes.ts
Normal file
61
packages/react/.storybook/themes.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { create } from '@storybook/theming';
|
||||
import { tokens } from '../src/cunningham-tokens';
|
||||
|
||||
const buildTheme = (colors: typeof tokens.themes.default.theme.colors & any) => {
|
||||
return {
|
||||
brandUrl: 'https://github.com/openfun/cunningham',
|
||||
brandImage: 'logo-cunningham.svg',
|
||||
brandTitle: 'Cunningham',
|
||||
brandTarget: '_self',
|
||||
|
||||
//
|
||||
colorPrimary: colors['primary-400'],
|
||||
colorSecondary: colors['primary-400'],
|
||||
|
||||
// UI
|
||||
appBg: colors['greyscale-100'],
|
||||
appContentBg: colors['greyscale-000'],
|
||||
appBorderColor: colors['greyscale-300'],
|
||||
appBorderRadius: 4,
|
||||
|
||||
// Text colors
|
||||
textColor: colors['greyscale-900'],
|
||||
textInverseColor: colors['greyscale-000'],
|
||||
|
||||
// Toolbar default and active colors
|
||||
barTextColor: colors['greyscale-500'],
|
||||
barSelectedColor: colors['greyscale-900'],
|
||||
barBg: colors['greyscale-000'],
|
||||
|
||||
// Form colors
|
||||
inputBg: colors['greyscale-000'],
|
||||
inputBorder: colors['greyscale-300'],
|
||||
inputTextColor: colors['greyscale-800'],
|
||||
inputBorderRadius: 2,
|
||||
};
|
||||
};
|
||||
|
||||
export const themes = {
|
||||
default: create({
|
||||
base: 'light',
|
||||
...buildTheme(tokens.themes.default.theme.colors),
|
||||
}),
|
||||
dark: create({
|
||||
base: 'dark',
|
||||
...buildTheme(tokens.themes.dark.theme.colors),
|
||||
}),
|
||||
};
|
||||
|
||||
export enum Themes {
|
||||
dark = 'dark',
|
||||
default = 'default'
|
||||
}
|
||||
|
||||
export const BACKGROUND_COLOR_TO_THEME = {
|
||||
'#0C1A2B': Themes.dark,
|
||||
};
|
||||
|
||||
export const getThemeFromGlobals = (globals: any): string => {
|
||||
const color = BACKGROUND_COLOR_TO_THEME[globals.backgrounds?.value];
|
||||
return color ?? Themes.default;
|
||||
};
|
||||
@@ -7,16 +7,6 @@
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_16_5113" x="-112.85" y="-113.135" width="722.099" height="318.964" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="58.2902"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_16_5113"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_16_5113" result="shape"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_16_5113" x1="248.5" y1="0" x2="248.5" y2="90" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.28125" stop-color="#5894E1"/>
|
||||
<stop offset="1" stop-color="#377FDB"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Reference in New Issue
Block a user