mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 04:48:53 +00:00
refactor(component): virtual rendering page list (#4775)
Co-authored-by: Joooye_34 <Joooye1991@gmail.com>
This commit is contained in:
@@ -24,6 +24,6 @@ export const workspaceType = style({
|
||||
});
|
||||
|
||||
export const scrollbar = style({
|
||||
transform: 'translateX(10px)',
|
||||
transform: 'translateX(8px)',
|
||||
width: '4px',
|
||||
});
|
||||
|
||||
@@ -15,6 +15,8 @@ export const scrollContainer = style({
|
||||
});
|
||||
|
||||
export const allPagesHeader = style({
|
||||
height: 100,
|
||||
alignItems: 'center',
|
||||
padding: '48px 16px 20px 24px',
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
@@ -23,7 +25,7 @@ export const allPagesHeader = style({
|
||||
});
|
||||
|
||||
export const allPagesHeaderTitle = style({
|
||||
fontSize: 'var(--affine-font-h-3)',
|
||||
fontSize: 'var(--affine-font-h-5)',
|
||||
fontWeight: 500,
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
display: 'flex',
|
||||
|
||||
@@ -4,10 +4,9 @@ import {
|
||||
FloatingToolbar,
|
||||
NewPageButton as PureNewPageButton,
|
||||
OperationCell,
|
||||
PageList,
|
||||
type PageListHandle,
|
||||
PageListScrollContainer,
|
||||
useCollectionManager,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/component/page-list';
|
||||
import { WorkspaceFlavour, WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { Trans } from '@affine/i18n';
|
||||
@@ -27,7 +26,6 @@ import clsx from 'clsx';
|
||||
import {
|
||||
type PropsWithChildren,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
@@ -145,19 +143,12 @@ const usePageOperationsRenderer = () => {
|
||||
const PageListFloatingToolbar = ({
|
||||
selectedIds,
|
||||
onClose,
|
||||
open,
|
||||
}: {
|
||||
open: boolean;
|
||||
selectedIds: string[];
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const open = selectedIds.length > 0;
|
||||
const handleOpenChange = useCallback(
|
||||
(open: boolean) => {
|
||||
if (!open) {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { setTrashModal } = useTrashModalHelper(
|
||||
currentWorkspace.blockSuiteWorkspace
|
||||
@@ -177,11 +168,7 @@ const PageListFloatingToolbar = ({
|
||||
}, [pageMetas, selectedIds, setTrashModal]);
|
||||
|
||||
return (
|
||||
<FloatingToolbar
|
||||
className={styles.floatingToolbar}
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
>
|
||||
<FloatingToolbar className={styles.floatingToolbar} open={open}>
|
||||
<FloatingToolbar.Item>
|
||||
<Trans
|
||||
i18nKey="com.affine.page.toolbar.selected"
|
||||
@@ -190,7 +177,7 @@ const PageListFloatingToolbar = ({
|
||||
<div className={styles.toolbarSelectedNumber}>
|
||||
{{ count: selectedIds.length } as any}
|
||||
</div>
|
||||
pages selected
|
||||
selected
|
||||
</Trans>
|
||||
</FloatingToolbar.Item>
|
||||
<FloatingToolbar.Button onClick={onClose} icon={<CloseIcon />} />
|
||||
@@ -245,9 +232,10 @@ export const AllPage = () => {
|
||||
);
|
||||
const [selectedPageIds, setSelectedPageIds] = useState<string[]>([]);
|
||||
const pageListRef = useRef<PageListHandle>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const deselectAllAndToggleSelect = useCallback(() => {
|
||||
setSelectedPageIds([]);
|
||||
|
||||
const [showFloatingToolbar, setShowFloatingToolbar] = useState(false);
|
||||
|
||||
const hideFloatingToolbar = useCallback(() => {
|
||||
pageListRef.current?.toggleSelectable();
|
||||
}, []);
|
||||
|
||||
@@ -257,24 +245,7 @@ export const AllPage = () => {
|
||||
return selectedPageIds.filter(id => ids.includes(id));
|
||||
}, [filteredPageMetas, selectedPageIds]);
|
||||
|
||||
const [showHeaderCreateNewPage, setShowHeaderCreateNewPage] = useState(false);
|
||||
// when PageListScrollContainer scrolls above 40px, show the create new page button on header
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (container) {
|
||||
const handleScroll = () => {
|
||||
setTimeout(() => {
|
||||
const scrollTop = container.scrollTop ?? 0;
|
||||
setShowHeaderCreateNewPage(scrollTop > 40);
|
||||
});
|
||||
};
|
||||
container.addEventListener('scroll', handleScroll);
|
||||
return () => {
|
||||
container.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}
|
||||
return;
|
||||
}, []);
|
||||
const [hideHeaderCreateNewPage, setHideHeaderCreateNewPage] = useState(true);
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
@@ -289,7 +260,7 @@ export const AllPage = () => {
|
||||
size="small"
|
||||
className={clsx(
|
||||
styles.headerCreateNewButton,
|
||||
!showHeaderCreateNewPage && styles.headerCreateNewButtonHidden
|
||||
hideHeaderCreateNewPage && styles.headerCreateNewButtonHidden
|
||||
)}
|
||||
>
|
||||
<PlusIcon />
|
||||
@@ -297,37 +268,36 @@ export const AllPage = () => {
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<PageListScrollContainer
|
||||
ref={containerRef}
|
||||
className={styles.scrollContainer}
|
||||
>
|
||||
<PageListHeader />
|
||||
{filteredPageMetas.length > 0 ? (
|
||||
<>
|
||||
<PageList
|
||||
ref={pageListRef}
|
||||
selectable="toggle"
|
||||
draggable
|
||||
selectedPageIds={filteredSelectedPageIds}
|
||||
onSelectedPageIdsChange={setSelectedPageIds}
|
||||
pages={filteredPageMetas}
|
||||
clickMode="link"
|
||||
isPreferredEdgeless={isPreferredEdgeless}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
pageOperationsRenderer={pageOperationsRenderer}
|
||||
/>
|
||||
<PageListFloatingToolbar
|
||||
selectedIds={filteredSelectedPageIds}
|
||||
onClose={deselectAllAndToggleSelect}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
{filteredPageMetas.length > 0 ? (
|
||||
<>
|
||||
<VirtualizedPageList
|
||||
ref={pageListRef}
|
||||
selectable="toggle"
|
||||
draggable
|
||||
atTopThreshold={80}
|
||||
atTopStateChange={setHideHeaderCreateNewPage}
|
||||
onSelectionActiveChange={setShowFloatingToolbar}
|
||||
heading={<PageListHeader />}
|
||||
selectedPageIds={filteredSelectedPageIds}
|
||||
onSelectedPageIdsChange={setSelectedPageIds}
|
||||
pages={filteredPageMetas}
|
||||
rowAsLink
|
||||
isPreferredEdgeless={isPreferredEdgeless}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
pageOperationsRenderer={pageOperationsRenderer}
|
||||
/>
|
||||
)}
|
||||
</PageListScrollContainer>
|
||||
<PageListFloatingToolbar
|
||||
open={showFloatingToolbar && filteredSelectedPageIds.length > 0}
|
||||
selectedIds={filteredSelectedPageIds}
|
||||
onClose={hideFloatingToolbar}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { toast } from '@affine/component';
|
||||
import {
|
||||
PageList,
|
||||
PageListScrollContainer,
|
||||
TrashOperationCell,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/component/page-list';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -61,30 +60,28 @@ export const TrashPage = () => {
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<WorkspaceHeader
|
||||
currentWorkspaceId={currentWorkspace.id}
|
||||
currentEntry={{
|
||||
subPath: WorkspaceSubPath.TRASH,
|
||||
}}
|
||||
/>
|
||||
<div className={styles.root}>
|
||||
<PageListScrollContainer className={styles.scrollContainer}>
|
||||
{filteredPageMetas.length > 0 ? (
|
||||
<PageList
|
||||
pages={filteredPageMetas}
|
||||
clickMode="link"
|
||||
groupBy={false}
|
||||
isPreferredEdgeless={isPreferredEdgeless}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
pageOperationsRenderer={pageOperationsRenderer}
|
||||
/>
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="trash"
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
)}
|
||||
</PageListScrollContainer>
|
||||
<WorkspaceHeader
|
||||
currentWorkspaceId={currentWorkspace.id}
|
||||
currentEntry={{
|
||||
subPath: WorkspaceSubPath.TRASH,
|
||||
}}
|
||||
/>
|
||||
{filteredPageMetas.length > 0 ? (
|
||||
<VirtualizedPageList
|
||||
pages={filteredPageMetas}
|
||||
rowAsLink
|
||||
groupBy={false}
|
||||
isPreferredEdgeless={isPreferredEdgeless}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
pageOperationsRenderer={pageOperationsRenderer}
|
||||
/>
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="trash"
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user