From 66500669c862c3aaa30de70d0e7ddb9955b60cb9 Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Sat, 10 May 2025 07:01:49 +0000 Subject: [PATCH] perf(core): optimize rendering of all docs (#12188) close AF-2605 [CleanShot 2025-05-08 at 13.56.38.mp4 (uploaded via Graphite) ](https://app.graphite.dev/media/video/LakojjjzZNf6ogjOVwKE/4e36e838-7c7f-4f0a-89a8-fd582c2ef573.mp4) ## Summary by CodeRabbit - **Refactor** - Centralized state management in the document explorer using a reactive context, replacing prop drilling and local state with observable streams for preferences, selection, grouping, and view options. - Updated multiple components (display menus, quick actions, doc list items, group headers) to consume and update state directly via context observables. - Simplified component signatures by removing now-unnecessary props related to preferences and state handlers. - **Style** - Adjusted user avatar display: avatars now only have right margin when user names are shown, and vertical alignment was improved. - **New Features** - User avatar elements now include a data attribute to indicate if the user name is displayed. - **Bug Fixes** - Improved handling of document tags to prevent errors when tags are not in the expected format. - **Documentation** - Added missing group header property for updated date fields in workspace property types. - **Chores** - Clarified and renamed internal types for quick actions to improve code clarity. --- .../core/src/components/explorer/context.ts | 69 ++++++--- .../explorer/display-menu/index.tsx | 67 +++----- .../explorer/display-menu/properties.tsx | 42 ++--- .../explorer/display-menu/quick-actions.tsx | 62 ++++---- .../explorer/docs-view/doc-list-item.tsx | 103 ++++++------- .../explorer/docs-view/group-header.tsx | 47 +++--- .../explorer/docs-view/properties.tsx | 3 +- .../explorer/docs-view/quick-actions.tsx | 25 ++- .../explorer/quick-actions.constants.tsx | 6 +- .../created-updated-by.tsx | 3 +- .../workspace-property-types/index.ts | 1 + .../workspace/all-page/all-page-header.tsx | 37 ++--- .../pages/workspace/all-page/all-page.tsx | 144 +++++------------- .../modules/cloud/views/public-user.css.ts | 7 +- .../src/modules/cloud/views/public-user.tsx | 1 + .../core/src/modules/doc/stores/docs.ts | 8 +- 16 files changed, 274 insertions(+), 351 deletions(-) diff --git a/packages/frontend/core/src/components/explorer/context.ts b/packages/frontend/core/src/components/explorer/context.ts index 1555a64b3..c3ccede0d 100644 --- a/packages/frontend/core/src/components/explorer/context.ts +++ b/packages/frontend/core/src/components/explorer/context.ts @@ -1,31 +1,50 @@ -import { createContext, type Dispatch, type SetStateAction } from 'react'; +import { LiveData } from '@toeverything/infra'; +import { createContext } from 'react'; import type { DocListItemView } from './docs-view/doc-list-item'; import type { ExplorerPreference } from './types'; -export type DocExplorerContextType = ExplorerPreference & { - view: DocListItemView; - setView: Dispatch>; - groups: Array<{ key: string; items: string[] }>; - collapsed: string[]; - selectMode?: boolean; - selectedDocIds: string[]; - prevCheckAnchorId?: string | null; - onToggleCollapse: (groupId: string) => void; - onToggleSelect: (docId: string) => void; - onSelect: Dispatch>; - setPrevCheckAnchorId: Dispatch>; +export type DocExplorerContextType = { + view$: LiveData; + groups$: LiveData>; + collapsedGroups$: LiveData; + selectMode$?: LiveData; + selectedDocIds$: LiveData; + prevCheckAnchorId$?: LiveData; +} & { + [K in keyof ExplorerPreference as `${K}$`]: LiveData; }; -export const DocExplorerContext = createContext({ - view: 'list', - setView: () => {}, - groups: [], - collapsed: [], - selectedDocIds: [], - prevCheckAnchorId: null, - onToggleSelect: () => {}, - onToggleCollapse: () => {}, - onSelect: () => {}, - setPrevCheckAnchorId: () => {}, -}); +export const DocExplorerContext = createContext( + {} as any +); + +export const createDocExplorerContext = () => + ({ + view$: new LiveData('list'), + groups$: new LiveData>([]), + collapsedGroups$: new LiveData([]), + selectMode$: new LiveData(false), + selectedDocIds$: new LiveData([]), + prevCheckAnchorId$: new LiveData(null), + filters$: new LiveData([ + { + type: 'system', + key: 'trash', + value: 'false', + method: 'is', + }, + ]), + groupBy$: new LiveData(undefined), + orderBy$: new LiveData(undefined), + displayProperties$: new LiveData( + [] + ), + showDocIcon$: new LiveData(true), + showDocPreview$: new LiveData(true), + quickFavorite$: new LiveData(false), + quickSelect$: new LiveData(false), + quickSplit$: new LiveData(false), + quickTrash$: new LiveData(false), + quickTab$: new LiveData(false), + }) satisfies DocExplorerContextType; diff --git a/packages/frontend/core/src/components/explorer/display-menu/index.tsx b/packages/frontend/core/src/components/explorer/display-menu/index.tsx index ab97f36d0..fc2b0f1d4 100644 --- a/packages/frontend/core/src/components/explorer/display-menu/index.tsx +++ b/packages/frontend/core/src/components/explorer/display-menu/index.tsx @@ -11,85 +11,63 @@ import type { } from '@affine/core/modules/collection-rules/types'; import { useI18n } from '@affine/i18n'; import { ArrowDownSmallIcon } from '@blocksuite/icons/rc'; +import { useLiveData } from '@toeverything/infra'; import type React from 'react'; -import { useCallback } from 'react'; +import { useCallback, useContext } from 'react'; -import type { ExplorerPreference } from '../types'; +import { DocExplorerContext } from '../context'; import { GroupByList, GroupByName } from './group'; import { OrderByList, OrderByName } from './order'; import { DisplayProperties } from './properties'; import { QuickActionsConfig } from './quick-actions'; import * as styles from './styles.css'; -const ExplorerDisplayMenu = ({ - preference, - onChange, -}: { - preference: ExplorerPreference; - onChange?: (preference: ExplorerPreference) => void; -}) => { +const ExplorerDisplayMenu = () => { const t = useI18n(); + const explorerContextValue = useContext(DocExplorerContext); + const groupBy = useLiveData(explorerContextValue.groupBy$); + const orderBy = useLiveData(explorerContextValue.orderBy$); const handleGroupByChange = useCallback( (groupBy: GroupByParams) => { - onChange?.({ - ...preference, - groupBy, - }); + explorerContextValue.groupBy$?.next(groupBy); }, - [onChange, preference] + [explorerContextValue.groupBy$] ); const handleOrderByChange = useCallback( (orderBy: OrderByParams) => { - onChange?.({ - ...preference, - orderBy, - }); + explorerContextValue.orderBy$?.next(orderBy); }, - [onChange, preference] + [explorerContextValue.orderBy$] ); return (
- } + items={} >
{t['com.affine.explorer.display-menu.grouping']()} - {preference.groupBy ? ( - - ) : null} + {groupBy ? : null}
- } + items={} >
{t['com.affine.explorer.display-menu.ordering']()} - {preference.orderBy ? ( - - ) : null} + {orderBy ? : null}
- + - +
); }; @@ -97,24 +75,15 @@ const ExplorerDisplayMenu = ({ export const ExplorerDisplayMenuButton = ({ style, className, - preference, menuProps, - onChange, }: { style?: React.CSSProperties; className?: string; - preference: ExplorerPreference; - onChange?: (preference: ExplorerPreference) => void; menuProps?: Omit; }) => { const t = useI18n(); return ( - - } - {...menuProps} - > + } {...menuProps}>