mirror of
https://github.com/zuiidea/antd-admin
synced 2026-10-28 20:03:57 +00:00
navbar
This commit is contained in:
@@ -1,21 +1,36 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import { Menu, Icon, Button } from 'antd'
|
||||
import { Link } from 'dva/router'
|
||||
import React, {PropTypes} from 'react'
|
||||
import {Menu, Icon, Popover} from 'antd'
|
||||
import {Link} from 'dva/router'
|
||||
import styles from './main.less'
|
||||
import Menus from './menu'
|
||||
|
||||
const SubMenu = Menu.SubMenu
|
||||
|
||||
function Header({ user, logout, switchSider, siderFold }) {
|
||||
function Header({user, logout, switchSider, siderFold, isNavbar ,location}) {
|
||||
let handleClickMenu = e => e.key === 'logout' && logout()
|
||||
const menusProps = {
|
||||
siderFold:false,
|
||||
darkTheme:false,
|
||||
isNavbar,
|
||||
location
|
||||
}
|
||||
return (
|
||||
<div className={styles.header}>
|
||||
<div className={styles.siderbutton} onClick={switchSider}>
|
||||
<Icon type={siderFold?"menu-unfold":"menu-fold"} />
|
||||
</div>
|
||||
{isNavbar
|
||||
? <Popover placement="bottomLeft" overlayClassName={styles.popovermenu} trigger="click" content={<Menus {...menusProps}/>}>
|
||||
<div className={styles.siderbutton}>
|
||||
<Icon type="bars"/>
|
||||
</div>
|
||||
</Popover>
|
||||
: <div className={styles.siderbutton} onClick={switchSider}>
|
||||
<Icon type={siderFold? 'menu-unfold': 'menu-fold'}/>
|
||||
</div>}
|
||||
|
||||
<Menu className="header-menu" mode="horizontal" onClick={handleClickMenu}>
|
||||
<SubMenu style={{ float: 'right' }}
|
||||
title={<span><Icon type="user" />{user.name}</span>}
|
||||
>
|
||||
<SubMenu style={{
|
||||
float: 'right'
|
||||
}} title={< span > <Icon type="user"/>
|
||||
{user.name} < /span>}>
|
||||
<Menu.Item key="logout">
|
||||
<a>注销</a>
|
||||
</Menu.Item>
|
||||
|
||||
@@ -4,36 +4,48 @@
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
|
||||
&.fold{
|
||||
.sider{
|
||||
&.withnavbar {
|
||||
.main {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.fold {
|
||||
.sider {
|
||||
width: 42px;
|
||||
.logo{
|
||||
img{
|
||||
|
||||
.logo {
|
||||
img {
|
||||
width: 28px;
|
||||
margin: 6px 7px;
|
||||
}
|
||||
}
|
||||
|
||||
:global{
|
||||
.ant-menu-root{
|
||||
:global {
|
||||
.ant-menu-root {
|
||||
width: 100%;
|
||||
&>.ant-menu-item {
|
||||
|
||||
& > .ant-menu-item {
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
.anticon{
|
||||
|
||||
.anticon {
|
||||
font-size: 14px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
&>.ant-menu-submenu{
|
||||
&>.ant-menu-submenu-title{
|
||||
|
||||
& > .ant-menu-submenu {
|
||||
& > .ant-menu-submenu-title {
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
.anticon{
|
||||
|
||||
.anticon {
|
||||
font-size: 14px;
|
||||
margin-right: 0;
|
||||
}
|
||||
&::after{
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +53,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.main{
|
||||
|
||||
.main {
|
||||
margin-left: 42px;
|
||||
}
|
||||
}
|
||||
@@ -55,10 +68,12 @@
|
||||
height: 100vh;
|
||||
transition: @transition-ease-out;
|
||||
box-shadow: @shadow-1;
|
||||
z-index: 1994;
|
||||
|
||||
&.light{
|
||||
&.light {
|
||||
background: #fff;
|
||||
.switchtheme{
|
||||
|
||||
.switchtheme {
|
||||
background: #fff;
|
||||
border-top: solid 1px #f8f8f8;
|
||||
}
|
||||
@@ -86,11 +101,12 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.anticon{
|
||||
.anticon {
|
||||
transition: @transition-ease-out;
|
||||
}
|
||||
}
|
||||
.switchtheme{
|
||||
|
||||
.switchtheme {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
@@ -102,22 +118,26 @@
|
||||
padding: 0 16px 0 24px;
|
||||
overflow: hidden;
|
||||
|
||||
span{
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
:global{
|
||||
.anticon{
|
||||
|
||||
:global {
|
||||
.anticon {
|
||||
min-width: 14px;
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
:global{
|
||||
.ant-menu{
|
||||
|
||||
:global {
|
||||
.ant-menu {
|
||||
transition: @transition-ease-out;
|
||||
.ant-menu-item, .ant-menu-submenu-title{
|
||||
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu-title {
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
}
|
||||
@@ -134,7 +154,8 @@
|
||||
}
|
||||
box-shadow: @shadow-2;
|
||||
position: relative;
|
||||
.siderbutton{
|
||||
|
||||
.siderbutton {
|
||||
height: 47px;
|
||||
width: 47px;
|
||||
line-height: 47px;
|
||||
@@ -143,7 +164,8 @@
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
transition: @transition-ease-in;
|
||||
&:hover{
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
background-color: fade(@primary-color, 15%);
|
||||
}
|
||||
@@ -169,7 +191,8 @@
|
||||
.content {
|
||||
min-height: e("calc(100vh - 184px)");
|
||||
position: relative;
|
||||
:global .content-inner{
|
||||
|
||||
:global .content-inner {
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
box-shadow: @shadow-1;
|
||||
@@ -220,11 +243,30 @@
|
||||
.ant-menu-item-selected {
|
||||
color: @primary-color;
|
||||
background-color: @dark-half;
|
||||
|
||||
& > a {
|
||||
color: @primary-color;
|
||||
}
|
||||
&:hover{
|
||||
background-color: @dark-half;
|
||||
|
||||
&:hover {
|
||||
background-color: @dark-half;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popovermenu {
|
||||
width: 280px;
|
||||
left: 12px!important;
|
||||
|
||||
:global .ant-popover-inner-content {
|
||||
padding: 0;
|
||||
.ant-menu-inline .ant-menu-item, .ant-menu-vertical .ant-menu-item{
|
||||
border-right: 0;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
.ant-menu-inline .ant-menu-selected, .ant-menu-inline .ant-menu-item-selected{
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import { Menu, Icon } from 'antd'
|
||||
import { Link } from 'dva/router'
|
||||
import styles from './main.less'
|
||||
import { menu } from '../../utils'
|
||||
|
||||
|
||||
const topMenus = menu.map( item => item.key)
|
||||
const getMenus = function (menuArray,siderFold,parentPath) {
|
||||
parentPath = parentPath || '/'
|
||||
return menuArray.map(item => {
|
||||
if (!!item.child) {
|
||||
return (
|
||||
<Menu.SubMenu key={item.key} title={<span>{item.icon ? <Icon type={item.icon} /> : ''}{siderFold&&topMenus.indexOf(item.key)>=0 ? '' : item.name}</span>}>
|
||||
{getMenus(item.child,siderFold,parentPath + item.key + '/')}
|
||||
</Menu.SubMenu>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Menu.Item key={item.key}>
|
||||
<Link to={parentPath + item.key}>
|
||||
{item.icon ? <Icon type={item.icon} /> : ''}
|
||||
{siderFold&&topMenus.indexOf(item.key)>=0 ? '' : item.name}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function Menus({ siderFold,darkTheme,location,isNavbar }) {
|
||||
const menuItems = getMenus(menu,siderFold)
|
||||
return (
|
||||
<Menu
|
||||
mode={siderFold?"vertical":"inline"}
|
||||
theme={darkTheme?"dark":"light"}
|
||||
defaultOpenKeys={isNavbar?menuItems.map(item => item.key):[]}
|
||||
defaultSelectedKeys={[location.pathname.split('/')[location.pathname.split('/').length - 1]||'dashboard']}>
|
||||
{menuItems}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
export default Menus
|
||||
@@ -2,45 +2,22 @@ import React, { PropTypes } from 'react'
|
||||
import { Menu, Icon, Switch } from 'antd'
|
||||
import { Link } from 'dva/router'
|
||||
import styles from './main.less'
|
||||
import { config, menu } from '../../utils'
|
||||
|
||||
|
||||
const topMenus = menu.map( item => item.key)
|
||||
const getMenus = function (menuArray,siderFold,parentPath) {
|
||||
parentPath = parentPath || '/'
|
||||
return menuArray.map(item => {
|
||||
if (!!item.child) {
|
||||
return (
|
||||
<Menu.SubMenu key={item.key} title={<span>{item.icon ? <Icon type={item.icon} /> : ''}{siderFold&&topMenus.indexOf(item.key)>=0 ? '' : item.name}</span>}>
|
||||
{getMenus(item.child,siderFold,parentPath + item.key + '/')}
|
||||
</Menu.SubMenu>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Menu.Item key={item.key}>
|
||||
<Link to={parentPath + item.key}>
|
||||
{item.icon ? <Icon type={item.icon} /> : ''}
|
||||
{siderFold&&topMenus.indexOf(item.key)>=0 ? '' : item.name}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
import { config } from '../../utils'
|
||||
import Menus from './menu'
|
||||
|
||||
function Sider({ siderFold,darkTheme,location,changeTheme }) {
|
||||
const menusProps={
|
||||
siderFold,
|
||||
darkTheme,
|
||||
location
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.logo}>
|
||||
<img src={config.logoSrc} />
|
||||
{siderFold?'':<span>{config.logoText}</span>}
|
||||
</div>
|
||||
<Menu
|
||||
mode={siderFold?"vertical":"inline"}
|
||||
theme={darkTheme?"dark":"light"}
|
||||
defaultSelectedKeys={[location.pathname.split('/')[location.pathname.split('/').length - 1]||'dashboard']}>
|
||||
{getMenus(menu,siderFold)}
|
||||
</Menu>
|
||||
<Menus {...menusProps}/>
|
||||
{!siderFold?<div className={styles.switchtheme}>
|
||||
<span><Icon type="bulb" />切换主题</span>
|
||||
<Switch onChange={changeTheme} defaultChecked={darkTheme} checkedChildren="黑" unCheckedChildren="白" />
|
||||
|
||||
+25
-1
@@ -13,10 +13,14 @@ export default {
|
||||
loginButtonLoading: false,
|
||||
siderFold:localStorage.getItem("antdAdminSiderFold")==="true"?true:false,
|
||||
darkTheme:localStorage.getItem("antdAdminDarkTheme")==="false"?false:true,
|
||||
isNavbar:document.body.clientWidth<769?true:false,
|
||||
},
|
||||
subscriptions : {
|
||||
setup({dispatch}) {
|
||||
dispatch({type: 'queryUser'})
|
||||
window.onresize = function(){
|
||||
dispatch({type: 'changeNavbar'})
|
||||
}
|
||||
}
|
||||
},
|
||||
effects : {
|
||||
@@ -66,7 +70,6 @@ export default {
|
||||
*switchSider({
|
||||
payload
|
||||
}, {put}) {
|
||||
console.log("switchSider");
|
||||
yield put({
|
||||
type: 'handleSwitchSider'
|
||||
})
|
||||
@@ -78,6 +81,15 @@ export default {
|
||||
type: 'handleChangeTheme'
|
||||
})
|
||||
},
|
||||
*changeNavbar({
|
||||
payload
|
||||
}, {put}) {
|
||||
if(document.body.clientWidth<769){
|
||||
yield put({type: 'showNavbar'})
|
||||
}else {
|
||||
yield put({type: 'hideNavbar'})
|
||||
}
|
||||
},
|
||||
},
|
||||
reducers : {
|
||||
loginSuccess(state, action) {
|
||||
@@ -133,5 +145,17 @@ export default {
|
||||
darkTheme: !state.darkTheme
|
||||
}
|
||||
},
|
||||
showNavbar(state) {
|
||||
return {
|
||||
...state,
|
||||
isNavbar: true
|
||||
}
|
||||
},
|
||||
hideNavbar(state) {
|
||||
return {
|
||||
...state,
|
||||
isNavbar: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -11,7 +11,7 @@ import {classnames} from '../utils'
|
||||
import '../components/layout/common.less'
|
||||
|
||||
function App({children, location, dispatch, app}) {
|
||||
const {login, loading, loginButtonLoading, user, siderFold, darkTheme} = app
|
||||
const {login, loading, loginButtonLoading, user, siderFold, darkTheme, isNavbar} = app
|
||||
const loginProps = {
|
||||
loading,
|
||||
loginButtonLoading,
|
||||
@@ -23,6 +23,8 @@ function App({children, location, dispatch, app}) {
|
||||
const headerProps = {
|
||||
user,
|
||||
siderFold,
|
||||
location,
|
||||
isNavbar,
|
||||
logout() {
|
||||
dispatch({type: 'app/logout'})
|
||||
},
|
||||
@@ -42,10 +44,10 @@ function App({children, location, dispatch, app}) {
|
||||
|
||||
return (
|
||||
<div>{login
|
||||
? <div className={classnames(styles.layout,{[styles.fold]:siderFold})}>
|
||||
<aside className={classnames(styles.sider,{[styles.light]:!darkTheme})}>
|
||||
? <div className={classnames(styles.layout,{[styles.fold]:isNavbar?false:siderFold},{[styles.withnavbar]:isNavbar})}>
|
||||
{!isNavbar?<aside className={classnames(styles.sider,{[styles.light]:!darkTheme})}>
|
||||
<Sider {...siderProps}/>
|
||||
</aside>
|
||||
</aside>:''}
|
||||
<div className={styles.main}>
|
||||
<Header {...headerProps}/>
|
||||
<Bread location={location}/>
|
||||
|
||||
Reference in New Issue
Block a user