Commit 05d37ea1 authored by Sendya's avatar Sendya

feat: SettingDrawer

parent f56f9539
export default {
theme: [
{
key: 'dark',
fileName: 'dark.css',
theme: 'dark'
},
{
key: '#F5222D',
fileName: '#F5222D.css',
modifyVars: {
'@primary-color': '#F5222D'
}
},
{
key: '#FA541C',
fileName: '#FA541C.css',
modifyVars: {
'@primary-color': '#FA541C'
}
},
{
key: '#FAAD14',
fileName: '#FAAD14.css',
modifyVars: {
'@primary-color': '#FAAD14'
}
},
{
key: '#13C2C2',
fileName: '#13C2C2.css',
modifyVars: {
'@primary-color': '#13C2C2'
}
},
{
key: '#52C41A',
fileName: '#52C41A.css',
modifyVars: {
'@primary-color': '#52C41A'
}
},
{
key: '#2F54EB',
fileName: '#2F54EB.css',
modifyVars: {
'@primary-color': '#2F54EB'
}
},
{
key: '#722ED1',
fileName: '#722ED1.css',
modifyVars: {
'@primary-color': '#722ED1'
}
},
{
key: '#F5222D',
theme: 'dark',
fileName: 'dark-#F5222D.css',
modifyVars: {
'@primary-color': '#F5222D'
}
},
{
key: '#FA541C',
theme: 'dark',
fileName: 'dark-#FA541C.css',
modifyVars: {
'@primary-color': '#FA541C'
}
},
{
key: '#FAAD14',
theme: 'dark',
fileName: 'dark-#FAAD14.css',
modifyVars: {
'@primary-color': '#FAAD14'
}
},
{
key: '#13C2C2',
theme: 'dark',
fileName: 'dark-#13C2C2.css',
modifyVars: {
'@primary-color': '#13C2C2'
}
},
{
key: '#52C41A',
theme: 'dark',
fileName: 'dark-#52C41A.css',
modifyVars: {
'@primary-color': '#52C41A'
}
},
{
key: '#2F54EB',
theme: 'dark',
fileName: 'dark-#2F54EB.css',
modifyVars: {
'@primary-color': '#2F54EB'
}
},
{
key: '#722ED1',
theme: 'dark',
fileName: 'dark-#722ED1.css',
modifyVars: {
'@primary-color': '#722ED1'
}
}
]
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.0.0-alpha.11", "@ant-design/icons": "^4.0.0-alpha.11",
"ant-design-vue": "^1.5.3", "ant-design-vue": "^1.5.4",
"core-js": "^3.1.2", "core-js": "^3.1.2",
"vue-i18n": "^8.15.0", "vue-i18n": "^8.15.0",
"vue-ls": "^3.2.1", "vue-ls": "^3.2.1",
......
...@@ -63,4 +63,11 @@ export { ...@@ -63,4 +63,11 @@ export {
export { export {
default as SmileOutline default as SmileOutline
} from '@ant-design/icons/lib/outline/SmileOutline' } from '@ant-design/icons/lib/outline/SmileOutline'
export {
default as CheckOutline
} from '@ant-design/icons/lib/outline/CheckOutline'
export {
default as EllipsisOutline
} from '@ant-design/icons/lib/outline/EllipsisOutline'
/* Layout end */ /* Layout end */
...@@ -3,7 +3,7 @@ import './BasicLayout.less' ...@@ -3,7 +3,7 @@ import './BasicLayout.less'
import { Avatar, Dropdown, Menu, Icon, Modal } from 'ant-design-vue' import { Avatar, Dropdown, Menu, Icon, Modal } from 'ant-design-vue'
import { asyncRouterMap } from '../config/router.config.js' import { asyncRouterMap } from '../config/router.config.js'
import { i18nRender } from '../locales' import { i18nRender } from '../locales'
import ProLayout, { GlobalFooter } from '@ant-design-vue/pro-layout' import ProLayout, { GlobalFooter, SettingDrawer } from '@ant-design-vue/pro-layout'
import SelectLang from '../components/SelectLang' import SelectLang from '../components/SelectLang'
import LogoSvg from '../assets/logo.svg?inline' import LogoSvg from '../assets/logo.svg?inline'
// import defaultSettings from '@config/defaultSettings' // import defaultSettings from '@config/defaultSettings'
...@@ -100,6 +100,8 @@ export default { ...@@ -100,6 +100,8 @@ export default {
contentWidth: true, contentWidth: true,
// 主题 'dark' | 'light' // 主题 'dark' | 'light'
theme: 'dark', theme: 'dark',
// 主色调
primaryColor: 'daybreak',
// 是否手机模式 // 是否手机模式
isMobile: false isMobile: false
} }
...@@ -110,7 +112,8 @@ export default { ...@@ -110,7 +112,8 @@ export default {
contentWidth, contentWidth,
autoHideHeader, autoHideHeader,
layout, layout,
theme theme,
primaryColor
} = this } = this
const handleMediaQuery = (val) => { const handleMediaQuery = (val) => {
...@@ -129,6 +132,12 @@ export default { ...@@ -129,6 +132,12 @@ export default {
} }
const menus = asyncRouterMap.find(item => item.path === '/').children const menus = asyncRouterMap.find(item => item.path === '/').children
const handleThemeChange = (theme) => {
this.theme = theme
}
const handleColorChange = (color) => {
this.primaryColor = color
}
const cdProps = { const cdProps = {
props: { props: {
menus, menus,
...@@ -154,6 +163,13 @@ export default { ...@@ -154,6 +163,13 @@ export default {
return ( return (
<ProLayout {...cdProps}> <ProLayout {...cdProps}>
<SettingDrawer
navTheme={theme}
layout={layout}
primaryColor={primaryColor}
onThemeChange={handleThemeChange}
onColorChange={handleColorChange}
/>
<router-view /> <router-view />
</ProLayout> </ProLayout>
) )
......
...@@ -42,5 +42,12 @@ export default { ...@@ -42,5 +42,12 @@ export default {
} }
} }
} }
} },
'app.setting.pagestyle': 'Page style setting',
'app.setting.pagestyle.light': 'Light style',
'app.setting.pagestyle.dark': 'Dark style',
'app.setting.pagestyle.realdark': 'RealDark style',
'app.setting.themecolor': 'Theme Color',
'app.setting.navigationmode': 'Navigation Mode'
} }
...@@ -12,11 +12,14 @@ import './core/library' ...@@ -12,11 +12,14 @@ import './core/library'
import { PageHeaderWrapper } from '@ant-design-vue/pro-layout' import { PageHeaderWrapper } from '@ant-design-vue/pro-layout'
import initializer from './core/bootstrap' import initializer from './core/bootstrap'
import './global.less' import './global.less'
import themePluginConfig from '@config/themePluginConfig'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.component('page-header-wrapper', PageHeaderWrapper) Vue.component('page-header-wrapper', PageHeaderWrapper)
window.umi_plugin_ant_themeVar = themePluginConfig.theme
window._vue = new Vue({ window._vue = new Vue({
router, router,
store, store,
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
], ],
"peerDependencies": { "peerDependencies": {
"vue": ">=2.5.0", "vue": ">=2.5.0",
"ant-design-vue": "^1.5.3", "ant-design-vue": "^1.5.4",
"umi-request": "^1.2.11", "umi-request": "^1.2.11",
"vue-container-query": "^0.1.0", "vue-container-query": "^0.1.0",
"vue-template-compiler": ">=2.5.0" "vue-template-compiler": ">=2.5.0"
......
import { Tooltip, Icon } from 'ant-design-vue'
const BlockCheckboxProps = {
value: {
type: String,
default: null
},
list: {
type: Array,
default: () => []
}
}
const baseClassName = 'ant-pro-setting-drawer-block-checbox'
const BlockCheckbox = {
props: BlockCheckboxProps,
render (h) {
const { value, list } = this
const handleChange = (key) => {
this.$emit('change', key)
}
return (
<div class={baseClassName} key={value}>
{list.map(item => (
<Tooltip title={item.title} key={item.key}>
<div class={`${baseClassName}-item`} onClick={() => handleChange(item.key)}>
<img src={item.url} alt={item.key} />
<div
class={`${baseClassName}-selectIcon`}
style={{
display: value === item.key ? 'block' : 'none'
}}
>
<Icon type="check" />
</div>
</div>
</Tooltip>
))}
</div>
)
}
}
export default BlockCheckbox
import './ThemeColor.less'
import PropTypes from 'ant-design-vue/es/_util/vue-types'
import { Tooltip, Icon } from 'ant-design-vue'
import { defaultI18nRender } from './index'
import { genThemeToString } from '../../utils/util'
const baseClassName = 'theme-color'
export const TagProps = {
color: PropTypes.string,
check: PropTypes.bool,
handleClick: PropTypes.func,
}
const Tag = {
props: TagProps,
render (h) {
const { color, check, handleClick } = this
return (
<div onClick={handleClick} style={{ backgroundColor: color }} ref="colorRef">
{ check ? <Icon type="check" /> : null }
</div>
)
}
}
export const ThemeColorProps = {
colors: PropTypes.array,
title: PropTypes.string,
value: PropTypes.string,
i18nRender: PropTypes.func
}
const ThemeColor = {
props: ThemeColorProps,
render (h) {
const { title, value, colors } = this
const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
const colorList = colors || []
if (colorList.length < 1) {
return null
}
const handleChange = (key) => {
this.$emit('change', key)
}
return (
<div class={baseClassName} ref={'ref'}>
<h3 class={`${baseClassName}-title`}>{title}</h3>
<div class={`${baseClassName}-content`}>
{colorList.map(item => {
const themeKey = genThemeToString(item.key)
return (
<Tooltip
key={item.color}
title={
themeKey ? i18n(`app.setting.themecolor.${themeKey}`) : item.key
}
>
<Tag
class={`${baseClassName}-block`}
color={item.color}
check={value === item.key || genThemeToString(value) === item.key}
handleClick={() => handleChange(item.key)}
/>
</Tooltip>
)
})}
</div>
</div>
)
}
}
export default ThemeColor
@import './index.less';
.@{ant-pro-setting-drawer}-content {
.theme-color {
margin-top: 24px;
overflow: hidden;
.theme-color-title {
margin-bottom: 12px;
font-size: 14px;
line-height: 22px;
}
.theme-color-block {
float: left;
width: 20px;
height: 20px;
margin-right: 8px;
color: #fff;
font-weight: bold;
text-align: center;
border-radius: 2px;
cursor: pointer;
}
}
}
import './index.less'
import PropTypes from 'ant-design-vue/es/_util/vue-types'
import { Divider, Drawer, Icon } from 'ant-design-vue'
import BlockCheckbox from './BlockCheckbox'
import ThemeColor from './ThemeColor'
import { updateTheme } from '../../utils/dynamicTheme'
const baseClassName = 'ant-pro-setting-drawer'
const BodyProps = {
title: {
type: String,
default: ''
}
}
const Body = {
props: BodyProps,
render (h) {
const { title } = this
return (
<div style={{ marginBottom: 24 }}>
<h3 class={`${baseClassName}-title`}>{title}</h3>
{this.$slots.default}
</div>
)
}
}
export const defaultI18nRender = (t) => t
const getThemeList = (i18nRender) => {
const list = window.umi_plugin_ant_themeVar || []
const themeList = [
{
key: 'light',
url: 'https://gw.alipayobjects.com/zos/antfincdn/NQ%24zoisaD2/jpRkZQMyYRryryPNtyIC.svg',
title: i18nRender('app.setting.pagestyle.light')
},
{
key: 'dark',
url: 'https://gw.alipayobjects.com/zos/antfincdn/XwFOFbLkSM/LCkqqYNmvBEbokSDscrm.svg',
title: i18nRender('app.setting.pagestyle.dark')
}
]
const darkColorList = [
{
key: 'daybreak',
color: '#1890ff',
theme: 'dark',
}
]
const lightColorList = [
{
key: 'daybreak',
color: '#1890ff',
theme: 'dark',
}
]
if (list.find((item) => item.theme === 'dark')) {
themeList.push({
key: 'realDark',
url: 'https://gw.alipayobjects.com/zos/antfincdn/hmKaLQvmY2/LCkqqYNmvBEbokSDscrm.svg',
title: i18nRender('app.setting.pagestyle.realdark'),
})
}
// insert theme color List
list.forEach(item => {
const color = (item.modifyVars || {})['@primary-color']
if (item.theme === 'dark' && color) {
darkColorList.push({
color,
...item,
})
}
if (!item.theme || item.theme === 'light') {
lightColorList.push({
color,
...item,
})
}
})
return {
colorList: {
dark: darkColorList,
light: lightColorList,
},
themeList,
}
}
const changeSetting = (key, value, hideMessageLoading) => {
console.log('handleColorChange', key, value)
if (key === 'navTheme') {
// 更新主题
}
if (key === 'primaryColor') {
// 更新主色调
updateTheme(value)
}
if (key === 'layout') {
// 更新布局模式
// value === 'topmenu' ? 'Fixed' : 'Fluid'
}
}
export const SettingDrawerProps = {
navTheme: PropTypes.oneOf(['dark', 'light', 'realDark']),
primaryColor: PropTypes.string,
layout: PropTypes.oneOf(['sidemenu', 'topmenu']),
colorWeak: PropTypes.bool,
}
const SettingDrawer = {
name: 'SettingDrawer',
props: SettingDrawerProps,
inject: ['locale'],
data () {
return {
show: true,
}
},
render (h) {
const {
setShow,
getContainer,
navTheme = 'dark',
primaryColor = 'daybreak',
layout = 'sidemenu',
colorWeak
} = this
const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
const themeList = getThemeList(i18n)
const iconStyle = {
color: '#fff',
fontSize: 20
}
const handleThemeChange = (key) => {
this.$emit('themeChange', key)
}
return (
<Drawer
visible={this.show}
width={300}
onClose={() => setShow(false)}
placement="right"
getContainer={getContainer}
/*handle={
<div class="ant-pro-setting-drawer-handle" onClick={() => setShow(!this.show)}>
{this.show
? (<Icon type="close" style={iconStyle} />)
: (<Icon type="setting" style={iconStyle} />)
}
</div>
}*/
style={{
zIndex: 999
}}
>
<template slot="handle">
<div class={`${baseClassName}-handle`} onClick={() => setShow(!this.show)}>
{this.show
? (<Icon type="close" style={iconStyle}/>)
: (<Icon type="setting" style={iconStyle}/>)
}
</div>
</template>
<div class={`${baseClassName}-content`}>
<Body title={i18n('app.setting.pagestyle')}>
<BlockCheckbox list={themeList.themeList} value={navTheme} onChange={handleThemeChange} />
</Body>
<ThemeColor
title={i18n('app.setting.themecolor')}
value={primaryColor}
colors={themeList.colorList[navTheme === 'realDark' ? 'dark' : 'light']}
onChange={(color) => {
this.$emit('colorChange', color)
changeSetting('primaryColor', color, null)
}}
/>
<Divider />
<Body title={i18n('app.setting.navigationmode')}>
<BlockCheckbox value={layout} onChange={(value) => {
this.$emit('layoutChange', value)
changeSetting('layout', value, null)
}} />
</Body>
</div>
</Drawer>
)
},
methods: {
setShow (flag) {
this.show = flag
}
}
}
export default SettingDrawer
@import '~ant-design-vue/es/style/themes/default.less';
@ant-pro-setting-drawer: ~'@{ant-prefix}-pro-setting-drawer';
.@{ant-pro-setting-drawer} {
&-content {
position: relative;
min-height: 100%;
.ant-list-item {
span {
flex: 1;
}
}
}
&-block-checbox {
display: flex;
&-item {
position: relative;
margin-right: 16px;
// box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
border-radius: @border-radius-base;
cursor: pointer;
img {
width: 48px;
}
}
&-selectIcon {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
padding-top: 15px;
padding-left: 24px;
color: @primary-color;
font-weight: bold;
font-size: 14px;
.action {
color: @primary-color;
}
}
}
&-color_block {
display: inline-block;
width: 38px;
height: 22px;
margin: 4px;
margin-right: 12px;
vertical-align: middle;
border-radius: 4px;
cursor: pointer;
}
&-title {
margin-bottom: 12px;
color: @heading-color;
font-size: 14px;
line-height: 22px;
}
&-handle {
position: absolute;
top: 240px;
right: 300px;
z-index: 0;
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
font-size: 16px;
text-align: center;
background: @primary-color;
border-radius: 4px 0 0 4px;
cursor: pointer;
pointer-events: auto;
}
&-production-hint {
margin-top: 16px;
font-size: 12px;
}
}
...@@ -2,6 +2,7 @@ import BasicLayout, { BasicLayoutProps } from './BasicLayout' ...@@ -2,6 +2,7 @@ import BasicLayout, { BasicLayoutProps } from './BasicLayout'
import BlockLayout from './BlockLayout' import BlockLayout from './BlockLayout'
import PageHeaderWrapper from './components/PageHeaderWrapper' import PageHeaderWrapper from './components/PageHeaderWrapper'
import GlobalFooter from './components/GlobalFooter' import GlobalFooter from './components/GlobalFooter'
import SettingDrawer from './components/SettingDrawer'
import DocumentTitle from './components/DocumentTitle' import DocumentTitle from './components/DocumentTitle'
import { updateTheme } from './utils/dynamicTheme' import { updateTheme } from './utils/dynamicTheme'
...@@ -9,6 +10,7 @@ export { ...@@ -9,6 +10,7 @@ export {
GlobalFooter, GlobalFooter,
PageHeaderWrapper, PageHeaderWrapper,
BlockLayout, BlockLayout,
SettingDrawer,
DocumentTitle, DocumentTitle,
BasicLayoutProps, BasicLayoutProps,
......
import client from 'webpack-theme-color-replacer/client' import client from 'webpack-theme-color-replacer/client'
import generate from '@ant-design/colors/lib/generate' import generate from '@ant-design/colors/lib/generate'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
......
...@@ -6,19 +6,28 @@ const getComponentFromProp = (instance, prop) => { ...@@ -6,19 +6,28 @@ const getComponentFromProp = (instance, prop) => {
return slots[prop] || instance.props[prop] return slots[prop] || instance.props[prop]
} }
/*const getComponentFromProp = (instance, prop) => {
const slots = instance.$slots
return slots[prop] || instance.$props[prop]
}*/
const isFun = (func) => { const isFun = (func) => {
return typeof func === 'function' return typeof func === 'function'
} }
/** const themeConfig = {
* 触发 window.resize daybreak: 'daybreak',
*/ '#1890ff': 'daybreak',
'#F5222D': 'dust',
'#FA541C': 'volcano',
'#FAAD14': 'sunset',
'#13C2C2': 'cyan',
'#52C41A': 'green',
'#2F54EB': 'geekblue',
'#722ED1': 'purple',
}
export function genThemeToString (val) {
return val && themeConfig[val] ? themeConfig[val] : val
}
export { export {
triggerEvent, triggerEvent,
inBrowser, inBrowser,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment