feat: add worksapce type label (#4045)

Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
JimmFly 2023-09-01 02:16:58 +08:00 committed by GitHub
parent 18d5a99af5
commit df4d71b0c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 213 additions and 20 deletions

View File

@ -14,6 +14,7 @@ import { useMemo } from 'react';
import { useWorkspace } from '../../../hooks/use-workspace';
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
import { ExportPanel } from './export';
import { LabelsPanel } from './labels';
import { MembersPanel } from './members';
import { ProfilePanel } from './profile';
import { PublishPanel } from './publish';
@ -69,6 +70,7 @@ export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
spreadCol={false}
>
<ProfilePanel workspace={workspace} {...props} />
<LabelsPanel workspace={workspace} {...props} />
</SettingRow>
</SettingWrapper>
<SettingWrapper title={t['AFFiNE Cloud']()}>

View File

@ -0,0 +1,103 @@
import type { AffineOfficialWorkspace } from '@affine/env/workspace';
import { useMemo } from 'react';
import { type WorkspaceSettingDetailProps } from './index';
import * as style from './style.css';
export interface LabelsPanelProps extends WorkspaceSettingDetailProps {
workspace: AffineOfficialWorkspace;
}
type WorkspaceStatus =
| 'local'
| 'syncCloud'
| 'syncDocker'
| 'selfHosted'
| 'joinedWorkspace'
| 'availableOffline'
| 'publishedToWeb';
type LabelProps = {
value: string;
background: string;
};
type LabelMap = {
[key in WorkspaceStatus]: LabelProps;
};
type labelConditionsProps = {
condition: boolean;
label: WorkspaceStatus;
};
const Label = ({ value, background }: LabelProps) => {
return (
<div>
<div className={style.workspaceLabel} style={{ background: background }}>
{value}
</div>
</div>
);
};
export const LabelsPanel = ({ workspace, isOwner }: LabelsPanelProps) => {
const labelMap: LabelMap = useMemo(
() => ({
local: {
value: 'Local',
background: 'var(--affine-tag-orange)',
},
syncCloud: {
value: 'Sync with AFFiNE Cloud',
background: 'var(--affine-tag-blue)',
},
syncDocker: {
value: 'Sync with AFFiNE Docker',
background: 'var(--affine-tag-green)',
},
selfHosted: {
value: 'Self-Hosted Server',
background: 'var(--affine-tag-purple)',
},
joinedWorkspace: {
value: 'Joined Workspace',
background: 'var(--affine-tag-yellow)',
},
availableOffline: {
value: 'Available Offline',
background: 'var(--affine-tag-green)',
},
publishedToWeb: {
value: 'Published to Web',
background: 'var(--affine-tag-blue)',
},
}),
[]
);
const labelConditions: labelConditionsProps[] = [
{ condition: !isOwner, label: 'joinedWorkspace' },
{ condition: workspace.flavour === 'local', label: 'local' },
{ condition: workspace.flavour === 'affine-cloud', label: 'syncCloud' },
{
condition: workspace.flavour === 'affine-public',
label: 'publishedToWeb',
},
//TODO: add these labels
// { status==="synced", label: 'availableOffline' }
// { workspace.flavour === 'affine-Docker', label: 'syncDocker' }
// { workspace.flavour === 'self-hosted', label: 'selfHosted' }
];
return (
<div className={style.labelWrapper}>
{labelConditions.map(
({ condition, label }) =>
condition && (
<Label
key={label}
value={labelMap[label].value}
background={labelMap[label].background}
/>
)
)}
</div>
);
};

View File

@ -12,6 +12,15 @@ export const profileHandlerWrapper = style({
marginLeft: '20px',
});
export const labelWrapper = style({
width: '100%',
display: 'flex',
alignItems: 'center',
marginTop: '24px',
gap: '10px',
flexWrap: 'wrap',
});
export const avatarWrapper = style({
width: '56px',
height: '56px',
@ -146,3 +155,17 @@ export const label = style({
color: 'var(--affine-text-secondary-color)',
marginBottom: '5px',
});
export const workspaceLabel = style({
width: '100%',
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center',
borderRadius: '6px',
padding: '2px 10px',
border: '1px solid var(--affine-white-30)',
fontSize: 'var(--affine-font-xs)',
color: 'var(--affine-text-primary-color)',
lineHeight: '20px',
whiteSpace: 'nowrap',
});

View File

@ -7,6 +7,7 @@ export const header = style({
position: 'relative',
padding: '0 16px',
minHeight: '52px',
background: 'var(--affine-background-primary-color)',
borderBottom: '1px solid var(--affine-border-color)',
zIndex: 2,
selectors: {

View File

@ -110,9 +110,9 @@ const CloudWorkSpaceList = ({
<>
<StyledModalHeader>
<StyledModalHeaderLeft>
<StyledModalTitle>
<StyledWorkspaceFlavourTitle>
{t['com.affine.workspace.cloud']()}
</StyledModalTitle>
</StyledWorkspaceFlavourTitle>
</StyledModalHeaderLeft>
</StyledModalHeader>
<StyledModalContent>

View File

@ -236,9 +236,8 @@ export const StyledModalBody = styled('div')(() => {
export const StyledWorkspaceFlavourTitle = styled('div')(() => {
return {
fontSize: '12px',
fontWeight: 600,
fontSize: 'var(--affine-font-xs)',
color: 'var(--affine-text-secondary-color)',
lineHeight: '20px',
marginBottom: '4px',
};
});

View File

@ -1,6 +1,10 @@
import { displayFlex, textEllipsis } from '@affine/component';
import { styled } from '@affine/component';
export const StyledSelectorContainer = styled('div')(() => {
export const StyledSelectorContainer = styled('div')(({
disableHoverBackground,
}: {
disableHoverBackground: boolean;
}) => {
return {
height: '58px',
display: 'flex',
@ -10,7 +14,7 @@ export const StyledSelectorContainer = styled('div')(() => {
color: 'var(--affine-text-primary-color)',
':hover': {
cursor: 'pointer',
background: 'var(--affine-hover-color)',
background: disableHoverBackground ? '' : 'var(--affine-hover-color)',
},
};
});
@ -38,10 +42,17 @@ export const StyledWorkspaceStatus = styled('div')(() => {
fontSize: 'var(--affine-font-sm)',
color: 'var(--affine-text-secondary-color)',
userSelect: 'none',
padding: '0 4px',
gap: '4px',
zIndex: '1',
svg: {
color: 'var(--affine-icon-color)',
fontSize: 'var(--affine-font-base)',
marginRight: '4px',
},
':hover': {
cursor: 'pointer',
borderRadius: '4px',
background: 'var(--affine-hover-color)',
},
};
});

View File

@ -1,9 +1,16 @@
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons';
import {
CloudWorkspaceIcon,
LocalWorkspaceIcon,
NoNetworkIcon,
} from '@blocksuite/icons';
import { Tooltip } from '@toeverything/components/tooltip';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import type React from 'react';
import { useCallback } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useCurrentLoginStatus } from '../../../../hooks/affine/use-current-login-status';
import { useSystemOnline } from '../../../../hooks/use-system-online';
import type { AllWorkspace } from '../../../../shared';
import { workspaceAvatarStyle } from './index.css';
import {
@ -29,7 +36,8 @@ export const WorkspaceSelector = ({
const [name] = useBlockSuiteWorkspaceName(
currentWorkspace.blockSuiteWorkspace
);
const [isHovered, setIsHovered] = useState(false);
const [container, setContainer] = useState<HTMLDivElement | null>(null);
// Open dialog when `Enter` or `Space` pressed
// TODO-Doma Refactor with `@radix-ui/react-dialog` or other libraries that handle these out of the box and be accessible by default
// TODO: Delete this?
@ -43,13 +51,48 @@ export const WorkspaceSelector = ({
},
[onClick]
);
const loginStatus = useCurrentLoginStatus();
const isOnline = useSystemOnline();
const content = useMemo(() => {
if (!isOnline) {
return 'Disconnected, please check your network connection';
}
if (
loginStatus === 'authenticated' &&
currentWorkspace.flavour !== 'local'
) {
return 'Sync with AFFiNE Cloud';
}
return 'Saved locally';
}, [currentWorkspace.flavour, isOnline, loginStatus]);
const WorkspaceStatus = () => {
if (!isOnline) {
return (
<>
<NoNetworkIcon />
Offline
</>
);
}
return (
<>
{currentWorkspace.flavour === 'local' ? (
<LocalWorkspaceIcon />
) : (
<CloudWorkspaceIcon />
)}
{currentWorkspace.flavour === 'local' ? 'Local' : 'AFFiNE Cloud'}
</>
);
};
return (
<StyledSelectorContainer
role="button"
tabIndex={0}
onClick={onClick}
onKeyDown={handleKeyDown}
disableHoverBackground={isHovered}
data-testid="current-workspace"
id="current-workspace"
>
@ -63,14 +106,25 @@ export const WorkspaceSelector = ({
<StyledWorkspaceName data-testid="workspace-name">
{name}
</StyledWorkspaceName>
<StyledWorkspaceStatus>
{currentWorkspace.flavour === 'local' ? (
<LocalWorkspaceIcon />
) : (
<CloudWorkspaceIcon />
)}
{currentWorkspace.flavour === 'local' ? 'Local' : 'AFFiNE Cloud'}
</StyledWorkspaceStatus>
<div style={{ display: 'flex' }}>
<Tooltip
content={content}
portalOptions={{
container,
}}
>
<StyledWorkspaceStatus
onMouseEnter={() => {
setIsHovered(true);
}}
ref={setContainer}
onMouseLeave={() => setIsHovered(false)}
onClick={e => e.stopPropagation()}
>
<WorkspaceStatus />
</StyledWorkspaceStatus>
</Tooltip>
</div>
</StyledSelectorWrapper>
</StyledSelectorContainer>
);

View File

@ -13,7 +13,7 @@ export const navWrapperStyle = style({
width: navWidthVar,
minWidth: navWidthVar,
height: '100%',
zIndex: 1,
zIndex: 3,
paddingBottom: '8px',
backgroundColor: 'transparent',
'@media': {