mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-28 04:53:53 +03:00
feat: add suspense to workspace settings (#3167)
Co-authored-by: Qi <474021214@qq.com>
This commit is contained in:
parent
37c8465af8
commit
3968deb6d4
@ -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}
|
||||||
|
@ -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 />}>
|
||||||
return (
|
<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
|
<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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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',
|
||||||
|
@ -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}
|
||||||
|
@ -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';
|
||||||
|
@ -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'
|
||||||
>
|
>
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -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} />;
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -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 (
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user