feat!: affine cloud support (#3813)

Co-authored-by: Hongtao Lye <codert.sn@gmail.com>
Co-authored-by: liuyi <forehalo@gmail.com>
Co-authored-by: LongYinan <lynweklm@gmail.com>
Co-authored-by: X1a0t <405028157@qq.com>
Co-authored-by: JimmFly <yangjinfei001@gmail.com>
Co-authored-by: Peng Xiao <pengxiao@outlook.com>
Co-authored-by: xiaodong zuo <53252747+zuoxiaodong0815@users.noreply.github.com>
Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com>
Co-authored-by: Qi <474021214@qq.com>
Co-authored-by: danielchim <kahungchim@gmail.com>
This commit is contained in:
Alex Yang
2023-08-29 05:07:05 -05:00
committed by GitHub
parent d0145c6f38
commit 2f6c4e3696
414 changed files with 19469 additions and 7591 deletions

View File

@@ -0,0 +1,30 @@
export const ErrorIcon = () => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="InformationFill_Duotone">
<g id="Icon (Stroke)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.33398 8.00065C1.33398 4.31875 4.31875 1.33398 8.00065 1.33398C11.6826 1.33398 14.6673 4.31875 14.6673 8.00065C14.6673 11.6826 11.6826 14.6673 8.00065 14.6673C4.31875 14.6673 1.33398 11.6826 1.33398 8.00065ZM7.33398 5.33398C7.33398 4.96579 7.63246 4.66732 8.00065 4.66732H8.00732C8.37551 4.66732 8.67398 4.96579 8.67398 5.33398C8.67398 5.70217 8.37551 6.00065 8.00732 6.00065H8.00065C7.63246 6.00065 7.33398 5.70217 7.33398 5.33398ZM8.00065 6.66732C8.36884 6.66732 8.66732 6.96579 8.66732 7.33398V10.6673C8.66732 11.0355 8.36884 11.334 8.00065 11.334C7.63246 11.334 7.33398 11.0355 7.33398 10.6673V7.33398C7.33398 6.96579 7.63246 6.66732 8.00065 6.66732Z"
fill="#EB4335"
/>
<path
d="M8.66732 7.33398C8.66732 6.96579 8.36884 6.66732 8.00065 6.66732C7.63246 6.66732 7.33398 6.96579 7.33398 7.33398V10.6673C7.33398 11.0355 7.63246 11.334 8.00065 11.334C8.36884 11.334 8.66732 11.0355 8.66732 10.6673V7.33398Z"
fill="white"
/>
<path
d="M8.00065 4.66732C7.63246 4.66732 7.33398 4.96579 7.33398 5.33398C7.33398 5.70217 7.63246 6.00065 8.00065 6.00065H8.00732C8.37551 6.00065 8.67398 5.70217 8.67398 5.33398C8.67398 4.96579 8.37551 4.66732 8.00732 4.66732H8.00065Z"
fill="white"
/>
</g>
</g>
</svg>
);
};

View File

