Co-authored-by: Simon He <57086651+Simon-He95@users.noreply.github.com>
237 lines
7.3 KiB
TypeScript
237 lines
7.3 KiB
TypeScript
import { Empty } from '@affine/component';
|
|
import type { ListData, TrashListData } from '@affine/component/page-list';
|
|
import {
|
|
filterByFilterList,
|
|
PageList,
|
|
PageListTrashView,
|
|
} from '@affine/component/page-list';
|
|
import type { View } from '@affine/env/filter';
|
|
import { Trans } from '@affine/i18n';
|
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
|
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
|
import type { PageMeta } from '@blocksuite/store';
|
|
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
|
import { getPagePreviewText } from '@toeverything/hooks/use-block-suite-page-preview';
|
|
import { useAtom } from 'jotai';
|
|
import type React from 'react';
|
|
import { useMemo } from 'react';
|
|
|
|
import { allPageModeSelectAtom } from '../../../atoms';
|
|
import { useBlockSuiteMetaHelper } from '../../../hooks/affine/use-block-suite-meta-helper';
|
|
import type { BlockSuiteWorkspace } from '../../../shared';
|
|
import { toast } from '../../../utils';
|
|
import { emptyDescButton, emptyDescKbd, pageListEmptyStyle } from './index.css';
|
|
import { usePageHelper } from './utils';
|
|
|
|
export type BlockSuitePageListProps = {
|
|
blockSuiteWorkspace: BlockSuiteWorkspace;
|
|
listType: 'all' | 'trash' | 'shared' | 'public';
|
|
isPublic?: true;
|
|
onOpenPage: (pageId: string, newTab?: boolean) => void;
|
|
view?: View;
|
|
};
|
|
|
|
const filter = {
|
|
all: (pageMeta: PageMeta) => !pageMeta.trash,
|
|
public: (pageMeta: PageMeta) => !pageMeta.trash,
|
|
trash: (pageMeta: PageMeta, allMetas: PageMeta[]) => {
|
|
const parentMeta = allMetas.find(m => m.subpageIds?.includes(pageMeta.id));
|
|
return !parentMeta?.trash && pageMeta.trash;
|
|
},
|
|
shared: (pageMeta: PageMeta) => pageMeta.isPublic && !pageMeta.trash,
|
|
};
|
|
|
|
const PageListEmpty = (props: {
|
|
createPage?: () => void;
|
|
listType: BlockSuitePageListProps['listType'];
|
|
}) => {
|
|
const { listType, createPage } = props;
|
|
const t = useAFFiNEI18N();
|
|
|
|
const getEmptyDescription = () => {
|
|
if (listType === 'all') {
|
|
const CreateNewPageButton = () => (
|
|
<button className={emptyDescButton} onClick={createPage}>
|
|
New Page
|
|
</button>
|
|
);
|
|
if (environment.isDesktop) {
|
|
const shortcut = environment.isMacOs ? '⌘ + N' : 'Ctrl + N';
|
|
return (
|
|
<Trans i18nKey="emptyAllPagesClient">
|
|
Click on the <CreateNewPageButton /> button Or press
|
|
<kbd className={emptyDescKbd}>{{ shortcut } as any}</kbd> to create
|
|
your first page.
|
|
</Trans>
|
|
);
|
|
}
|
|
return (
|
|
<Trans i18nKey="emptyAllPages">
|
|
Click on the
|
|
<CreateNewPageButton />
|
|
button to create your first page.
|
|
</Trans>
|
|
);
|
|
}
|
|
if (listType === 'trash') {
|
|
return t['emptyTrash']();
|
|
}
|
|
if (listType === 'shared') {
|
|
return t['emptySharedPages']();
|
|
}
|
|
return;
|
|
};
|
|
|
|
return (
|
|
<div className={pageListEmptyStyle}>
|
|
<Empty
|
|
title={t['com.affine.emptyDesc']()}
|
|
description={getEmptyDescription()}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const BlockSuitePageList: React.FC<BlockSuitePageListProps> = ({
|
|
blockSuiteWorkspace,
|
|
onOpenPage,
|
|
listType,
|
|
isPublic = false,
|
|
view,
|
|
}) => {
|
|
const pageMetas = useBlockSuitePageMeta(blockSuiteWorkspace);
|
|
const {
|
|
toggleFavorite,
|
|
removeToTrash,
|
|
restoreFromTrash,
|
|
permanentlyDeletePage,
|
|
cancelPublicPage,
|
|
} = useBlockSuiteMetaHelper(blockSuiteWorkspace);
|
|
const [filterMode] = useAtom(allPageModeSelectAtom);
|
|
const { createPage, createEdgeless, importFile, isPreferredEdgeless } =
|
|
usePageHelper(blockSuiteWorkspace);
|
|
const t = useAFFiNEI18N();
|
|
const list = useMemo(
|
|
() =>
|
|
pageMetas
|
|
.filter(pageMeta => {
|
|
if (filterMode === 'all') {
|
|
return true;
|
|
}
|
|
if (filterMode === 'edgeless') {
|
|
return isPreferredEdgeless(pageMeta.id);
|
|
}
|
|
if (filterMode === 'page') {
|
|
return !isPreferredEdgeless(pageMeta.id);
|
|
}
|
|
console.error('unknown filter mode', pageMeta, filterMode);
|
|
return true;
|
|
})
|
|
.filter(pageMeta => {
|
|
if (!filter[listType](pageMeta, pageMetas)) {
|
|
return false;
|
|
}
|
|
if (!view) {
|
|
return true;
|
|
}
|
|
return filterByFilterList(view.filterList, {
|
|
'Is Favourited': !!pageMeta.favorite,
|
|
Created: pageMeta.createDate,
|
|
Updated: pageMeta.updatedDate ?? pageMeta.createDate,
|
|
});
|
|
}),
|
|
[pageMetas, filterMode, isPreferredEdgeless, listType, view]
|
|
);
|
|
|
|
if (listType === 'trash') {
|
|
const pageList: TrashListData[] = list.map(pageMeta => {
|
|
const page = blockSuiteWorkspace.getPage(pageMeta.id);
|
|
const preview = page ? getPagePreviewText(page) : undefined;
|
|
return {
|
|
icon: isPreferredEdgeless(pageMeta.id) ? (
|
|
<EdgelessIcon />
|
|
) : (
|
|
<PageIcon />
|
|
),
|
|
pageId: pageMeta.id,
|
|
title: pageMeta.title,
|
|
preview,
|
|
createDate: new Date(pageMeta.createDate),
|
|
trashDate: pageMeta.trashDate
|
|
? new Date(pageMeta.trashDate)
|
|
: undefined,
|
|
onClickPage: () => onOpenPage(pageMeta.id),
|
|
onClickRestore: () => {
|
|
restoreFromTrash(pageMeta.id);
|
|
},
|
|
onRestorePage: () => {
|
|
restoreFromTrash(pageMeta.id);
|
|
toast(t['restored']({ title: pageMeta.title || 'Untitled' }));
|
|
},
|
|
onPermanentlyDeletePage: () => {
|
|
permanentlyDeletePage(pageMeta.id);
|
|
toast(t['Permanently deleted']());
|
|
},
|
|
};
|
|
});
|
|
return (
|
|
<PageListTrashView
|
|
list={pageList}
|
|
fallback={<PageListEmpty listType={listType} />}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const pageList: ListData[] = list.map(pageMeta => {
|
|
const page = blockSuiteWorkspace.getPage(pageMeta.id);
|
|
const preview = page ? getPagePreviewText(page) : undefined;
|
|
return {
|
|
icon: isPreferredEdgeless(pageMeta.id) ? <EdgelessIcon /> : <PageIcon />,
|
|
pageId: pageMeta.id,
|
|
title: pageMeta.title,
|
|
preview,
|
|
favorite: !!pageMeta.favorite,
|
|
isPublicPage: !!pageMeta.isPublic,
|
|
createDate: new Date(pageMeta.createDate),
|
|
updatedDate: new Date(pageMeta.updatedDate ?? pageMeta.createDate),
|
|
onClickPage: () => onOpenPage(pageMeta.id),
|
|
onOpenPageInNewTab: () => onOpenPage(pageMeta.id, true),
|
|
onClickRestore: () => {
|
|
restoreFromTrash(pageMeta.id);
|
|
},
|
|
removeToTrash: () => {
|
|
removeToTrash(pageMeta.id);
|
|
toast(t['Successfully deleted']());
|
|
},
|
|
onRestorePage: () => {
|
|
restoreFromTrash(pageMeta.id);
|
|
toast(t['restored']({ title: pageMeta.title || 'Untitled' }));
|
|
},
|
|
bookmarkPage: () => {
|
|
const status = pageMeta.favorite;
|
|
toggleFavorite(pageMeta.id);
|
|
toast(
|
|
status ? t['Removed from Favorites']() : t['Added to Favorites']()
|
|
);
|
|
},
|
|
onDisablePublicSharing: () => {
|
|
cancelPublicPage(pageMeta.id);
|
|
toast('Successfully disabled', {
|
|
portal: document.body,
|
|
});
|
|
},
|
|
};
|
|
});
|
|
|
|
return (
|
|
<PageList
|
|
onCreateNewPage={createPage}
|
|
onCreateNewEdgeless={createEdgeless}
|
|
onImportFile={importFile}
|
|
isPublicWorkspace={isPublic}
|
|
list={pageList}
|
|
fallback={<PageListEmpty createPage={createPage} listType={listType} />}
|
|
/>
|
|
);
|
|
};
|