refactor: split storybook (#2706)

This commit is contained in:
Himself65
2023-06-07 16:55:06 +08:00
committed by GitHub
parent f4be15baec
commit c4c4ec6a67
35 changed files with 195 additions and 165 deletions

View File

@@ -1,156 +0,0 @@
import {
DeleteTemporarilyIcon,
SettingsIcon,
SidebarIcon,
} from '@blocksuite/icons';
import type { Meta, StoryFn } from '@storybook/react';
import { useAtom } from 'jotai';
import { type PropsWithChildren, useState } from 'react';
import { IconButton } from '../..';
import { AppSidebar, AppSidebarFallback, appSidebarOpenAtom } from '.';
import { AddPageButton } from './add-page-button';
import { CategoryDivider } from './category-divider';
import { navHeaderStyle, sidebarButtonStyle } from './index.css';
import { MenuLinkItem } from './menu-item';
import { QuickSearchInput } from './quick-search-input';
import {
SidebarContainer,
SidebarScrollableContainer,
} from './sidebar-containers';
export default {
title: 'Components/AppSidebar',
component: AppSidebar,
} satisfies Meta;
const Container = ({ children }: PropsWithChildren) => (
<main
style={{
position: 'relative',
width: '100vw',
height: 'calc(100vh - 40px)',
overflow: 'hidden',
display: 'flex',
flexDirection: 'row',
}}
>
{children}
</main>
);
const Main = () => {
const [open, setOpen] = useAtom(appSidebarOpenAtom);
return (
<div>
<div className={navHeaderStyle}>
{!open && (
<IconButton
className={sidebarButtonStyle}
onClick={() => {
setOpen(true);
}}
>
<SidebarIcon width={24} height={24} />
</IconButton>
)}
</div>
</div>
);
};
export const Default: StoryFn = () => {
return (
<>
<Container>
<AppSidebar />
<Main />
</Container>
</>
);
};
export const Fallback = () => {
return (
<Container>
<AppSidebarFallback />
<Main />
</Container>
);
};
export const WithItems: StoryFn = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<Container>
<AppSidebar>
<SidebarContainer>
<QuickSearchInput />
<div style={{ height: '20px' }} />
<MenuLinkItem
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Settings
</MenuLinkItem>
<MenuLinkItem
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Settings
</MenuLinkItem>
<MenuLinkItem
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Settings
</MenuLinkItem>
</SidebarContainer>
<SidebarScrollableContainer>
<CategoryDivider label="Favorites" />
<MenuLinkItem
collapsed={collapsed}
onCollapsedChange={setCollapsed}
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Collapsible Item
</MenuLinkItem>
<MenuLinkItem
collapsed={!collapsed}
onCollapsedChange={setCollapsed}
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Collapsible Item
</MenuLinkItem>
<MenuLinkItem
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Settings
</MenuLinkItem>
<CategoryDivider label="Others" />
<MenuLinkItem
icon={<DeleteTemporarilyIcon />}
href="/test"
onClick={() => alert('opened')}
>
Trash
</MenuLinkItem>
</SidebarScrollableContainer>
<SidebarContainer>
<AddPageButton />
</SidebarContainer>
</AppSidebar>
<Main />
</Container>
);
};

View File