@@ -0,0 +1,100 @@
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { passwordStrength } from 'check-password-strength';
import { type FC, useEffect } from 'react';
import { useCallback, useState } from 'react';
import { Input, type InputProps } from '../../../ui/input';
import { ErrorIcon } from './error';
import { SuccessIcon } from './success';
import { Tag } from './tag';
export type Status = 'weak' | 'medium' | 'strong' | 'maximum';
export const PasswordInput: FC<
InputProps & {
onPass: (password: string) => void;
onPrevent: () => void;
}
> = ({ onPass, onPrevent, ...inputProps }) => {
const t = useAFFiNEI18N();
const [status, setStatus] = useState<Status | null>(null);
const [confirmStatus, setConfirmStatus] = useState<
'success' | 'error' | null
>(null);
const [password, setPassWord] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const onPasswordChange = useCallback((value: string) => {
setPassWord(value);
if (!value) {
return setStatus(null);
}
if (value.length > 20) {
return setStatus('maximum');
}
switch (passwordStrength(value).id) {
case 0:
case 1:
setStatus('weak');
break;
case 2:
setStatus('medium');
break;
case 3:
setStatus('strong');
break;
}
}, []);
const onConfirmPasswordChange = useCallback((value: string) => {
setConfirmPassword(value);
}, []);
useEffect(() => {
if (password === confirmPassword) {
setConfirmStatus('success');
} else {
setConfirmStatus('error');
}
}, [confirmPassword, password]);
useEffect(() => {
if (confirmStatus === 'success' && password.length > 7) {
onPass(password);
} else {
onPrevent();
}
}, [confirmStatus, onPass, onPrevent, password]);
return (
<>
<Input
type="password"
size="extraLarge"
style={{ marginBottom: 20 }}
placeholder={t['com.affine.auth.set.password.placeholder']()}
onChange={onPasswordChange}
endFix={status ? <Tag status={status} /> : null}
{...inputProps}
/>
<Input
type="password"
size="extraLarge"
placeholder={t['com.affine.auth.set.password.placeholder.confirm']()}
onChange={onConfirmPasswordChange}
endFix={
confirmStatus ? (
confirmStatus === 'success' ? (
<SuccessIcon />
) : (
<ErrorIcon />
)
) : null
}
{...inputProps}
/>
</>
);
};

View File

@@ -0,0 +1,28 @@
import { style } from '@vanilla-extract/css';
export const tag = style({
padding: '0 15px',
height: 20,
lineHeight: '20px',
borderRadius: 10,
fontSize: 'var(--affine-font-xs)',
selectors: {
'&.weak': {
backgroundColor: 'var(--affine-tag-red)',
color: 'var(--affine-error-color)',
},
'&.medium': {
backgroundColor: 'var(--affine-tag-orange)',
color: 'var(--affine-warning-color)',
},
'&.strong': {
backgroundColor: 'var(--affine-tag-green)',
color: 'var(--affine-success-color)',
},
'&.maximum': {
backgroundColor: 'var(--affine-tag-red)',
color: 'var(--affine-error-color)',
},
},
});

View File

@@ -0,0 +1,28 @@
export const SuccessIcon = () => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SingleSelect">
<path
id="Ellipse 2102 (Stroke)"
fillRule="evenodd"
clipRule="evenodd"
d="M1.5 8C1.5 4.41015 4.41015 1.5 8 1.5C11.5899 1.5 14.5 4.41015 14.5 8C14.5 11.5899 11.5899 14.5 8 14.5C4.41015 14.5 1.5 11.5899 1.5 8Z"
fill="#10CB86"
/>
<path
id="Icon (Stroke)"
fillRule="evenodd"
clipRule="evenodd"
d="M11.0052 5.63143C11.2087 5.81802 11.2225 6.13431 11.0359 6.33787L7.36923 10.3379C7.27708 10.4384 7.14786 10.4969 7.01151 10.4999C6.87517 10.5028 6.74353 10.45 6.6471 10.3536L4.98043 8.68689C4.78517 8.49163 4.78517 8.17505 4.98043 7.97978C5.17569 7.78452 5.49228 7.78452 5.68754 7.97978L6.98495 9.27719L10.2987 5.66214C10.4853 5.45858 10.8016 5.44483 11.0052 5.63143Z"
fill="white"
/>
</g>
</svg>
);
};

View File

@@ -0,0 +1,28 @@
import clsx from 'clsx';
import { type FC, useMemo } from 'react';
import type { Status } from './index';
import { tag } from './style.css';
export const Tag: FC<{ status: Status }> = ({ status }) => {
const textMap = useMemo<{ [K in Status]: string }>(() => {
return {
weak: 'Weak',
medium: 'Medium',
strong: 'Strong',
maximum: 'Maximum',
};
}, []);
return (
<div
className={clsx(tag, {
weak: status === 'weak',
medium: status === 'medium',
strong: status === 'strong',
maximum: status === 'maximum',
})}
>
{textMap[status]}
</div>
);
};