From 985c03af9565a09701e5f49414fe326ce54705d2 Mon Sep 17 00:00:00 2001 From: "Jingwei.Zhang" Date: Tue, 8 Nov 2022 17:49:10 +0800 Subject: [PATCH] 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 --- config/webpack.common.js | 10 +- src/asset/image/cloud-logo.svg | 15 +++ src/asset/image/global-menu.png | Bin 0 -> 204 bytes src/asset/image/logo-extend.svg | 10 -- src/asset/image/logo-small.svg | 18 --- src/components/Layout/GlobalHeader/index.jsx | 31 ++++- src/components/Layout/GlobalHeader/index.less | 14 ++- .../Layout/GlobalNav/Left/index.jsx | 50 ++++++++ .../Layout/GlobalNav/Left/index.less | 18 +++ .../Layout/GlobalNav/Right/index.jsx | 74 ++++++++++++ .../Layout/GlobalNav/Right/index.less | 38 ++++++ src/components/Layout/GlobalNav/common.jsx | 29 +++++ src/components/Layout/GlobalNav/index.jsx | 111 ++++++++++++++++++ src/components/Layout/GlobalNav/index.less | 22 ++++ src/layouts/Base/Menu.jsx | 27 ----- src/layouts/Base/index.jsx | 10 +- src/layouts/Base/index.less | 6 +- src/locales/en.json | 1 + src/locales/zh.json | 1 + 19 files changed, 412 insertions(+), 73 deletions(-) create mode 100644 src/asset/image/cloud-logo.svg create mode 100644 src/asset/image/global-menu.png delete mode 100644 src/asset/image/logo-extend.svg delete mode 100644 src/asset/image/logo-small.svg create mode 100644 src/components/Layout/GlobalNav/Left/index.jsx create mode 100644 src/components/Layout/GlobalNav/Left/index.less create mode 100644 src/components/Layout/GlobalNav/Right/index.jsx create mode 100644 src/components/Layout/GlobalNav/Right/index.less create mode 100644 src/components/Layout/GlobalNav/common.jsx create mode 100644 src/components/Layout/GlobalNav/index.jsx create mode 100644 src/components/Layout/GlobalNav/index.less diff --git a/config/webpack.common.js b/config/webpack.common.js index f702deb4..62803569 100644 --- a/config/webpack.common.js +++ b/config/webpack.common.js @@ -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')], }, ], }, diff --git a/src/asset/image/cloud-logo.svg b/src/asset/image/cloud-logo.svg new file mode 100644 index 00000000..b2024c36 --- /dev/null +++ b/src/asset/image/cloud-logo.svg @@ -0,0 +1,15 @@ + + + 编组 4 + + + + Cloud + + + + + + + + \ No newline at end of file diff --git a/src/asset/image/global-menu.png b/src/asset/image/global-menu.png new file mode 100644 index 0000000000000000000000000000000000000000..6b90fc5c561c4f8bb96e09e3946568710cb77b3a GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^8bEBp!3HGzHFkXiQj$dBA{!;o^?} z7s@)EElz#Cf5gUj!nw)y%IDutRahI)#2LgW70;h^@NVp`6RCfuC_MSfeTaEp`}Z>e zk6474Fq!O=^O?YPp`xDOEbpMy@8i0)or$dH4*%W$V-7>!1O=8i>}sq&297!o;ve=m z|4LlQk|_L(J*?uu=Ys#bcIpk%DjbZn(=-yA{)_)%I9g%AX~4SZDbRTgp00i_>zopr E073&#bN~PV literal 0 HcmV?d00001 diff --git a/src/asset/image/logo-extend.svg b/src/asset/image/logo-extend.svg deleted file mode 100644 index c6f6e49c..00000000 --- a/src/asset/image/logo-extend.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/src/asset/image/logo-small.svg b/src/asset/image/logo-small.svg deleted file mode 100644 index 763663ef..00000000 --- a/src/asset/image/logo-small.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - logo - - - - - - \ No newline at end of file diff --git a/src/components/Layout/GlobalHeader/index.jsx b/src/components/Layout/GlobalHeader/index.jsx index 41941b80..f293c135 100644 --- a/src/components/Layout/GlobalHeader/index.jsx +++ b/src/components/Layout/GlobalHeader/index.jsx @@ -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 ( +
+ + logo + +
+ ); + }; + return (
+ + {renderLogo()} {!isAdminPage && }
diff --git a/src/components/Layout/GlobalHeader/index.less b/src/components/Layout/GlobalHeader/index.less index f9de405a..bf3cad42 100644 --- a/src/components/Layout/GlobalHeader/index.less +++ b/src/components/Layout/GlobalHeader/index.less @@ -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; + } +} diff --git a/src/components/Layout/GlobalNav/Left/index.jsx b/src/components/Layout/GlobalNav/Left/index.jsx new file mode 100644 index 00000000..62144c87 --- /dev/null +++ b/src/components/Layout/GlobalNav/Left/index.jsx @@ -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 ( +
+ + {item.name} + +
+ ); + }; + + render() { + const { items } = this.props; + return ; + } +} diff --git a/src/components/Layout/GlobalNav/Left/index.less b/src/components/Layout/GlobalNav/Left/index.less new file mode 100644 index 00000000..e5fe8563 --- /dev/null +++ b/src/components/Layout/GlobalNav/Left/index.less @@ -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; + } +} diff --git a/src/components/Layout/GlobalNav/Right/index.jsx b/src/components/Layout/GlobalNav/Right/index.jsx new file mode 100644 index 00000000..05153421 --- /dev/null +++ b/src/components/Layout/GlobalNav/Right/index.jsx @@ -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 ( +
+ + {name} + +
+ ); + }); + return items; + }; + + renderNavItem = (item) => { + const { name = '' } = item || {}; + + return ( +
+
{name}
+
+ {this.renderNavItemChildren(item)} +
+
+ ); + }; + + render() { + const { items } = this.props; + if (!items.length) { + return null; + } + + return ( + + ); + } +} diff --git a/src/components/Layout/GlobalNav/Right/index.less b/src/components/Layout/GlobalNav/Right/index.less new file mode 100644 index 00000000..e74be330 --- /dev/null +++ b/src/components/Layout/GlobalNav/Right/index.less @@ -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; + } +} diff --git a/src/components/Layout/GlobalNav/common.jsx b/src/components/Layout/GlobalNav/common.jsx new file mode 100644 index 00000000..b27ca8f6 --- /dev/null +++ b/src/components/Layout/GlobalNav/common.jsx @@ -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; +}; diff --git a/src/components/Layout/GlobalNav/index.jsx b/src/components/Layout/GlobalNav/index.jsx new file mode 100644 index 00000000..b6f6e739 --- /dev/null +++ b/src/components/Layout/GlobalNav/index.jsx @@ -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 ( + <> +
+ menu-icon +
+ + + + } + > +
+ +
+
+ + ); + } +} + +export default observer(GlobalNav); diff --git a/src/components/Layout/GlobalNav/index.less b/src/components/Layout/GlobalNav/index.less new file mode 100644 index 00000000..9b3b6921 --- /dev/null +++ b/src/components/Layout/GlobalNav/index.less @@ -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; +} diff --git a/src/layouts/Base/Menu.jsx b/src/layouts/Base/Menu.jsx index 14f9262f..919d6caa 100644 --- a/src/layouts/Base/Menu.jsx +++ b/src/layouts/Base/Menu.jsx @@ -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 ( -
- - logo - -
- ); - } - 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} diff --git a/src/layouts/Base/index.jsx b/src/layouts/Base/index.jsx index 4ce195fb..a671d51b 100644 --- a/src/layouts/Base/index.jsx +++ b/src/layouts/Base/index.jsx @@ -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 { ); render() { - const { collapsed } = this.state; const { pathname } = this.props.location; const currentRoutes = this.getCurrentMenu(pathname); return (
{this.renderNotice()} -
+
{/* {this.renderLogo()} */} {this.renderHeader()}
diff --git a/src/layouts/Base/index.less b/src/layouts/Base/index.less index 6b72aeb8..363fc190 100644 --- a/src/layouts/Base/index.less +++ b/src/layouts/Base/index.less @@ -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; diff --git a/src/locales/en.json b/src/locales/en.json index cd2c4a03..265ef097 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -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", diff --git a/src/locales/zh.json b/src/locales/zh.json index 2bdee839..a6472084 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -2068,6 +2068,7 @@ "Server Status": "服务状态", "Server Type": "服务类型", "Service": "服务", + "Service List": "服务列表", "Service Port ID": "服务端口ID", "Service State": "服务状态", "Service Status": "管理状态",