@@ -131,7 +131,9 @@ export const AppSidebarFallback = (): ReactElement | null => {
export * from './add-page-button';
export * from './app-updater-button';
export * from './category-divider';
export * from './index.css';
export * from './menu-item';
export * from './quick-search-input';
export * from './sidebar-containers';
export * from './sidebar-header';
export { appSidebarFloatingAtom, appSidebarOpenAtom, appSidebarResizingAtom };

View File

@@ -1,126 +0,0 @@
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store';
import { createMemoryStorage, Workspace } from '@blocksuite/store';
import { expect } from '@storybook/jest';
import type { Meta, StoryFn } from '@storybook/react';
import { useState } from 'react';
import type { EditorProps } from '.';
import { BlockSuiteEditor } from '.';
const blockSuiteWorkspace = new Workspace({
id: 'test',
blobStorages: [createMemoryStorage],
});
function initPage(page: Page): void {
// 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:frame', {}, pageBlockId);
page.addBlock(
'affine:paragraph',
{
text: new page.Text('This is a paragraph.'),
},
frameId
);
page.resetHistory();
}
blockSuiteWorkspace.register(AffineSchemas).register(__unstableSchemas);
const page = blockSuiteWorkspace.createPage('page0');
initPage(page);
type BlockSuiteMeta = Meta<typeof BlockSuiteEditor>;
export default {
title: 'BlockSuite/Editor',
component: BlockSuiteEditor,
} satisfies BlockSuiteMeta;
const Template: StoryFn<EditorProps> = (props: Partial<EditorProps>) => {
return (
<div
style={{
height: '100vh',
width: '100vw',
overflow: 'auto',
}}
>
<BlockSuiteEditor onInit={initPage} page={page} mode="page" {...props} />
<div
style={{
position: 'absolute',
right: 12,
bottom: 12,
}}
id="toolWrapper"
/>
</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',
};
export const Error: StoryFn = () => {
const [props, setProps] = useState<Pick<EditorProps, 'page' | 'onInit'>>({
page: null!,
onInit: null!,
});
return (
<BlockSuiteEditor
{...props}
mode="page"
onReset={() => {
setProps({
page,
onInit: initPage,
});
}}
/>
);
};
Error.play = async ({ canvasElement }) => {
{
const editorContainer = canvasElement.querySelector(
'[data-testid="editor-page0"]'
);
expect(editorContainer).toBeNull();
}
{
const button = canvasElement.querySelector(
'[data-testid="error-fallback-reset-button"]'
) as HTMLButtonElement;
expect(button).not.toBeNull();
button.click();
await new Promise<void>(resolve => setTimeout(() => resolve(), 50));
}
{
const editorContainer = canvasElement.querySelector(
'[data-testid="editor-page0"]'
);
expect(editorContainer).not.toBeNull();
}
};

View File

@@ -1,65 +0,0 @@
import { initPage } from '@affine/env/blocksuite';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import type { Meta } from '@storybook/react';
import { BlockSuiteEditor } from '../block-suite-editor';
import { ImagePreviewModal } from '.';
export default {
title: 'Component/ImagePreviewModal',
component: ImagePreviewModal,
} satisfies Meta;
const workspace = createEmptyBlockSuiteWorkspace(
'test',
WorkspaceFlavour.LOCAL
);
const page = workspace.createPage('page0');
initPage(page);
fetch(new URL('@affine-test/fixtures/large-image.png', import.meta.url))
.then(res => res.arrayBuffer())
.then(async buffer => {
const id = await workspace.blobs.set(
new Blob([buffer], { type: 'image/png' })
);
const frameId = page.getBlockByFlavour('affine:frame')[0].id;
page.addBlock(
'affine:paragraph',
{
text: new page.Text('Please double click the image to preview it.'),
},
frameId
);
page.addBlock(
'affine:embed',
{
sourceId: id,
},
frameId
);
});
export const Default = () => {
return (
<>
<div
style={{
height: '100vh',
width: '100vw',
overflow: 'auto',
}}
>
<BlockSuiteEditor mode="page" page={page} onInit={initPage} />
</div>
<div
style={{
position: 'absolute',
right: 12,
bottom: 12,
}}
id="toolWrapper"
/>
</>
);
};

View File

@@ -1,200 +0,0 @@
import type { Meta } from '@storybook/react';
import { useAtomValue, useSetAtom } from 'jotai';
import { NotificationCenter, pushNotificationAtom } from '.';
import { expandNotificationCenterAtom } from './index.jotai';
export default {
title: 'AFFiNE/NotificationCenter',
component: NotificationCenter,
} satisfies Meta<typeof NotificationCenter>;
let id = 0;
export const Basic = () => {
const push = useSetAtom(pushNotificationAtom);
const expand = useAtomValue(expandNotificationCenterAtom);
return (
<>
<div>{expand ? 'expanded' : 'collapsed'}</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: `${key} message`,
timeout: 3000,
progressingBar: true,
undo: async () => {
console.log('undo');
},
type: 'info',
});
}}
>
Push timeout notification
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: `${key} message`,
type: 'info',
});
}}
>
Push notification with no timeout
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'info',
});
}}
>
Push notification with no message
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'success',
theme: 'light',
});
}}
>
light success
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'success',
theme: 'dark',
});
}}
>
dark success
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'info',
theme: 'light',
});
}}
>
light info
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'info',
theme: 'dark',
});
}}
>
dark info
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'warning',
theme: 'light',
});
}}
>
light warning
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'warning',
theme: 'dark',
});
}}
>
dark warning
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'error',
theme: 'light',
});
}}
>
light error
</button>
</div>
<div>
<button
onClick={() => {
const key = id++;
push({
key: `${key}`,
title: `${key} title`,
message: ``,
type: 'error',
theme: 'dark',
});
}}
>
dark error
</button>
</div>
<NotificationCenter />
</>
);
};

View File

@@ -26,8 +26,11 @@ import {
removeNotificationAtom,
} from './index.jotai';
// only expose necessary function atom to avoid misuse
export { pushNotificationAtom, removeNotificationAtom };
export {
expandNotificationCenterAtom,
pushNotificationAtom,
removeNotificationAtom,
};
type Height = {
height: number;
notificationKey: number | string;

View File

@@ -1,12 +0,0 @@
import type { Meta } from '@storybook/react';
import { PageDetailSkeleton } from '.';
export default {
title: 'AFFiNE/PageDetailSkeleton',
component: PageDetailSkeleton,
} satisfies Meta<typeof PageDetailSkeleton>;
export const Basic = () => {
return <PageDetailSkeleton />;
};

View File

@@ -1,73 +0,0 @@
import { WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { arrayMove } from '@dnd-kit/sortable';
import type { Meta } from '@storybook/react';
import { useState } from 'react';
import type { WorkspaceListProps } from './index';
import { WorkspaceList } from './index';
export default {
title: 'AFFiNE/WorkspaceList',
component: WorkspaceList,
} satisfies Meta<WorkspaceListProps>;
export const Default = () => {
const [items, setItems] = useState(() => {
const items = [
{
id: '1',
flavour: WorkspaceFlavour.LOCAL,
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace(
'1',
WorkspaceFlavour.LOCAL
),
providers: [],
},
{
id: '2',
flavour: WorkspaceFlavour.LOCAL,
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace(
'2',
WorkspaceFlavour.LOCAL
),
providers: [],
},
{
id: '3',
flavour: WorkspaceFlavour.LOCAL,
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace(
'3',
WorkspaceFlavour.LOCAL
),
providers: [],
},
] satisfies WorkspaceListProps['items'];
items.forEach(item => {
item.blockSuiteWorkspace.meta.setName(item.id);
});
return items;
});
return (
<WorkspaceList
currentWorkspaceId={null}
items={items}
onClick={() => {}}
onSettingClick={() => {}}
onDragEnd={event => {
const { active, over } = event;
if (active.id !== over?.id) {
setItems(items => {
const oldIndex = items.findIndex(item => item.id === active.id);
const newIndex = items.findIndex(item => item.id === over?.id);
return arrayMove(items, oldIndex, newIndex);
});
}
}}
/>
);
};