- {title === 'AFFiNE Cloud' && }
+
{title}
{subTitle}
diff --git a/packages/frontend/component/src/components/auth-components/auth-input.tsx b/packages/frontend/component/src/components/auth-components/auth-input.tsx
index 7e2ae52d8e..053601a226 100644
--- a/packages/frontend/component/src/components/auth-components/auth-input.tsx
+++ b/packages/frontend/component/src/components/auth-components/auth-input.tsx
@@ -8,14 +8,12 @@ export type AuthInputProps = InputProps & {
label?: string;
error?: boolean;
errorHint?: ReactNode;
- withoutHint?: boolean;
onEnter?: () => void;
};
export const AuthInput = ({
label,
error,
errorHint,
- withoutHint = false,
onEnter,
className,
...inputProps
@@ -23,7 +21,7 @@ export const AuthInput = ({
return (
{label ?
: null}
@@ -34,14 +32,8 @@ export const AuthInput = ({
onEnter={onEnter}
{...inputProps}
/>
- {error && errorHint && !withoutHint ? (
-
- {errorHint}
-
+ {error && errorHint ? (
+
{errorHint}
) : null}
);
diff --git a/packages/frontend/component/src/components/auth-components/back-button.tsx b/packages/frontend/component/src/components/auth-components/back-button.tsx
index fa886dd8cb..555fde0743 100644
--- a/packages/frontend/component/src/components/auth-components/back-button.tsx
+++ b/packages/frontend/component/src/components/auth-components/back-button.tsx
@@ -1,6 +1,5 @@
import { useI18n } from '@affine/i18n';
import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc';
-import { cssVar } from '@toeverything/theme';
import type { FC } from 'react';
import type { ButtonProps } from '../../ui/button';
@@ -12,11 +11,7 @@ export const BackButton: FC
= props => {
}
{...props}
diff --git a/packages/frontend/component/src/components/auth-components/index.tsx b/packages/frontend/component/src/components/auth-components/index.tsx
index 3d2622a013..b01facbf6f 100644
--- a/packages/frontend/component/src/components/auth-components/index.tsx
+++ b/packages/frontend/component/src/components/auth-components/index.tsx
@@ -1,10 +1,12 @@
+export * from './auth-container';
export * from './auth-content';
+export * from './auth-footer';
+export * from './auth-header';
export * from './auth-input';
export * from './auth-page-container';
export * from './back-button';
export * from './change-email-page';
export * from './change-password-page';
-export * from './modal-header';
export * from './onboarding-page';
export * from './password-input';
export * from './set-password-page';
diff --git a/packages/frontend/component/src/components/auth-components/share.css.ts b/packages/frontend/component/src/components/auth-components/share.css.ts
index c145edc64c..d7d6fb9d25 100644
--- a/packages/frontend/component/src/components/auth-components/share.css.ts
+++ b/packages/frontend/component/src/components/auth-components/share.css.ts
@@ -1,14 +1,25 @@
import { cssVar } from '@toeverything/theme';
-import { globalStyle, keyframes, style } from '@vanilla-extract/css';
-export const modalHeaderWrapper = style({});
-globalStyle(`${modalHeaderWrapper} .logo`, {
+import { globalStyle, style } from '@vanilla-extract/css';
+export const authContainer = style({
+ display: 'flex',
+ flexDirection: 'column',
+ height: '100%',
+ width: '100%',
+ minHeight: '422px',
+});
+
+export const authHeaderWrapper = style({
+ marginBottom: '20px',
+});
+globalStyle(`${authHeaderWrapper} .logo`, {
fontSize: cssVar('fontH3'),
fontWeight: 600,
color: cssVar('black'),
marginRight: '6px',
verticalAlign: 'middle',
});
-globalStyle(`${modalHeaderWrapper} > p:first-of-type`, {
+
+globalStyle(`${authHeaderWrapper} > p:first-of-type`, {
fontSize: cssVar('fontH5'),
fontWeight: 600,
marginBottom: '4px',
@@ -16,20 +27,37 @@ globalStyle(`${modalHeaderWrapper} > p:first-of-type`, {
display: 'flex',
alignItems: 'center',
});
-globalStyle(`${modalHeaderWrapper} > p:last-of-type`, {
+globalStyle(`${authHeaderWrapper} > p:last-of-type`, {
fontSize: cssVar('fontH4'),
fontWeight: 600,
lineHeight: '28px',
});
+
+export const authContent = style({
+ fontSize: cssVar('fontBase'),
+ lineHeight: cssVar('fontH3'),
+ flexGrow: 1,
+});
+
+globalStyle(`${authContent} > *:not(:last-child)`, {
+ marginBottom: '20px',
+});
+
export const authInputWrapper = style({
- paddingBottom: '30px',
position: 'relative',
selectors: {
- '&.without-hint': {
- paddingBottom: '20px',
+ '&.with-hint': {
+ marginBottom: '8px',
},
},
});
+
+export const authFooter = style({});
+
+globalStyle(`${authFooter} > *:not(:last-child)`, {
+ marginBottom: '20px',
+});
+
globalStyle(`${authInputWrapper} label`, {
display: 'block',
color: cssVar('textSecondaryColor'),
@@ -38,109 +66,17 @@ globalStyle(`${authInputWrapper} label`, {
fontWeight: 600,
lineHeight: '22px',
});
-export const formHint = style({
- fontSize: cssVar('fontSm'),
- position: 'absolute',
- bottom: '4px',
- height: '22px',
- left: 0,
- lineHeight: '22px',
- selectors: {
- '&.error': {
- color: cssVar('errorColor'),
- },
- '&.warning': {
- color: cssVar('warningColor'),
- },
- },
-});
-const rotate = keyframes({
- '0%': {
- transform: 'rotate(0deg)',
- },
- '50%': {
- transform: 'rotate(180deg)',
- },
- '100%': {
- transform: 'rotate(360deg)',
- },
-});
-export const loading = style({
- width: '15px',
- height: '15px',
- position: 'relative',
- borderRadius: '50%',
- overflow: 'hidden',
- backgroundColor: cssVar('borderColor'),
- selectors: {
- '&::after': {
- content: '""',
- width: '12px',
- height: '12px',
- position: 'absolute',
- left: '0',
- right: '0',
- top: '0',
- bottom: '0',
- margin: 'auto',
- backgroundColor: '#fff',
- zIndex: 2,
- borderRadius: '50%',
- },
- '&::before': {
- content: '""',
- width: '20px',
- height: '20px',
- backgroundColor: cssVar('blue'),
- position: 'absolute',
- left: '50%',
- bottom: '50%',
- zIndex: '1',
- transformOrigin: 'left bottom',
- animation: `${rotate} 1.5s infinite linear`,
- },
- },
-});
-export const authContent = style({
- fontSize: cssVar('fontBase'),
- lineHeight: cssVar('fontH3'),
- marginTop: '30px',
+
+export const authInputError = style({
+ color: cssVar('errorColor'),
+ fontSize: cssVar('fontXs'),
+ lineHeight: '20px',
});
+
globalStyle(`${authContent} a`, {
color: cssVar('linkColor'),
});
-export const authCodeContainer = style({
- paddingBottom: '40px',
- position: 'relative',
-});
-export const authCodeWrapper = style({
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
-});
-export const authCodeErrorMessage = style({
- color: cssVar('errorColor'),
- fontSize: cssVar('fontSm'),
- textAlign: 'center',
- lineHeight: '1.5',
- position: 'absolute',
- left: 0,
- right: 0,
- bottom: 5,
- margin: 'auto',
-});
-export const resendButtonWrapper = style({
- height: 32,
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center',
- marginTop: 30,
-});
-globalStyle(`${resendButtonWrapper} .resend-code-hint`, {
- fontWeight: 600,
- fontSize: cssVar('fontSm'),
- marginRight: 8,
-});
+
export const authPageContainer = style({
height: '100vh',
width: '100vw',
diff --git a/packages/frontend/component/src/type.d.ts b/packages/frontend/component/src/type.d.ts
index bcafcc1e71..ce48fcaedd 100644
--- a/packages/frontend/component/src/type.d.ts
+++ b/packages/frontend/component/src/type.d.ts
@@ -7,3 +7,8 @@ declare module '*.png' {
const src: string;
export default src;
}
+
+declare module '*.inline.svg' {
+ const src: string;
+ export default src;
+}
diff --git a/packages/frontend/core/src/components/affine/auth/oauth.tsx b/packages/frontend/core/src/components/affine/auth/oauth.tsx
index 1de97d7ad5..7be403761a 100644
--- a/packages/frontend/core/src/components/affine/auth/oauth.tsx
+++ b/packages/frontend/core/src/components/affine/auth/oauth.tsx
@@ -96,7 +96,7 @@ function OAuthProvider({
variant="primary"
block
size="extraLarge"
- style={{ marginTop: 30, width: '100%' }}
+ style={{ width: '100%' }}
prefix={icon}
onClick={onClick}
>
diff --git a/packages/frontend/core/src/components/sign-in/add-selfhosted.tsx b/packages/frontend/core/src/components/sign-in/add-selfhosted.tsx
index d993681d56..42bded45c5 100644
--- a/packages/frontend/core/src/components/sign-in/add-selfhosted.tsx
+++ b/packages/frontend/core/src/components/sign-in/add-selfhosted.tsx
@@ -1,8 +1,10 @@
import { Button } from '@affine/component';
import {
+ AuthContainer,
AuthContent,
+ AuthFooter,
+ AuthHeader,
AuthInput,
- ModalHeader,
} from '@affine/component/auth-components';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { ServersService } from '@affine/core/modules/cloud';
@@ -18,6 +20,7 @@ import {
} from 'react';
import type { SignInState } from '.';
+import { Back } from './back';
import * as styles from './style.css';
function normalizeURL(url: string) {
@@ -85,8 +88,8 @@ export const AddSelfhostedStep = ({
}, [changeState, onConnect, serversService, state]);
return (
- <>
-
+
+
{t['com.affine.auth.sign.add-selfhosted.connect-button']()}
+
+
-
- >
+
+
+
);
};
diff --git a/packages/frontend/core/src/components/sign-in/back.tsx b/packages/frontend/core/src/components/sign-in/back.tsx
new file mode 100644
index 0000000000..6b3b5999f4
--- /dev/null
+++ b/packages/frontend/core/src/components/sign-in/back.tsx
@@ -0,0 +1,18 @@
+import { BackButton } from '@affine/component/auth-components';
+import { type Dispatch, type SetStateAction, useCallback } from 'react';
+
+import type { SignInState } from '.';
+
+interface BackButtonProps {
+ changeState: Dispatch>;
+}
+export function Back({ changeState }: BackButtonProps) {
+ const onClick = useCallback(() => {
+ changeState(prev => ({
+ ...prev,
+ step: 'signIn',
+ }));
+ }, [changeState]);
+
+ return ;
+}
diff --git a/packages/frontend/core/src/components/sign-in/background-arts/art-dark.inline.svg b/packages/frontend/core/src/components/sign-in/background-arts/art-dark.inline.svg
new file mode 100644
index 0000000000..e058e4c57f
--- /dev/null
+++ b/packages/frontend/core/src/components/sign-in/background-arts/art-dark.inline.svg
@@ -0,0 +1,86 @@
+
diff --git a/packages/frontend/core/src/components/sign-in/background-arts/art-light.inline.svg b/packages/frontend/core/src/components/sign-in/background-arts/art-light.inline.svg
new file mode 100644
index 0000000000..5a5cca7c13
--- /dev/null
+++ b/packages/frontend/core/src/components/sign-in/background-arts/art-light.inline.svg
@@ -0,0 +1,86 @@
+
diff --git a/packages/frontend/core/src/components/sign-in/background-arts/index.tsx b/packages/frontend/core/src/components/sign-in/background-arts/index.tsx
new file mode 100644
index 0000000000..f665c1727d
--- /dev/null
+++ b/packages/frontend/core/src/components/sign-in/background-arts/index.tsx
@@ -0,0 +1,18 @@
+import { useTheme } from 'next-themes';
+
+import darkArt from './art-dark.inline.svg';
+import lightArt from './art-light.inline.svg';
+import { arts, wrapper } from './style.css';
+
+export function SignInBackgroundArts() {
+ const { resolvedTheme } = useTheme();
+
+ return (
+
+

+
+ );
+}
diff --git a/packages/frontend/core/src/components/sign-in/background-arts/style.css.ts b/packages/frontend/core/src/components/sign-in/background-arts/style.css.ts
new file mode 100644
index 0000000000..bea396c01b
--- /dev/null
+++ b/packages/frontend/core/src/components/sign-in/background-arts/style.css.ts
@@ -0,0 +1,14 @@
+import { style } from '@vanilla-extract/css';
+
+export const wrapper = style({
+ position: 'relative',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+});
+
+export const arts = style({
+ position: 'absolute',
+ top: '128px',
+});
diff --git a/packages/frontend/core/src/components/sign-in/index.tsx b/packages/frontend/core/src/components/sign-in/index.tsx
index 3bcb0ef07a..005a7ef892 100644
--- a/packages/frontend/core/src/components/sign-in/index.tsx
+++ b/packages/frontend/core/src/components/sign-in/index.tsx
@@ -19,6 +19,7 @@ export interface SignInState {
server?: Server;
initialServerBaseUrl?: string;
email?: string;
+ hasPassword?: boolean;
redirectUrl?: string;
}
diff --git a/packages/frontend/core/src/components/sign-in/sign-in-with-email.tsx b/packages/frontend/core/src/components/sign-in/sign-in-with-email.tsx
index 6957535590..0337d754d3 100644
--- a/packages/frontend/core/src/components/sign-in/sign-in-with-email.tsx
+++ b/packages/frontend/core/src/components/sign-in/sign-in-with-email.tsx
@@ -1,9 +1,10 @@
import { notify } from '@affine/component';
import {
+ AuthContainer,
AuthContent,
+ AuthFooter,
+ AuthHeader,
AuthInput,
- BackButton,
- ModalHeader,
} from '@affine/component/auth-components';
import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
@@ -26,6 +27,7 @@ import {
} from 'react';
import type { SignInState } from '.';
+import { Back } from './back';
import { Captcha } from './captcha';
import * as style from './style.css';
@@ -123,10 +125,6 @@ export const SignInWithEmailStep = ({
changeState(prev => ({ ...prev, step: 'signInWithPassword' }));
}, [changeState]);
- const onBackBottomClick = useCallback(() => {
- changeState(prev => ({ ...prev, step: 'signIn' }));
- }, [changeState]);
-
const onOtpChanged = useCallback((value: string) => {
setOtp(value);
setOtpError(undefined);
@@ -158,54 +156,55 @@ export const SignInWithEmailStep = ({
return !verifyToken && needCaptcha ? (
<>
-
+
-
+
>
) : (
- <>
-
+
-
- }}
+
+
+ }}
+ />
+
+
+
-
-
+
-
-
-
-
+
-
- {t['com.affine.auth.sign.auth.code.message']()}
-
-
- ),
- }}
- />
-
+
+
+ {t['com.affine.auth.sign.auth.code.message']()}
+
+ {state.hasPassword && (
+
+ ),
+ }}
+ />
+ )}
+
-
- >
+
+
+
);
};
diff --git a/packages/frontend/core/src/components/sign-in/sign-in-with-password.tsx b/packages/frontend/core/src/components/sign-in/sign-in-with-password.tsx
index f79ac964b5..002fcfd5fe 100644
--- a/packages/frontend/core/src/components/sign-in/sign-in-with-password.tsx
+++ b/packages/frontend/core/src/components/sign-in/sign-in-with-password.tsx
@@ -1,8 +1,10 @@
-import { notify, Wrapper } from '@affine/component';
+import { notify } from '@affine/component';
import {
+ AuthContainer,
+ AuthContent,
+ AuthFooter,
+ AuthHeader,
AuthInput,
- BackButton,
- ModalHeader,
} from '@affine/component/auth-components';
import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
@@ -20,6 +22,7 @@ import type { Dispatch, SetStateAction } from 'react';
import { useCallback, useEffect, useState } from 'react';
import type { SignInState } from '.';
+import { Back } from './back';
import { Captcha } from './captcha';
import * as styles from './style.css';
@@ -105,18 +108,13 @@ export const SignInWithPasswordStep = ({
}, [changeState]);
return (
- <>
-
+
-
+
{t['com.affine.auth.sign.in']()}
-
- {
- changeState(prev => ({ ...prev, step: 'signIn' }));
- }, [changeState])}
- />
- >
+
+
+
+
+
);
};
diff --git a/packages/frontend/core/src/components/sign-in/sign-in.tsx b/packages/frontend/core/src/components/sign-in/sign-in.tsx
index efbe5e2199..f25b1842ac 100644
--- a/packages/frontend/core/src/components/sign-in/sign-in.tsx
+++ b/packages/frontend/core/src/components/sign-in/sign-in.tsx
@@ -1,5 +1,10 @@
import { Button, notify } from '@affine/component';
-import { AuthInput, ModalHeader } from '@affine/component/auth-components';
+import {
+ AuthContainer,
+ AuthContent,
+ AuthHeader,
+ AuthInput,
+} from '@affine/component/auth-components';
import { OAuth } from '@affine/core/components/affine/auth/oauth';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { AuthService, ServerService } from '@affine/core/modules/cloud';
@@ -7,7 +12,11 @@ import type { AuthSessionStatus } from '@affine/core/modules/cloud/entities/sess
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { ServerDeploymentType } from '@affine/graphql';
import { Trans, useI18n } from '@affine/i18n';
-import { ArrowRightBigIcon, PublishIcon } from '@blocksuite/icons/rc';
+import {
+ ArrowRightBigIcon,
+ LocalWorkspaceIcon,
+ PublishIcon,
+} from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import { cssVar } from '@toeverything/theme';
import {
@@ -93,6 +102,7 @@ export const SignInStep = ({
...prev,
email,
step: 'signInWithPassword',
+ hasPassword: true,
}));
} else {
if (magicLink) {
@@ -100,6 +110,7 @@ export const SignInStep = ({
...prev,
email,
step: 'signInWithEmail',
+ hasPassword: false,
}));
} else {
notify.error({
@@ -113,6 +124,7 @@ export const SignInStep = ({
...prev,
email,
step: 'signInWithEmail',
+ hasPassword: false,
}));
} else {
notify.error({
@@ -140,15 +152,15 @@ export const SignInStep = ({
}, [changeState]);
return (
- <>
-
+
-
+
+
-
{!isSelfhosted &&
- BUILD_CONFIG.isElectron &&
- enableMultipleCloudServers && (
-
- }
- onClick={onAddSelfhosted}
- >
- {t['com.affine.auth.sign.add-selfhosted']()}
-
- )}
-
- {t['com.affine.mobile.sign-in.skip.hint']()}
-
+ BUILD_CONFIG.isElectron &&
+ enableMultipleCloudServers ? (
+
+ }
+ onClick={onAddSelfhosted}
+ >
+ {t['com.affine.auth.sign.add-selfhosted']()}
+
+ ) : (
+
+ {t['com.affine.mobile.sign-in.skip.hint']()}
+
+ )}
}
+ prefix={
}
>
{t['com.affine.mobile.sign-in.skip.link']()}
-
- >
+
+
);
};
diff --git a/packages/frontend/core/src/components/sign-in/style.css.ts b/packages/frontend/core/src/components/sign-in/style.css.ts
index 931ccfdd1a..c83413b73a 100644
--- a/packages/frontend/core/src/components/sign-in/style.css.ts
+++ b/packages/frontend/core/src/components/sign-in/style.css.ts
@@ -2,16 +2,12 @@ import { cssVar } from '@toeverything/theme';
import { cssVarV2 } from '@toeverything/theme/v2';
import { globalStyle, style } from '@vanilla-extract/css';
-export const authModalContent = style({
- marginTop: '30px',
-});
-
export const authMessage = style({
- marginTop: '30px',
color: cssVar('textSecondaryColor'),
fontSize: cssVar('fontXs'),
- lineHeight: 1.5,
+ lineHeight: '20px',
});
+
globalStyle(`${authMessage} a`, {
color: cssVar('linkColor'),
});
@@ -42,14 +38,7 @@ export const linkButton = style({
userSelect: 'none',
});
-export const resendButtonWrapper = style({
- marginTop: 20,
-});
-
export const addSelfhostedButton = style({
- marginTop: 10,
- marginLeft: -5,
- marginBottom: 16,
color: cssVarV2('text/link'),
});
@@ -62,8 +51,6 @@ export const skipDivider = style({
gap: 12,
alignItems: 'center',
height: 20,
- marginTop: 12,
- marginBottom: 12,
});
export const skipDividerLine = style({
diff --git a/packages/frontend/core/src/desktop/dialogs/change-password/index.tsx b/packages/frontend/core/src/desktop/dialogs/change-password/index.tsx
index cd9a5d5e24..d3b628ca26 100644
--- a/packages/frontend/core/src/desktop/dialogs/change-password/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/change-password/index.tsx
@@ -1,8 +1,8 @@
-import { Button, Modal, notify, Wrapper } from '@affine/component';
+import { Button, Modal, notify } from '@affine/component';
import {
AuthContent,
+ AuthHeader,
AuthInput,
- ModalHeader,
} from '@affine/component/auth-components';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
@@ -108,7 +108,7 @@ export const ChangePasswordDialog = ({
style: { padding: '44px 40px 20px' },
}}
>
-
- {hasPassword
- ? t['com.affine.auth.reset.password.message']()
- : t['com.affine.auth.set.password.message']({
- min: String(passwordLimits.minLength),
- max: String(passwordLimits.maxLength),
- })}
-
-
-
+
+ {hasPassword
+ ? t['com.affine.auth.reset.password.message']()
+ : t['com.affine.auth.set.password.message']({
+ min: String(passwordLimits.minLength),
+ max: String(passwordLimits.maxLength),
+ })}
+
-
-
-
+
+
);
};
diff --git a/packages/frontend/core/src/desktop/dialogs/sign-in/index.tsx b/packages/frontend/core/src/desktop/dialogs/sign-in/index.tsx
index 7816142cef..41e8086fef 100644
--- a/packages/frontend/core/src/desktop/dialogs/sign-in/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/sign-in/index.tsx
@@ -24,7 +24,7 @@ export const SignInDialog = ({
open
onOpenChange={() => close()}
width={400}
- minHeight={500}
+ height={550}
contentOptions={{
['data-testid' as string]: 'auth-modal',
style: { padding: '44px 40px 20px' },
diff --git a/packages/frontend/core/src/desktop/dialogs/verify-email/index.tsx b/packages/frontend/core/src/desktop/dialogs/verify-email/index.tsx
index bef3fa5732..0ff4933c4f 100644
--- a/packages/frontend/core/src/desktop/dialogs/verify-email/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/verify-email/index.tsx
@@ -1,8 +1,8 @@
-import { Button, Modal, notify, Wrapper } from '@affine/component';
+import { Button, Modal, notify } from '@affine/component';
import {
AuthContent,
+ AuthHeader,
AuthInput,
- ModalHeader,
} from '@affine/component/auth-components';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
@@ -106,28 +106,18 @@ export const VerifyEmailDialog = ({
style: { padding: '44px 40px 20px' },
}}
>
-
- {t['com.affine.auth.verify.email.message']({ email })}
-
-
-
+ {t['com.affine.auth.verify.email.message']({ email })}
-
-
+