如何在 Storybook 6.0 中自定义深色和浅色主题

Posted

技术标签:

【中文标题】如何在 Storybook 6.0 中自定义深色和浅色主题【英文标题】:How to customize both dark and light themes in Storybook 6.0 【发布时间】:2020-11-10 16:07:30 【问题描述】:

我正在使用浅色和深色主题制作 PWA,我想创建我的 Storybook 浅色和深色主题来反映这些主题。

所以我创建了一个函数,如果我将 Material UI Theme 和基本名称传递给它,它将返回一个新的 Storybook 主题对象。

但是如何将这 2 个对象作为主题传递给 Storybook?

我发现我应该去manager.js并添加以下代码

import theme from '../src/theme/theme'
import createThemeFromMUITheme from './create-theme-from-mui-theme'
import addons from '@storybook/addons'

addons.setConfig(
  theme: createThemeFromMUITheme('light', theme.light),
)

但是如何设置明暗主题?

我试过了

import theme from '../src/theme/theme'
import createThemeFromMUITheme from './create-theme-from-mui-theme'
import addons from '@storybook/addons'

addons.setConfig(
  theme: 
    light: createThemeFromMUITheme('light', theme.light),
    dark: createThemeFromMUITheme('dark', theme.dark)
  ,
)

但这使得故事书什么也没有显示(但它并没有失败)

请帮忙:-)

编辑:我也尝试了以下

import theme from '../src/theme/theme'
import createThemeFromMUITheme from './create-theme-from-mui-theme'
import addons from '@storybook/addons'

addons.setConfig(
  theme: createThemeFromMUITheme('light', theme.light),
)

addons.setConfig(
  theme: createThemeFromMUITheme('dark', theme.dark),
)

编辑 #2:从 createThemeFromMUITheme 返回的主题配置对象是有效的顺便说一句

如果有人想要我制作的将 MUI 主题对象转换为 SB 主题对象的函数 - 那么就是这样......

(我还没有弄乱表单颜色...)

import  create  from '@storybook/theming/create'

const createThemeFromMUITheme = (name, theme) => 
  return create(
    base: name,

    colorPrimary: theme.palette.primary.main,
    colorSecondary: theme.palette.secondary.main,

    // UI
    appBg: theme.palette.background.default,
    appContentBg: theme.palette.background.paper,
    appBorderColor: theme.palette.background.paper,
    appBorderRadius: theme.shape.borderRadius,

    // Typography
    fontBase: theme.typography.fontFamily,
    fontCode: 'monospace',

    // Text colors
    textColor: theme.palette.text.primary,
    textInverseColor: theme.palette.text.secondary,

    // Toolbar default and active colors
    barTextColor: theme.palette.text.primary,
    barSelectedColor: theme.palette.text.secondary,
    barBg: theme.palette.background.default,

    brandTitle: 'Add your brand title here',
    brandUrl: 'https://yourbrandurl.com',
    brandImage: 'https://placehold.it/350x150',
  )


export default createThemeFromMUITheme

【问题讨论】:

【参考方案1】:

默认情况下,您只能为故事书显示一个主题 但是您可以使用名为 storybook-dark-mode 的插件在深色和浅色主题之间切换,这是插件页面here

一个例子把它放在 preview.js 文件中:


import  addParameters  from '@storybook/react'; // or any other type of storybook

addParameters(
  darkMode: 
    // Set the initial theme
    current: 'light'
    // Override the default dark theme
    dark:  ...themes.dark, appBg: 'black' ,
    // Override the default light theme
    light:  ...themes.normal, appBg: 'red' 
  
);

那么你的故事书中就会有一个这样的切换按钮

【讨论】:

感谢您的帮助伙伴-您将因打扰回答我而获得声誉! Youre welcome sorry if it was not what you looking at exactly, And Thanks, im 很高兴它有助于找到答案。【参考方案2】:

嗯 - 解决方案正盯着我的眼睛,但像往常一样,我没有足够阅读文档。

我确实安装了 storybook-dark-theme,我的想法是完全集成 MUI,这样浅色主题将显示我的应用程序浅色主题,深色主题将显示我的深色主题 - 组件也是如此。

这样,明暗主题切换器就变得完全全球化了。

然而,它确实比你写的要多一点。

这就是我的目标

您可以从这里下载所有内容 Link to my github with the solution

当故事书第一次渲染时,它将使用默认主题,因此在您已经覆盖的明暗主题开始之前,您会出现一些闪烁。

