mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor: lazy load workspaces (#3091)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Skeleton } from '@mui/material';
|
||||
import { NoSsr, Skeleton } from '@mui/material';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
@@ -107,7 +107,9 @@ export function AppSidebar(props: AppSidebarProps): ReactElement {
|
||||
data-enable-animation={enableAnimation && !isResizing}
|
||||
>
|
||||
<nav className={navStyle} ref={navRef} data-testid="app-sidebar">
|
||||
<SidebarHeader router={props.router} />
|
||||
<NoSsr>
|
||||
<SidebarHeader router={props.router} />
|
||||
</NoSsr>
|
||||
<div className={navBodyStyle} data-testid="sliderBar-inner">
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import type {
|
||||
AffineCloudWorkspace,
|
||||
LocalWorkspace,
|
||||
} from '@affine/env/workspace';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { useStaticBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import {
|
||||
CloudWorkspaceIcon as DefaultCloudWorkspaceIcon,
|
||||
CollaborationIcon as DefaultJoinedWorkspaceIcon,
|
||||
LocalDataIcon as DefaultLocalDataIcon,
|
||||
LocalWorkspaceIcon as DefaultLocalWorkspaceIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
@@ -18,16 +22,8 @@ import {
|
||||
} from './styles';
|
||||
|
||||
export type WorkspaceTypeProps = {
|
||||
workspace: AffineCloudWorkspace | LocalWorkspace;
|
||||
flavour: WorkspaceFlavour;
|
||||
};
|
||||
|
||||
import {
|
||||
CloudWorkspaceIcon as DefaultCloudWorkspaceIcon,
|
||||
CollaborationIcon as DefaultJoinedWorkspaceIcon,
|
||||
LocalDataIcon as DefaultLocalDataIcon,
|
||||
LocalWorkspaceIcon as DefaultLocalWorkspaceIcon,
|
||||
} from '@blocksuite/icons';
|
||||
|
||||
const JoinedWorkspaceIcon = () => {
|
||||
return <DefaultJoinedWorkspaceIcon style={{ color: '#FF646B' }} />;
|
||||
};
|
||||
@@ -43,12 +39,12 @@ const LocalDataIcon = () => {
|
||||
return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />;
|
||||
};
|
||||
|
||||
const WorkspaceType: FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
const WorkspaceType: FC<WorkspaceTypeProps> = ({ flavour }) => {
|
||||
const t = useAFFiNEI18N();
|
||||
// fixme: cloud regression
|
||||
const isOwner = true;
|
||||
|
||||
if (workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
if (flavour === WorkspaceFlavour.LOCAL) {
|
||||
return (
|
||||
<p title={t['Local Workspace']()}>
|
||||
<LocalWorkspaceIcon />
|
||||
@@ -72,51 +68,46 @@ const WorkspaceType: FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
|
||||
export type WorkspaceCardProps = {
|
||||
currentWorkspaceId: string | null;
|
||||
workspace: AffineCloudWorkspace | LocalWorkspace;
|
||||
onClick: (workspace: AffineCloudWorkspace | LocalWorkspace) => void;
|
||||
onSettingClick: (workspace: AffineCloudWorkspace | LocalWorkspace) => void;
|
||||
meta: RootWorkspaceMetadata;
|
||||
onClick: (workspaceId: string) => void;
|
||||
onSettingClick: (workspaceId: string) => void;
|
||||
};
|
||||
|
||||
export const WorkspaceCard: FC<WorkspaceCardProps> = ({
|
||||
workspace,
|
||||
onClick,
|
||||
onSettingClick,
|
||||
currentWorkspaceId,
|
||||
meta,
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
|
||||
const workspace = useStaticBlockSuiteWorkspace(meta.id);
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace);
|
||||
|
||||
return (
|
||||
<StyledCard
|
||||
data-testid="workspace-card"
|
||||
onClick={useCallback(() => {
|
||||
onClick(workspace);
|
||||
}, [onClick, workspace])}
|
||||
onClick(meta.id);
|
||||
}, [onClick, meta.id])}
|
||||
active={workspace.id === currentWorkspaceId}
|
||||
>
|
||||
<WorkspaceAvatar size={58} workspace={workspace} />
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
|
||||
<WorkspaceType workspace={workspace} />
|
||||
{workspace.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<WorkspaceType flavour={meta.flavour} />
|
||||
{meta.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<p title={t['Available Offline']()}>
|
||||
<LocalDataIcon />
|
||||
<span>{t['Available Offline']()}</span>
|
||||
</p>
|
||||
)}
|
||||
{/* {workspace.flavour === WorkspaceFlavour.AFFINE && workspace.public && (
|
||||
<p title={t['Published to Web']()}>
|
||||
<PublishIcon />
|
||||
<span>{t['Published to Web']()}</span>
|
||||
</p>
|
||||
)} */}
|
||||
</StyleWorkspaceInfo>
|
||||
<StyledSettingLink
|
||||
className="setting-entry"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onSettingClick(workspace);
|
||||
onSettingClick(meta.id);
|
||||
}}
|
||||
>
|
||||
<SettingsIcon />
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
import type {
|
||||
AffineCloudWorkspace,
|
||||
AffinePublicWorkspace,
|
||||
LocalWorkspace,
|
||||
} from '@affine/env/workspace';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import * as RadixAvatar from '@radix-ui/react-avatar';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url';
|
||||
@@ -15,11 +10,7 @@ import { avatarImageStyle, avatarStyle } from './index.css';
|
||||
|
||||
export type WorkspaceAvatarProps = {
|
||||
size?: number;
|
||||
workspace:
|
||||
| AffineCloudWorkspace
|
||||
| LocalWorkspace
|
||||
| AffinePublicWorkspace
|
||||
| null;
|
||||
workspace: Workspace | null;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
@@ -60,13 +51,9 @@ export const WorkspaceAvatar: React.FC<WorkspaceAvatarProps> = ({
|
||||
workspace,
|
||||
...props
|
||||
}) => {
|
||||
if (workspace && 'blockSuiteWorkspace' in workspace) {
|
||||
if (workspace) {
|
||||
return (
|
||||
<BlockSuiteWorkspaceAvatar
|
||||
{...props}
|
||||
size={size}
|
||||
workspace={workspace.blockSuiteWorkspace}
|
||||
/>
|
||||
<BlockSuiteWorkspaceAvatar {...props} size={size} workspace={workspace} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {
|
||||
AffineCloudWorkspace,
|
||||
LocalWorkspace,
|
||||
} from '@affine/env/workspace';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import {
|
||||
DndContext,
|
||||
@@ -10,7 +11,8 @@ import {
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import { SortableContext, useSortable } from '@dnd-kit/sortable';
|
||||
import type { FC } from 'react';
|
||||
import type { CSSProperties, FC } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { WorkspaceCard } from '../../components/card/workspace-card';
|
||||
import { workspaceItemStyle } from './index.css';
|
||||
@@ -19,26 +21,29 @@ export type WorkspaceListProps = {
|
||||
disabled?: boolean;
|
||||
currentWorkspaceId: string | null;
|
||||
items: (AffineCloudWorkspace | LocalWorkspace)[];
|
||||
onClick: (workspace: AffineCloudWorkspace | LocalWorkspace) => void;
|
||||
onSettingClick: (workspace: AffineCloudWorkspace | LocalWorkspace) => void;
|
||||
onClick: (workspaceId: string) => void;
|
||||
onSettingClick: (workspaceId: string) => void;
|
||||
onDragEnd: (event: DragEndEvent) => void;
|
||||
};
|
||||
|
||||
const SortableWorkspaceItem: FC<
|
||||
Omit<WorkspaceListProps, 'items'> & {
|
||||
item: AffineCloudWorkspace | LocalWorkspace;
|
||||
item: RootWorkspaceMetadata;
|
||||
}
|
||||
> = props => {
|
||||
const { setNodeRef, attributes, listeners, transform } = useSortable({
|
||||
id: props.item.id,
|
||||
});
|
||||
const style: React.CSSProperties = {
|
||||
transform: transform
|
||||
? `translate3d(${transform.x}px, ${transform.y}px, 0)`
|
||||
: undefined,
|
||||
pointerEvents: props.disabled ? 'none' : undefined,
|
||||
opacity: props.disabled ? 0.6 : undefined,
|
||||
};
|
||||
const style: CSSProperties = useMemo(
|
||||
() => ({
|
||||
transform: transform
|
||||
? `translate3d(${transform.x}px, ${transform.y}px, 0)`
|
||||
: undefined,
|
||||
pointerEvents: props.disabled ? 'none' : undefined,
|
||||
opacity: props.disabled ? 0.6 : undefined,
|
||||
}),
|
||||
[props.disabled, transform]
|
||||
);
|
||||
return (
|
||||
<div
|
||||
className={workspaceItemStyle}
|
||||
@@ -50,7 +55,7 @@ const SortableWorkspaceItem: FC<
|
||||
>
|
||||
<WorkspaceCard
|
||||
currentWorkspaceId={props.currentWorkspaceId}
|
||||
workspace={props.item}
|
||||
meta={props.item}
|
||||
onClick={props.onClick}
|
||||
onSettingClick={props.onSettingClick}
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import type { TooltipProps } from '@mui/material';
|
||||
import { NoSsr } from '@mui/material';
|
||||
|
||||
import { styled } from '../../styles';
|
||||
import { Popper, type PopperProps } from '../popper';
|
||||
import StyledPopperContainer from '../shared/container';
|
||||
|
||||
const StyledTooltip = styled(StyledPopperContainer)(() => {
|
||||
return {
|
||||
maxWidth: '320px',
|
||||
@@ -19,11 +21,13 @@ const StyledTooltip = styled(StyledPopperContainer)(() => {
|
||||
export const Tooltip = (props: PopperProps & Omit<TooltipProps, 'title'>) => {
|
||||
const { content, placement = 'top-start', children } = props;
|
||||
return (
|
||||
<Popper
|
||||
{...props}
|
||||
content={<StyledTooltip placement={placement}>{content}</StyledTooltip>}
|
||||
>
|
||||
{children}
|
||||
</Popper>
|
||||
<NoSsr>
|
||||
<Popper
|
||||
{...props}
|
||||
content={<StyledTooltip placement={placement}>{content}</StyledTooltip>}
|
||||
>
|
||||
{children}
|
||||
</Popper>
|
||||
</NoSsr>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user