From 061949354c23d3549e50203af1b5ef422157b3ce Mon Sep 17 00:00:00 2001 From: Evan Simkowitz Date: Thu, 26 Sep 2024 18:58:25 -0700 Subject: [PATCH] Storybook with dark mode support (#880) --- .storybook/custom-addons/theme/register.ts | 15 ++++++++ .storybook/main.ts | 2 + .storybook/manager.ts | 6 --- .storybook/preview.tsx | 29 +++++++++++++++ .storybook/theme.ts | 12 +++++- package.json | 2 + yarn.lock | 43 ++++++++++++++++++++-- 7 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 .storybook/custom-addons/theme/register.ts delete mode 100644 .storybook/manager.ts diff --git a/.storybook/custom-addons/theme/register.ts b/.storybook/custom-addons/theme/register.ts new file mode 100644 index 000000000..fd43c2b9f --- /dev/null +++ b/.storybook/custom-addons/theme/register.ts @@ -0,0 +1,15 @@ +import { FORCE_RE_RENDER } from "@storybook/core-events"; +import { addons } from "@storybook/manager-api"; +import { dark, light } from "../../theme"; + +addons.register("theme-switcher", (api) => { + const query = window.matchMedia("(prefers-color-scheme: dark)"); + const update = () => { + const theme = query.matches ? dark : light; + api.setOptions({ theme }); + addons.getChannel().emit(FORCE_RE_RENDER); + }; + + addons.getChannel().on("storiesConfigured", update); + query.addEventListener("change", update); +}); diff --git a/.storybook/main.ts b/.storybook/main.ts index 98ad949cc..567956228 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -10,6 +10,8 @@ const config: StorybookConfig = { "@storybook/addon-essentials", "@chromatic-com/storybook", "@storybook/addon-interactions", + "storybook-dark-mode", + "./custom-addons/theme/register", ], core: {}, diff --git a/.storybook/manager.ts b/.storybook/manager.ts deleted file mode 100644 index 34e8f196c..000000000 --- a/.storybook/manager.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { addons } from "@storybook/manager-api"; -import theme from "./theme"; - -addons.setConfig({ - theme, -}); diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index d0d802178..f6307cf83 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -7,6 +7,13 @@ import "../frontend/app/theme.less"; import "../frontend/app/app.less"; import "../frontend/app/reset.less"; import "./global.css"; +import { light, dark } from "./theme"; +import { DocsContainer } from "@storybook/addon-docs"; + +import { addons } from "@storybook/preview-api"; +import { DARK_MODE_EVENT_NAME } from "storybook-dark-mode"; + +const channel = addons.getChannel(); const preview: Preview = { parameters: { @@ -16,6 +23,28 @@ const preview: Preview = { date: /Date$/i, }, }, + darkMode: { + dark, + light, + stylePreview: true, + classTarget: "html", + }, + docs: { + container: (props) => { + const [isDark, setDark] = React.useState(); + + React.useEffect(() => { + channel.on(DARK_MODE_EVENT_NAME, setDark); + return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark); + }, [channel, setDark]); + + return ( +
+ +
+ ); + }, + }, }, decorators: [ diff --git a/.storybook/theme.ts b/.storybook/theme.ts index 23fad617a..974418aea 100644 --- a/.storybook/theme.ts +++ b/.storybook/theme.ts @@ -1,9 +1,17 @@ import { create } from "@storybook/theming"; -export default create({ +export const light = create({ base: "light", brandTitle: "Wave Terminal Storybook", - brandUrl: "https://www.waveterm.dev", + brandUrl: "https://storybook.waveterm.dev", brandImage: "../assets/wave-light.png", brandTarget: "_self", }); + +export const dark = create({ + base: "dark", + brandTitle: "Wave Terminal Storybook", + brandUrl: "https://storybook.waveterm.dev", + brandImage: "../assets/wave-dark.png", + brandTarget: "_self", +}); diff --git a/package.json b/package.json index 2dbfae979..5bb146040 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@storybook/react": "^8.3.3", "@storybook/react-vite": "^8.3.3", "@storybook/test": "^8.3.3", + "@storybook/theming": "^8.3.3", "@types/css-tree": "^2", "@types/debug": "^4", "@types/electron": "^1.6.10", @@ -66,6 +67,7 @@ "rollup-plugin-flow": "^1.1.1", "semver": "^7.6.3", "storybook": "^8.3.3", + "storybook-dark-mode": "^4.0.2", "ts-node": "^10.9.2", "tslib": "^2.6.3", "tsx": "^4.19.1", diff --git a/yarn.lock b/yarn.lock index 074c6fee6..b61b66e38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1683,7 +1683,7 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:^8.3.3": +"@storybook/components@npm:^8.0.0, @storybook/components@npm:^8.3.3": version: 8.3.3 resolution: "@storybook/components@npm:8.3.3" peerDependencies: @@ -1692,6 +1692,15 @@ __metadata: languageName: node linkType: hard +"@storybook/core-events@npm:^8.0.0": + version: 8.3.3 + resolution: "@storybook/core-events@npm:8.3.3" + peerDependencies: + storybook: ^8.3.3 + checksum: 10c0/9ea51ec1b4c94d28e6bcb3b31dc21d98a4aa9685a0158ef42160f1934d6208db41b1461945b05fbe5dbb09fa629342c3576f4729f591b84471f70829bcbaf461 + languageName: node + linkType: hard + "@storybook/core@npm:8.3.3": version: 8.3.3 resolution: "@storybook/core@npm:8.3.3" @@ -1750,6 +1759,16 @@ __metadata: languageName: node linkType: hard +"@storybook/icons@npm:^1.2.5": + version: 1.2.12 + resolution: "@storybook/icons@npm:1.2.12" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 10c0/97f6a7b7841fb5a0d1c8a30c36173469e7b0814a674c8103c7c0fd8803f0f7c2a778545af864012d40883195a533534dbc98541deac2bafe31e6a3fe37fdfc66 + languageName: node + linkType: hard + "@storybook/instrumenter@npm:8.3.3": version: 8.3.3 resolution: "@storybook/instrumenter@npm:8.3.3" @@ -1763,7 +1782,7 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-api@npm:^8.3.3": +"@storybook/manager-api@npm:^8.0.0, @storybook/manager-api@npm:^8.3.3": version: 8.3.3 resolution: "@storybook/manager-api@npm:8.3.3" peerDependencies: @@ -1872,7 +1891,7 @@ __metadata: languageName: node linkType: hard -"@storybook/theming@npm:^8.3.3": +"@storybook/theming@npm:^8.0.0, @storybook/theming@npm:^8.3.3": version: 8.3.3 resolution: "@storybook/theming@npm:8.3.3" peerDependencies: @@ -10292,6 +10311,22 @@ __metadata: languageName: node linkType: hard +"storybook-dark-mode@npm:^4.0.2": + version: 4.0.2 + resolution: "storybook-dark-mode@npm:4.0.2" + dependencies: + "@storybook/components": "npm:^8.0.0" + "@storybook/core-events": "npm:^8.0.0" + "@storybook/global": "npm:^5.0.0" + "@storybook/icons": "npm:^1.2.5" + "@storybook/manager-api": "npm:^8.0.0" + "@storybook/theming": "npm:^8.0.0" + fast-deep-equal: "npm:^3.1.3" + memoizerific: "npm:^1.11.3" + checksum: 10c0/d4fc652ff080f6cc9f0effab0c989b66ead3372b267c2c328eef608f27c9822bf47aaa177405e42768b2de22f8a3e9a0280af50430efd0cf78bd6ed1f12c8b29 + languageName: node + linkType: hard + "storybook@npm:^8.3.3": version: 8.3.3 resolution: "storybook@npm:8.3.3" @@ -11351,6 +11386,7 @@ __metadata: "@storybook/react": "npm:^8.3.3" "@storybook/react-vite": "npm:^8.3.3" "@storybook/test": "npm:^8.3.3" + "@storybook/theming": "npm:^8.3.3" "@table-nav/core": "npm:^0.0.7" "@table-nav/react": "npm:^0.0.7" "@tanstack/react-table": "npm:^8.20.5" @@ -11423,6 +11459,7 @@ __metadata: shell-quote: "npm:^1.8.1" sprintf-js: "npm:^1.1.3" storybook: "npm:^8.3.3" + storybook-dark-mode: "npm:^4.0.2" throttle-debounce: "npm:^5.0.2" tinycolor2: "npm:^1.6.0" ts-node: "npm:^10.9.2"