mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-09 13:15:51 +08:00
feat(storybook): improve code (#3786)
This commit is contained in:
@@ -34,5 +34,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
workingDir: apps/storybook
|
workingDir: apps/storybook
|
||||||
buildScriptName: build
|
buildScriptName: build
|
||||||
onlyStoryNames: 'Preview/**'
|
onlyChanged: true
|
||||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { mergeConfig } from 'vite';
|
|||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||||
import { getRuntimeConfig } from '../../core/.webpack/runtime-config';
|
import { getRuntimeConfig } from '../../core/.webpack/runtime-config';
|
||||||
|
import turbosnap from 'vite-plugin-turbosnap';
|
||||||
|
|
||||||
runCli(
|
runCli(
|
||||||
{
|
{
|
||||||
@@ -33,7 +34,7 @@ export default {
|
|||||||
framework: {
|
framework: {
|
||||||
name: '@storybook/react-vite',
|
name: '@storybook/react-vite',
|
||||||
},
|
},
|
||||||
async viteFinal(config, _) {
|
async viteFinal(config, { configType }) {
|
||||||
return mergeConfig(config, {
|
return mergeConfig(config, {
|
||||||
assetsInclude: ['**/*.md'],
|
assetsInclude: ['**/*.md'],
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -41,6 +42,9 @@ export default {
|
|||||||
tsconfigPaths({
|
tsconfigPaths({
|
||||||
root: fileURLToPath(new URL('../../../', import.meta.url)),
|
root: fileURLToPath(new URL('../../../', import.meta.url)),
|
||||||
}),
|
}),
|
||||||
|
configType === 'PRODUCTION'
|
||||||
|
? turbosnap({ rootDir: config.root ?? process.cwd() })
|
||||||
|
: null,
|
||||||
],
|
],
|
||||||
define: {
|
define: {
|
||||||
'process.env': {},
|
'process.env': {},
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import '@affine/component/theme/theme.css';
|
|||||||
import '@toeverything/components/style.css';
|
import '@toeverything/components/style.css';
|
||||||
import { createI18n } from '@affine/i18n';
|
import { createI18n } from '@affine/i18n';
|
||||||
import { ThemeProvider, useTheme } from 'next-themes';
|
import { ThemeProvider, useTheme } from 'next-themes';
|
||||||
import type { ComponentType } from 'react';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { useDarkMode } from 'storybook-dark-mode';
|
import { useDarkMode } from 'storybook-dark-mode';
|
||||||
import { setup } from '@affine/core/bootstrap/setup';
|
import { setup } from '@affine/core/bootstrap/setup';
|
||||||
import { AffineContext } from '@affine/component/context';
|
import { AffineContext } from '@affine/component/context';
|
||||||
import { use } from 'foxact/use';
|
import { use } from 'foxact/use';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import type { Decorator } from '@storybook/react';
|
||||||
|
|
||||||
const setupPromise = setup();
|
const setupPromise = setup();
|
||||||
|
|
||||||
@@ -24,38 +24,42 @@ export const parameters = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const createI18nDecorator = () => {
|
const i18n = createI18n();
|
||||||
const i18n = createI18n();
|
const withI18n: Decorator = (Story, context) => {
|
||||||
const withI18n = (Story: any, context: any) => {
|
const locale = context.globals.locale;
|
||||||
const locale = context.globals.locale;
|
useSWR(
|
||||||
useEffect(() => {
|
locale,
|
||||||
i18n.changeLanguage(locale);
|
async () => {
|
||||||
}, [locale]);
|
await i18n.changeLanguage(locale);
|
||||||
return <Story {...context} />;
|
},
|
||||||
};
|
{
|
||||||
return withI18n;
|
suspense: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return <Story {...context} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Component = () => {
|
const ThemeChange = () => {
|
||||||
const isDark = useDarkMode();
|
const isDark = useDarkMode();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
useEffect(() => {
|
if (theme.resolvedTheme === 'dark' && !isDark) {
|
||||||
theme.setTheme(isDark ? 'dark' : 'light');
|
theme.setTheme('light');
|
||||||
}, [isDark]);
|
} else if (theme.resolvedTheme === 'light' && isDark) {
|
||||||
|
theme.setTheme('dark');
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const decorators = [
|
const withContextDecorator: Decorator = (Story, context) => {
|
||||||
(Story: ComponentType) => {
|
use(setupPromise);
|
||||||
use(setupPromise);
|
return (
|
||||||
return (
|
<ThemeProvider>
|
||||||
<ThemeProvider>
|
<AffineContext>
|
||||||
<AffineContext>
|
<ThemeChange />
|
||||||
<Component />
|
<Story {...context} />
|
||||||
<Story />
|
</AffineContext>
|
||||||
</AffineContext>
|
</ThemeProvider>
|
||||||
</ThemeProvider>
|
);
|
||||||
);
|
};
|
||||||
},
|
|
||||||
createI18nDecorator(),
|
export const decorators = [withContextDecorator, withI18n];
|
||||||
];
|
|
||||||
|
|||||||
@@ -41,7 +41,8 @@
|
|||||||
"chromatic": "^6.22.0",
|
"chromatic": "^6.22.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "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": {
|
"peerDependencies": {
|
||||||
"@blocksuite/blocks": "*",
|
"@blocksuite/blocks": "*",
|
||||||
|
|||||||
@@ -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',
|
|
||||||
};
|
|
||||||
@@ -24,6 +24,9 @@ const FakeApp = () => {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Preview/Core',
|
title: 'Preview/Core',
|
||||||
|
parameters: {
|
||||||
|
chromatic: { disableSnapshot: false },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Index: StoryFn = () => {
|
export const Index: StoryFn = () => {
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { AFFiNEDatePicker } from '@affine/component/date-picker';
|
import { AFFiNEDatePicker } from '@affine/component/date-picker';
|
||||||
import type { StoryFn } from '@storybook/react';
|
import type { Meta, StoryFn } from '@storybook/react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'AFFiNE/AFFiNEDatePicker',
|
title: 'AFFiNE/AFFiNEDatePicker',
|
||||||
component: AFFiNEDatePicker,
|
component: AFFiNEDatePicker,
|
||||||
};
|
parameters: {
|
||||||
|
chromatic: { disableSnapshot: true },
|
||||||
|
},
|
||||||
|
} satisfies Meta;
|
||||||
|
|
||||||
export const Default: StoryFn = () => {
|
export const Default: StoryFn = () => {
|
||||||
const [value, setValue] = useState<string>(new Date().toString());
|
const [value, setValue] = useState<string>(new Date().toString());
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
import { toast } from '@affine/component';
|
import { toast } from '@affine/component';
|
||||||
import { ImportPage } from '@affine/component/import-page';
|
import { ImportPage } from '@affine/component/import-page';
|
||||||
import type { StoryFn } from '@storybook/react';
|
import type { StoryFn } from '@storybook/react';
|
||||||
|
import type { Meta } from '@storybook/react';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'AFFiNE/ImportPage',
|
title: 'AFFiNE/ImportPage',
|
||||||
component: ImportPage,
|
component: ImportPage,
|
||||||
};
|
} satisfies Meta;
|
||||||
|
|
||||||
const Template: StoryFn<typeof ImportPage> = args => <ImportPage {...args} />;
|
const Template: StoryFn<typeof ImportPage> = args => <ImportPage {...args} />;
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import { userEvent } from '@storybook/testing-library';
|
|||||||
export default {
|
export default {
|
||||||
title: 'AFFiNE/PageList',
|
title: 'AFFiNE/PageList',
|
||||||
component: PageList,
|
component: PageList,
|
||||||
|
parameters: {
|
||||||
|
chromatic: { disableSnapshot: true },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AffineOperationCell: StoryFn<OperationCellProps> = ({
|
export const AffineOperationCell: StoryFn<OperationCellProps> = ({
|
||||||
|
|||||||
@@ -727,6 +727,7 @@ __metadata:
|
|||||||
storybook: ^7.3.1
|
storybook: ^7.3.1
|
||||||
storybook-addon-react-router-v6: ^2.0.4
|
storybook-addon-react-router-v6: ^2.0.4
|
||||||
storybook-dark-mode: ^3.0.1
|
storybook-dark-mode: ^3.0.1
|
||||||
|
vite-plugin-turbosnap: ^1.0.2
|
||||||
wait-on: ^7.0.1
|
wait-on: ^7.0.1
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@blocksuite/blocks": "*"
|
"@blocksuite/blocks": "*"
|
||||||
@@ -32465,6 +32466,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"vite-tsconfig-paths@npm:^4.2.0":
|
||||||
version: 4.2.0
|
version: 4.2.0
|
||||||
resolution: "vite-tsconfig-paths@npm:4.2.0"
|
resolution: "vite-tsconfig-paths@npm:4.2.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user