mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-23 05:33:08 +03:00
feat: add worksapce type label (#4045)
Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
parent
18d5a99af5
commit
df4d71b0c8
@ -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']()}>
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
@ -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',
|
||||
});
|
||||
|
@ -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: {
|
||||
|
@ -110,9 +110,9 @@ const CloudWorkSpaceList = ({
|
||||
<>
|
||||
<StyledModalHeader>
|
||||
<StyledModalHeaderLeft>
|
||||
<StyledModalTitle>
|
||||
<StyledWorkspaceFlavourTitle>
|
||||
{t['com.affine.workspace.cloud']()}
|
||||
</StyledModalTitle>
|
||||
</StyledWorkspaceFlavourTitle>
|
||||
</StyledModalHeaderLeft>
|
||||
</StyledModalHeader>
|
||||
<StyledModalContent>
|
||||
|
@ -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',
|
||||
};
|
||||
});
|
||||
|
@ -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)',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -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'}
|
||||
<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>
|
||||
);
|
||||
|
@ -13,7 +13,7 @@ export const navWrapperStyle = style({
|
||||
width: navWidthVar,
|
||||
minWidth: navWidthVar,
|
||||
height: '100%',
|
||||
zIndex: 1,
|
||||
zIndex: 3,
|
||||
paddingBottom: '8px',
|
||||
backgroundColor: 'transparent',
|
||||
'@media': {
|
||||
|
Loading…
Reference in New Issue
Block a user