@yyp92-cli/template-react-pc 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +15 -0
  3. package/template/.env.development +5 -0
  4. package/template/.env.production +4 -0
  5. package/template/.env.test +4 -0
  6. package/template/.eslintrc.cjs +18 -0
  7. package/template/README.md +9 -0
  8. package/template/index.html +13 -0
  9. package/template/package.json +42 -0
  10. package/template/pnpm-lock.yaml +3583 -0
  11. package/template/public/vite.svg +1 -0
  12. package/template/src/antdTheme/darkTheme.ts +1 -0
  13. package/template/src/antdTheme/lightTheme.ts +68 -0
  14. package/template/src/app.scss +29 -0
  15. package/template/src/app.tsx +14 -0
  16. package/template/src/assets/iconfont/demo.css +539 -0
  17. package/template/src/assets/iconfont/demo_index.html +211 -0
  18. package/template/src/assets/iconfont/iconfont.css +19 -0
  19. package/template/src/assets/iconfont/iconfont.js +1 -0
  20. package/template/src/assets/iconfont/iconfont.json +16 -0
  21. package/template/src/assets/iconfont/iconfont.ttf +0 -0
  22. package/template/src/assets/iconfont/iconfont.woff +0 -0
  23. package/template/src/assets/iconfont/iconfont.woff2 +0 -0
  24. package/template/src/assets/react.svg +1 -0
  25. package/template/src/components/403/index.tsx +22 -0
  26. package/template/src/components/404/index.tsx +24 -0
  27. package/template/src/components/index.ts +3 -0
  28. package/template/src/components/layout/content/index.module.scss +22 -0
  29. package/template/src/components/layout/content/index.tsx +77 -0
  30. package/template/src/components/layout/footer/index.module.scss +12 -0
  31. package/template/src/components/layout/footer/index.tsx +15 -0
  32. package/template/src/components/layout/header/index.module.scss +21 -0
  33. package/template/src/components/layout/header/index.tsx +104 -0
  34. package/template/src/components/layout/index.module.scss +8 -0
  35. package/template/src/components/layout/index.tsx +59 -0
  36. package/template/src/components/layout/side/index.module.scss +31 -0
  37. package/template/src/components/layout/side/index.tsx +116 -0
  38. package/template/src/components/layout-horizontal/content/index.module.scss +22 -0
  39. package/template/src/components/layout-horizontal/content/index.tsx +73 -0
  40. package/template/src/components/layout-horizontal/footer/index.module.scss +12 -0
  41. package/template/src/components/layout-horizontal/footer/index.tsx +15 -0
  42. package/template/src/components/layout-horizontal/header/index.module.scss +23 -0
  43. package/template/src/components/layout-horizontal/header/index.tsx +105 -0
  44. package/template/src/components/layout-horizontal/index.module.scss +8 -0
  45. package/template/src/components/layout-horizontal/index.tsx +59 -0
  46. package/template/src/components/layout-horizontal/side/index.module.scss +32 -0
  47. package/template/src/components/layout-horizontal/side/index.tsx +115 -0
  48. package/template/src/components/login/index.module.scss +23 -0
  49. package/template/src/components/login/index.tsx +121 -0
  50. package/template/src/global/constants.ts +4 -0
  51. package/template/src/pages/home/index.module.scss +0 -0
  52. package/template/src/pages/home/index.tsx +85 -0
  53. package/template/src/router/router.tsx +164 -0
  54. package/template/src/service/api.ts +9 -0
  55. package/template/src/service/config.ts +9 -0
  56. package/template/src/service/index.ts +1 -0
  57. package/template/src/service/request/index.ts +265 -0
  58. package/template/src/service/request/type.ts +5 -0
  59. package/template/src/service/service.ts +27 -0
  60. package/template/src/store/login.ts +40 -0
  61. package/template/src/store/menus.ts +28 -0
  62. package/template/src/store/permission.ts +28 -0
  63. package/template/src/theme/darkTheme.scss +47 -0
  64. package/template/src/theme/lightTheme.scss +49 -0
  65. package/template/src/utils/base64ToBlob.ts +41 -0
  66. package/template/src/utils/cache.ts +44 -0
  67. package/template/src/utils/changeTheme.ts +14 -0
  68. package/template/src/utils/download.ts +45 -0
  69. package/template/src/utils/filterMenu.ts +34 -0
  70. package/template/src/utils/index.ts +5 -0
  71. package/template/src/vite-env.d.ts +5 -0
  72. package/template/tsconfig.json +45 -0
  73. package/template/tsconfig.node.json +10 -0
  74. package/template/vite.config.ts +49 -0
