mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 17:16:16 +08:00
refactor: move WorkspaceCard (#1803)
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { PermissionType } from '@affine/workspace/affine/api';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { WorkspaceAvatar } from '../workspace-avatar';
|
||||
import {
|
||||
StyledCard,
|
||||
StyledSettingLink,
|
||||
StyleWorkspaceInfo,
|
||||
StyleWorkspaceTitle,
|
||||
} from './styles';
|
||||
|
||||
export type WorkspaceTypeProps = {
|
||||
workspace: AffineWorkspace | LocalWorkspace;
|
||||
};
|
||||
|
||||
import {
|
||||
CloudWorkspaceIcon as DefaultCloudWorkspaceIcon,
|
||||
JoinedWorkspaceIcon as DefaultJoinedWorkspaceIcon,
|
||||
LocalDataIcon as DefaultLocalDataIcon,
|
||||
LocalWorkspaceIcon as DefaultLocalWorkspaceIcon,
|
||||
PublishIcon as DefaultPublishIcon,
|
||||
} from '@blocksuite/icons';
|
||||
|
||||
const JoinedWorkspaceIcon = () => {
|
||||
return <DefaultJoinedWorkspaceIcon style={{ color: '#FF646B' }} />;
|
||||
};
|
||||
const LocalWorkspaceIcon = () => {
|
||||
return <DefaultLocalWorkspaceIcon style={{ color: '#FDBD32' }} />;
|
||||
};
|
||||
|
||||
const CloudWorkspaceIcon = () => {
|
||||
return <DefaultCloudWorkspaceIcon style={{ color: '#60A5FA' }} />;
|
||||
};
|
||||
|
||||
const LocalDataIcon = () => {
|
||||
return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />;
|
||||
};
|
||||
const PublishIcon = () => {
|
||||
return <DefaultPublishIcon style={{ color: '#8699FF' }} />;
|
||||
};
|
||||
|
||||
const WorkspaceType: React.FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
const { t } = useTranslation();
|
||||
let isOwner = true;
|
||||
if (workspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
isOwner = workspace.permission === PermissionType.Owner;
|
||||
} else if (workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
isOwner = true;
|
||||
}
|
||||
|
||||
if (workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
return (
|
||||
<p title={t('Local Workspace')}>
|
||||
<LocalWorkspaceIcon />
|
||||
<span>{t('Local Workspace')}</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return isOwner ? (
|
||||
<p title={t('Cloud Workspace')}>
|
||||
<CloudWorkspaceIcon />
|
||||
<span>{t('Cloud Workspace')}</span>
|
||||
</p>
|
||||
) : (
|
||||
<p title={t('Joined Workspace')}>
|
||||
<JoinedWorkspaceIcon />
|
||||
<span>{t('Joined Workspace')}</span>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export type WorkspaceCardProps = {
|
||||
currentWorkspaceId: string | null;
|
||||
workspace: AffineWorkspace | LocalWorkspace;
|
||||
onClick: (workspace: AffineWorkspace | LocalWorkspace) => void;
|
||||
onSettingClick: (workspace: AffineWorkspace | LocalWorkspace) => void;
|
||||
};
|
||||
|
||||
export const WorkspaceCard: React.FC<WorkspaceCardProps> = ({
|
||||
workspace,
|
||||
onClick,
|
||||
onSettingClick,
|
||||
currentWorkspaceId,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
|
||||
|
||||
return (
|
||||
<StyledCard
|
||||
data-testid="workspace-card"
|
||||
onClick={useCallback(() => {
|
||||
onClick(workspace);
|
||||
}, [onClick, workspace])}
|
||||
active={workspace.id === currentWorkspaceId}
|
||||
>
|
||||
<WorkspaceAvatar size={58} workspace={workspace} />
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
|
||||
<WorkspaceType workspace={workspace} />
|
||||
{workspace.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"
|
||||
hoverBackground="#fff"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onSettingClick(workspace);
|
||||
}}
|
||||
>
|
||||
<SettingsIcon />
|
||||
</StyledSettingLink>
|
||||
</StyledCard>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
import { displayFlex, styled, textEllipsis } from '../..';
|
||||
import { IconButton } from '../..';
|
||||
|
||||
export const StyleWorkspaceInfo = styled('div')(({ theme }) => {
|
||||
return {
|
||||
marginLeft: '15px',
|
||||
width: '202px',
|
||||
p: {
|
||||
height: '20px',
|
||||
fontSize: theme.font.sm,
|
||||
...displayFlex('flex-start', 'center'),
|
||||
},
|
||||
svg: {
|
||||
marginRight: '10px',
|
||||
fontSize: '16px',
|
||||
flexShrink: 0,
|
||||
},
|
||||
span: {
|
||||
flexGrow: 1,
|
||||
...textEllipsis(1),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const StyleWorkspaceTitle = styled('div')(({ theme }) => {
|
||||
return {
|
||||
fontSize: theme.font.base,
|
||||
fontWeight: 600,
|
||||
lineHeight: '24px',
|
||||
marginBottom: '10px',
|
||||
maxWidth: '200px',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledCard = styled('div')<{
|
||||
active?: boolean;
|
||||
}>(({ theme, active }) => {
|
||||
const borderColor = active ? theme.colors.primaryColor : 'transparent';
|
||||
return {
|
||||
width: '310px',
|
||||
height: '124px',
|
||||
cursor: 'pointer',
|
||||
padding: '16px',
|
||||
boxShadow: '0px 0px 8px rgba(0, 0, 0, 0.1)',
|
||||
borderRadius: '12px',
|
||||
border: `1px solid ${borderColor}`,
|
||||
...displayFlex('flex-start', 'flex-start'),
|
||||
marginBottom: '24px',
|
||||
transition: 'background .2s',
|
||||
background: theme.palette.mode === 'light' ? '#FFF' : '#2C2C2C',
|
||||
position: 'relative',
|
||||
':hover': {
|
||||
background: theme.colors.cardHoverBackground,
|
||||
'.add-icon': {
|
||||
borderColor: theme.colors.primaryColor,
|
||||
color: theme.colors.primaryColor,
|
||||
},
|
||||
'.setting-entry': {
|
||||
opacity: 1,
|
||||
pointerEvents: 'auto',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledModalHeader = styled('div')(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
height: '72px',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
borderRadius: '24px 24px 0 0',
|
||||
padding: '0 40px',
|
||||
...displayFlex('space-between', 'center'),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSettingLink = styled(IconButton)(({ theme }) => {
|
||||
return {
|
||||
position: 'absolute',
|
||||
right: '6px',
|
||||
bottom: '6px',
|
||||
opacity: 0,
|
||||
pointerEvents: 'none',
|
||||
transition: 'all .15s',
|
||||
':hover': {
|
||||
background: theme.colors.pageBackground,
|
||||
},
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user