feat: new collections (#4530)

Co-authored-by: Peng Xiao <pengxiao@outlook.com>
This commit is contained in:
3720
2023-10-27 17:06:59 +08:00
committed by GitHub
parent 9fc0152cb1
commit ef8024c657
133 changed files with 8382 additions and 3743 deletions
@@ -59,6 +59,6 @@ export const Basic: StoryFn<typeof Checkbox> = props => {
Basic.args = {
checked: true,
disabled: false,
intermediate: false,
indeterminate: false,
onChange: console.log,
};
+233 -154
View File
@@ -1,22 +1,30 @@
import { Empty, toast } from '@affine/component';
import type { OperationCellProps } from '@affine/component/page-list';
import { toast } from '@affine/component';
import {
FloatingToolbar,
NewPageButton,
OperationCell,
type OperationCellProps,
PageList,
PageListTrashView,
PageListItem,
type PageListItemProps,
type PageListProps,
PageListScrollContainer,
PageTags,
type PageTagsProps,
} from '@affine/component/page-list';
import type { Collection } from '@affine/env/filter';
import { PageIcon } from '@blocksuite/icons';
import { expect } from '@storybook/jest';
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
import { PageIcon, TagsIcon } from '@blocksuite/icons';
import { Schema, Workspace } from '@blocksuite/store';
import type { Meta, StoryFn } from '@storybook/react';
import { userEvent } from '@storybook/testing-library';
import { atom } from 'jotai';
import { initEmptyPage } from '@toeverything/infra/blocksuite';
import { useState } from 'react';
import { withRouter } from 'storybook-addon-react-router-v6';
export default {
title: 'AFFiNE/PageList',
component: PageList,
parameters: {
layout: 'fullscreen',
chromatic: { disableSnapshot: true },
},
} satisfies Meta;
@@ -30,7 +38,6 @@ AffineOperationCell.args = {
isPublic: true,
onToggleFavoritePage: () => toast('Toggle favorite page'),
onDisablePublicSharing: () => toast('Disable public sharing'),
onOpenPageInNewTab: () => toast('Open page in new tab'),
onRemoveToTrash: () => toast('Remove to trash'),
};
AffineOperationCell.play = async ({ canvasElement }) => {
@@ -59,163 +66,235 @@ AffineNewPageButton.play = async ({ canvasElement }) => {
await userEvent.click(dropdown);
};
export const AffineAllPageList: StoryFn<typeof PageList> = ({ ...props }) => (
<PageList {...props} />
const testTags = [
{
color: 'red',
id: 'test-tag-id-0',
value: 'foo',
},
{
color: 'pink',
id: 'test-tag-id-1',
value: 'bar',
},
{
color: 'purple',
id: 'test-tag-id-2',
value: 'foobar',
},
{
color: 'black',
id: 'test-tag-id-3',
value: 'affine',
},
{
color: 'orange',
id: 'test-tag-id-4',
value: 'blocksuite',
},
{
color: 'yellow',
id: 'test-tag-id-5',
value: 'toeverything',
},
{
color: 'green',
id: 'test-tag-id-6',
value: 'toeverything',
},
{
color: 'blue',
id: 'test-tag-id-7',
value: 'toeverything',
},
{
color: 'indigo',
id: 'test-tag-id-8',
value: 'toeverything',
},
{
color: 'teal',
id: 'test-tag-id-9',
value: 'toeverything',
},
{
color: 'cyan',
id: 'test-tag-id-10',
value: 'toeverything',
},
{
color: 'gray',
id: 'test-tag-id-11',
value: 'toeverything',
},
{
color: 'red',
id: 'test-tag-id-12',
value: 'toeverything',
},
];
export const ListItem: StoryFn<PageListItemProps> = props => (
<PageListItem {...props}></PageListItem>
);
const baseAtom = atom<Collection[]>([]);
AffineAllPageList.args = {
isPublicWorkspace: false,
onCreateNewPage: () => toast('Create new page'),
onCreateNewEdgeless: () => toast('Create new edgeless'),
onImportFile: () => toast('Import file'),
collectionsAtom: atom(
get => get(baseAtom),
async (_, set, update) => {
set(baseAtom, update);
}
),
list: [
{
pageId: '1',
favorite: false,
icon: <PageIcon />,
isPublicPage: true,
title: 'Last Page',
tags: [],
preview: 'this is page preview',
createDate: new Date('2021-01-01'),
updatedDate: new Date('2023-08-15'),
bookmarkPage: () => toast('Bookmark page'),
onClickPage: () => toast('Click page'),
onDisablePublicSharing: () => toast('Disable public sharing'),
onOpenPageInNewTab: () => toast('Open page in new tab'),
removeToTrash: () => toast('Remove to trash'),
},
{
pageId: '3',
favorite: false,
icon: <PageIcon />,
isPublicPage: true,
title:
'1 Example Public Page with long title that will be truncated because it is too too long',
tags: [],
preview:
'this is page preview and it is very long and will be truncated because it is too long and it is very long and will be truncated because it is too long',
createDate: new Date('2021-01-01'),
updatedDate: new Date('2021-01-02'),
bookmarkPage: () => toast('Bookmark page'),
onClickPage: () => toast('Click page'),
onDisablePublicSharing: () => toast('Disable public sharing'),
onOpenPageInNewTab: () => toast('Open page in new tab'),
removeToTrash: () => toast('Remove to trash'),
},
{
pageId: '2',
favorite: true,
isPublicPage: false,
icon: <PageIcon />,
title: '2 Favorited Page 2021',
tags: [],
createDate: new Date('2021-01-02'),
updatedDate: new Date('2021-01-01'),
bookmarkPage: () => toast('Bookmark page'),
onClickPage: () => toast('Click page'),
onDisablePublicSharing: () => toast('Disable public sharing'),
onOpenPageInNewTab: () => toast('Open page in new tab'),
removeToTrash: () => toast('Remove to trash'),
},
{
pageId: '4',
favorite: false,
isPublicPage: false,
icon: <PageIcon />,
title: 'page created in 2023-04-01',
tags: [],
createDate: new Date('2023-04-01'),
updatedDate: new Date('2023-04-01'),
bookmarkPage: () => toast('Bookmark page'),
onClickPage: () => toast('Click page'),
onDisablePublicSharing: () => toast('Disable public sharing'),
onOpenPageInNewTab: () => toast('Open page in new tab'),
removeToTrash: () => toast('Remove to trash'),
},
],
ListItem.args = {
pageId: 'test-page-id',
title: 'Test Page Title',
preview:
'this is page preview and it is very long and will be truncated because it is too long and it is very long and will be truncated because it is too long',
icon: <PageIcon />,
to: '/hello',
selectable: true,
createDate: new Date('2021-01-01'),
updatedDate: new Date('2023-08-15'),
draggable: true,
tags: testTags,
selected: true,
};
export const AffineEmptyAllPageList: StoryFn<typeof PageList> = ({
...props
}) => <PageList {...props} />;
ListItem.decorators = [withRouter];
AffineEmptyAllPageList.args = {
isPublicWorkspace: false,
onCreateNewPage: () => toast('Create new page'),
onCreateNewEdgeless: () => toast('Create new edgeless'),
onImportFile: () => toast('Import file'),
list: [],
fallback: (
<Empty
title="Empty"
description={
<div>
empty description, click{' '}
<button
onClick={() => {
toast('click');
}}
>
button
</button>
</div>
}
/>
),
export const ListItemTags: StoryFn<PageTagsProps> = props => (
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<div style={{ width: '300px' }}>
<PageTags {...props}></PageTags>
</div>
</div>
);
ListItemTags.args = {
tags: testTags,
hoverExpandDirection: 'left',
widthOnHover: 600,
maxItems: 5,
};
export const AffinePublicPageList: StoryFn<typeof PageList> = ({
...props
}) => <PageList {...props} />;
AffinePublicPageList.args = {
...AffineAllPageList.args,
isPublicWorkspace: true,
export const PageListStory: StoryFn<PageListProps> = (props, { loaded }) => {
return (
<PageListScrollContainer
style={{
height: '100vh',
}}
>
<PageList {...props} {...loaded}></PageList>
</PageListScrollContainer>
);
};
export const AffineAllPageMobileList: StoryFn<typeof PageList> = ({
...props
}) => <PageList {...props} />;
PageListStory.args = {
groupBy: 'createDate',
};
AffineAllPageMobileList.args = AffineAllPageList.args;
AffineAllPageMobileList.parameters = {
viewport: {
defaultViewport: 'mobile2',
PageListStory.argTypes = {
selectable: {
control: 'radio',
options: [true, 'toggle', false],
},
hideHeader: {
type: 'boolean',
},
};
export const AffineTrashPageList: StoryFn<typeof PageListTrashView> = ({
...props
}) => <PageListTrashView {...props} />;
async function createAndInitPage(
workspace: Workspace,
title: string,
preview: string
) {
const page = workspace.createPage();
await initEmptyPage(page, title);
page.getBlockByFlavour('affine:paragraph').at(0)?.text?.insert(preview, 0);
return page;
}
AffineTrashPageList.args = {
list: [
{
pageId: '1',
icon: <PageIcon />,
title: 'Example Page',
preview: 'this is trash page preview',
createDate: new Date('2021-01-01'),
trashDate: new Date('2021-01-01'),
onClickPage: () => toast('Click page'),
onPermanentlyDeletePage: () => toast('Permanently delete page'),
onRestorePage: () => toast('Restore page'),
},
{
pageId: '2',
icon: <PageIcon />,
title: 'Example Page with long title that will be truncated',
createDate: new Date('2021-01-01'),
onClickPage: () => toast('Click page'),
onPermanentlyDeletePage: () => toast('Permanently delete page'),
onRestorePage: () => toast('Restore page'),
},
],
PageListStory.loaders = [
async () => {
const schema = new Schema();
schema.register(AffineSchemas).register(__unstableSchemas);
const workspace = new Workspace({
id: 'test-workspace-id',
schema,
});
workspace.meta.setProperties({
tags: {
options: structuredClone(testTags),
},
});
const page1 = await createAndInitPage(
workspace,
'This is page 1',
'Hello World from page 1'
);
const page2 = await createAndInitPage(
workspace,
'This is page 2',
'Hello World from page 2'
);
const page3 = await createAndInitPage(
workspace,
'This is page 3',
'Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3'
);
await createAndInitPage(
workspace,
'This is page 4',
'Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3'
);
page1.meta.createDate = new Date('2021-01-01').getTime();
page2.meta.createDate = page2.meta.createDate - 3600 * 1000 * 24;
page3.meta.createDate = page3.meta.createDate - 3600 * 1000 * 24 * 7;
workspace.meta.pageMetas[3].tags = testTags.slice(0, 3).map(t => t.id);
workspace.meta.pageMetas[2].tags = testTags.slice(0, 12).map(t => t.id);
return {
blockSuiteWorkspace: workspace,
pages: workspace.meta.pages,
};
},
];
export const FloatingToolbarStory: StoryFn<typeof FloatingToolbar> = props => {
const [open, setOpen] = useState(false);
return (
<div
style={{
height: '100vh',
overflow: 'auto',
}}
>
<button
style={{
border: '1px solid black',
padding: '10px',
}}
onClick={() => setOpen(o => !o)}
>
{open ? 'hide' : 'show'}
</button>
<FloatingToolbar
style={{ position: 'fixed', bottom: '20px', width: '100%' }}
{...props}
open={open}
onOpenChange={setOpen}
>
<FloatingToolbar.Item>10 Selected</FloatingToolbar.Item>
<FloatingToolbar.Separator />
<FloatingToolbar.Button
icon={<TagsIcon />}
label="Add Tags"
onClick={console.log}
/>
<FloatingToolbar.Button
icon={<TagsIcon />}
label="Add Tags"
onClick={console.log}
/>
</FloatingToolbar>
</div>
);
};