From 1e5a4a68498c2f05d2f65c2b11feccdbde652477 Mon Sep 17 00:00:00 2001 From: Alex Yang <himself65@outlook.com> Date: Wed, 16 Aug 2023 15:07:55 -0500 Subject: [PATCH] feat(storybook): improve code (#3786) --- .github/workflows/publish-storybook.yml | 2 +- apps/storybook/.storybook/main.ts | 6 +- apps/storybook/.storybook/preview.tsx | 64 +++++++------ apps/storybook/package.json | 3 +- .../stories/block-suite-editor.stories.tsx | 92 ------------------- apps/storybook/src/stories/core.stories.tsx | 3 + .../src/stories/datepicker.stories.tsx | 7 +- .../src/stories/import-page.stories.tsx | 3 +- .../src/stories/page-list.stories.tsx | 3 + yarn.lock | 8 ++ 10 files changed, 63 insertions(+), 128 deletions(-) delete mode 100644 apps/storybook/src/stories/block-suite-editor.stories.tsx diff --git a/.github/workflows/publish-storybook.yml b/.github/workflows/publish-storybook.yml index 4a65bff2da..dbd7db584f 100644 --- a/.github/workflows/publish-storybook.yml +++ b/.github/workflows/publish-storybook.yml @@ -34,5 +34,5 @@ jobs: with: workingDir: apps/storybook buildScriptName: build - onlyStoryNames: 'Preview/**' + onlyChanged: true projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} diff --git a/apps/storybook/.storybook/main.ts b/apps/storybook/.storybook/main.ts index aa5d7ef2c6..42d67843a4 100644 --- a/apps/storybook/.storybook/main.ts +++ b/apps/storybook/.storybook/main.ts @@ -5,6 +5,7 @@ import { mergeConfig } from 'vite'; import tsconfigPaths from 'vite-tsconfig-paths'; import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; import { getRuntimeConfig } from '../../core/.webpack/runtime-config'; +import turbosnap from 'vite-plugin-turbosnap'; runCli( { @@ -33,7 +34,7 @@ export default { framework: { name: '@storybook/react-vite', }, - async viteFinal(config, _) { + async viteFinal(config, { configType }) { return mergeConfig(config, { assetsInclude: ['**/*.md'], plugins: [ @@ -41,6 +42,9 @@ export default { tsconfigPaths({ root: fileURLToPath(new URL('../../../', import.meta.url)), }), + configType === 'PRODUCTION' + ? turbosnap({ rootDir: config.root ?? process.cwd() }) + : null, ], define: { 'process.env': {}, diff --git a/apps/storybook/.storybook/preview.tsx b/apps/storybook/.storybook/preview.tsx index 783454fc06..f8b7551cc4 100644 --- a/apps/storybook/.storybook/preview.tsx +++ b/apps/storybook/.storybook/preview.tsx @@ -4,12 +4,12 @@ import '@affine/component/theme/theme.css'; import '@toeverything/components/style.css'; import { createI18n } from '@affine/i18n'; import { ThemeProvider, useTheme } from 'next-themes'; -import type { ComponentType } from 'react'; -import { useEffect } from 'react'; import { useDarkMode } from 'storybook-dark-mode'; import { setup } from '@affine/core/bootstrap/setup'; import { AffineContext } from '@affine/component/context'; import { use } from 'foxact/use'; +import useSWR from 'swr'; +import type { Decorator } from '@storybook/react'; const setupPromise = setup(); @@ -24,38 +24,42 @@ export const parameters = { }, }; -const createI18nDecorator = () => { - const i18n = createI18n(); - const withI18n = (Story: any, context: any) => { - const locale = context.globals.locale; - useEffect(() => { - i18n.changeLanguage(locale); - }, [locale]); - return <Story {...context} />; - }; - return withI18n; +const i18n = createI18n(); +const withI18n: Decorator = (Story, context) => { + const locale = context.globals.locale; + useSWR( + locale, + async () => { + await i18n.changeLanguage(locale); + }, + { + suspense: true, + } + ); + return <Story {...context} />; }; -const Component = () => { +const ThemeChange = () => { const isDark = useDarkMode(); const theme = useTheme(); - useEffect(() => { - theme.setTheme(isDark ? 'dark' : 'light'); - }, [isDark]); + if (theme.resolvedTheme === 'dark' && !isDark) { + theme.setTheme('light'); + } else if (theme.resolvedTheme === 'light' && isDark) { + theme.setTheme('dark'); + } return null; }; -export const decorators = [ - (Story: ComponentType) => { - use(setupPromise); - return ( - <ThemeProvider> - <AffineContext> - <Component /> - <Story /> - </AffineContext> - </ThemeProvider> - ); - }, - createI18nDecorator(), -]; +const withContextDecorator: Decorator = (Story, context) => { + use(setupPromise); + return ( + <ThemeProvider> + <AffineContext> + <ThemeChange /> + <Story {...context} /> + </AffineContext> + </ThemeProvider> + ); +}; + +export const decorators = [withContextDecorator, withI18n]; diff --git a/apps/storybook/package.json b/apps/storybook/package.json index b16d98302a..99cb37ed50 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -41,7 +41,8 @@ "chromatic": "^6.22.0", "react": "18.2.0", "react-dom": "18.2.0", - "storybook-addon-react-router-v6": "^2.0.4" + "storybook-addon-react-router-v6": "^2.0.4", + "vite-plugin-turbosnap": "^1.0.2" }, "peerDependencies": { "@blocksuite/blocks": "*", diff --git a/apps/storybook/src/stories/block-suite-editor.stories.tsx b/apps/storybook/src/stories/block-suite-editor.stories.tsx deleted file mode 100644 index c640ef8918..0000000000 --- a/apps/storybook/src/stories/block-suite-editor.stories.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* deepscan-disable USELESS_ARROW_FUNC_BIND */ -import { BlockHubWrapper } from '@affine/component/block-hub'; -import type { EditorProps } from '@affine/component/block-suite-editor'; -import { BlockSuiteEditor } from '@affine/component/block-suite-editor'; -import { rootBlockHubAtom } from '@affine/workspace/atom'; -import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models'; -import type { EditorContainer } from '@blocksuite/editor'; -import type { Page } from '@blocksuite/store'; -import { createMemoryStorage, Schema, Workspace } from '@blocksuite/store'; -import { expect } from '@storybook/jest'; -import type { Meta, StoryFn } from '@storybook/react'; -import { use } from 'foxact/use'; - -const schema = new Schema(); - -schema.register(AffineSchemas).register(__unstableSchemas); - -const blockSuiteWorkspace = new Workspace({ - id: 'test', - blobStorages: [createMemoryStorage], - schema, -}); - -async function initPage(page: Page) { - await page.waitForLoaded(); - // Add page block and surface block at root level - const pageBlockId = page.addBlock('affine:page', { - title: new page.Text('Hello, world!'), - }); - page.addBlock('affine:surface', {}, pageBlockId); - const frameId = page.addBlock('affine:note', {}, pageBlockId); - page.addBlock( - 'affine:paragraph', - { - text: new page.Text('This is a paragraph.'), - }, - frameId - ); - page.resetHistory(); -} - -const page = blockSuiteWorkspace.createPage('page0'); - -type BlockSuiteMeta = Meta<typeof BlockSuiteEditor>; -export default { - title: 'BlockSuite/Editor', - component: BlockSuiteEditor, -} satisfies BlockSuiteMeta; - -const Template: StoryFn<EditorProps> = (props: Partial<EditorProps>) => { - if (!page.loaded) { - use(initPage(page)); - } - return ( - <div - style={{ - height: '100vh', - width: '100vw', - overflow: 'auto', - }} - > - <BlockSuiteEditor onInit={initPage} page={page} mode="page" {...props} /> - <BlockHubWrapper - style={{ - position: 'absolute', - right: 12, - bottom: 12, - }} - blockHubAtom={rootBlockHubAtom} - /> - </div> - ); -}; - -export const Empty = Template.bind({}); -Empty.play = async ({ canvasElement }) => { - await new Promise<void>(resolve => { - setTimeout(() => resolve(), 500); - }); - const editorContainer = canvasElement.querySelector( - '[data-testid="editor-page0"]' - ) as HTMLDivElement; - expect(editorContainer).not.toBeNull(); - const editor = editorContainer.querySelector( - 'editor-container' - ) as EditorContainer; - expect(editor).not.toBeNull(); -}; - -Empty.args = { - mode: 'page', -}; diff --git a/apps/storybook/src/stories/core.stories.tsx b/apps/storybook/src/stories/core.stories.tsx index 76bb513537..d6c1278c87 100644 --- a/apps/storybook/src/stories/core.stories.tsx +++ b/apps/storybook/src/stories/core.stories.tsx @@ -24,6 +24,9 @@ const FakeApp = () => { export default { title: 'Preview/Core', + parameters: { + chromatic: { disableSnapshot: false }, + }, }; export const Index: StoryFn = () => { diff --git a/apps/storybook/src/stories/datepicker.stories.tsx b/apps/storybook/src/stories/datepicker.stories.tsx index 52490f2ff4..f69cc96359 100644 --- a/apps/storybook/src/stories/datepicker.stories.tsx +++ b/apps/storybook/src/stories/datepicker.stories.tsx @@ -1,11 +1,14 @@ import { AFFiNEDatePicker } from '@affine/component/date-picker'; -import type { StoryFn } from '@storybook/react'; +import type { Meta, StoryFn } from '@storybook/react'; import { useState } from 'react'; export default { title: 'AFFiNE/AFFiNEDatePicker', component: AFFiNEDatePicker, -}; + parameters: { + chromatic: { disableSnapshot: true }, + }, +} satisfies Meta; export const Default: StoryFn = () => { const [value, setValue] = useState<string>(new Date().toString()); diff --git a/apps/storybook/src/stories/import-page.stories.tsx b/apps/storybook/src/stories/import-page.stories.tsx index f7b4df5e16..37867a60c1 100644 --- a/apps/storybook/src/stories/import-page.stories.tsx +++ b/apps/storybook/src/stories/import-page.stories.tsx @@ -2,11 +2,12 @@ import { toast } from '@affine/component'; import { ImportPage } from '@affine/component/import-page'; import type { StoryFn } from '@storybook/react'; +import type { Meta } from '@storybook/react'; export default { title: 'AFFiNE/ImportPage', component: ImportPage, -}; +} satisfies Meta; const Template: StoryFn<typeof ImportPage> = args => <ImportPage {...args} />; diff --git a/apps/storybook/src/stories/page-list.stories.tsx b/apps/storybook/src/stories/page-list.stories.tsx index 7a9086dee3..b3ef056fc0 100644 --- a/apps/storybook/src/stories/page-list.stories.tsx +++ b/apps/storybook/src/stories/page-list.stories.tsx @@ -13,6 +13,9 @@ import { userEvent } from '@storybook/testing-library'; export default { title: 'AFFiNE/PageList', component: PageList, + parameters: { + chromatic: { disableSnapshot: true }, + }, }; export const AffineOperationCell: StoryFn<OperationCellProps> = ({ diff --git a/yarn.lock b/yarn.lock index f84fce762d..b12d1715e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -727,6 +727,7 @@ __metadata: storybook: ^7.3.1 storybook-addon-react-router-v6: ^2.0.4 storybook-dark-mode: ^3.0.1 + vite-plugin-turbosnap: ^1.0.2 wait-on: ^7.0.1 peerDependencies: "@blocksuite/blocks": "*" @@ -32465,6 +32466,13 @@ __metadata: languageName: node linkType: hard +"vite-plugin-turbosnap@npm:^1.0.2": + version: 1.0.2 + resolution: "vite-plugin-turbosnap@npm:1.0.2" + checksum: c5da204cd9fa0dbf8a5f3c151681057da0f8cec3acbec94bdc04e525d410d85bd87c46b73498ba20c487fe61a68b1486b0f88bc51fec48d7053d1f3597411231 + languageName: node + linkType: hard + "vite-tsconfig-paths@npm:^4.2.0": version: 4.2.0 resolution: "vite-tsconfig-paths@npm:4.2.0"