Skip to content

Commit 3995234

Browse files
committed
πŸ§‘β€πŸ’»(storybook) Allow to switch between default and dark theme
In order to ease component development for both themes, we add a tool to be able to enable dark theme.
1 parent f85ea72 commit 3995234

File tree

11 files changed

+846
-519
lines changed

11 files changed

+846
-519
lines changed

β€Ž.storybook/manager.tsxβ€Ž

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* eslint-disable react-hooks/rules-of-hooks */
2+
import { addons, types, useStorybookApi } from '@storybook/manager-api';
3+
import { getThemeFromGlobals, themes } from './theme';
4+
import { useEffect } from 'react';
5+
import { useGlobals } from '@storybook/manager-api';
6+
7+
addons.setConfig({ theme: themes.default });
8+
9+
/**
10+
* This add-on is just here to apply the theme to the Storybook manager ( the top-most frame
11+
* containing sidebar, toolbar, etc ) when the theme is switched.
12+
*
13+
* The reason why we needed to add this add-on is that add-ons are the only place from where you can
14+
* dynamically change the current theme of the manager.
15+
*/
16+
addons.register('theme-synchronizer', () => {
17+
addons.add('theme-synchronizer/main', {
18+
title: 'Theme synchronizer',
19+
//πŸ‘‡ Sets the type of UI element in Storybook
20+
type: types.TOOL,
21+
//πŸ‘‡ Shows the Toolbar UI element if either the Canvas or Docs tab is active
22+
match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
23+
render: () => {
24+
const api = useStorybookApi();
25+
const [globals] = useGlobals();
26+
const theme = getThemeFromGlobals(globals);
27+
useEffect(() => {
28+
api.setOptions({
29+
theme: themes[theme]
30+
})
31+
}, [theme, api]);
32+
return null;
33+
},
34+
});
35+
});

β€Ž.storybook/preview-head.htmlβ€Ž

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<style>
2+
code {
3+
margin: 0 2px;
4+
padding: 3px 5px;
5+
white-space: nowrap;
6+
border-radius: 3px;
7+
border: 1px solid #eeeeee;
8+
color: rgba(51, 51, 51, 0.9);
9+
background-color: #f8f8f8;
10+
}
11+
/* Prevent the index.scss font-family to override code blocks's one. */
12+
pre * {
13+
font-family:
14+
ui-monospace, Menlo, Monaco, "Roboto Mono", "Oxygen Mono",
15+
"Ubuntu Monospace", "Source Code Pro", "Droid Sans Mono", "Courier New",
16+
monospace;
17+
}
18+
19+
.cunningham-theme--dark {
20+
.prismjs {
21+
background-color: var(--c--globals--colors--gray-800) !important;
22+
}
23+
}
24+
</style>

β€Ž.storybook/preview.tsxβ€Ž

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@ import "./../src/index.scss";
33
import "./../src/styles/fonts.scss";
44
import "./../src/style-stories.scss";
55
import type { Preview } from "@storybook/react";
6+
import { DocsContainer } from "@storybook/blocks";
67
import React from "react";
8+
import { BACKGROUND_COLOR_TO_THEME, getThemeFromGlobals, themes } from "./theme";
9+
10+
const DocsWithTheme = (props) => {
11+
const theme = getThemeFromGlobals(props.context.store.userGlobals.globals);
12+
return (
13+
<CunninghamProvider theme={theme}>
14+
<DocsContainer {...props} theme={themes[theme]} />
15+
</CunninghamProvider>
16+
);
17+
};
718

