index.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import React, { PureComponent } from 'react';
  2. import { Select, message, Drawer, List, Switch, Divider, Icon, Button, Alert, Tooltip } from 'antd';
  3. import { formatMessage } from 'umi/locale';
  4. import { CopyToClipboard } from 'react-copy-to-clipboard';
  5. import { connect } from 'dva';
  6. import omit from 'omit.js';
  7. import styles from './index.less';
  8. import ThemeColor from './ThemeColor';
  9. import BlockChecbox from './BlockChecbox';
  10. const { Option } = Select;
  11. const Body = ({ children, title, style }) => (
  12. <div
  13. style={{
  14. ...style,
  15. marginBottom: 24,
  16. }}
  17. >
  18. <h3 className={styles.title}>{title}</h3>
  19. {children}
  20. </div>
  21. );
  22. @connect(({ setting }) => ({ setting }))
  23. class SettingDrawer extends PureComponent {
  24. state = {
  25. collapse: false,
  26. };
  27. getLayoutSetting = () => {
  28. const {
  29. setting: { contentWidth, fixedHeader, layout, autoHideHeader, fixSiderbar },
  30. } = this.props;
  31. return [
  32. {
  33. title: formatMessage({ id: 'app.setting.content-width' }),
  34. action: (
  35. <Select
  36. value={contentWidth}
  37. size="small"
  38. onSelect={value => this.changeSetting('contentWidth', value)}
  39. style={{ width: 80 }}
  40. >
  41. {layout === 'sidemenu' ? null : (
  42. <Option value="Fixed">
  43. {formatMessage({ id: 'app.setting.content-width.fixed' })}
  44. </Option>
  45. )}
  46. <Option value="Fluid">
  47. {formatMessage({ id: 'app.setting.content-width.fluid' })}
  48. </Option>
  49. </Select>
  50. ),
  51. },
  52. {
  53. title: formatMessage({ id: 'app.setting.fixedheader' }),
  54. action: (
  55. <Switch
  56. size="small"
  57. checked={!!fixedHeader}
  58. onChange={checked => this.changeSetting('fixedHeader', checked)}
  59. />
  60. ),
  61. },
  62. {
  63. title: formatMessage({ id: 'app.setting.hideheader' }),
  64. disabled: !fixedHeader,
  65. disabledReason: '固定 Header 时有效',
  66. action: (
  67. <Switch
  68. size="small"
  69. checked={!!autoHideHeader}
  70. onChange={checked => this.changeSetting('autoHideHeader', checked)}
  71. />
  72. ),
  73. },
  74. {
  75. title: formatMessage({ id: 'app.setting.fixedsidebar' }),
  76. disabled: layout === 'topmenu',
  77. disabledReason: '侧边菜单布局时有效',
  78. action: (
  79. <Switch
  80. size="small"
  81. checked={!!fixSiderbar}
  82. onChange={checked => this.changeSetting('fixSiderbar', checked)}
  83. />
  84. ),
  85. },
  86. ];
  87. };
  88. changeSetting = (key, value) => {
  89. const { setting } = this.props;
  90. const nextState = { ...setting };
  91. nextState[key] = value;
  92. if (key === 'layout') {
  93. nextState.contentWidth = value === 'topmenu' ? 'Fixed' : 'Fluid';
  94. } else if (key === 'fixedHeader' && !value) {
  95. nextState.autoHideHeader = false;
  96. }
  97. this.setState(nextState, () => {
  98. const { dispatch } = this.props;
  99. dispatch({
  100. type: 'setting/changeSetting',
  101. payload: this.state,
  102. });
  103. });
  104. };
  105. togglerContent = () => {
  106. const { collapse } = this.state;
  107. this.setState({ collapse: !collapse });
  108. };
  109. renderLayoutSettingItem = item => {
  110. const action = React.cloneElement(item.action, {
  111. disabled: item.disabled,
  112. });
  113. return (
  114. <Tooltip title={item.disabled ? item.disabledReason : ''} placement="left">
  115. <List.Item actions={[action]}>
  116. <span style={{ opacity: item.disabled ? '0.5' : '' }}>{item.title}</span>
  117. </List.Item>
  118. </Tooltip>
  119. );
  120. };
  121. render() {
  122. const { setting } = this.props;
  123. const { navTheme, primaryColor, layout, colorWeak } = setting;
  124. const { collapse } = this.state;
  125. return (
  126. <Drawer
  127. visible={collapse}
  128. width={300}
  129. onClose={this.togglerContent}
  130. placement="right"
  131. handler={
  132. <div className={styles.handle}>
  133. <Icon
  134. type={collapse ? 'close' : 'setting'}
  135. style={{
  136. color: '#fff',
  137. fontSize: 20,
  138. }}
  139. />
  140. </div>
  141. }
  142. onHandleClick={this.togglerContent}
  143. style={{
  144. zIndex: 999,
  145. }}
  146. >
  147. <div className={styles.content}>
  148. <Body title={formatMessage({ id: 'app.setting.pagestyle' })}>
  149. <BlockChecbox
  150. list={[
  151. {
  152. key: 'dark',
  153. url: 'https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg',
  154. title: formatMessage({ id: 'app.setting.pagestyle.dark' }),
  155. },
  156. {
  157. key: 'light',
  158. url: 'https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg',
  159. title: formatMessage({ id: 'app.setting.pagestyle.light' }),
  160. },
  161. ]}
  162. value={navTheme}
  163. onChange={value => this.changeSetting('navTheme', value)}
  164. />
  165. </Body>
  166. <ThemeColor
  167. title={formatMessage({ id: 'app.setting.themecolor' })}
  168. value={primaryColor}
  169. onChange={color => this.changeSetting('primaryColor', color)}
  170. />
  171. <Divider />
  172. <Body title={formatMessage({ id: 'app.setting.navigationmode' })}>
  173. <BlockChecbox
  174. list={[
  175. {
  176. key: 'sidemenu',
  177. url: 'https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg',
  178. title: formatMessage({ id: 'app.setting.sidemenu' }),
  179. },
  180. {
  181. key: 'topmenu',
  182. url: 'https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg',
  183. title: formatMessage({ id: 'app.setting.topmenu' }),
  184. },
  185. ]}
  186. value={layout}
  187. onChange={value => this.changeSetting('layout', value)}
  188. />
  189. </Body>
  190. <List
  191. split={false}
  192. dataSource={this.getLayoutSetting()}
  193. renderItem={this.renderLayoutSettingItem}
  194. />
  195. <Divider />
  196. <Body title={formatMessage({ id: 'app.setting.othersettings' })}>
  197. <List.Item
  198. actions={[
  199. <Switch
  200. size="small"
  201. checked={!!colorWeak}
  202. onChange={checked => this.changeSetting('colorWeak', checked)}
  203. />,
  204. ]}
  205. >
  206. {formatMessage({ id: 'app.setting.weakmode' })}
  207. </List.Item>
  208. </Body>
  209. <Divider />
  210. <CopyToClipboard
  211. text={JSON.stringify(omit(setting, ['colorWeak']), null, 2)}
  212. onCopy={() => message.success(formatMessage({ id: 'app.setting.copyinfo' }))}
  213. >
  214. <Button block icon="copy">
  215. {formatMessage({ id: 'app.setting.copy' })}
  216. </Button>
  217. </CopyToClipboard>
  218. <Alert
  219. type="warning"
  220. className={styles.productionHint}
  221. message={
  222. <div>
  223. {formatMessage({ id: 'app.setting.production.hint' })}{' '}
  224. <a
  225. href="https://u.ant.design/pro-v2-default-settings"
  226. target="_blank"
  227. rel="noopener noreferrer"
  228. >
  229. src/defaultSettings.js
  230. </a>
  231. </div>
  232. }
  233. />
  234. </div>
  235. </Drawer>
  236. );
  237. }
  238. }
  239. export default SettingDrawer;