13 changed files with 325 additions and 365 deletions
@ -0,0 +1,33 @@ |
|||
import { Icon } from 'antd'; |
|||
import React from 'react'; |
|||
import style from './index.less'; |
|||
|
|||
const BlockChecbox = ({ value, onChange, list }) => { |
|||
return ( |
|||
<div className={style.blockChecbox} key={value}> |
|||
{list.map(item => { |
|||
return ( |
|||
<div |
|||
key={item.key} |
|||
className={style.item} |
|||
onClick={() => { |
|||
onChange(item.key); |
|||
}} |
|||
> |
|||
<img src={item.url} alt={item.key} /> |
|||
<div |
|||
className={style.selectIcon} |
|||
style={{ |
|||
display: value === item.key ? 'block' : 'none', |
|||
}} |
|||
> |
|||
<Icon type="check" /> |
|||
</div> |
|||
</div> |
|||
); |
|||
})} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default BlockChecbox; |
|||
@ -0,0 +1,52 @@ |
|||
import { Icon } from 'antd'; |
|||
import React from 'react'; |
|||
import styles from './ThemeColor.less'; |
|||
|
|||
const Tag = ({ color, check, ...rest }) => { |
|||
return ( |
|||
<div |
|||
{...rest} |
|||
style={{ |
|||
backgroundColor: color, |
|||
}} |
|||
> |
|||
{check ? <Icon type="check" /> : ''} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const ThemeColor = ({ colors, value, onChange }) => { |
|||
let colorList = colors; |
|||
if (!colors) { |
|||
colorList = [ |
|||
'#F5222D', |
|||
'#FA541C', |
|||
'#FAAD14', |
|||
'#13C2C2', |
|||
'#52C41A', |
|||
'#1890FF', |
|||
'#2F54EB', |
|||
'#722ED1', |
|||
]; |
|||
} |
|||
return ( |
|||
<div className={styles.themeColor}> |
|||
<h3 className={styles.title}>主题色</h3> |
|||
<div className={styles.content}> |
|||
{colorList.map(color => { |
|||
return ( |
|||
<Tag |
|||
className={styles.colorBlock} |
|||
key={color} |
|||
color={color} |
|||
check={value === color} |
|||
onClick={() => onChange && onChange(color)} |
|||
/> |
|||
); |
|||
})} |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default ThemeColor; |
|||
@ -0,0 +1,21 @@ |
|||
.themeColor { |
|||
overflow: hidden; |
|||
margin-top: 24px; |
|||
.title { |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.65); |
|||
line-height: 22px; |
|||
margin-bottom: 12px; |
|||
} |
|||
.colorBlock { |
|||
width: 20px; |
|||
height: 20px; |
|||
border-radius: 2px; |
|||
float: left; |
|||
cursor: pointer; |
|||
margin-right: 8px; |
|||
text-align: center; |
|||
color: #fff; |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
@ -0,0 +1,187 @@ |
|||
import React, { PureComponent } from 'react'; |
|||
import { Select, message, List, Switch, Divider } from 'antd'; |
|||
import DrawerMenu from 'rc-drawer-menu'; |
|||
import { connect } from 'dva'; |
|||
import styles from './index.less'; |
|||
import ThemeColor from './ThemeColor'; |
|||
import BlockChecbox from './BlockChecbox'; |
|||
|
|||
const Body = ({ children, title, style }) => ( |
|||
<div |
|||
style={{ |
|||
...style, |
|||
marginBottom: 24, |
|||
}} |
|||
> |
|||
<h3 className={styles.title}>{title}</h3> |
|||
{children} |
|||
</div> |
|||
); |
|||
|
|||
@connect(({ setting }) => ({ setting })) |
|||
class SettingDarwer extends PureComponent { |
|||
componentDidMount() { |
|||
const { themeColor } = this.props.setting; |
|||
if (themeColor !== '#1890FF') { |
|||
this.colorChange(themeColor); |
|||
} |
|||
} |
|||
getLayOutSetting = () => { |
|||
const { grid, fixedHeader, autoHideHeader, fixSiderbar } = this.props.setting; |
|||
return [ |
|||
{ |
|||
title: '栅格模式', |
|||
action: [ |
|||
<Select |
|||
value={grid} |
|||
size="small" |
|||
onSelect={value => this.changeSetting('grid', value)} |
|||
style={{ width: 80 }} |
|||
> |
|||
<Select.Option value="Wide">Wide</Select.Option> |
|||
<Select.Option value="Fluid">Fluid</Select.Option> |
|||
</Select>, |
|||
], |
|||
}, |
|||
{ |
|||
title: 'Fixed Header', |
|||
action: [ |
|||
<Switch |
|||
size="small" |
|||
checked={!!fixedHeader} |
|||
onChange={checked => this.changeSetting('fixedHeader', checked)} |
|||
/>, |
|||
], |
|||
}, |
|||
{ |
|||
title: '下滑时隐藏 Header', |
|||
action: [ |
|||
<Switch |
|||
size="small" |
|||
checked={!!autoHideHeader} |
|||
onChange={checked => this.changeSetting('autoHideHeader', checked)} |
|||
/>, |
|||
], |
|||
}, |
|||
{ |
|||
title: 'Fix Siderbar', |
|||
action: [ |
|||
<Switch |
|||
size="small" |
|||
checked={!!fixSiderbar} |
|||
onChange={checked => this.changeSetting('fixSiderbar', checked)} |
|||
/>, |
|||
], |
|||
}, |
|||
]; |
|||
}; |
|||
changeSetting = (key, value) => { |
|||
const nextState = { ...this.props.setting }; |
|||
nextState[key] = value; |
|||
if (key === 'layout') { |
|||
if (value === 'topmenu') { |
|||
nextState.grid = 'Wide'; |
|||
} else { |
|||
nextState.grid = 'Fluid'; |
|||
} |
|||
} |
|||
this.setState(nextState, () => { |
|||
this.props.dispatch({ |
|||
type: 'setting/changeSetting', |
|||
payload: this.state, |
|||
}); |
|||
}); |
|||
}; |
|||
togglerContent = () => { |
|||
this.changeSetting('collapse', !this.props.setting.collapse); |
|||
}; |
|||
colorChange = color => { |
|||
this.changeSetting('themeColor', color); |
|||
const hideMessage = message.loading('正在编译主题!', 0); |
|||
setTimeout(() => { |
|||
window.less |
|||
.modifyVars({ |
|||
'@primary-color': color, |
|||
}) |
|||
.then(() => { |
|||
hideMessage(); |
|||
}) |
|||
.catch(() => { |
|||
message.error(`Failed to update theme`); |
|||
}); |
|||
}, 200); |
|||
}; |
|||
render() { |
|||
const { collapse, silderTheme, themeColor, layout } = this.props.setting; |
|||
return ( |
|||
<div className={styles.settingDarwer}> |
|||
<div className={styles.mini_bar} onClick={this.togglerContent}> |
|||
<img |
|||
alt="logo" |
|||
src="https://gw.alipayobjects.com/zos/rmsportal/ApQgLmeZDNJMomKNvavq.svg" |
|||
/> |
|||
</div> |
|||
<DrawerMenu |
|||
parent={null} |
|||
level={null} |
|||
handleChild={null} |
|||
open={collapse} |
|||
placement="right" |
|||
width="336px" |
|||
style={{ |
|||
zIndex: 999, |
|||
}} |
|||
onMaskClick={this.togglerContent} |
|||
> |
|||
<div className={styles.content}> |
|||
<Body title="整体风格设置"> |
|||
<BlockChecbox |
|||
list={[ |
|||
{ |
|||
key: 'dark', |
|||
url: 'https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg', |
|||
}, |
|||
{ |
|||
key: 'light', |
|||
url: 'https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg', |
|||
}, |
|||
]} |
|||
value={silderTheme} |
|||
onChange={value => this.changeSetting('silderTheme', value)} |
|||
/> |
|||
</Body> |
|||
|
|||
<ThemeColor value={themeColor} onChange={this.colorChange} /> |
|||
|
|||
<Divider /> |
|||
|
|||
<Body title="导航设置 "> |
|||
<BlockChecbox |
|||
list={[ |
|||
{ |
|||
key: 'sidemenu', |
|||
url: 'https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg', |
|||
}, |
|||
{ |
|||
key: 'topmenu', |
|||
url: 'https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg', |
|||
}, |
|||
]} |
|||
value={layout} |
|||
onChange={value => this.changeSetting('layout', value)} |
|||
/> |
|||
</Body> |
|||
|
|||
<List |
|||
split={false} |
|||
dataSource={this.getLayOutSetting()} |
|||
renderItem={item => <List.Item actions={item.action}>{item.title}</List.Item>} |
|||
/> |
|||
</div> |
|||
</DrawerMenu> |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
export default SettingDarwer; |
|||
@ -1,23 +0,0 @@ |
|||
import { Tooltip } from 'antd'; |
|||
import React from 'react'; |
|||
import NavSate from './navState'; |
|||
import style from './index.less'; |
|||
|
|||
const LayoutSetting = ({ value, onChange }) => { |
|||
return ( |
|||
<div className={style.layoutSetting}> |
|||
{['sidemenu', 'topmenu'].map(layout => ( |
|||
<div className={style.item} onClick={() => onChange && onChange(layout)} key={layout}> |
|||
<NavSate type={layout} state={value === layout ? 'active' : 'default'} alt={layout} /> |
|||
</div> |
|||
))} |
|||
<Tooltip title="等待后期实现!"> |
|||
<div key="topside" className={style.item}> |
|||
<NavSate type="topside" state="disable" alt="topside" /> |
|||
</div> |
|||
</Tooltip> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default LayoutSetting; |
|||
@ -1,52 +0,0 @@ |
|||
import React from 'react'; |
|||
import styles from './ThemeColor.less'; |
|||
|
|||
const Tag = ({ color, ...rest }) => { |
|||
return ( |
|||
<div |
|||
{...rest} |
|||
style={{ |
|||
backgroundColor: color, |
|||
}} |
|||
/> |
|||
); |
|||
}; |
|||
|
|||
const ThemeColor = ({ colors, value, onChange }) => { |
|||
let colorList = colors; |
|||
if (!colors) { |
|||
colorList = [ |
|||
'#F5222D', |
|||
'#FA541C', |
|||
'#FA8C16', |
|||
'#FAAD14', |
|||
'#FADB14', |
|||
'#A0D911', |
|||
'#52C41A', |
|||
'#13C2C2', |
|||
'#1890FF', |
|||
'#2F54EB', |
|||
'#722ED1', |
|||
'#EB2F96', |
|||
]; |
|||
} |
|||
return ( |
|||
<div className={styles.themeColor}> |
|||
<h3 className={styles.title}>主题颜色</h3> |
|||
{colorList.map(color => { |
|||
const classname = |
|||
value === color ? `${styles.colorBlock} ${styles.active}` : styles.colorBlock; |
|||
return ( |
|||
<Tag |
|||
className={classname} |
|||
key={color} |
|||
color={color} |
|||
onClick={() => onChange && onChange(color)} |
|||
/> |
|||
); |
|||
})} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default ThemeColor; |
|||
@ -1,27 +0,0 @@ |
|||
.themeColor { |
|||
overflow: hidden; |
|||
margin-top: 15px; |
|||
margin-left: -5px; |
|||
margin-right: -5px; |
|||
.title { |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.65); |
|||
line-height: 22px; |
|||
margin-bottom: 5px; |
|||
} |
|||
.colorBlock { |
|||
width: 16px; |
|||
height: 16px; |
|||
border-radius: 2px; |
|||
float: left; |
|||
cursor: pointer; |
|||
margin: 5px; |
|||
&.active { |
|||
width: 18px; |
|||
height: 18px; |
|||
margin: 4px; |
|||
border: 2px solid hsl(90, 100%, 50%); |
|||
box-shadow: 0 0 4px 0 hsl(90, 100%, 50%); |
|||
} |
|||
} |
|||
} |
|||
@ -1,206 +0,0 @@ |
|||
import React, { PureComponent, Fragment } from 'react'; |
|||
import { Select, message, List, Switch, Divider, Radio } from 'antd'; |
|||
import DrawerMenu from 'rc-drawer-menu'; |
|||
import { connect } from 'dva'; |
|||
import styles from './index.less'; |
|||
import ThemeColor from './ThemeColor'; |
|||
import LayoutSeting from './LayoutSetting'; |
|||
|
|||
const RadioGroup = Radio.Group; |
|||
|
|||
const ColorBlock = ({ color, title }) => ( |
|||
<Fragment> |
|||
<div |
|||
className={styles.color_block} |
|||
style={{ |
|||
backgroundColor: color, |
|||
}} |
|||
/> |
|||
<div className={styles.color_block_title}>{title}</div> |
|||
</Fragment> |
|||
); |
|||
|
|||
const Body = ({ children, title, style }) => ( |
|||
<div |
|||
style={{ |
|||
padding: 15, |
|||
...style, |
|||
}} |
|||
> |
|||
<h3 className={styles.bodyTitle}>{title}</h3> |
|||
{children} |
|||
</div> |
|||
); |
|||
@connect(({ setting }) => ({ setting })) |
|||
class Sidebar extends PureComponent { |
|||
componentDidMount() { |
|||
const { themeColor } = this.props.setting; |
|||
if (themeColor !== '#1890FF') { |
|||
this.colorChange(themeColor); |
|||
} |
|||
} |
|||
getLayOutSetting = () => { |
|||
const { grid, fixedHeader, autoHideHeader, fixSiderbar, layout } = this.props.setting; |
|||
return [ |
|||
{ |
|||
title: '栅格模式', |
|||
isShow: true, |
|||
action: [ |
|||
<Select |
|||
value={grid} |
|||
onSelect={value => this.changeSetting('grid', value)} |
|||
style={{ width: 120 }} |
|||
> |
|||
<Select.Option value="Wide">Wide</Select.Option> |
|||
<Select.Option value="Fluid">Fluid</Select.Option> |
|||
</Select>, |
|||
], |
|||
}, |
|||
{ |
|||
title: 'Fixed Header', |
|||
isShow: true, |
|||
action: [ |
|||
<Switch |
|||
checked={!!fixedHeader} |
|||
onChange={checked => this.changeSetting('fixedHeader', checked)} |
|||
/>, |
|||
], |
|||
}, |
|||
{ |
|||
title: '↳ 下滑时隐藏 Header', |
|||
isShow: true, |
|||
action: [ |
|||
<Switch |
|||
checked={!!autoHideHeader} |
|||
onChange={checked => this.changeSetting('autoHideHeader', checked)} |
|||
/>, |
|||
], |
|||
}, |
|||
{ |
|||
title: 'Fix Siderbar', |
|||
isShow: layout === 'sidemenu', |
|||
action: [<Switch checked={!!fixSiderbar} onChange={this.fixSiderbar} />], |
|||
}, |
|||
].filter(item => item.isShow); |
|||
}; |
|||
fixSiderbar = checked => { |
|||
this.changeSetting('fixSiderbar', checked); |
|||
}; |
|||
changeSetting = (key, value) => { |
|||
const nextState = { ...this.props.setting }; |
|||
nextState[key] = value; |
|||
if (key === 'layout') { |
|||
if (value === 'topmenu') { |
|||
nextState.grid = 'Wide'; |
|||
} else { |
|||
nextState.grid = 'Fluid'; |
|||
} |
|||
} |
|||
this.setState(nextState, () => { |
|||
this.props.dispatch({ |
|||
type: 'setting/changeSetting', |
|||
payload: this.state, |
|||
}); |
|||
}); |
|||
}; |
|||
togglerContent = () => { |
|||
this.changeSetting('collapse', !this.props.setting.collapse); |
|||
}; |
|||
colorChange = color => { |
|||
this.changeSetting('themeColor', color); |
|||
const hideMessage = message.loading('正在编译主题!', 0); |
|||
window.less |
|||
.modifyVars({ |
|||
'@primary-color': color, |
|||
}) |
|||
.then(() => { |
|||
hideMessage(); |
|||
}) |
|||
.catch(() => { |
|||
message.error(`Failed to update theme`); |
|||
}); |
|||
}; |
|||
render() { |
|||
const radioStyle = { |
|||
display: 'block', |
|||
}; |
|||
const { collapse, silderTheme, themeColor, layout, colorWeak } = this.props.setting; |
|||
return ( |
|||
<div className={styles.sidebar}> |
|||
<div className={styles.mini_bar} onClick={this.togglerContent}> |
|||
<img |
|||
alt="logo" |
|||
src="https://gw.alipayobjects.com/zos/rmsportal/ApQgLmeZDNJMomKNvavq.svg" |
|||
/> |
|||
</div> |
|||
<DrawerMenu |
|||
parent={null} |
|||
level={null} |
|||
handleChild={null} |
|||
open={collapse} |
|||
placement="right" |
|||
width="336px" |
|||
onMaskClick={this.togglerContent} |
|||
> |
|||
<div className={styles.content}> |
|||
<Body |
|||
title="整体风格设置" |
|||
style={{ |
|||
paddingBottom: 10, |
|||
}} |
|||
> |
|||
<RadioGroup |
|||
onChange={({ target }) => this.changeSetting('silderTheme', target.value)} |
|||
value={silderTheme} |
|||
> |
|||
<Radio style={radioStyle} value="dark"> |
|||
<ColorBlock color="#002140" title="深色导航" /> |
|||
</Radio> |
|||
<Radio style={radioStyle} value="light"> |
|||
<ColorBlock color="#E9E9E9" title="浅色导航" /> |
|||
</Radio> |
|||
</RadioGroup> |
|||
<ThemeColor value={themeColor} onChange={this.colorChange} /> |
|||
</Body> |
|||
<Divider style={{ margin: 0 }} /> |
|||
<Body title="导航设置 "> |
|||
<LayoutSeting |
|||
value={layout} |
|||
onChange={value => this.changeSetting('layout', value)} |
|||
/> |
|||
<List |
|||
split={false} |
|||
dataSource={this.getLayOutSetting()} |
|||
renderItem={item => <List.Item actions={item.action}>{item.title}</List.Item>} |
|||
/> |
|||
</Body> |
|||
<Divider style={{ margin: 0 }} /> |
|||
<Body title="其他设置"> |
|||
<List |
|||
split={false} |
|||
dataSource={[ |
|||
{ |
|||
title: '色弱模式', |
|||
action: [ |
|||
<Select |
|||
value={colorWeak} |
|||
onSelect={value => this.changeSetting('colorWeak', value)} |
|||
style={{ width: 120 }} |
|||
> |
|||
<Select.Option value="open">打开</Select.Option> |
|||
<Select.Option value="close">关闭</Select.Option> |
|||
</Select>, |
|||
], |
|||
}, |
|||
]} |
|||
renderItem={item => <List.Item actions={item.action}>{item.title}</List.Item>} |
|||
/> |
|||
</Body> |
|||
</div> |
|||
</DrawerMenu> |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
export default Sidebar; |
|||
@ -1,26 +0,0 @@ |
|||
import React from 'react'; |
|||
|
|||
const UrlMap = { |
|||
sidemenu: { |
|||
active: 'https://gw.alipayobjects.com/zos/rmsportal/WEqgEeCsLvecmwJwbhif.svg', |
|||
default: 'https://gw.alipayobjects.com/zos/rmsportal/bjdhEDZlJzyMlyGbFQQd.svg', |
|||
disable: 'https://gw.alipayobjects.com/zos/rmsportal/VeCtUculrOjKzkzSzrye.svg', |
|||
}, |
|||
topside: { |
|||
active: 'https://gw.alipayobjects.com/zos/rmsportal/RbntcRzDHttDvYfKxsPc.svg', |
|||
default: 'https://gw.alipayobjects.com/zos/rmsportal/gqjBdnSHfVYIFvpGbLZV.svg', |
|||
disable: 'https://gw.alipayobjects.com/zos/rmsportal/VlSlQQkUGdbcOZdbUgMp.svg', |
|||
}, |
|||
topmenu: { |
|||
active: 'https://gw.alipayobjects.com/zos/rmsportal/nWoQtAGvMihfwxKZEzAi.svg', |
|||
default: 'https://gw.alipayobjects.com/zos/rmsportal/tbfuZcaGaYQGyeaiTaDg.svg', |
|||
disable: 'https://gw.alipayobjects.com/zos/rmsportal/VYNKTivFAQOBBbZkkWNb.svg', |
|||
}, |
|||
}; |
|||
|
|||
const navState = ({ alt, type, state }) => { |
|||
const url = UrlMap[type][state]; |
|||
return <img src={url} alt={alt} />; |
|||
}; |
|||
|
|||
export default navState; |
|||
Loading…
Reference in new issue