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,
type SettingModalProps,
} from '@affine/component/setting-components';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import { ContactWithUsIcon } from '@blocksuite/icons';
import { useAtomValue } from 'jotai';
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 {
GeneralSetting,
@ -40,14 +35,7 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
}) => {
const t = useAFFiNEI18N();
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
const [currentWorkspace] = useCurrentWorkspace();
const generalSettingList = useGeneralSettingList();
const workspaceList = useMemo(() => {
return workspaces.filter(
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
);
}, [workspaces]);
const onGeneralSettingClick = useCallback(
(key: GeneralSettingKeys) => {
@ -76,8 +64,6 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
<SettingSidebar
generalSettingList={generalSettingList}
onGeneralSettingClick={onGeneralSettingClick}
currentWorkspace={currentWorkspace as AllWorkspace}
workspaceList={workspaceList}
onWorkspaceSettingClick={onWorkspaceSettingClick}
selectedGeneralKey={activeTab}
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 { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import { useStaticBlockSuiteWorkspace } from '@toeverything/hooks/use-block-suite-workspace';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
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 {
GeneralSettingKeys,
GeneralSettingList,
} from '../general-setting';
import {
accountButton,
settingSlideBar,
sidebarItemsWrapper,
sidebarSelectItem,
@ -20,25 +26,19 @@ import {
sidebarTitle,
} from './style.css';
export const SettingSidebar = ({
generalSettingList,
onGeneralSettingClick,
currentWorkspace,
workspaceList,
onWorkspaceSettingClick,
selectedWorkspaceId,
selectedGeneralKey,
onAccountSettingClick,
}: {
export const SettingSidebar: FC<{
generalSettingList: GeneralSettingList;
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
currentWorkspace: AllWorkspace;
workspaceList: RootWorkspaceMetadata[];
onWorkspaceSettingClick: (workspaceId: string) => void;
selectedWorkspaceId: string | null;
selectedGeneralKey: string | null;
onAccountSettingClick: () => void;
}> = ({
generalSettingList,
onGeneralSettingClick,
onWorkspaceSettingClick,
selectedWorkspaceId,
selectedGeneralKey,
}) => {
const t = useAFFiNEI18N();
return (
@ -70,10 +70,29 @@ export const SettingSidebar = ({
{t['com.affine.settings.workspace']()}
</div>
<div className={clsx(sidebarItemsWrapper, 'scroll')}>
{workspaceList.map(workspace => {
return (
<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 (
<>
{workspaces.map(workspace => {
return (
<Suspense key={workspace.id} fallback={<WorkspaceListItemSkeleton />}>
<WorkspaceListItem
key={workspace.id}
meta={workspace}
onClick={() => {
onWorkspaceSettingClick(workspace.id);
@ -81,30 +100,10 @@ export const SettingSidebar = ({
isCurrent={workspace.id === currentWorkspace.id}
isActive={workspace.id === selectedWorkspaceId}
/>
);
})}
</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>
</Suspense>
);
})}
</>
);
};

View File

@ -14,6 +14,10 @@ globalStyle(`${settingContent} .wrapper`, {
maxWidth: '560px',
margin: '0 auto',
});
globalStyle(`${settingContent} .wrapper::-webkit-scrollbar`, {
display: 'none',
});
globalStyle(`${settingContent} .content`, {
minHeight: '100%',
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 { useSetAtom } from 'jotai';
import { useRouter } from 'next/router';
@ -29,7 +30,7 @@ export const WorkspaceSetting = ({ workspaceId }: { workspaceId: string }) => {
const onTransformWorkspace = useOnTransformWorkspace();
return (
<Suspense fallback={<div>loading</div>}>
<Suspense fallback={<WorkspaceDetailSkeleton />}>
<NewSettingsDetail
onTransformWorkspace={onTransformWorkspace}
onDeleteWorkspace={onDeleteWorkspace}

View File

@ -1,4 +1,6 @@
export { SettingModal, type SettingModalProps } from './modal';
export { SettingHeader } from './setting-header';
export { SettingRow } from './setting-row';
export * from './workspace-detail-skeleton';
export * from './workspace-list-skeleton';
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';
export const SettingHeader: FC<
{ title: string; subtitle?: string } & Omit<
{ title: ReactNode; subtitle?: ReactNode } & Omit<
HTMLAttributes<HTMLDivElement>,
'title'
>

View File

@ -1,12 +1,12 @@
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';
export const SettingRow: FC<
PropsWithChildren<{
name: string | ReactElement;
desc: string | ReactElement;
name: ReactNode;
desc: ReactNode;
style?: CSSProperties;
onClick?: () => void;
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';
export const SettingWrapper: FC<
PropsWithChildren<{
title?: string;
title?: ReactNode;
}>
> = ({ title, children }) => {
return (

View File

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