@@ -0,0 +1,31 @@
1
+ .side {
2
+ flex-shrink: 0;
3
+ width: 200px;
4
+ height: 100%;
5
+ display: flex;
6
+ flex-direction: column;
7
+
8
+ .logo {
9
+ height: 50px;
10
+ box-sizing: border-box;
11
+ flex-shrink: 0;
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ border-bottom: 1px solid var(--border-color-base);
16
+ border-right: 1px solid var(--border-color-base);
17
+
18
+ img {
19
+ width: 32px;
20
+ height: 32px;
21
+ margin-right: 12px;
22
+ }
23
+ }
24
+
25
+
26
+ .menu {
27
+ flex: 1;
28
+ overflow-y: auto;
29
+ border-right: 1px solid var(--border-color-base) !important;
30
+ }
31
+ }
@@ -0,0 +1,116 @@
1
+ import React, {useEffect, useLayoutEffect} from 'react'
2
+ import {Menu} from 'antd'
3
+ import type { MenuProps } from 'antd';
4
+ import {useNavigate, useLocation} from 'react-router-dom'
5
+ import {ComponentMap} from '@/router/router'
6
+ import { menusStore } from '@/store/menus'
7
+
8
+ import styles from './index.module.scss'
9
+
10
+
11
+ type MenuItem = Required<MenuProps>['items'][number];
12
+
13
+
14
+ interface SideProps {
15
+ [key: string]: any
16
+ }
17
+
18
+ export const Side: React.FC<SideProps> = () => {
19
+ const location = useLocation()
20
+ const navigate = useNavigate()
21
+ const {menus} = menusStore()
22
+
23
+ // 激活的父菜单
24
+ const [openKeys, setOpenKeys] = React.useState<string[]>([])
25
+ // 激活的菜单项
26
+ const [selectedKeys, setSelectedKeys] = React.useState<string[]>([])
27
+ // 菜单
28
+ const [newMenuList, setNewMenuList] = React.useState<MenuItem[]>([])
29
+
30
+ useLayoutEffect(() => {
31
+ const newMenuList = menus.map((item: any) => {
32
+ const Icon = ComponentMap[item.icon]
33
+
34
+ return {
35
+ ...item,
36
+ icon: <Icon />
37
+ }
38
+ })
39
+ setNewMenuList(newMenuList)
40
+ }, [menus])
41
+
42
+ useEffect(() => {
43
+ const {pathname} = location ?? {}
44
+ const newPathname = pathname.slice(1)
45
+
46
+ if (newPathname === '') {
47
+ const openKey = menus[0]?.key
48
+ const selectedKey = menus[0]?.children?.[0]?.key
49
+
50
+ setOpenKeys([openKey])
51
+ setSelectedKeys([selectedKey])
52
+ navigate(`/${menus[0]?.key}/${menus[0]?.children?.[0]?.key}`)
53
+ }
54
+ else {
55
+ const pathnameList = newPathname.split('/')
56
+
57
+ if (pathnameList.length === 1) {
58
+ setOpenKeys([])
59
+ setSelectedKeys([pathnameList[0]])
60
+ }
61
+ else if (pathnameList.length === 2) {
62
+ setOpenKeys([pathnameList[0]])
63
+ setSelectedKeys([pathnameList[1]])
64
+ }
65
+ }
66
+ }, [])
67
+
68
+
69
+ // ********* 操作 ********
70
+ const onMenuItemOpenChange: MenuProps['onOpenChange'] = (openKeys: string[]) => {
71
+ const currentKey = openKeys.slice(-1)
72
+ setOpenKeys(currentKey)
73
+ }
74
+
75
+ const onMenuItemClick: MenuProps['onClick'] = (e: any) => {
76
+ const {keyPath} = e ?? {}
77
+
78
+ if (keyPath.length === 1) {
79
+ setSelectedKeys(keyPath[0])
80
+ navigate(`/${keyPath[0]}`)
81
+ }
82
+ else if (keyPath.length === 2) {
83
+ setSelectedKeys(keyPath[0])
84
+ navigate(`/${keyPath[1]}/${keyPath[0]}`)
85
+ }
86
+ }
87
+
88
+
89
+ // ********* 渲染 ********
90
+ return (
91
+ <div className={styles.side}>
92
+ <div className={styles.logo}>
93
+ <img
94
+ src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
95
+ alt="logo"
96
+ />
97
+
98
+ <span>财务系统</span>
99
+ </div>
100
+
101
+ <Menu
102
+ className={styles.menu}
103
+ style={{
104
+ width: 200,
105
+ height: '100%'
106
+ }}
107
+ mode={'inline'}
108
+ items={newMenuList}
109
+ openKeys={openKeys}
110
+ selectedKeys={selectedKeys}
111
+ onOpenChange={onMenuItemOpenChange}
112
+ onClick={onMenuItemClick}
113
+ />
114
+ </div>
115
+ )
116
+ }
@@ -0,0 +1,22 @@
1
+ .layoutContent {
2
+ flex: 1;
3
+ width: 100%;
4
+ height: 100%;
5
+ display: flex;
6
+ }
7
+
8
+ .wraper {
9
+ flex: 1;
10
+ width: 100%;
11
+ height: 100%;
12
+ display: flex;
13
+ flex-direction: column;
14
+ }
15
+
16
+ .contentInner {
17
+ flex: 1;
18
+ display: flex;
19
+ flex-direction: column;
20
+ box-sizing: border-box;
21
+ padding: 16px 20px;
22
+ }
@@ -0,0 +1,73 @@
1
+ import React, {useState, useEffect} from 'react'
2
+ import { Outlet, useLocation, useNavigate } from 'react-router-dom'
3
+
4
+ import { Header } from '../header'
5
+ import { Footer } from '../footer'
6
+ import { routerConfig } from '@/router/router'
7
+ import type { RouterConfigItemProps } from '@/router/router'
8
+ import { permissionStore } from '@/store/permission'
9
+
10
+ import styles from './index.module.scss'
11
+
12
+ interface ContentProps {
13
+ [key: string]: any
14
+ }
15
+
16
+
17
+ const Content: React.FC<ContentProps> = ({ }) => {
18
+ const location = useLocation()
19
+ const navigate = useNavigate()
20
+ const {
21
+ permissions
22
+ } = permissionStore()
23
+
24
+ const [currentRouter, setCurrentRouter] = useState<RouterConfigItemProps>()
25
+
26
+ useEffect(() => {
27
+ const { pathname } = location ?? {}
28
+ const newPathname = pathname.slice(1)
29
+
30
+ if (newPathname !== '') {
31
+ const pathnameList = newPathname.split('/')
32
+ const condition = pathnameList.length === 1
33
+ ? permissions.includes(pathnameList[0])
34
+ : pathnameList.length === 2
35
+ ? permissions.includes(pathnameList[1])
36
+ : false
37
+
38
+ if (condition) {
39
+ let newCurrentRouter: any = {}
40
+
41
+ if (pathnameList.length === 1) {
42
+ newCurrentRouter = routerConfig[0]?.children?.find((group: any) => group.key === pathnameList[0]) ?? {}
43
+ }
44
+ else if (pathnameList.length === 2) {
45
+ const parent = routerConfig[0]?.children?.find((group: any) => group.key === pathnameList[0]) ?? {}
46
+ newCurrentRouter = parent?.children?.find((item: any) => item.key === pathnameList[1])
47
+ }
48
+
49
+ setCurrentRouter(newCurrentRouter)
50
+ }
51
+ else {
52
+ navigate('/403')
53
+ }
54
+ }
55
+ }, [location])
56
+
57
+ // ********** 渲染 **********
58
+ return (
59
+ <div className={styles.layoutContent}>
60
+ <div className={styles.wraper}>
61
+ {!currentRouter?.showFullScreen && <Header />}
62
+
63
+ <div className={styles.contentInner}>
64
+ <Outlet />
65
+ </div>
66
+
67
+ {!currentRouter?.showFullScreen && <Footer />}
68
+ </div>
69
+ </div>
70
+ )
71
+ }
72
+
73
+ export default Content
@@ -0,0 +1,12 @@
1
+ .footer {
2
+ flex-shrink: 0;
3
+ width: 100%;
4
+ height: 50px;
5
+ box-sizing: border-box;
6
+ border-top: 1px solid var(--border-color-base);
7
+ display: flex;
8
+ justify-content: center;
9
+ align-items: center;
10
+ font-size: 12px;
11
+ background: var(--bg-grey-color);
12
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+
3
+ import styles from './index.module.scss'
4
+
5
+ interface FooterProps {
6
+ [key: string]: any
7
+ }
8
+
9
+ export const Footer: React.FC<FooterProps> = ({}) => {
10
+ return (
11
+ <div className={styles.footer}>
12
+ <div>财务系统注意事项</div>
13
+ </div>
14
+ )
15
+ }
@@ -0,0 +1,23 @@
1
+ .header {
2
+ box-sizing: border-box;
3
+ flex-shrink: 0;
4
+ width: 100%;
5
+ height: 50px;
6
+ padding: 0 20px;
7
+ display: flex;
8
+ justify-content: space-between;
9
+ align-items: center;
10
+ border-bottom: 1px solid var(--border-color-base);
11
+
12
+ .avatar {
13
+ flex-shrink: 0;
14
+ margin-left: 20px;
15
+ display: flex;
16
+ align-items: center;
17
+
18
+ & > div {
19
+ margin-left: 10px;
20
+ font-size: 12px;
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,105 @@
1
+ import React, { useState } from 'react'
2
+ import {useNavigate} from 'react-router-dom'
3
+ import { Avatar, Button, Dropdown, Switch, Tooltip } from 'antd'
4
+ import type { MenuProps } from 'antd'
5
+ import { FullscreenExitOutlined, FullscreenOutlined, UserOutlined } from '@ant-design/icons'
6
+ import { localCache, getDarkTheme } from '@/utils'
7
+ import { LOGIN_TOKEN, USER_INFO, MENUS, PERMISSION } from '@/global/constants'
8
+ import {Side} from '../side'
9
+
10
+ import styles from './index.module.scss'
11
+
12
+ interface HeaderProps {
13
+ [key: string]: any
14
+ }
15
+
16
+ export const Header: React.FC<HeaderProps> = ({}) => {
17
+ const navigate = useNavigate()
18
+ const [isFullScreen, setIsFullScreen] = useState<boolean>(false)
19
+
20
+
21
+ // ********* 操作 *********
22
+ const handleLogout = () => {
23
+ localCache.removeCache(LOGIN_TOKEN)
24
+ localCache.removeCache(USER_INFO)
25
+ localCache.removeCache(MENUS)
26
+ localCache.removeCache(PERMISSION)
27
+
28
+ navigate('/login')
29
+ }
30
+
31
+ const handleFullScreen = () => {
32
+ // dom对象的一个属性:可以用来判断当前是不是全屏模式
33
+ // 全屏:true, 不是全屏:false
34
+ const full = document.fullscreenElement
35
+
36
+ if (!full) {
37
+ setIsFullScreen(true)
38
+ document.documentElement.requestFullscreen()
39
+ }
40
+ else {
41
+ setIsFullScreen(false)
42
+ document.exitFullscreen()
43
+ }
44
+ }
45
+
46
+ const handleChangeTheme = (checked: boolean) => {
47
+ getDarkTheme(checked)
48
+ }
49
+
50
+
51
+ // ********* 渲染 *********
52
+ const items: MenuProps['items'] = [
53
+ {
54
+ label: (
55
+ <div
56
+ onClick={handleLogout}
57
+ >退出登录</div>
58
+ ),
59
+ key: '0',
60
+ },
61
+ ]
62
+
63
+ return (
64
+ <div className={styles.header}>
65
+ <Side />
66
+
67
+ <div className={styles.avatar}>
68
+ <Tooltip title="切换主题">
69
+ <Switch
70
+ checkedChildren="暗黑"
71
+ unCheckedChildren="明亮"
72
+ defaultChecked={false}
73
+ onChange={handleChangeTheme}
74
+ />
75
+ </Tooltip>
76
+
77
+ <Tooltip title="全屏">
78
+ <Button
79
+ style={{
80
+ margin: '0 10px'
81
+ }}
82
+ shape="circle"
83
+ icon={
84
+ !isFullScreen
85
+ ? <FullscreenOutlined />
86
+ : <FullscreenExitOutlined />
87
+ }
88
+ onClick={handleFullScreen}
89
+ />
90
+ </Tooltip>
91
+
92
+ <Avatar
93
+ style={{ backgroundColor: '#87d068' }}
94
+ icon={<UserOutlined />}
95
+ />
96
+
97
+ <Dropdown
98
+ menu={{ items }}
99
+ >
100
+ <div>{'xxx 已登录'}</div>
101
+ </Dropdown>
102
+ </div>
103
+ </div>
104
+ )
105
+ }
@@ -0,0 +1,8 @@
1
+ .layout {
2
+ width: 100%;
3
+ height: 100%;
4
+ min-width: 1000px;
5
+ display: flex;
6
+ background: var(--bg-white-color);
7
+ color: var(--text-color);
8
+ }
@@ -0,0 +1,59 @@
1
+ import React, { useEffect } from 'react'
2
+ import { ConfigProvider } from 'antd'
3
+ import dayjs from 'dayjs';
4
+ import 'dayjs/locale/zh-cn';
5
+ import zhCN from 'antd/locale/zh_CN';
6
+ import { lightToken } from '@/antdTheme/lightTheme'
7
+ import Content from './content'
8
+
9
+ import styles from './index.module.scss'
10
+
11
+ interface LayoutProps {
12
+ [key: string]: any
13
+ }
14
+
15
+ const Layout: React.FC<LayoutProps> = ({ }) => {
16
+ useEffect(() => {
17
+ getDarkTheme(0)
18
+ dayjs.locale('zh-cn')
19
+ }, [])
20
+
21
+
22
+ // ********** 操作 **********
23
+ // 主题切换
24
+ const getDarkTheme = (theme: number) => {
25
+ // 获取根元素
26
+ const root = document.documentElement;
27
+
28
+ if (theme != 1) {
29
+ // 修改 data-theme 属性的值为 "light"
30
+ root.setAttribute('data-theme', 'light');
31
+ return
32
+ }
33
+
34
+ // 修改 data-theme 属性的值为 "dark"
35
+ root.setAttribute('data-theme', 'dark');
36
+ }
37
+
38
+
39
+ // ********** 渲染 **********
40
+
41
+ return (
42
+ <div className={styles.layout}>
43
+ <ConfigProvider
44
+ // 主题
45
+ theme={lightToken}
46
+ locale={zhCN}
47
+
48
+ button={{
49
+ // 设置为 false 时,移除按钮中 2 个汉字之间的空格
50
+ autoInsertSpace: false,
51
+ }}
52
+ >
53
+ <Content />
54
+ </ConfigProvider>
55
+ </div>
56
+ )
57
+ }
58
+
59
+ export default Layout
@@ -0,0 +1,32 @@
1
+ .side {
2
+ flex: 1;
3
+ width: 100%;
4
+ height: 100%;
5
+ display: flex;
6
+ overflow: hidden;
7
+
8
+ .logo {
9
+ width: 169px;
10
+ height: 50px;
11
+ box-sizing: border-box;
12
+ flex-shrink: 0;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ border-right: 1px solid var(--border-color-base);
17
+ border-bottom: none;
18
+
19
+ img {
20
+ width: 32px;
21
+ height: 32px;
22
+ margin-right: 12px;
23
+ }
24
+ }
25
+
26
+
27
+ .menu {
28
+ flex: 1;
29
+ overflow-x: auto;
30
+ overflow-y: hidden;
31
+ }
32
+ }
@@ -0,0 +1,115 @@
1
+ import React, {useEffect, useLayoutEffect} from 'react'
2
+ import {Menu} from 'antd'
3
+ import type { MenuProps } from 'antd';
4
+ import {useNavigate, useLocation} from 'react-router-dom'
5
+ import {ComponentMap} from '@/router/router'
6
+ import { menusStore } from '@/store/menus'
7
+
8
+ import styles from './index.module.scss'
9
+
10
+
11
+ type MenuItem = Required<MenuProps>['items'][number];
12
+
13
+
14
+ interface SideProps {
15
+ [key: string]: any
16
+ }
17
+
18
+ export const Side: React.FC<SideProps> = ({}) => {
19
+ const navigate = useNavigate();
20
+ const location = useLocation()
21
+ const {menus} = menusStore()
22
+
23
+ // 激活的父菜单
24
+ const [openKeys, setOpenKeys] = React.useState<string[]>([])
25
+ // 激活的菜单项
26
+ const [selectedKeys, setSelectedKeys] = React.useState<string[]>([])
27
+ // 菜单
28
+ const [menuList, setMenuList] = React.useState<MenuItem[]>([])
29
+
30
+ useLayoutEffect(() => {
31
+ const newMenuList = menus.map((item: any) => {
32
+ const Icon = ComponentMap[item.icon]
33
+
34
+ return {
35
+ ...item,
36
+ icon: <Icon />
37
+ }
38
+ })
39
+ setMenuList(newMenuList)
40
+ }, [menus])
41
+
42
+ useEffect(() => {
43
+ const {pathname} = location ?? {}
44
+ const newPathname = pathname.slice(1)
45
+
46
+ if (newPathname === '') {
47
+ const openKey = menus[0]?.key
48
+ const selectedKey = menus[0]?.children?.[0]?.key
49
+
50
+ // setOpenKeys([openKey])
51
+ setSelectedKeys([selectedKey])
52
+ navigate(`/${menus[0]?.key}/${menus[0]?.children?.[0]?.key}`)
53
+ }
54
+ else {
55
+ const pathnameList = newPathname.split('/')
56
+
57
+ if (pathnameList.length === 1) {
58
+ setOpenKeys([])
59
+ setSelectedKeys([pathnameList[0]])
60
+ }
61
+ else if (pathnameList.length === 2) {
62
+ // setOpenKeys([pathnameList[0]])
63
+ setSelectedKeys([pathnameList[1]])
64
+ }
65
+ }
66
+ }, [])
67
+
68
+
69
+ // ********* 操作 ********
70
+ const onMenuItemOpenChange: MenuProps['onOpenChange'] = (openKeys: string[]) => {
71
+ const currentKey = openKeys.slice(-1)
72
+ setOpenKeys(currentKey)
73
+ }
74
+
75
+ const onMenuItemClick: MenuProps['onClick'] = (e: any) => {
76
+ const {keyPath} = e ?? {}
77
+
78
+ if (keyPath.length === 1) {
79
+ setSelectedKeys(keyPath[0])
80
+ navigate(`/${keyPath[0]}`)
81
+ }
82
+ else if (keyPath.length === 2) {
83
+ setSelectedKeys(keyPath[0])
84
+ navigate(`/${keyPath[1]}/${keyPath[0]}`)
85
+ }
86
+ }
87
+
88
+
89
+ // ********* 渲染 ********
90
+ return (
91
+ <div className={styles.side}>
92
+ <div className={styles.logo}>
93
+ <img
94
+ src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
95
+ alt="logo"
96
+ />
97
+
98
+ <span>财务系统</span>
99
+ </div>
100
+
101
+ <Menu
102
+ className={styles.menu}
103
+ style={{
104
+ borderBottom: 'none'
105
+ }}
106
+ mode={'horizontal'}
107
+ items={menuList}
108
+ openKeys={openKeys}
109
+ selectedKeys={selectedKeys}
110
+ onOpenChange={onMenuItemOpenChange}
111
+ onClick={onMenuItemClick}
112
+ />
113
+ </div>
114
+ )
115
+ }
@@ -0,0 +1,23 @@
1
+ .login {
2
+ width: 100%;
3
+ height: 100%;
4
+ display: flex;
5
+ flex-direction: column;
6
+ justify-content: center;
7
+ align-items: center;
8
+
9
+ .loginInner {
10
+ width: 500px;
11
+ padding: 16px;
12
+ border-radius: 10px;
13
+ box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
14
+
15
+
16
+ .title {
17
+ font-size: 18px;
18
+ font-weight: 600;
19
+ text-align: center;
20
+ margin-bottom: 20px;
21
+ }
22
+ }
23
+ }