style: login

This commit is contained in:
jialin
2024-07-08 14:46:33 +08:00
parent b753528e44
commit 01e9b70f6d
20 changed files with 178 additions and 40 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+11
View File
@@ -0,0 +1,11 @@
// footer all styles
.footer {
position: fixed;
bottom: 0;
width: 100%;
background-color: transparent;
padding: 20px 0;
text-align: center;
font-size: var(--font-size-middle);
color: var(--color-text-2);
}
+24
View File
@@ -0,0 +1,24 @@
import { useIntl } from '@umijs/max';
import { Space } from 'antd';
import './index.less';
const Footer: React.FC = () => {
const intl = useIntl();
return (
<div className="footer">
<div className="footer-content">
<div className="footer-content-left">
<div className="footer-content-left-text">
<Space size={4}>
<span>&copy;</span>
<span> {new Date().getFullYear()}</span>
<span> {intl.formatMessage({ id: 'settings.company' })}</span>
</Space>
</div>
</div>
</div>
</div>
);
};
export default Footer;
@@ -35,6 +35,7 @@ const Wrapper: React.FC<WrapperProps> = ({
<div <div
className={classNames( className={classNames(
wrapperStyle['wrapper-box'], wrapperStyle['wrapper-box'],
'field-wrapper',
wrapperStyle[`validate-status-${status}`], wrapperStyle[`validate-status-${status}`],
addAfter ? wrapperStyle['seal-input-wrapper-addafter'] : '', addAfter ? wrapperStyle['seal-input-wrapper-addafter'] : '',
disabled ? wrapperStyle['seal-input-wrapper-disabled'] : '', disabled ? wrapperStyle['seal-input-wrapper-disabled'] : '',
+20 -11
View File
@@ -22,6 +22,8 @@ html {
--font-weight-medium: 600; --font-weight-medium: 600;
--font-weight-bold: 700; --font-weight-bold: 700;
--color-text-1: var(--ant-color-text); --color-text-1: var(--ant-color-text);
--color-text-3: rgba(0, 0, 0, 45%);
--color-text-2: rgba(0, 0, 0, 65%);
--color-bg-light-1: #e6f6ff; --color-bg-light-1: #e6f6ff;
--font-size-base: 12px; --font-size-base: 12px;
--font-size-large: 16px; --font-size-large: 16px;
@@ -59,7 +61,7 @@ html {
--ant-font-size: var(--font-size-base); --ant-font-size: var(--font-size-base);
&.ant-menu-css-var { &.ant-menu-css-var {
--ant-menu-item-selected-bg: var(--color-white-1); // --ant-menu-item-selected-bg: var(--color-white-1);
--ant-menu-item-border-radius: 8px; --ant-menu-item-border-radius: 8px;
--ant-menu-item-selected-color: var(--ant-color-primary); --ant-menu-item-selected-color: var(--ant-color-primary);
--ant-menu-item-hover-bg: var(--color-white-1); --ant-menu-item-hover-bg: var(--color-white-1);
@@ -107,7 +109,7 @@ html {
.css-var-ri.ant-menu-css-var, .css-var-ri.ant-menu-css-var,
.css-var-rh.ant-menu-css-var { .css-var-rh.ant-menu-css-var {
--ant-menu-item-height: 46px; --ant-menu-item-height: 46px;
--ant-menu-item-selected-bg: var(--color-white-1); // --ant-menu-item-selected-bg: var(--color-white-1);
--ant-menu-item-border-radius: 8px; --ant-menu-item-border-radius: 8px;
--ant-menu-item-selected-color: var(--ant-color-primary); --ant-menu-item-selected-color: var(--ant-color-primary);
--ant-menu-item-hover-bg: var(--color-white-1); --ant-menu-item-hover-bg: var(--color-white-1);
@@ -265,6 +267,10 @@ body {
padding-left: 20px; padding-left: 20px;
} }
.ant-pro-sider-logo-collapsed {
padding-left: 12px;
}
.ant-pro-sider .ant-layout-sider-children { .ant-pro-sider .ant-layout-sider-children {
background-color: var(--color-fill-sider); background-color: var(--color-fill-sider);
// box-shadow: var(--box-shadow-base); // box-shadow: var(--box-shadow-base);
@@ -394,15 +400,18 @@ body {
height: 100%; height: 100%;
} }
} }
// .login-wrapper {
// position: fixed; .login-wrapper {
// top: 0; position: fixed;
// left: 0; top: 0;
// bottom: 0; left: 0;
// right: 0; bottom: 0;
// background: url('@/assets/images/bg-2.png') center center no-repeat; right: 0;
// background-size: cover; min-height: 100vh;
// } z-index: -1;
background: url('@/assets/images/bg-2.png') center center no-repeat;
background-size: cover;
}
.ant-pro-page-container { .ant-pro-page-container {
background: transparent; background: transparent;
+5 -1
View File
@@ -2,10 +2,14 @@
// This file is generated by Umi automatically // This file is generated by Umi automatically
// DO NOT CHANGE IT MANUALLY! // DO NOT CHANGE IT MANUALLY!
import GpustackLogo from '@/assets/images/gpustack-logo.png'; import GpustackLogo from '@/assets/images/gpustack-logo.png';
import SmallLogo from '@/assets/images/small-logo-200x200.png';
import React from 'react'; import React from 'react';
const LogoIcon: React.FC = () => { const LogoIcon: React.FC = () => {
return <img src={GpustackLogo} alt="logo" style={{ height: 16 }} />; return <img src={GpustackLogo} alt="logo" style={{ height: 16 }} />;
}; };
const SLogoIcon: React.FC = () => {
return <img src={SmallLogo} alt="logo" style={{ height: 24 }} />;
};
export default LogoIcon; export { LogoIcon, SLogoIcon };
+11 -6
View File
@@ -4,6 +4,7 @@ import { userAtom } from '@/atoms/user';
import { logout } from '@/pages/login/apis'; import { logout } from '@/pages/login/apis';
import { useAccessMarkedRoutes } from '@@/plugin-access'; import { useAccessMarkedRoutes } from '@@/plugin-access';
import { useModel } from '@@/plugin-model'; import { useModel } from '@@/plugin-model';
import { ProLayout } from '@ant-design/pro-components'; import { ProLayout } from '@ant-design/pro-components';
import { import {
Link, Link,
@@ -17,13 +18,12 @@ import {
type IRoute type IRoute
} from '@umijs/max'; } from '@umijs/max';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { useMemo } from 'react'; import { useMemo, useState } from 'react';
import Exception from './Exception'; import Exception from './Exception';
import './Layout.css'; import './Layout.css';
import Logo from './Logo'; import { LogoIcon, SLogoIcon } from './Logo';
import { getRightRenderContent } from './rightRender'; import { getRightRenderContent } from './rightRender';
import { patchRoutes } from './runtime'; import { patchRoutes } from './runtime';
const loginPath = '/login'; const loginPath = '/login';
// 过滤出需要显示的路由, 这里的filterFn 指 不希望显示的层级 // 过滤出需要显示的路由, 这里的filterFn 指 不希望显示的层级
@@ -84,6 +84,7 @@ export default (props: any) => {
const navigate = useNavigate(); const navigate = useNavigate();
const intl = useIntl(); const intl = useIntl();
const { clientRoutes, pluginManager } = useAppData(); const { clientRoutes, pluginManager } = useAppData();
const [collapsed, setCollapsed] = useState(false);
const initialInfo = (useModel && useModel('@@initialState')) || { const initialInfo = (useModel && useModel('@@initialState')) || {
initialState: undefined, initialState: undefined,
@@ -94,7 +95,6 @@ export default (props: any) => {
const userConfig = { const userConfig = {
title: '', title: '',
layout: 'mix',
locale: true locale: true
}; };
@@ -145,12 +145,18 @@ export default (props: any) => {
location={location} location={location}
title={userConfig.title} title={userConfig.title}
navTheme="light" navTheme="light"
layout="side"
disableMobile={true}
siderWidth={220} siderWidth={220}
onMenuHeaderClick={(e) => { onMenuHeaderClick={(e) => {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
navigate('/'); navigate('/');
}} }}
collapsed={collapsed}
onCollapse={(collapsed) => {
setCollapsed(collapsed);
}}
onPageChange={(route) => { onPageChange={(route) => {
const { location } = history; const { location } = history;
@@ -178,9 +184,8 @@ export default (props: any) => {
}} }}
formatMessage={formatMessage} formatMessage={formatMessage}
menu={{ locale: true }} menu={{ locale: true }}
logo={Logo} logo={collapsed ? SLogoIcon : LogoIcon}
menuItemRender={(menuItemProps, defaultDom) => { menuItemRender={(menuItemProps, defaultDom) => {
console.log('meurender=========', { defaultDom });
if (menuItemProps.isUrl || menuItemProps.children) { if (menuItemProps.isUrl || menuItemProps.children) {
return defaultDom; return defaultDom;
} }
+66
View File
@@ -0,0 +1,66 @@
import {
AppstoreOutlined,
MailOutlined,
SettingOutlined
} from '@ant-design/icons';
import { Menu, type MenuProps } from 'antd';
import React from 'react';
type MenuItem = Required<MenuProps>['items'][number];
const items: MenuItem[] = [
{
key: 'sub1',
icon: <MailOutlined />,
label: 'Navigation One',
children: [
{
key: '1-1',
label: 'Item 1',
type: 'group',
children: [
{ key: '1', label: 'Option 1' },
{ key: '2', label: 'Option 2' }
]
},
{
key: '1-2',
label: 'Item 2',
type: 'group',
children: [
{ key: '3', label: 'Option 3' },
{ key: '4', label: 'Option 4' }
]
}
]
},
{
key: 'sub2',
icon: <AppstoreOutlined />,
label: 'Navigation Two',
children: [
{ key: '5', label: 'Option 5' },
{ key: '6', label: 'Option 6' },
{
key: 'sub3',
label: 'Submenu'
}
]
},
{
key: 'sub4',
label: 'Navigation Three',
icon: <SettingOutlined />,
children: [
{ key: '9', label: 'Option 9' },
{ key: '10', label: 'Option 10' },
{ key: '11', label: 'Option 11' },
{ key: '12', label: 'Option 12' }
]
}
];
const RenderLinks: React.FC = () => {
return <Menu mode="vertical" items={items} />;
};
export default React.memo(RenderLinks);
+4 -13
View File
@@ -62,6 +62,7 @@ export function getRightRenderContent(opts: {
<SelectLang <SelectLang
style={{ padding: '10px 18px', marginBottom: '20px' }} style={{ padding: '10px 18px', marginBottom: '20px' }}
reload={false} reload={false}
mode="vertical"
icon={ icon={
<span style={{ fontSize: '12px' }}> <span style={{ fontSize: '12px' }}>
<GlobalOutlined /> <GlobalOutlined />
@@ -113,18 +114,6 @@ export function getRightRenderContent(opts: {
history.push('/profile'); history.push('/profile');
} }
}, },
// {
// key: 'theme',
// label: (
// <>
// <SunOutlined />
// 外观
// </>
// ),
// onClick: () => {
// console.log('theme');
// }
// },
{ {
key: 'logout', key: 'logout',
label: ( label: (
@@ -158,7 +147,9 @@ export function getRightRenderContent(opts: {
}; };
} else { } else {
// 需要 antd 4.20.0 以上版本 // 需要 antd 4.20.0 以上版本
dropdownProps = { overlay: <Menu {...langMenu} mode="vertical" /> }; dropdownProps = {
overlay: <Menu {...langMenu} mode="vertical" />
};
} }
return ( return (
+2 -1
View File
@@ -186,5 +186,6 @@ export default {
'common.filter.name': 'Filter by name', 'common.filter.name': 'Filter by name',
'common.form.password': 'Password', 'common.form.password': 'Password',
'common.form.username': 'Username', 'common.form.username': 'Username',
'common.login.rember': 'Remember me' 'common.login.rember': 'Remember me',
'settings.company': 'SEAL'
}; };
+2 -1
View File
@@ -179,5 +179,6 @@ export default {
'common.filter.name': '名称查询', 'common.filter.name': '名称查询',
'common.form.password': '密码', 'common.form.password': '密码',
'common.form.username': '用户名', 'common.form.username': '用户名',
'common.login.rember': '记住我' 'common.login.rember': '记住我',
'settings.company': '数澈软件'
}; };
+1 -1
View File
@@ -155,7 +155,7 @@ const LoginForm = () => {
<div> <div>
<Form <Form
form={form} form={form}
style={{ width: '400px', margin: '0 auto', paddingTop: '10%' }} style={{ width: '400px', margin: '0 auto' }}
onFinish={handleLogin} onFinish={handleLogin}
> >
{renderWelCome(intl)} {renderWelCome(intl)}
+1 -1
View File
@@ -46,7 +46,7 @@ const PasswordForm: React.FC = () => {
</div> </div>
<Form <Form
form={form} form={form}
style={{ width: '400px', margin: '0 auto', paddingTop: '5%' }} style={{ width: '400px', margin: '0 auto' }}
onFinish={handleSubmit} onFinish={handleSubmit}
> >
<h2 className="justify-center m-b-20 flex-column flex-center"> <h2 className="justify-center m-b-20 flex-column flex-center">
+16
View File
@@ -0,0 +1,16 @@
:local(.login-form-wrapper) {
margin: 0 auto;
border-radius: 8px;
width: max-content;
height: max-content;
padding: 32px;
background-color: rgba(255, 255, 255, 50%);
:global(.field-wrapper) {
background-color: transparent !important;
}
}
:local(.box) {
padding-top: 10%;
}
+11 -3
View File
@@ -1,9 +1,11 @@
import { userAtom } from '@/atoms/user'; import { userAtom } from '@/atoms/user';
import Footer from '@/components/footer';
import { history } from '@umijs/max'; import { history } from '@umijs/max';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { useEffect } from 'react'; import { useEffect } from 'react';
import LoginForm from './components/login-form'; import LoginForm from './components/login-form';
import PasswordForm from './components/password-form'; import PasswordForm from './components/password-form';
import styles from './components/styles.less';
const Login = () => { const Login = () => {
const [userInfo, setUserInfo] = useAtom(userAtom); const [userInfo, setUserInfo] = useAtom(userAtom);
@@ -21,9 +23,15 @@ const Login = () => {
}, [userInfo]); }, [userInfo]);
return ( return (
<div className="login-wrapper"> <>
{userInfo?.require_password_change ? <PasswordForm /> : <LoginForm />} <div className="login-wrapper"></div>
</div> <div className={styles.box}>
<div className={styles['login-form-wrapper']}>
{userInfo?.require_password_change ? <PasswordForm /> : <LoginForm />}
</div>
<Footer />
</div>
</>
); );
}; };
+3 -2
View File
@@ -24,7 +24,8 @@ import AddModal from './components/add-modal';
import { FormData, ListItem } from './config/types'; import { FormData, ListItem } from './config/types';
const { Column } = Table; const { Column } = Table;
const Models: React.FC = () => { const Users: React.FC = () => {
console.log('users======');
const rowSelection = useTableRowSelection(); const rowSelection = useTableRowSelection();
const { sortOrder, setSortOrder } = useTableSort({ const { sortOrder, setSortOrder } = useTableSort({
defaultSortOrder: 'descend' defaultSortOrder: 'descend'
@@ -328,4 +329,4 @@ const Models: React.FC = () => {
); );
}; };
export default Models; export default Users;