mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(sign-in): add message box
This commit is contained in:
parent
6fc29557ca
commit
3ab6a018fe
7 changed files with 46 additions and 3 deletions
|
@ -17,6 +17,8 @@
|
||||||
--color-button-text: #f5f5f5;
|
--color-button-text: #f5f5f5;
|
||||||
--color-button-text-disabled: #eee;
|
--color-button-text-disabled: #eee;
|
||||||
--color-error: #ff6b66;
|
--color-error: #ff6b66;
|
||||||
|
--color-error-background: #{rgba(#ff6b66, 0.15)};
|
||||||
|
--color-error-border: #{rgba(#ff6b66, 0.35)};
|
||||||
|
|
||||||
/* Shadow */
|
/* Shadow */
|
||||||
--shadow-button: 2px 2px 8px rgb(60 76 227 / 25%);
|
--shadow-button: 2px 2px 8px rgb(60 76 227 / 25%);
|
||||||
|
|
13
packages/ui/src/components/MessageBox/index.module.scss
Normal file
13
packages/ui/src/components/MessageBox/index.module.scss
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
@use '/src/scss/underscore' as _;
|
||||||
|
|
||||||
|
.messageBox {
|
||||||
|
font: var(--font-body);
|
||||||
|
padding: _.unit(2) _.unit(5);
|
||||||
|
border-radius: _.unit();
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
color: var(--color-error);
|
||||||
|
background: var(--color-error-background);
|
||||||
|
border: 1px solid var(--color-error-border);
|
||||||
|
}
|
||||||
|
}
|
14
packages/ui/src/components/MessageBox/index.tsx
Normal file
14
packages/ui/src/components/MessageBox/index.tsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
className?: string;
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MessageBox = ({ className, children }: Props) => {
|
||||||
|
return <div className={classNames(styles.messageBox, styles.error, className)}>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessageBox;
|
|
@ -2,6 +2,7 @@
|
||||||
"translation": {
|
"translation": {
|
||||||
"sign-in": "Sign In",
|
"sign-in": "Sign In",
|
||||||
"sign-in.loading": "Signing in...",
|
"sign-in.loading": "Signing in...",
|
||||||
|
"sign-in.error": "Username or password invalid.",
|
||||||
"sign-in.username": "Username",
|
"sign-in.username": "Username",
|
||||||
"sign-in.password": "Password"
|
"sign-in.password": "Password"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"translation": {
|
"translation": {
|
||||||
"sign-in": "登录",
|
"sign-in": "登录",
|
||||||
"sign-in.loading": "登录中...",
|
"sign-in.loading": "登录中...",
|
||||||
|
"sign-in.error": "用户名或密码错误。",
|
||||||
"sign-in.username": "用户名",
|
"sign-in.username": "用户名",
|
||||||
"sign-in.password": "密码"
|
"sign-in.password": "密码"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,17 @@
|
||||||
margin-bottom: _.unit(9);
|
margin-bottom: _.unit(9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
margin-top: _.unit(3);
|
||||||
|
margin-bottom: _.unit(-6);
|
||||||
|
}
|
||||||
|
|
||||||
> input:not([type='button']) {
|
> input:not([type='button']) {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
margin-top: _.unit(3);
|
margin-top: _.unit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
> input[type='button'] {
|
> input[type='button'] {
|
||||||
margin-top: _.unit(6);
|
margin-top: _.unit(12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import Input from '@/components/Input';
|
import Input from '@/components/Input';
|
||||||
|
import MessageBox from '@/components/MessageBox';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
export type PageState = 'idle' | 'loading' | 'error';
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [pageState, setPageState] = useState<PageState>('idle');
|
||||||
|
const isLoading = pageState === 'loading';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles.wrapper}>
|
<form className={styles.wrapper}>
|
||||||
|
@ -28,11 +32,14 @@ const Home = () => {
|
||||||
value={password}
|
value={password}
|
||||||
onChange={setPassword}
|
onChange={setPassword}
|
||||||
/>
|
/>
|
||||||
|
{pageState === 'error' && (
|
||||||
|
<MessageBox className={styles.box}>{t('sign-in.error')}</MessageBox>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
isDisabled={isLoading}
|
isDisabled={isLoading}
|
||||||
value={isLoading ? t('sign-in.loading') : t('sign-in')}
|
value={isLoading ? t('sign-in.loading') : t('sign-in')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsLoading(true);
|
setPageState('loading');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in a new issue