mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 13:25:12 +00:00
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:
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -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)',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user