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 ;
- };
- 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 ;
};
-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 (
-
-
-
-
-
-
- );
- },
- createI18nDecorator(),
-];
+const withContextDecorator: Decorator = (Story, context) => {
+ use(setupPromise);
+ return (
+
+
+
+
+
+
+ );
+};
+
+export const decorators = [withContextDecorator, withI18n];
diff --git a/apps/storybook/package.json b/apps/storybook/package.json
index 3af827bffb..e7127d2497 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;
-export default {
- title: 'BlockSuite/Editor',
- component: BlockSuiteEditor,
-} satisfies BlockSuiteMeta;
-
-const Template: StoryFn = (props: Partial) => {
- if (!page.loaded) {
- use(initPage(page));
- }
- return (
-
-
-
-
- );
-};
-
-export const Empty = Template.bind({});
-Empty.play = async ({ canvasElement }) => {
- await new Promise(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(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 = 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 = ({
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"