mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-28 15:02:32 +03:00
feat(core): support create cloud workspace (#5771)
close TOV-475 has not logged: https://github.com/toeverything/AFFiNE/assets/102217452/b9aa2806-7dbd-4235-895d-5b27effb5831 has logged : https://github.com/toeverything/AFFiNE/assets/102217452/259a1c35-c6ab-4a52-9e03-4438ca64e620 client has not logged: https://github.com/toeverything/AFFiNE/assets/102217452/af6ef528-6fb8-4a27-842f-00c9669afcb2
This commit is contained in:
parent
c22216c71a
commit
4ea4a2d25f
1
packages/common/env/src/global.ts
vendored
1
packages/common/env/src/global.ts
vendored
@ -32,6 +32,7 @@ export const runtimeFlagsSchema = z.object({
|
||||
enableEnhanceShareMode: z.boolean(),
|
||||
enablePayment: z.boolean(),
|
||||
enablePageHistory: z.boolean(),
|
||||
allowLocalWorkspace: z.boolean(),
|
||||
// this is for the electron app
|
||||
serverUrlPrefix: z.string(),
|
||||
enableMoveDatabase: z.boolean(),
|
||||
|
@ -69,6 +69,8 @@ export const modalFooter = style({
|
||||
export const confirmModalContent = style({
|
||||
marginTop: '12px',
|
||||
marginBottom: '20px',
|
||||
height: '100%',
|
||||
overflowY: 'auto',
|
||||
});
|
||||
export const confirmModalContainer = style({
|
||||
display: 'flex',
|
||||
|
@ -43,3 +43,7 @@ export const switchCheckedStyle = style({
|
||||
},
|
||||
},
|
||||
});
|
||||
export const switchDisabledStyle = style({
|
||||
cursor: 'not-allowed',
|
||||
opacity: 0.5,
|
||||
});
|
||||
|
@ -13,6 +13,7 @@ export type SwitchProps = Omit<HTMLAttributes<HTMLLabelElement>, 'onChange'> & {
|
||||
checked?: boolean;
|
||||
onChange?: (checked: boolean) => void;
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export const Switch = ({
|
||||
@ -20,6 +21,7 @@ export const Switch = ({
|
||||
onChange: onChangeProp,
|
||||
children,
|
||||
className,
|
||||
disabled,
|
||||
...otherProps
|
||||
}: SwitchProps) => {
|
||||
const [checkedState, setCheckedState] = useState(checkedProp);
|
||||
@ -27,11 +29,14 @@ export const Switch = ({
|
||||
const checked = onChangeProp ? checkedProp : checkedState;
|
||||
const onChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
const newChecked = event.target.checked;
|
||||
if (onChangeProp) onChangeProp(newChecked);
|
||||
else setCheckedState(newChecked);
|
||||
},
|
||||
[onChangeProp]
|
||||
[disabled, onChangeProp]
|
||||
);
|
||||
|
||||
return (
|
||||
@ -47,6 +52,7 @@ export const Switch = ({
|
||||
<span
|
||||
className={clsx(styles.switchStyle, {
|
||||
[styles.switchCheckedStyle]: checked,
|
||||
[styles.switchDisabledStyle]: disabled,
|
||||
})}
|
||||
/>
|
||||
</label>
|
||||
|
@ -33,6 +33,7 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
enableEnhanceShareMode: false,
|
||||
enablePayment: true,
|
||||
enablePageHistory: true,
|
||||
allowLocalWorkspace: false,
|
||||
serverUrlPrefix: 'https://app.affine.pro',
|
||||
editorFlags,
|
||||
appVersion: packageJson.version,
|
||||
@ -75,6 +76,7 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
enableEnhanceShareMode: false,
|
||||
enablePayment: true,
|
||||
enablePageHistory: true,
|
||||
allowLocalWorkspace: false,
|
||||
serverUrlPrefix: 'https://affine.fail',
|
||||
editorFlags,
|
||||
appVersion: packageJson.version,
|
||||
@ -138,6 +140,11 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
: buildFlags.mode === 'development'
|
||||
? true
|
||||
: currentBuildPreset.enablePageHistory,
|
||||
allowLocalWorkspace: process.env.ALLOW_LOCAL_WORKSPACE
|
||||
? process.env.ALLOW_LOCAL_WORKSPACE === 'true'
|
||||
: buildFlags.mode === 'development'
|
||||
? true
|
||||
: currentBuildPreset.allowLocalWorkspace,
|
||||
};
|
||||
|
||||
if (buildFlags.mode === 'development') {
|
||||
@ -149,6 +156,6 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
// environment preset will overwrite current build preset
|
||||
// this environment variable is for debug proposes only
|
||||
// do not put them into CI
|
||||
...(process.env.CI ? {} : environmentPreset),
|
||||
...(process.env.CI ? { allowLocalWorkspace: true } : environmentPreset),
|
||||
};
|
||||
}
|
||||
|
@ -1,36 +1,76 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const header = style({
|
||||
position: 'relative',
|
||||
marginTop: '44px',
|
||||
});
|
||||
export const content = style({
|
||||
padding: '0 40px',
|
||||
fontSize: '18px',
|
||||
lineHeight: '26px',
|
||||
});
|
||||
globalStyle(`${content} p`, {
|
||||
marginTop: '12px',
|
||||
marginBottom: '16px',
|
||||
});
|
||||
export const contentTitle = style({
|
||||
fontSize: '20px',
|
||||
lineHeight: '28px',
|
||||
|
||||
export const subTitle = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
color: cssVar('textPrimaryColor'),
|
||||
fontWeight: 600,
|
||||
paddingBottom: '16px',
|
||||
});
|
||||
export const buttonGroup = style({
|
||||
|
||||
export const avatarWrapper = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
gap: '20px',
|
||||
margin: '24px 0',
|
||||
margin: '10px 0',
|
||||
});
|
||||
export const radioGroup = style({
|
||||
|
||||
export const workspaceNameWrapper = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px',
|
||||
padding: '12px 0',
|
||||
});
|
||||
export const radio = style({
|
||||
cursor: 'pointer',
|
||||
appearance: 'auto',
|
||||
marginRight: '12px',
|
||||
export const affineCloudWrapper = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '6px',
|
||||
paddingTop: '10px',
|
||||
});
|
||||
|
||||
export const card = style({
|
||||
padding: '12px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
borderRadius: '8px',
|
||||
backgroundColor: cssVar('backgroundSecondaryColor'),
|
||||
minHeight: '114px',
|
||||
position: 'relative',
|
||||
});
|
||||
|
||||
export const cardText = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
gap: '12px',
|
||||
});
|
||||
|
||||
export const cardTitle = style({
|
||||
fontSize: cssVar('fontBase'),
|
||||
color: cssVar('textPrimaryColor'),
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
export const cardDescription = style({
|
||||
fontSize: cssVar('fontXs'),
|
||||
color: cssVar('textSecondaryColor'),
|
||||
maxWidth: '288px',
|
||||
});
|
||||
|
||||
export const cloudTips = style({
|
||||
fontSize: cssVar('fontXs'),
|
||||
color: cssVar('textSecondaryColor'),
|
||||
});
|
||||
|
||||
export const cloudSvgContainer = style({
|
||||
width: '146px',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
position: 'absolute',
|
||||
bottom: '0',
|
||||
right: '0',
|
||||
});
|
||||
|
@ -1,9 +1,15 @@
|
||||
import { Input, toast } from '@affine/component';
|
||||
import { Avatar, Input, Switch, toast } from '@affine/component';
|
||||
import {
|
||||
ConfirmModal,
|
||||
type ConfirmModalProps,
|
||||
Modal,
|
||||
} from '@affine/component/ui/modal';
|
||||
import {
|
||||
authAtom,
|
||||
openDisableCloudAlertModalAtom,
|
||||
setPageModeAtom,
|
||||
} from '@affine/core/atoms';
|
||||
import { useCurrentLoginStatus } from '@affine/core/hooks/affine/use-current-login-status';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { apis } from '@affine/electron-api';
|
||||
@ -17,12 +23,13 @@ import {
|
||||
initEmptyPage,
|
||||
} from '@toeverything/infra/blocksuite';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { setPageModeAtom } from '../../../atoms';
|
||||
import * as style from './index.css';
|
||||
import { CloudSvg } from '../share-page-modal/cloud-svg';
|
||||
import * as styles from './index.css';
|
||||
|
||||
type CreateWorkspaceStep =
|
||||
| 'set-db-location'
|
||||
@ -40,18 +47,55 @@ interface ModalProps {
|
||||
}
|
||||
|
||||
interface NameWorkspaceContentProps extends ConfirmModalProps {
|
||||
onConfirmName: (name: string) => void;
|
||||
onConfirmName: (
|
||||
name: string,
|
||||
workspaceFlavour: WorkspaceFlavour,
|
||||
avatar?: File
|
||||
) => void;
|
||||
}
|
||||
|
||||
const shouldEnableCloud =
|
||||
!runtimeConfig.allowLocalWorkspace && !environment.isDesktop;
|
||||
|
||||
const NameWorkspaceContent = ({
|
||||
onConfirmName,
|
||||
...props
|
||||
}: NameWorkspaceContentProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const [workspaceName, setWorkspaceName] = useState('');
|
||||
const [enable, setEnable] = useState(shouldEnableCloud);
|
||||
const loginStatus = useCurrentLoginStatus();
|
||||
const setDisableCloudOpen = useSetAtom(openDisableCloudAlertModalAtom);
|
||||
|
||||
const setOpenSignIn = useSetAtom(authAtom);
|
||||
|
||||
const openSignInModal = useCallback(() => {
|
||||
if (!runtimeConfig.enableCloud) {
|
||||
setDisableCloudOpen(true);
|
||||
} else {
|
||||
setOpenSignIn(state => ({
|
||||
...state,
|
||||
openModal: true,
|
||||
}));
|
||||
}
|
||||
}, [setDisableCloudOpen, setOpenSignIn]);
|
||||
|
||||
const onSwitchChange = useCallback(
|
||||
(checked: boolean) => {
|
||||
if (loginStatus !== 'authenticated') {
|
||||
return openSignInModal();
|
||||
}
|
||||
return setEnable(checked);
|
||||
},
|
||||
[loginStatus, openSignInModal]
|
||||
);
|
||||
|
||||
const handleCreateWorkspace = useCallback(() => {
|
||||
onConfirmName(workspaceName);
|
||||
}, [onConfirmName, workspaceName]);
|
||||
onConfirmName(
|
||||
workspaceName,
|
||||
enable ? WorkspaceFlavour.AFFINE_CLOUD : WorkspaceFlavour.LOCAL
|
||||
);
|
||||
}, [enable, onConfirmName, workspaceName]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(event: KeyboardEvent<HTMLInputElement>) => {
|
||||
@ -61,7 +105,9 @@ const NameWorkspaceContent = ({
|
||||
},
|
||||
[handleCreateWorkspace, workspaceName]
|
||||
);
|
||||
const t = useAFFiNEI18N();
|
||||
// TODO: Support uploading avatars.
|
||||
// Currently, when we create a new workspace and upload an avatar at the same time,
|
||||
// an error occurs after the creation is successful: get blob 404 not found
|
||||
return (
|
||||
<ConfirmModal
|
||||
defaultOpen={true}
|
||||
@ -80,16 +126,56 @@ const NameWorkspaceContent = ({
|
||||
onConfirm={handleCreateWorkspace}
|
||||
{...props}
|
||||
>
|
||||
<Input
|
||||
autoFocus
|
||||
data-testid="create-workspace-input"
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={t['com.affine.nameWorkspace.placeholder']()}
|
||||
maxLength={64}
|
||||
minLength={0}
|
||||
onChange={setWorkspaceName}
|
||||
size="large"
|
||||
/>
|
||||
<div className={styles.avatarWrapper}>
|
||||
<Avatar size={56} name={workspaceName} colorfulFallback />
|
||||
</div>
|
||||
|
||||
<div className={styles.workspaceNameWrapper}>
|
||||
<div className={styles.subTitle}>
|
||||
{t['com.affine.nameWorkspace.subtitle.workspace-name']()}
|
||||
</div>
|
||||
<Input
|
||||
autoFocus
|
||||
data-testid="create-workspace-input"
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={t['com.affine.nameWorkspace.placeholder']()}
|
||||
maxLength={64}
|
||||
minLength={0}
|
||||
onChange={setWorkspaceName}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.affineCloudWrapper}>
|
||||
<div className={styles.subTitle}>{t['AFFiNE Cloud']()}</div>
|
||||
<div className={styles.card}>
|
||||
<div className={styles.cardText}>
|
||||
<div className={styles.cardTitle}>
|
||||
<span>{t['com.affine.nameWorkspace.affine-cloud.title']()}</span>
|
||||
<Switch
|
||||
checked={enable}
|
||||
onChange={onSwitchChange}
|
||||
disabled={shouldEnableCloud}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.cardDescription}>
|
||||
{t['com.affine.nameWorkspace.affine-cloud.description']()}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.cloudSvgContainer}>
|
||||
<CloudSvg />
|
||||
</div>
|
||||
</div>
|
||||
{shouldEnableCloud ? (
|
||||
<a
|
||||
className={styles.cloudTips}
|
||||
href={runtimeConfig.downloadUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t['com.affine.nameWorkspace.affine-cloud.web-tips']()}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
</ConfirmModal>
|
||||
);
|
||||
};
|
||||
@ -145,11 +231,11 @@ export const CreateWorkspaceModal = ({
|
||||
}, [mode, onClose, onCreate, t, workspaceManager]);
|
||||
|
||||
const onConfirmName = useAsyncCallback(
|
||||
async (name: string) => {
|
||||
async (name: string, workspaceFlavour: WorkspaceFlavour) => {
|
||||
// this will be the last step for web for now
|
||||
// fix me later
|
||||
const { id } = await workspaceManager.createWorkspace(
|
||||
WorkspaceFlavour.LOCAL,
|
||||
workspaceFlavour,
|
||||
async workspace => {
|
||||
workspace.meta.setName(name);
|
||||
if (runtimeConfig.enablePreloading) {
|
||||
@ -201,7 +287,7 @@ export const CreateWorkspaceModal = ({
|
||||
style: { padding: '10px' },
|
||||
}}
|
||||
>
|
||||
<div className={style.header}></div>
|
||||
<div className={styles.header}></div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,20 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
|
||||
export const CloudSvg = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="146"
|
||||
height="84"
|
||||
viewBox="0 0 146 84"
|
||||
fill="none"
|
||||
>
|
||||
<g opacity="0.1">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M66.9181 15.9788C52.6393 15.9788 41.064 27.5541 41.064 41.8329C41.064 43.7879 41.2801 45.687 41.6881 47.5094C42.2383 49.9676 40.6923 52.4066 38.2344 52.9579C29.4068 54.938 22.814 62.8293 22.814 72.2496C22.814 83.1687 31.6657 92.0204 42.5848 92.0204H97.3348C111.614 92.0204 123.189 80.4451 123.189 66.1663C123.189 51.8874 111.614 40.3121 97.3348 40.3121C97.1618 40.3121 96.9892 40.3138 96.8169 40.3172C94.6134 40.3603 92.6941 38.8222 92.2561 36.6623C89.8629 24.8606 79.4226 15.9788 66.9181 15.9788ZM31.939 41.8329C31.939 22.5145 47.5997 6.85376 66.9181 6.85376C82.573 6.85376 95.8181 17.1339 100.285 31.3098C118.223 32.808 132.314 47.8415 132.314 66.1663C132.314 85.4847 116.653 101.145 97.3348 101.145H42.5848C26.6261 101.145 13.689 88.2083 13.689 72.2496C13.689 59.9818 21.3304 49.5073 32.1102 45.3122C31.9969 44.1668 31.939 43.0061 31.939 41.8329Z"
|
||||
fill={cssVar('iconColor')}
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
@ -21,7 +21,6 @@ export const menuItemStyle = style({
|
||||
});
|
||||
export const descriptionStyle = style({
|
||||
wordWrap: 'break-word',
|
||||
// wordBreak: 'break-all',
|
||||
fontSize: cssVar('fontXs'),
|
||||
lineHeight: '20px',
|
||||
color: cssVar('textSecondaryColor'),
|
||||
|
@ -8,6 +8,10 @@ import {
|
||||
import { PublicLinkDisableModal } from '@affine/component/disable-public-link';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu';
|
||||
import type { PageMode } from '@affine/core/atoms';
|
||||
import { currentModeAtom } from '@affine/core/atoms/mode';
|
||||
import { useIsSharedPage } from '@affine/core/hooks/affine/use-is-shared-page';
|
||||
import { useServerBaseUrl } from '@affine/core/hooks/affine/use-server-config';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||
@ -15,33 +19,11 @@ import { useAtomValue } from 'jotai';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import type { PageMode } from '../../../../atoms';
|
||||
import { currentModeAtom } from '../../../../atoms/mode';
|
||||
import { useIsSharedPage } from '../../../../hooks/affine/use-is-shared-page';
|
||||
import { useServerBaseUrl } from '../../../../hooks/affine/use-server-config';
|
||||
import { CloudSvg } from '../cloud-svg';
|
||||
import * as styles from './index.css';
|
||||
import type { ShareMenuProps } from './share-menu';
|
||||
import { useSharingUrl } from './use-share-url';
|
||||
|
||||
const CloudSvg = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="146"
|
||||
height="84"
|
||||
viewBox="0 0 146 84"
|
||||
fill="none"
|
||||
>
|
||||
<g opacity="0.1">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M66.9181 15.9788C52.6393 15.9788 41.064 27.5541 41.064 41.8329C41.064 43.7879 41.2801 45.687 41.6881 47.5094C42.2383 49.9676 40.6923 52.4066 38.2344 52.9579C29.4068 54.938 22.814 62.8293 22.814 72.2496C22.814 83.1687 31.6657 92.0204 42.5848 92.0204H97.3348C111.614 92.0204 123.189 80.4451 123.189 66.1663C123.189 51.8874 111.614 40.3121 97.3348 40.3121C97.1618 40.3121 96.9892 40.3138 96.8169 40.3172C94.6134 40.3603 92.6941 38.8222 92.2561 36.6623C89.8629 24.8606 79.4226 15.9788 66.9181 15.9788ZM31.939 41.8329C31.939 22.5145 47.5997 6.85376 66.9181 6.85376C82.573 6.85376 95.8181 17.1339 100.285 31.3098C118.223 32.808 132.314 47.8415 132.314 66.1663C132.314 85.4847 116.653 101.145 97.3348 101.145H42.5848C26.6261 101.145 13.689 88.2083 13.689 72.2496C13.689 59.9818 21.3304 49.5073 32.1102 45.3122C31.9969 44.1668 31.939 43.0061 31.939 41.8329Z"
|
||||
fill="var(--affine-icon-color)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const LocalSharePage = (props: ShareMenuProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
|
@ -36,7 +36,9 @@ export const AddWorkspace = ({
|
||||
className={styles.ItemContainer}
|
||||
>
|
||||
<div className={styles.ItemText}>
|
||||
{t['com.affine.workspaceList.addWorkspace.create']()}
|
||||
{runtimeConfig.enableSQLiteProvider && environment.isDesktop
|
||||
? t['com.affine.workspaceList.addWorkspace.create']()
|
||||
: t['com.affine.workspaceList.addWorkspace.create-cloud']()}
|
||||
</div>
|
||||
</MenuItem>
|
||||
</div>
|
||||
|
@ -73,11 +73,37 @@ export const UserWithWorkspaceList = ({
|
||||
const isAuthenticated = useMemo(() => status === 'authenticated', [status]);
|
||||
|
||||
const setOpenCreateWorkspaceModal = useSetAtom(openCreateWorkspaceModalAtom);
|
||||
const setDisableCloudOpen = useSetAtom(openDisableCloudAlertModalAtom);
|
||||
|
||||
const setOpenSignIn = useSetAtom(authAtom);
|
||||
|
||||
const openSignInModal = useCallback(() => {
|
||||
if (!runtimeConfig.enableCloud) {
|
||||
setDisableCloudOpen(true);
|
||||
} else {
|
||||
setOpenSignIn(state => ({
|
||||
...state,
|
||||
openModal: true,
|
||||
}));
|
||||
}
|
||||
}, [setDisableCloudOpen, setOpenSignIn]);
|
||||
|
||||
const onNewWorkspace = useCallback(() => {
|
||||
if (
|
||||
!isAuthenticated &&
|
||||
!environment.isDesktop &&
|
||||
!runtimeConfig.allowLocalWorkspace
|
||||
) {
|
||||
return openSignInModal();
|
||||
}
|
||||
setOpenCreateWorkspaceModal('new');
|
||||
onEventEnd?.();
|
||||
}, [onEventEnd, setOpenCreateWorkspaceModal]);
|
||||
}, [
|
||||
isAuthenticated,
|
||||
onEventEnd,
|
||||
openSignInModal,
|
||||
setOpenCreateWorkspaceModal,
|
||||
]);
|
||||
|
||||
const onAddWorkspace = useCallback(() => {
|
||||
setOpenCreateWorkspaceModal('add');
|
||||
|
@ -698,6 +698,10 @@
|
||||
"com.affine.nameWorkspace.description": "A workspace is your virtual space to capture, create and plan as just one person or together as a team.",
|
||||
"com.affine.nameWorkspace.placeholder": "Set a Workspace name",
|
||||
"com.affine.nameWorkspace.title": "Name Your Workspace",
|
||||
"com.affine.nameWorkspace.subtitle.workspace-name": "Workspace Name",
|
||||
"com.affine.nameWorkspace.affine-cloud.title": "Sync across devices with AFFiNE Cloud",
|
||||
"com.affine.nameWorkspace.affine-cloud.description": "Enabling AFFiNE Cloud allows you to synchronise and backup data, as well as support multi-user collaboration and content publishing.",
|
||||
"com.affine.nameWorkspace.affine-cloud.web-tips": "If you want the workspace to be stored locally, you can download the desktop client.",
|
||||
"com.affine.new_edgeless": "New Edgeless",
|
||||
"com.affine.new_import": "Import",
|
||||
"com.affine.notFoundPage.backButton": "Back Home",
|
||||
@ -1013,6 +1017,7 @@
|
||||
"com.affine.workspaceLeave.button.leave": "Leave",
|
||||
"com.affine.workspaceLeave.description": "After you leave, you will no longer be able to access the contents of this workspace.",
|
||||
"com.affine.workspaceList.addWorkspace.create": "Create Workspace",
|
||||
"com.affine.workspaceList.addWorkspace.create-cloud": "Create Cloud Workspace",
|
||||
"com.affine.workspaceList.workspaceListType.cloud": "Cloud Sync",
|
||||
"com.affine.workspaceList.workspaceListType.local": "Local Storage",
|
||||
"com.affine.workspaceSubPath.all": "All docs",
|
||||
|
Loading…
Reference in New Issue
Block a user