diff --git a/package.json b/package.json
index 3e74580..2105e79 100644
--- a/package.json
+++ b/package.json
@@ -17,9 +17,11 @@
"@mui/icons-material": "^5.11.9",
"@mui/material": "^5.11.9",
"@next/font": "13.1.6",
+ "formik": "^2.2.9",
"next": "13.1.6",
"react": "18.2.0",
- "react-dom": "18.2.0"
+ "react-dom": "18.2.0",
+ "yup": "^1.0.0"
},
"devDependencies": {
"@types/node": "18.13.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f91dd89..7634f1b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,6 +13,7 @@ specifiers:
eslint: ^8.34.0
eslint-config-next: ^13.1.6
eslint-config-prettier: ^8.6.0
+ formik: ^2.2.9
husky: ^8.0.0
lint-staged: ^13.1.2
next: 13.1.6
@@ -20,6 +21,7 @@ specifiers:
react: 18.2.0
react-dom: 18.2.0
typescript: ^4.9.5
+ yup: ^1.0.0
dependencies:
'@emotion/react': 11.10.6_pmekkgnqduwlme35zpnqhenc34
@@ -28,9 +30,11 @@ dependencies:
'@mui/icons-material': 5.11.9_ofpk46txu7v2f5mzrtv4xsczka
'@mui/material': 5.11.9_xqeqsl5kvjjtyxwyi3jhw3yuli
'@next/font': 13.1.6
+ formik: 2.2.9_react@18.2.0
next: 13.1.6_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
+ yup: 1.0.0
devDependencies:
'@types/node': 18.13.0
@@ -1071,6 +1075,11 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
+ /deepmerge/2.2.1:
+ resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/define-lazy-prop/2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
@@ -1606,6 +1615,21 @@ packages:
is-callable: 1.2.7
dev: true
+ /formik/2.2.9_react@18.2.0:
+ resolution: {integrity: sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==}
+ peerDependencies:
+ react: '>=16.8.0'
+ dependencies:
+ deepmerge: 2.2.1
+ hoist-non-react-statics: 3.3.2
+ lodash: 4.17.21
+ lodash-es: 4.17.21
+ react: 18.2.0
+ react-fast-compare: 2.0.4
+ tiny-warning: 1.0.3
+ tslib: 1.14.1
+ dev: false
+
/fs.realpath/1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
@@ -2151,10 +2175,18 @@ packages:
p-locate: 5.0.0
dev: true
+ /lodash-es/4.17.21:
+ resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+ dev: false
+
/lodash.merge/4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
+ /lodash/4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ dev: false
+
/log-update/4.0.0:
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
engines: {node: '>=10'}
@@ -2500,6 +2532,10 @@ packages:
object-assign: 4.1.1
react-is: 16.13.1
+ /property-expr/2.0.5:
+ resolution: {integrity: sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==}
+ dev: false
+
/punycode/2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@@ -2519,6 +2555,10 @@ packages:
scheduler: 0.23.0
dev: false
+ /react-fast-compare/2.0.4:
+ resolution: {integrity: sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==}
+ dev: false
+
/react-is/16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@@ -2866,6 +2906,10 @@ packages:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: true
+ /tiny-case/1.0.3:
+ resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
+ dev: false
+
/tiny-glob/0.2.9:
resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}
dependencies:
@@ -2873,6 +2917,10 @@ packages:
globrex: 0.1.2
dev: true
+ /tiny-warning/1.0.3:
+ resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
+ dev: false
+
/to-fast-properties/2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
@@ -2885,6 +2933,10 @@ packages:
is-number: 7.0.0
dev: true
+ /toposort/2.0.2:
+ resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
+ dev: false
+
/tsconfig-paths/3.14.1:
resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==}
dependencies:
@@ -2896,7 +2948,6 @@ packages:
/tslib/1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
- dev: true
/tslib/2.5.0:
resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
@@ -2928,6 +2979,11 @@ packages:
engines: {node: '>=10'}
dev: true
+ /type-fest/2.19.0:
+ resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
+ engines: {node: '>=12.20'}
+ dev: false
+
/typed-array-length/1.0.4:
resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
dependencies:
@@ -3041,3 +3097,12 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
+
+ /yup/1.0.0:
+ resolution: {integrity: sha512-bRZIyMkoe212ahGJTE32cr2dLkJw53Va+Uw5mzsBKpcef9zCGQ23k/xtpQUfGwdWPKvCIlR8CzFwchs2rm2XpQ==}
+ dependencies:
+ property-expr: 2.0.5
+ tiny-case: 1.0.3
+ toposort: 2.0.2
+ type-fest: 2.19.0
+ dev: false
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 926739b..cb457e6 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,9 +1,15 @@
import type { AppProps } from 'next/app'
+import CssBaseline from '@mui/material/CssBaseline'
import '@fontsource/roboto/300.css'
import '@fontsource/roboto/400.css'
import '@fontsource/roboto/500.css'
import '@fontsource/roboto/700.css'
export default function App({ Component, pageProps }: AppProps) {
- return
+ return (
+ <>
+
+
+ >
+ )
}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index be69a8d..39a4136 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,7 +1,3 @@
-import { Inter } from '@next/font/google'
-
-const inter = Inter({ subsets: ['latin'] })
-
export default function Home() {
return <>hello world>
}
diff --git a/src/pages/login.tsx b/src/pages/login.tsx
new file mode 100644
index 0000000..7be079a
--- /dev/null
+++ b/src/pages/login.tsx
@@ -0,0 +1,92 @@
+import Avatar from '@mui/material/Avatar'
+import Button from '@mui/material/Button'
+import TextField from '@mui/material/TextField'
+import Link from '@mui/material/Link'
+import Grid from '@mui/material/Grid'
+import Box from '@mui/material/Box'
+import LockOutlinedIcon from '@mui/icons-material/LockOutlined'
+import Typography from '@mui/material/Typography'
+import Container from '@mui/material/Container'
+import { useFormik } from 'formik'
+import * as yup from '@/utils/validation'
+
+export default function SignIn() {
+ const formik = useFormik({
+ initialValues: {
+ email: '',
+ password: '',
+ },
+ validateOnChange: false,
+ validationSchema: yup.object({
+ email: yup.emailSchema,
+ password: yup.passwordSchema,
+ }),
+ onSubmit: (values) => {
+ console.log(JSON.stringify(values, null, 2))
+ },
+ })
+
+ return (
+
+
+
+
+
+
+ 登录
+
+
+
+
+
+
+
+
+ 忘记密码?
+
+
+
+
+ 注册
+
+
+
+
+
+
+ )
+}
diff --git a/src/utils/validation.ts b/src/utils/validation.ts
new file mode 100644
index 0000000..e925cc1
--- /dev/null
+++ b/src/utils/validation.ts
@@ -0,0 +1,16 @@
+import * as yup from 'yup'
+
+export * from 'yup'
+
+export const emailSchema = yup
+ .string()
+ .email('请输入正确的邮箱')
+ .required('请输入邮箱')
+
+export const passwordSchema = yup
+ .string()
+ .required('请输入密码')
+ .matches(/^.{8,18}$/, '8~18个字符')
+ .matches(/^(.*)?\d+(.*)?$/, '至少一个数字')
+ .matches(/^(?=.*[a-z])(?=.*[A-Z])[^]*$/, '大写字母和小写字母')
+ .matches(/^[^\s].*[^\s]$/, '首尾字符不能是空格')