refactor: menu component
This commit is contained in:
parent
5bb0d9f336
commit
a604eed44d
@ -15,6 +15,13 @@ export default defineConfig({
|
|||||||
'pathRewrite': { '^/api' : '/api' },
|
'pathRewrite': { '^/api' : '/api' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
locale: {
|
||||||
|
default: 'zh-CN',
|
||||||
|
// antd: false,
|
||||||
|
// title: false,
|
||||||
|
baseNavigator: false,
|
||||||
|
baseSeparator: '-',
|
||||||
|
},
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
exact: false,
|
exact: false,
|
||||||
|
30
packages/app/src/components/menu/index.tsx
Normal file
30
packages/app/src/components/menu/index.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Layout, Menu, Breadcrumb } from 'antd';
|
||||||
|
import { Link, useLocation } from 'umi';
|
||||||
|
import Icon from '@/components/icons';
|
||||||
|
|
||||||
|
function pathcamp(path1: string, path2: string) {
|
||||||
|
if (path1 === path2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return path1.indexOf(`${path2}/`) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (props: any) => {
|
||||||
|
const { items = [], ...restProps } = props;
|
||||||
|
const location = useLocation();
|
||||||
|
let paths = items.map(item => item.path);
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
defaultSelectedKeys={paths.filter(path => pathcamp(location.pathname, path)).concat(location.pathname)}
|
||||||
|
defaultOpenKeys={paths.filter(path => pathcamp(location.pathname, path)).concat(location.pathname)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{items.map(item => (
|
||||||
|
<Menu.Item key={item.path}>
|
||||||
|
<Link to={item.path}><Icon type={item.icon}/> {item.title}</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
33
packages/app/src/components/pages/AvatarDropdown/index.tsx
Normal file
33
packages/app/src/components/pages/AvatarDropdown/index.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Layout, Menu, Dropdown, Avatar } from 'antd';
|
||||||
|
import './style.less';
|
||||||
|
import { history, Link, request, useModel } from 'umi';
|
||||||
|
import { ProfileOutlined, LogoutOutlined, UserOutlined, CodeOutlined } from '@ant-design/icons';
|
||||||
|
import Icon from '@/components/icons';
|
||||||
|
|
||||||
|
const overlay = (
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item disabled><ProfileOutlined /> 个人资料</Menu.Item>
|
||||||
|
<Menu.Divider></Menu.Divider>
|
||||||
|
<Menu.Item onClick={async () => {
|
||||||
|
await request('/users:logout');
|
||||||
|
localStorage.removeItem('NOCOBASE_TOKEN');
|
||||||
|
(window as any).routesReload();
|
||||||
|
history.push('/login');;
|
||||||
|
// window.location.href = '/login';
|
||||||
|
}}><LogoutOutlined/> 退出登录</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default (props: any) => {
|
||||||
|
const { initialState = {}, loading, error, refresh, setInitialState } = useModel('@@initialState');
|
||||||
|
return (
|
||||||
|
<div className={'avatar-dropdown-wrapper'}>
|
||||||
|
<Dropdown overlay={overlay} placement="bottomRight">
|
||||||
|
<span style={{display: 'block'}} className="dropdown-link" onClick={e => e.preventDefault()}>
|
||||||
|
<Avatar size={'small'} icon={<UserOutlined/>} style={{marginRight: 5}}/> {initialState.currentUser.nickname}
|
||||||
|
</span>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
13
packages/app/src/components/pages/AvatarDropdown/style.less
Normal file
13
packages/app/src/components/pages/AvatarDropdown/style.less
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.avatar-dropdown-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
|
&:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
.dropdown-link {
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Layout, Menu, Breadcrumb } from 'antd';
|
import { Layout, Breadcrumb } from 'antd';
|
||||||
import { Link } from 'umi';
|
import { Link } from 'umi';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import Icon from '@/components/icons';
|
import Menu from '@/components/menu';
|
||||||
|
|
||||||
export function SideMenuLayout(props: any) {
|
export function SideMenuLayout(props: any) {
|
||||||
const { menu = [] } = props.page;
|
const { menu = [] } = props.page;
|
||||||
@ -10,13 +10,7 @@ export function SideMenuLayout(props: any) {
|
|||||||
return (
|
return (
|
||||||
<Layout style={{height: 'calc(100vh - 48px)'}}>
|
<Layout style={{height: 'calc(100vh - 48px)'}}>
|
||||||
<Layout.Sider className={'nb-sider'} theme={'light'}>
|
<Layout.Sider className={'nb-sider'} theme={'light'}>
|
||||||
<Menu mode={'inline'} defaultSelectedKeys={['2']}>
|
<Menu items={menu} mode={'inline'}/>
|
||||||
{menu.map(item => (
|
|
||||||
<Menu.Item key={item.path}>
|
|
||||||
<Link to={item.path}><Icon type={item.icon}/> {item.title}</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu>
|
|
||||||
</Layout.Sider>
|
</Layout.Sider>
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
@ -1,45 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Layout, Menu, Dropdown, Avatar } from 'antd';
|
import { Layout, Dropdown, Avatar } from 'antd';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { history, Link, request, useModel } from 'umi';
|
import { history, Link, request, useModel } from 'umi';
|
||||||
import { UserOutlined } from '@ant-design/icons';
|
import { UserOutlined, CodeOutlined } from '@ant-design/icons';
|
||||||
import Icon from '@/components/icons';
|
import AvatarDropdown from '../AvatarDropdown';
|
||||||
|
import Menu from '@/components/menu';
|
||||||
const overlay = (
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item disabled>个人资料</Menu.Item>
|
|
||||||
<Menu.Divider></Menu.Divider>
|
|
||||||
<Menu.Item onClick={async () => {
|
|
||||||
await request('/users:logout');
|
|
||||||
localStorage.removeItem('NOCOBASE_TOKEN');
|
|
||||||
(window as any).routesReload();
|
|
||||||
history.push('/login');;
|
|
||||||
// window.location.href = '/login';
|
|
||||||
}}>退出登录</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
|
|
||||||
export function TopMenuLayout(props: any) {
|
export function TopMenuLayout(props: any) {
|
||||||
const { menu = [] } = props.page;
|
const { menu = [] } = props.page;
|
||||||
const { initialState = {}, loading, error, refresh, setInitialState } = useModel('@@initialState');
|
|
||||||
return (
|
return (
|
||||||
<Layout style={{ height: '100vh' }}>
|
<Layout style={{ height: '100vh' }}>
|
||||||
<Layout.Header style={{height: 48, lineHeight: '48px', padding: 0}} className="nb-header">
|
<Layout.Header style={{height: 48, lineHeight: '48px', padding: 0}} className="nb-header">
|
||||||
<div className="logo" style={{width: 200, height: 20, float: 'left'}}/>
|
<div className="logo" style={{width: 200, height: 20, float: 'left'}}><CodeOutlined /> NocoBase</div>
|
||||||
<Menu style={{float: 'left'}} theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
|
<Menu items={menu} className={'noco-top-menu'} style={{float: 'left'}} theme="dark" mode="horizontal">
|
||||||
{menu.map(item => (
|
|
||||||
<Menu.Item key={item.path}>
|
|
||||||
<Link to={item.path}><Icon type={item.icon}/>{item.title}</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu>
|
</Menu>
|
||||||
<div className={'noco-user'} style={{position: 'absolute', right: 24, color: 'rgba(255, 255, 255, 0.65)'}}>
|
<AvatarDropdown/>
|
||||||
<Dropdown overlay={overlay} placement="bottomRight">
|
|
||||||
<span className="nbui-dropdown-link" onClick={e => e.preventDefault()}>
|
|
||||||
<Avatar size={'small'} icon={<UserOutlined/>} style={{marginRight: 5}}/> {initialState.currentUser.nickname}
|
|
||||||
</span>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
.logo {
|
||||||
|
// font-family: 'Michroma', sans-serif;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding-left: 28px;
|
||||||
|
font-size: 18px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
.noco-top-menu.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover,
|
||||||
|
.noco-top-menu.ant-menu.ant-menu-dark .ant-menu-item-selected,
|
||||||
|
.noco-top-menu.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user