819
const preview: Preview = {
920
decorators: [
10-
(Story) => (
11-
<CunninghamProvider currentLocale="en-US">
21+
(Story, context) => (
22+
<CunninghamProvider currentLocale="en-US" theme={getThemeFromGlobals(context.globals)}>
1223
<div>
1324
<Story />
1425
</div>
@@ -17,19 +28,21 @@ const preview: Preview = {
1728
],
1829
parameters: {
1930
backgrounds: {
20-
values: [
21-
// πŸ‘‡ Add your own
22-
{ name: "Gray", value: "#F7F9F2" },
23-
],
24-
// πŸ‘‡ Specify which background is shown by default
25-
default: "light",
31+
default: null,
32+
values: Object.entries(BACKGROUND_COLOR_TO_THEME).map((value) => ({
33+
name: value[1],
34+
value: value[0],
35+
})),
2636
},
2737
controls: {
2838
matchers: {
2939
color: /(background|color)$/i,
3040
date: /Date$/i,
3141
},
3242
},
43+
docs: {
44+
container: DocsWithTheme,
45+
},
3346
},
3447
};
3548

β€Ž.storybook/theme.tsβ€Ž

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { create } from "@storybook/theming";
2+
import { tokens } from "../src/cunningham-tokens";
3+
4+
const buildTheme = (
5+
{ globals, contextuals }: typeof tokens.themes.default,
6+
type: "default" | "dark" = "default"
7+
) => {
8+
return {
9+
brandUrl: "https://github.com/suitenumerique/cunningham",
10+
brandImage: `storybook/logo-uikit-${type}.svg`,
11+
brandTitle: "La Suite UI Kit",
12+
brandTarget: "_self",
13+
14+
//
15+
colorPrimary: contextuals.content.semantic.brand.primary, // content.brand.primary
16+
colorSecondary: contextuals.content.semantic.brand.primary, // content.brand.secondary
17+
18+
fontBase: globals.font.families.base,
19+
20+
// UI
21+
appBg: contextuals.background.surface.secondary, // background.surface.tertiary
22+
appContentBg: contextuals.background.surface.tertiary, // background.surface.primary
23+
appBorderColor: contextuals.border.surface.primary, // border.surface.primary
24+
appBorderRadius: 4,
25+
26+
// Text colors
27+
textColor: contextuals.content.semantic.neutral.primary, // content.neutral.primary
28+
textInverseColor: contextuals.content.semantic.neutral.secondary, // content.neutral.secondary
29+
textMutedColor: contextuals.content.semantic.neutral.tertiary,
30+
31+
// Toolbar default and active colors
32+
barTextColor: contextuals.content.semantic.neutral.tertiary, // content.neutral.tertiary
33+
barSelectedColor: contextuals.content.semantic.neutral.primary, // content.neutral.primary
34+
barSelectedTextColor: contextuals.content.semantic.neutral.primary, // content.neutral.primary
35+
barBg: contextuals.background.surface.primary, // background.surface.primary
36+
37+
// Form colors
38+
inputBg: contextuals.background.surface.primary, // background.surface.primary
39+
inputBorder: contextuals.border.semantic.neutral.secondary, // border.neutral.secondary
40+
inputTextColor: contextuals.content.semantic.neutral.primary, // content.neutral.primary
41+
inputBorderRadius: 2,
42+
43+
// Code preview colors
44+
codeBg: contextuals.background.surface.secondary, // background.surface.secondary
45+
codeColor: contextuals.content.semantic.neutral.primary, // content.neutral.primary
46+
};
47+
};
48+
49+
export const themes = {
50+
default: create({
51+
base: "light",
52+
...buildTheme(tokens.themes.default),
53+
}),
54+
dark: create({
55+
base: "dark",
56+
...buildTheme(tokens.themes.dark, "dark"),
57+
}),
58+
};
59+
60+
export enum Themes {
61+
dark = "dark",
62+
default = "default",
63+
}
64+
65+
export const BACKGROUND_COLOR_TO_THEME = {
66+
"#181B24": Themes.dark,
67+
};
68+
69+
export const getThemeFromGlobals = (globals: any): string => {
70+
const color = BACKGROUND_COLOR_TO_THEME[globals.backgrounds?.value];
71+
return color ?? Themes.default;
72+
};

β€Žpackage.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"lint": "eslint . --report-unused-disable-directives",
2929
"preview": "vite preview",
3030
"test": "vitest run",
31-
"build-theme": "cunningham -g css,scss -o src && mv src/cunningham-tokens.scss src/cunningham-tokens-sass.scss",
31+
"build-theme": "cunningham -g css,scss,ts -o src && mv src/cunningham-tokens.scss src/cunningham-tokens-sass.scss",
3232
"storybook": "storybook dev -p 6006",
3333
"build-storybook": "storybook build"
3434
},
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

β€Žsrc/components/button/button.stories.tsxβ€Ž

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const colors: ButtonProps["color"][] = [
2121
"brand",
2222
"neutral",
2323
"info",
24-
"success",
2524
"warning",
2625
"error",
2726
"success",

0 commit comments

Comments
Β (0)