第一次点击会使其保持浅色主题,但现在它将使用您的浅色主题。

解决这个问题的方法是用manager.ts中的浅色主题初始化,就像这样

import  addons  from '@storybook/addons'
import  theme as appTheme  from '../src/theme/theme'
import  createThemeFromMuiTheme  from './utils/create-theme-from-mui-theme'

addons.setConfig(
    theme: createThemeFromMuiTheme(
        theme: appTheme.light,
        options: 
            base: 'light',
            brandTitle: 'Storybook with MUI',
            brandUrl: 'https://www.github.com/IgorSzyporyn/storybook-with-mui'
        ,
    )
)

然后在preview.ts 中,您需要像这样设置明暗覆盖

import React from 'react'
import  addDecorator  from '@storybook/react'
import  theme as appTheme  from '../src/theme/theme'
import  WithMuiTheme  from './components/WithMuiTheme'
import  createThemeFromMuiTheme  from './utils/create-theme-from-mui-theme'

addDecorator((story) => <WithMuiTheme>story()</WithMuiTheme>)

export const parameters = 
    exportedParameter: 'exportedParameter',
    darkMode: 
        current: 'light',
        light: createThemeFromMuiTheme( theme: appTheme.light, asStorybookTheme: false ),
        dark: createThemeFromMuiTheme( theme: appTheme.dark, asStorybookTheme: false )
    ,

让你的装饰器包装像这样./components/WithMuiThemeProps

import React from 'react'
import  MuiThemeProvider, CssBaseline, StylesProvider  from '@material-ui/core'
import  useThemeType  from '../hooks/UseThemeType'
import  theme  from '../../src/theme/theme'

type WithMuiThemeProps = 
    children: React.ReactNode


export const WithMuiTheme = ( children : WithMuiThemeProps) => 
    const themeType = useThemeType()

    return (
        <MuiThemeProvider theme=theme[themeType]>
            <CssBaseline />
            <StylesProvider injectFirst>children</StylesProvider>
        </MuiThemeProvider>
    )

这是使更新发生的钩子./hooks/UseThemeType.ts

import React from 'react'
import addons from '@storybook/addons'

const channel = addons.getChannel()

export const useThemeType = () => 
    const [isDark, setDark] = React.useState(false)

    React.useEffect(() => 
        channel.on('DARK_MODE', setDark)
        return () => channel.off('DARK_MODE', setDark)
    , [channel, setDark])

    const paletteType = isDark ? 'dark' : 'light'

    return paletteType

最后是./utils/create-theme-from-mui-theme.ts

import  create  from '@storybook/theming/create'
import  Theme  from '@material-ui/core'

type CreateThemFromMuiTheme = 
    theme: Theme
    options?: Object
    asStorybookTheme?: boolean


export const createThemeFromMuiTheme = (
    theme,
    options = ,
    asStorybookTheme = true,
: CreateThemFromMuiTheme) => 
    const themeValue = 
        colorPrimary: theme.palette.primary.main,
        colorSecondary: theme.palette.secondary.main,

        // UI
        appBg: theme.palette.background.paper,
        appContentBg: theme.palette.background.default,
        appBorderColor: theme.palette.background.paper,
        appBorderRadius: theme.shape.borderRadius,

        // Typography
        fontBase: theme.typography.fontFamily,
        fontCode: 'monospace',

        // Text colors
        textColor: theme.palette.text.primary,
        textInverseColor: theme.palette.text.secondary,

        // Toolbar default and active colors
        barTextColor: theme.palette.text.secondary,
        barSelectedColor: theme.palette.secondary.main,
        barBg: theme.palette.background.default,

        // Form color
        inputBg: 'transparent',
        inputBorder: 'silver',
        inputTextColor: theme.palette.text.primary,
        inputBorderRadius: theme.shape.borderRadius,

        ...options,
    

    return asStorybookTheme ? create(themeValue) : themeValue

现在您将能够使用完全集成到 Storybook 中的主题 - 当您切换 Storybook 主题时,Storybook 本身将变为主题,您使用的组件也会发生变化。

【讨论】:

以上是关于如何在 Storybook 6.0 中自定义深色和浅色主题的主要内容,如果未能解决你的问题,请参考以下文章

在.NET 6.0中自定义接口路由

如何在 Swift 中自定义 UISlider 值

在.NET 6.0中使用不同的托管模型

在.NET 6.0中使用不同的托管模型

.Net 6.0全局异常捕获

如何让 Storybook 使用项目的 CSS 变量