feat: add suspense to workspace settings (#3167)

Co-authored-by: Qi <474021214@qq.com>
This commit is contained in:
Alex Yang 2023-07-11 23:50:30 +08:00 committed by GitHub
parent 37c8465af8
commit 3968deb6d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 115 additions and 67 deletions

View File

@ -2,16 +2,11 @@ import {
SettingModal as SettingModalBase, SettingModal as SettingModalBase,
type SettingModalProps, type SettingModalProps,
} from '@affine/component/setting-components'; } from '@affine/component/setting-components';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import { ContactWithUsIcon } from '@blocksuite/icons'; import { ContactWithUsIcon } from '@blocksuite/icons';
import { useAtomValue } from 'jotai';
import type React from 'react'; import type React from 'react';
import { useCallback, useMemo } from 'react'; import { useCallback } from 'react';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import type { AllWorkspace } from '../../../shared';
import { AccountSetting } from './account-setting'; import { AccountSetting } from './account-setting';
import { import {
GeneralSetting, GeneralSetting,
@ -40,14 +35,7 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
}) => { }) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
const [currentWorkspace] = useCurrentWorkspace();
const generalSettingList = useGeneralSettingList(); const generalSettingList = useGeneralSettingList();
const workspaceList = useMemo(() => {
return workspaces.filter(
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
);
}, [workspaces]);
const onGeneralSettingClick = useCallback( const onGeneralSettingClick = useCallback(
(key: GeneralSettingKeys) => { (key: GeneralSettingKeys) => {
@ -76,8 +64,6 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
<SettingSidebar <SettingSidebar
generalSettingList={generalSettingList} generalSettingList={generalSettingList}
onGeneralSettingClick={onGeneralSettingClick} onGeneralSettingClick={onGeneralSettingClick}
currentWorkspace={currentWorkspace as AllWorkspace}
workspaceList={workspaceList}
onWorkspaceSettingClick={onWorkspaceSettingClick} onWorkspaceSettingClick={onWorkspaceSettingClick}
selectedGeneralKey={activeTab} selectedGeneralKey={activeTab}
selectedWorkspaceId={workspaceId} selectedWorkspaceId={workspaceId}

View File

@ -1,18 +1,24 @@
import { UserAvatar } from '@affine/component/user-avatar'; import {
WorkspaceListItemSkeleton,
WorkspaceListSkeleton,
} from '@affine/component/setting-components';
import { WorkspaceAvatar } from '@affine/component/workspace-avatar'; import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { RootWorkspaceMetadata } from '@affine/workspace/atom'; import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import { useStaticBlockSuiteWorkspace } from '@toeverything/hooks/use-block-suite-workspace'; import { useStaticBlockSuiteWorkspace } from '@toeverything/hooks/use-block-suite-workspace';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtomValue } from 'jotai';
import type { FC } from 'react';
import { Suspense } from 'react';
import type { AllWorkspace } from '../../../../shared'; import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
import type { import type {
GeneralSettingKeys, GeneralSettingKeys,
GeneralSettingList, GeneralSettingList,
} from '../general-setting'; } from '../general-setting';
import { import {
accountButton,
settingSlideBar, settingSlideBar,
sidebarItemsWrapper, sidebarItemsWrapper,
sidebarSelectItem, sidebarSelectItem,
@ -20,25 +26,19 @@ import {
sidebarTitle, sidebarTitle,
} from './style.css'; } from './style.css';
export const SettingSidebar = ({ export const SettingSidebar: FC<{
generalSettingList,
onGeneralSettingClick,
currentWorkspace,
workspaceList,
onWorkspaceSettingClick,
selectedWorkspaceId,
selectedGeneralKey,
onAccountSettingClick,
}: {
generalSettingList: GeneralSettingList; generalSettingList: GeneralSettingList;
onGeneralSettingClick: (key: GeneralSettingKeys) => void; onGeneralSettingClick: (key: GeneralSettingKeys) => void;
currentWorkspace: AllWorkspace;
workspaceList: RootWorkspaceMetadata[];
onWorkspaceSettingClick: (workspaceId: string) => void; onWorkspaceSettingClick: (workspaceId: string) => void;
selectedWorkspaceId: string | null; selectedWorkspaceId: string | null;
selectedGeneralKey: string | null; selectedGeneralKey: string | null;
onAccountSettingClick: () => void; onAccountSettingClick: () => void;
}> = ({
generalSettingList,
onGeneralSettingClick,
onWorkspaceSettingClick,
selectedWorkspaceId,
selectedGeneralKey,
}) => { }) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return ( return (
@ -70,10 +70,29 @@ export const SettingSidebar = ({
{t['com.affine.settings.workspace']()} {t['com.affine.settings.workspace']()}
</div> </div>
<div className={clsx(sidebarItemsWrapper, 'scroll')}> <div className={clsx(sidebarItemsWrapper, 'scroll')}>
{workspaceList.map(workspace => { <Suspense fallback={<WorkspaceListSkeleton />}>
<WorkspaceList
onWorkspaceSettingClick={onWorkspaceSettingClick}
selectedWorkspaceId={selectedWorkspaceId}
/>
</Suspense>
</div>
</div>
);
};
export const WorkspaceList: FC<{
onWorkspaceSettingClick: (workspaceId: string) => void;
selectedWorkspaceId: string | null;
}> = ({ onWorkspaceSettingClick, selectedWorkspaceId }) => {
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
const [currentWorkspace] = useCurrentWorkspace();
return ( return (
<>
{workspaces.map(workspace => {
return (
<Suspense key={workspace.id} fallback={<WorkspaceListItemSkeleton />}>
<WorkspaceListItem <WorkspaceListItem
key={workspace.id}
meta={workspace} meta={workspace}
onClick={() => { onClick={() => {
onWorkspaceSettingClick(workspace.id); onWorkspaceSettingClick(workspace.id);
@ -81,30 +100,10 @@ export const SettingSidebar = ({
isCurrent={workspace.id === currentWorkspace.id} isCurrent={workspace.id === currentWorkspace.id}
isActive={workspace.id === selectedWorkspaceId} isActive={workspace.id === selectedWorkspaceId}
/> />
</Suspense>
); );
})} })}
</div> </>
{runtimeConfig.enableCloud && (
<div className={accountButton} onClick={onAccountSettingClick}>
<UserAvatar
size={28}
name="Account NameAccount Name"
url={''}
className="avatar"
/>
<div className="content">
<div className="name" title="xxx">
Account NameAccount Name
</div>
<div className="email" title="xxx">
xxxxxxxx@gmail.comxxxxxxxx@gmail.com
</div>
</div>
</div>
)}
</div>
); );
}; };

View File

@ -14,6 +14,10 @@ globalStyle(`${settingContent} .wrapper`, {
maxWidth: '560px', maxWidth: '560px',
margin: '0 auto', margin: '0 auto',
}); });
globalStyle(`${settingContent} .wrapper::-webkit-scrollbar`, {
display: 'none',
});
globalStyle(`${settingContent} .content`, { globalStyle(`${settingContent} .content`, {
minHeight: '100%', minHeight: '100%',
paddingBottom: '80px', paddingBottom: '80px',

View File

@ -1,3 +1,4 @@
import { WorkspaceDetailSkeleton } from '@affine/component/setting-components';
import { usePassiveWorkspaceEffect } from '@toeverything/hooks/use-block-suite-workspace'; import { usePassiveWorkspaceEffect } from '@toeverything/hooks/use-block-suite-workspace';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
@ -29,7 +30,7 @@ export const WorkspaceSetting = ({ workspaceId }: { workspaceId: string }) => {
const onTransformWorkspace = useOnTransformWorkspace(); const onTransformWorkspace = useOnTransformWorkspace();
return ( return (
<Suspense fallback={<div>loading</div>}> <Suspense fallback={<WorkspaceDetailSkeleton />}>
<NewSettingsDetail <NewSettingsDetail
onTransformWorkspace={onTransformWorkspace} onTransformWorkspace={onTransformWorkspace}
onDeleteWorkspace={onDeleteWorkspace} onDeleteWorkspace={onDeleteWorkspace}

View File

@ -1,4 +1,6 @@
export { SettingModal, type SettingModalProps } from './modal'; export { SettingModal, type SettingModalProps } from './modal';
export { SettingHeader } from './setting-header'; export { SettingHeader } from './setting-header';
export { SettingRow } from './setting-row'; export { SettingRow } from './setting-row';
export * from './workspace-detail-skeleton';
export * from './workspace-list-skeleton';
export { SettingWrapper } from './wrapper'; export { SettingWrapper } from './wrapper';

View File

@ -1,9 +1,9 @@
import type { FC, HTMLAttributes } from 'react'; import type { FC, HTMLAttributes, ReactNode } from 'react';
import { settingHeader } from './share.css'; import { settingHeader } from './share.css';
export const SettingHeader: FC< export const SettingHeader: FC<
{ title: string; subtitle?: string } & Omit< { title: ReactNode; subtitle?: ReactNode } & Omit<
HTMLAttributes<HTMLDivElement>, HTMLAttributes<HTMLDivElement>,
'title' 'title'
> >

View File

@ -1,12 +1,12 @@
import clsx from 'clsx'; import clsx from 'clsx';
import type { CSSProperties, FC, PropsWithChildren, ReactElement } from 'react'; import type { CSSProperties, FC, PropsWithChildren, ReactNode } from 'react';
import { settingRow } from './share.css'; import { settingRow } from './share.css';
export const SettingRow: FC< export const SettingRow: FC<
PropsWithChildren<{ PropsWithChildren<{
name: string | ReactElement; name: ReactNode;
desc: string | ReactElement; desc: ReactNode;
style?: CSSProperties; style?: CSSProperties;
onClick?: () => void; onClick?: () => void;
spreadCol?: boolean; spreadCol?: boolean;

View File

@ -0,0 +1,25 @@
import { Skeleton } from '@mui/material';
import { SettingHeader } from './setting-header';
import { SettingRow } from './setting-row';
import { SettingWrapper } from './wrapper';
export const WorkspaceDetailSkeleton = () => {
return (
<>
<SettingHeader title={<Skeleton />} subtitle={<Skeleton />} />
{new Array(3).fill(0).map((_, index) => {
return (
<SettingWrapper title={<Skeleton />} key={index}>
<SettingRow
name={<Skeleton />}
desc={<Skeleton />}
spreadCol={false}
></SettingRow>
</SettingWrapper>
);
})}
</>
);
};

View File

@ -0,0 +1,30 @@
import { Skeleton } from '@mui/material';
import { FlexWrapper } from '../../ui/layout';
export const WorkspaceListItemSkeleton = () => {
return (
<FlexWrapper
alignItems="center"
style={{ padding: '0 8px', height: 30, marginBottom: 4 }}
>
<Skeleton
variant="circular"
width={14}
height={14}
style={{ marginRight: 10 }}
/>
<Skeleton variant="rectangular" height={16} style={{ flexGrow: 1 }} />
</FlexWrapper>
);
};
export const WorkspaceListSkeleton = () => {
return (
<>
{new Array(5).fill(0).map((_, index) => {
return <WorkspaceListItemSkeleton key={index} />;
})}
</>
);
};

View File

@ -1,9 +1,9 @@
import type { FC, PropsWithChildren } from 'react'; import type { FC, PropsWithChildren, ReactNode } from 'react';
import { wrapper } from './share.css'; import { wrapper } from './share.css';
export const SettingWrapper: FC< export const SettingWrapper: FC<
PropsWithChildren<{ PropsWithChildren<{
title?: string; title?: ReactNode;
}> }>
> = ({ title, children }) => { > = ({ title, children }) => {
return ( return (

View File

@ -4,8 +4,8 @@ import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
import MuiCollapse from '@mui/material/Collapse'; import MuiCollapse from '@mui/material/Collapse';
import MuiFade from '@mui/material/Fade'; import MuiFade from '@mui/material/Fade';
import MuiGrow from '@mui/material/Grow'; import MuiGrow from '@mui/material/Grow';
import MuiSkeleton from '@mui/material/Skeleton';
import MuiSlide from '@mui/material/Slide'; import MuiSlide from '@mui/material/Slide';
export { export {
MuiAvatar, MuiAvatar,
MuiBreadcrumbs, MuiBreadcrumbs,
@ -13,5 +13,6 @@ export {
MuiCollapse, MuiCollapse,
MuiFade, MuiFade,
MuiGrow, MuiGrow,
MuiSkeleton,
MuiSlide, MuiSlide,
}; };