This commit is contained in:
zuiidea
2016-12-29 23:38:25 +08:00
parent 75884305a0
commit 960ab30a33
6 changed files with 178 additions and 74 deletions
+25 -10
View File
@@ -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>
+70 -28
View File
@@ -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;
}
}
}
+44
View File
@@ -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
+8 -31
View File
@@ -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
View File
@@ -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
View File
@@ -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}/>