feat: add global navigation
1. Add global navigation at the left top position of the whole page 2. Update the right menu layout to adjust the global navigation 3. The global navigation show the extended menu in the console/user center/administrator Change-Id: Iee64af2821bd034e3818166308512d946e44cbe7
This commit is contained in:
parent
5ba32d6dde
commit
985c03af95
@ -72,10 +72,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
],
|
||||
include: [
|
||||
root('src/asset/image/logo-small.svg'),
|
||||
root('src/asset/image/logo-extend.svg'),
|
||||
],
|
||||
include: [root('src/asset/image/cloud-logo.svg')],
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|ttf|eot|svg)$/,
|
||||
@ -88,10 +85,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: [
|
||||
root('src/asset/image/logo-small.svg'),
|
||||
root('src/asset/image/logo-extend.svg'),
|
||||
],
|
||||
exclude: [root('src/asset/image/cloud-logo.svg')],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
15
src/asset/image/cloud-logo.svg
Normal file
15
src/asset/image/cloud-logo.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="126px" height="42px" viewBox="0 0 126 42" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>编组 4</title>
|
||||
<g id="告警规则" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="编组-4" transform="translate(10.002982, 7.000000)">
|
||||
<text id="Cloud" font-family="PingFangSC-Regular, PingFang SC" font-size="24" font-weight="normal" fill="#494949">
|
||||
<tspan x="42.9970183" y="25">Cloud</tspan>
|
||||
</text>
|
||||
<polygon id="路径" stroke="#585858" stroke-width="2" points="14.0154766 1.11256653 8.19282386 12 4.1084658 12 -1.14038261e-13 19.1172391 4.1084658 25.8509105 20.9312248 25.8509105 29.9938305 11.1692991 24.0703059 1.11256653"></polygon>
|
||||
<path d="M32.4091531,12.7434777 L33.0925968,13.5333933 L25.2417074,26.4522009 L24.100354,26.4522009 L32.4091531,12.7434777 Z" id="矩形" stroke="#04B0FE"></path>
|
||||
<path d="M35.0124938,15.3307533 L35.6973288,16.1215034 L29.265661,26.4522009 L28.1113416,26.4522009 L35.0124938,15.3307533 Z" id="矩形备份-3" stroke="#04B0FE"></path>
|
||||
<path d="M36.9703461,18.6980407 L37.5559217,19.1760971 L33.0324712,26.4522009 L32.1155903,26.4522009 L36.9703461,18.6980407 Z" id="矩形备份-4" stroke="#04B0FE"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/asset/image/global-menu.png
Normal file
BIN
src/asset/image/global-menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 204 B |
@ -1,10 +0,0 @@
|
||||
<svg id="layer" data-name="layer" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 114 35">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
isolation: isolate;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<image class="cls-1" width="114" height="35" xlink:href="data:image/png;base64,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"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.6 KiB |
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="44px" height="31px" viewBox="0 0 44 31" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>logo</title>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g transform="translate(-15.000000, -60.000000)" fill-rule="nonzero">
|
||||
<g id="logo" transform="translate(15.000000, 60.000000)">
|
||||
<g id="logo" transform="translate(22.000000, 15.500000) scale(-1, 1) rotate(-180.000000) translate(-22.000000, -15.500000) ">
|
||||
<path d="M38.5227273,18.2727273 C38.5227273,18.2045455 36.375,14.1136364 33.7840909,9.17045455 L29.0113636,0.170454545 L27.4772727,0.0681818182 C26.625,-5.03694308e-14 25.9090909,0.0340909091 25.9090909,0.136363636 C25.9090909,0.238636364 27.75,3.78409091 30,8.01136364 C32.25,12.2386364 34.3977273,16.2954545 34.7727273,17.0454545 C35.4204545,18.3409091 35.5568182,18.4090909 36.9886364,18.4090909 C37.8409091,18.4090909 38.5227273,18.3409091 38.5227273,18.2727273 Z" id="path" fill="#03A9F4"></path>
|
||||
<path d="M40.5,14.4204545 L41.1477273,13.125 L37.5340909,6.57954545 L33.9204545,0.0340909091 L32.2840909,-5.81353147e-14 L30.6477273,-5.81353147e-14 L31.9431818,2.31818182 C32.6590909,3.57954545 34.6022727,7.125 36.3068182,10.1590909 C37.9772727,13.1931818 39.4772727,15.6818182 39.6136364,15.6818182 C39.75,15.6818182 40.1590909,15.1022727 40.5,14.4204545 Z" id="path" fill="#03A9F4"></path>
|
||||
<path d="M41.1818182,4.39772727 L38.7272727,-5.81353147e-14 L37.2613636,-5.81353147e-14 C36.4431818,-5.81353147e-14 35.7954545,0.0681818182 35.7954545,0.170454545 C35.7954545,0.272727273 37.1931818,2.89772727 38.8977273,6 L42.0340909,11.625 L42.8181818,10.2272727 L43.6363636,8.79545455 L41.1818182,4.39772727 Z" id="path" fill="#03AAF6"></path>
|
||||
<g transform="translate(0.000000, 1.022727)" fill="#FFFFFF">
|
||||
<path d="M24.2045455,5.16758353e-14 L25.0227273,1.63636364 C25.4425837,2.47607656 27.3922815,6.03890708 29.4514838,9.74505958 L29.7954545,10.3636364 C31.9772727,14.2840909 33.75,17.625 33.75,17.7954545 C33.75,17.9659091 32.4204545,20.5568182 30.7840909,23.5227273 L30.7840909,23.5227273 L27.7840909,28.9772727 L15.1704545,28.9772727 L12.1704545,23.5227273 L9.17045455,18.0681818 L4.90909091,18.0681818 L2.45454545,13.6704545 C1.09090909,11.25 -1.77635684e-14,9.17045455 -1.77635684e-14,9.06818182 C-1.77635684e-14,8.79545455 3.23863636,2.96590909 4.29545455,1.29545455 L4.29545455,1.29545455 L5.11363636,5.16758353e-14 L24.2045455,5.16758353e-14 Z M22.4318182,3.06818182 L6.54545455,3.06818182 L4.90909091,6.06818182 L3.30681818,9.03409091 L4.875,11.9318182 L6.44318182,14.8295455 L8.65909091,14.9318182 L10.875,15.0340909 L13.8409091,20.4545455 L16.8409091,25.9090909 L26.1136364,25.9090909 L28.2272727,22.0568182 C29.3863636,19.9090909 30.3409091,18 30.3409091,17.7954545 C30.3409091,17.5909091 28.5681818,14.2159091 26.3863636,10.2613636 L26.3863636,10.2613636 L22.4318182,3.06818182 Z" id="shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.1 KiB |
@ -13,14 +13,41 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import RightContent from './RightContent';
|
||||
import { Link } from 'react-router-dom';
|
||||
import cloudLogo from 'asset/image/cloud-logo.svg';
|
||||
import { getPath } from 'utils/route-map';
|
||||
import classnames from 'classnames';
|
||||
import GlobalNav from '../GlobalNav';
|
||||
import ProjectDropdown from './ProjectDropdown';
|
||||
import RightContent from './RightContent';
|
||||
import styles from './index.less';
|
||||
|
||||
export default function HeaderContent(props) {
|
||||
const { isAdminPage = false } = props;
|
||||
const { isAdminPage = false, navItems = [] } = props;
|
||||
|
||||
const getRouteName = (routeName) =>
|
||||
isAdminPage ? `${routeName}Admin` : routeName;
|
||||
|
||||
const getRoutePath = (routeName, params = {}, query = {}) => {
|
||||
const realName = getRouteName(routeName);
|
||||
return getPath({ key: realName, params, query });
|
||||
};
|
||||
|
||||
const renderLogo = () => {
|
||||
const homeUrl = getRoutePath('overview');
|
||||
return (
|
||||
<div className={classnames(styles.logo)}>
|
||||
<Link to={homeUrl}>
|
||||
<img src={cloudLogo} alt="logo" className={styles['logo-image']} />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.header}>
|
||||
<GlobalNav navItems={navItems} />
|
||||
{renderLogo()}
|
||||
{!isAdminPage && <ProjectDropdown />}
|
||||
<RightContent {...props} />
|
||||
</div>
|
||||
|
@ -108,7 +108,7 @@
|
||||
z-index: 200;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
padding-left: 36px;
|
||||
padding-left: 0;
|
||||
overflow: hidden;
|
||||
color: @title-color;
|
||||
background-color: #fff;
|
||||
@ -175,3 +175,15 @@
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
// margin: @size-medium 38px;
|
||||
float: left;
|
||||
height: @header-height;
|
||||
padding: 0 46px;
|
||||
line-height: @header-height;
|
||||
|
||||
img {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
50
src/components/Layout/GlobalNav/Left/index.jsx
Normal file
50
src/components/Layout/GlobalNav/Left/index.jsx
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2021 99cloud
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { navItemPropType, getFirstLevelNavItemLink } from '../common';
|
||||
// import { pickFixedParams } from 'utils';
|
||||
import styles from './index.less';
|
||||
|
||||
export default class Left extends React.Component {
|
||||
static propTypes = {
|
||||
items: PropTypes.arrayOf(navItemPropType),
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
items: [],
|
||||
};
|
||||
|
||||
renderItem = (item) => {
|
||||
return (
|
||||
<div className={styles.item} key={item.path}>
|
||||
<Link
|
||||
onClick={this.props.onClose}
|
||||
to={getFirstLevelNavItemLink(item)}
|
||||
className={styles['item-label']}
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { items } = this.props;
|
||||
return <div id="global-nav-left">{items.map(this.renderItem)}</div>;
|
||||
}
|
||||
}
|
18
src/components/Layout/GlobalNav/Left/index.less
Normal file
18
src/components/Layout/GlobalNav/Left/index.less
Normal file
@ -0,0 +1,18 @@
|
||||
.item {
|
||||
padding: 12px 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.item-label {
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: #000;
|
||||
|
||||
&:hover {
|
||||
color: #000;
|
||||
}
|
||||
}
|
74
src/components/Layout/GlobalNav/Right/index.jsx
Normal file
74
src/components/Layout/GlobalNav/Right/index.jsx
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2021 99cloud
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { navItemPropType } from '../common';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
export default class Right extends React.Component {
|
||||
static propTypes = {
|
||||
items: PropTypes.arrayOf(navItemPropType),
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
items: [],
|
||||
};
|
||||
|
||||
renderNavItemChildren = (item) => {
|
||||
const { children = [] } = item;
|
||||
const currentChildren = children.length ? children : [item];
|
||||
const { onClose } = this.props;
|
||||
const items = currentChildren.map((it) => {
|
||||
const { name, path } = it;
|
||||
return (
|
||||
<div key={`${name}-${path}`} className={styles['children-item']}>
|
||||
<Link onClick={onClose} to={path}>
|
||||
<span className={styles['link-name']}>{name}</span>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return items;
|
||||
};
|
||||
|
||||
renderNavItem = (item) => {
|
||||
const { name = '' } = item || {};
|
||||
|
||||
return (
|
||||
<div className={styles['nav-item']}>
|
||||
<div className={styles.title}>{name}</div>
|
||||
<div classnames={styles.children}>
|
||||
{this.renderNavItemChildren(item)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { items } = this.props;
|
||||
if (!items.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.right} id="global-nav-right">
|
||||
{items.map(this.renderNavItem)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
38
src/components/Layout/GlobalNav/Right/index.less
Normal file
38
src/components/Layout/GlobalNav/Right/index.less
Normal file
@ -0,0 +1,38 @@
|
||||
.right {
|
||||
columns: 200px 3;
|
||||
column-gap: 12px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
break-inside: avoid;
|
||||
|
||||
.title {
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
margin-bottom: 4px;
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.children-item {
|
||||
position: relative;
|
||||
height: 32px;
|
||||
margin-right: 8px;
|
||||
line-height: 32px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 5%);
|
||||
}
|
||||
|
||||
.link-name {
|
||||
color: #000;
|
||||
}
|
||||
}
|
29
src/components/Layout/GlobalNav/common.jsx
Normal file
29
src/components/Layout/GlobalNav/common.jsx
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2021 99cloud
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const navItemPropType = PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
path: PropTypes.string,
|
||||
children: PropTypes.arrayOf(navItemPropType),
|
||||
});
|
||||
|
||||
export const getFirstLevelNavItemLink = (item) => {
|
||||
const { children = [] } = item;
|
||||
if (!children.length) {
|
||||
return item.path;
|
||||
}
|
||||
return item.children[0].path;
|
||||
};
|
111
src/components/Layout/GlobalNav/index.jsx
Normal file
111
src/components/Layout/GlobalNav/index.jsx
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2021 99cloud
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Drawer } from 'antd';
|
||||
import menuIcon from 'asset/image/global-menu.png';
|
||||
import { navItemPropType } from './common';
|
||||
import Left from './Left';
|
||||
import Right from './Right';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
export class GlobalNav extends React.Component {
|
||||
static propTypes = {
|
||||
navItems: PropTypes.arrayOf(navItemPropType),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
navItems: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
visible: false,
|
||||
};
|
||||
}
|
||||
|
||||
onClose = () => {
|
||||
this.setState({ visible: false });
|
||||
};
|
||||
|
||||
onToggleOpen = () => {
|
||||
this.setState(({ visible }) => {
|
||||
return {
|
||||
visible: !visible,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { visible } = this.state;
|
||||
const { navItems = [] } = this.props;
|
||||
|
||||
const drawerStyle = {
|
||||
top: '40px',
|
||||
height: 'calc(100% - 40px)',
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles['global-nav-icon']} onClick={this.onToggleOpen}>
|
||||
<img
|
||||
src={menuIcon}
|
||||
alt="menu-icon"
|
||||
className={styles['global-nav-icon-icon']}
|
||||
/>
|
||||
</div>
|
||||
<Drawer
|
||||
title={t('Service List')}
|
||||
placement="left"
|
||||
closable={false}
|
||||
onClose={this.onClose}
|
||||
visible={visible}
|
||||
style={drawerStyle}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
width="240"
|
||||
destroyOnClose
|
||||
>
|
||||
<Left items={navItems} onClose={this.onClose} />
|
||||
</Drawer>
|
||||
<Drawer
|
||||
title={null}
|
||||
placement="left"
|
||||
closable
|
||||
onClose={this.onClose}
|
||||
visible={visible}
|
||||
style={{
|
||||
...drawerStyle,
|
||||
left: visible ? '240px' : 0,
|
||||
}}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
mask
|
||||
width="1020"
|
||||
maskStyle={{ backgroundColor: 'transparent' }}
|
||||
closeIcon={<CloseOutlined style={{ fontSize: '20px' }} />}
|
||||
>
|
||||
<div className={styles.main}>
|
||||
<Right items={navItems} onClose={this.onClose} />
|
||||
</div>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default observer(GlobalNav);
|
22
src/components/Layout/GlobalNav/index.less
Normal file
22
src/components/Layout/GlobalNav/index.less
Normal file
@ -0,0 +1,22 @@
|
||||
@import '~styles/variables';
|
||||
|
||||
.global-nav-icon {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: @header-height;
|
||||
height: @header-height;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: @header-height;
|
||||
text-align: center;
|
||||
background-color: @primary-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.global-nav-icon-icon {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 32px 32px 0;
|
||||
}
|
@ -15,12 +15,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Menu, Tooltip } from 'antd';
|
||||
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { toJS } from 'mobx';
|
||||
import classnames from 'classnames';
|
||||
import logoSmall from 'asset/image/logo-small.svg';
|
||||
import logoExtend from 'asset/image/logo-extend.svg';
|
||||
import { getPath } from 'utils/route-map';
|
||||
import styles from './index.less';
|
||||
|
||||
@ -66,10 +63,6 @@ export class LayoutMenu extends Component {
|
||||
this.setState({ collapsed });
|
||||
};
|
||||
|
||||
getImage(isExtend) {
|
||||
return !isExtend ? logoSmall : logoExtend;
|
||||
}
|
||||
|
||||
changeCollapse = () => {
|
||||
const { collapsed } = this.state;
|
||||
this.setState({
|
||||
@ -235,25 +228,6 @@ export class LayoutMenu extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
renderLogo() {
|
||||
const { collapsed, hover } = this.state;
|
||||
const isExtend = !collapsed || hover;
|
||||
const imageSvg = this.getImage(isExtend);
|
||||
const homeUrl = this.getRoutePath('overview');
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
styles.logo,
|
||||
!isExtend ? styles['logo-collapse'] : ''
|
||||
)}
|
||||
>
|
||||
<Link to={homeUrl}>
|
||||
<img src={imageSvg} alt="logo" className={styles['logo-image']} />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentRoutes } = this.props;
|
||||
const selectedKeys = this.getSelectedKeys(currentRoutes);
|
||||
@ -270,7 +244,6 @@ export class LayoutMenu extends Component {
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
>
|
||||
{this.renderLogo()}
|
||||
{this.renderMenu(selectedKeys)}
|
||||
{trigger}
|
||||
</div>
|
||||
|
@ -93,6 +93,10 @@ export class BaseLayout extends Component {
|
||||
return ret;
|
||||
}
|
||||
|
||||
get globalNav() {
|
||||
return this.menu;
|
||||
}
|
||||
|
||||
get menu() {
|
||||
const menu = this.filterMenuByHidden(this.originMenu);
|
||||
const newMenu = this.getMenuAllowed(menu);
|
||||
@ -246,20 +250,18 @@ export class BaseLayout extends Component {
|
||||
<GlobalHeader
|
||||
{...this.props}
|
||||
isAdminPage={this.isAdminPage}
|
||||
navItems={this.globalNav}
|
||||
isUserCenterPage={this.isUserCenterPage}
|
||||
/>
|
||||
);
|
||||
|
||||
render() {
|
||||
const { collapsed } = this.state;
|
||||
const { pathname } = this.props.location;
|
||||
const currentRoutes = this.getCurrentMenu(pathname);
|
||||
return (
|
||||
<div className={styles['base-layout']}>
|
||||
{this.renderNotice()}
|
||||
<Header
|
||||
className={collapsed ? styles['header-collapsed'] : styles.header}
|
||||
>
|
||||
<Header className={styles.header}>
|
||||
{/* {this.renderLogo()} */}
|
||||
{this.renderHeader()}
|
||||
</Header>
|
||||
|
@ -7,12 +7,12 @@
|
||||
.header {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: @header-height;
|
||||
padding: 0;
|
||||
padding-left: 230px;
|
||||
color: @white;
|
||||
}
|
||||
|
||||
@ -247,10 +247,10 @@
|
||||
|
||||
.base-layout-sider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: @header-height;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
z-index: 1;
|
||||
width: 230px;
|
||||
background-color: @sider-background;
|
||||
transition: all 0.2s;
|
||||
|
@ -2068,6 +2068,7 @@
|
||||
"Server Status": "Server Status",
|
||||
"Server Type": "Server Type",
|
||||
"Service": "Service",
|
||||
"Service List": "Service List",
|
||||
"Service Port ID": "Service Port ID",
|
||||
"Service State": "Service State",
|
||||
"Service Status": "Service Status",
|
||||
|
@ -2068,6 +2068,7 @@
|
||||
"Server Status": "服务状态",
|
||||
"Server Type": "服务类型",
|
||||
"Service": "服务",
|
||||
"Service List": "服务列表",
|
||||
"Service Port ID": "服务端口ID",
|
||||
"Service State": "服务状态",
|
||||
"Service Status": "管理状态",
|
||||
|
Loading…
x
Reference in New Issue
Block a user