refactor: theme color change (#543)

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/544/head
Ryan Wang 2022-04-08 14:55:59 +08:00 committed by GitHub
parent e8bd5e262b
commit cd5016d12f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 554 additions and 8214 deletions

View File

@ -20,7 +20,7 @@
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"@codemirror/basic-setup": "^0.19.1",
"@codemirror/basic-setup": "^0.19.3",
"@codemirror/lang-html": "^0.19.4",
"@codemirror/lang-java": "^0.19.1",
"@halo-dev/admin-api": "^1.0.0",
@ -30,10 +30,10 @@
"enquire.js": "^2.1.6",
"filepond": "^4.30.3",
"filepond-plugin-file-validate-type": "^1.2.6",
"filepond-plugin-image-preview": "^4.6.10",
"filepond-plugin-image-preview": "^4.6.11",
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"marked": "^4.0.12",
"marked": "^4.0.13",
"md5.js": "^1.3.5",
"nprogress": "^0.2.0",
"tiny-pinyin": "^1.3.2",
@ -50,23 +50,25 @@
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.17.8",
"@ant-design/colors": "3.2.2",
"@babel/core": "^7.17.9",
"@babel/eslint-parser": "^7.17.0",
"@vue/cli-plugin-babel": "~5.0.3",
"@vue/cli-plugin-eslint": "~5.0.3",
"@vue/cli-plugin-router": "~5.0.3",
"@vue/cli-plugin-vuex": "~5.0.3",
"@vue/cli-service": "~5.0.3",
"@vue/cli-plugin-babel": "~5.0.4",
"@vue/cli-plugin-eslint": "~5.0.4",
"@vue/cli-plugin-router": "~5.0.4",
"@vue/cli-plugin-vuex": "~5.0.4",
"@vue/cli-service": "~5.0.4",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"eslint-plugin-vue": "^8.6.0",
"husky": "^6.0.0",
"less": "^3.13.1",
"less-loader": "^5.0.0",
"lint-staged": "^11.2.6",
"prettier": "^2.6.0",
"prettier": "^2.6.2",
"tailwindcss": "^3.0.23",
"vue-template-compiler": "^2.6.14"
"vue-template-compiler": "^2.6.14",
"webpack-theme-color-replacer": "^1.3.26"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -136,9 +136,10 @@
<script>
import config from '@/config/defaultSettings'
import { colorList, updateTheme } from './setting'
import { colorList } from './setting'
import { mixin, mixinDevice } from '@/mixins/mixin'
import { mapActions, mapGetters } from 'vuex'
import { updateTheme } from '@/utils/dynamicTheme'
export default {
mixins: [mixin, mixinDevice],

View File

@ -1,8 +1,3 @@
import { message } from 'ant-design-vue/es'
// import defaultSettings from '../defaultSettings';
let lessNodesAppended
const colorList = [
{
key: '红色',
@ -38,63 +33,4 @@ const colorList = [
}
]
const updateTheme = primaryColor => {
// Don't compile less in production!
/* if (process.env.NODE_ENV === 'production') {
return;
} */
// Determine if the component is remounted
if (!primaryColor) {
return
}
const hideMessage = message.loading('正在编译主题!', 0)
function buildIt() {
if (!window.less) {
return
}
setTimeout(() => {
window.less
.modifyVars({
'@primary-color': primaryColor
})
.then(() => {
hideMessage()
})
.catch(() => {
message.error('Failed to update theme')
hideMessage()
})
}, 200)
}
if (!lessNodesAppended) {
// insert less.js and color.less
const lessStyleNode = document.createElement('link')
const lessConfigNode = document.createElement('script')
const lessScriptNode = document.createElement('script')
lessStyleNode.setAttribute('rel', 'stylesheet/less')
lessStyleNode.setAttribute('href', '/color.less')
lessConfigNode.innerHTML = `
window.less = {
async: true,
env: 'production',
javascriptEnabled: true
};
`
lessScriptNode.src = 'https://unpkg.com/less@3.8.1/dist/less.min.js'
lessScriptNode.async = true
lessScriptNode.onload = () => {
buildIt()
lessScriptNode.onload = null
}
document.body.appendChild(lessStyleNode)
document.body.appendChild(lessConfigNode)
document.body.appendChild(lessScriptNode)
lessNodesAppended = true
} else {
buildIt()
}
}
export { updateTheme, colorList }
export { colorList }

View File

@ -799,7 +799,8 @@ body {
}
// 附件图片样式
.attachments-group, .photos-group {
.attachments-group,
.photos-group {
&-item {
padding: 0;
height: 130px;
@ -823,6 +824,10 @@ body {
z-index: 1000 !important;
}
.ant-btn-link {
border-color: transparent !important;
}
.header-comment-popover {
.ant-popover-content {
.ant-popover-inner-content {

33
src/utils/dynamicTheme.js Normal file
View File

@ -0,0 +1,33 @@
// see https://github.com/vueComponent/pro-components/blob/v1.0.9/src/utils/dynamicTheme.js
// license: https://github.com/vueComponent/pro-components/blob/v1.0.9/LICENSE
import client from 'webpack-theme-color-replacer/client'
import generate from '@ant-design/colors/lib/generate'
import { message } from 'ant-design-vue'
export const themeColor = {
getAntdSerials(color) {
const lightens = new Array(9).fill().map((t, i) => {
return client.varyColor.lighten(color, i / 10)
})
const colorPalettes = generate(color)
const rgb = client.varyColor.toNum3(color.replace('#', '')).join(',')
return lightens.concat(colorPalettes).concat(rgb)
},
changeColor(newColor) {
const options = {
newColors: this.getAntdSerials(newColor),
changeUrl(cssUrl) {
return `/${cssUrl}`
}
}
return client.changer.changeColor(options, Promise)
}
}
export const updateTheme = newPrimaryColor => {
const hideMessage = message.loading('正在切换主题', 0)
themeColor.changeColor(newPrimaryColor).then(() => {
hideMessage()
})
}

View File

@ -0,0 +1,46 @@
// see https://github.com/vueComponent/pro-components/blob/v1.0.9/examples/config/dynamicTheme.js
// license: https://github.com/vueComponent/pro-components/blob/v1.0.9/LICENSE
const ThemeColorReplacer = require('webpack-theme-color-replacer')
const generate = require('@ant-design/colors/lib/generate').default
const getAntdSerials = color => {
const lightens = new Array(9).fill().map((t, i) => {
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
})
const colorPalettes = generate(color)
const rgb = ThemeColorReplacer.varyColor.toNum3(color.replace('#', '')).join(',')
return lightens.concat(colorPalettes).concat(rgb)
}
const themePluginOption = {
fileName: 'css/theme-colors-[contenthash:8].css',
matchColors: getAntdSerials('#1890ff'),
changeSelector(selector) {
switch (selector) {
case '.ant-calendar-today .ant-calendar-date':
return ':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)' + selector
case '.ant-btn:focus,.ant-btn:hover':
return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger):not(.ant-btn-link),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger):not(.ant-btn-link)'
case '.ant-btn.active,.ant-btn:active':
return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger):not(.ant-btn-link),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger):not(.ant-btn-link)'
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
return ':not(.ant-steps-item-process)' + selector
case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover'
case '.ant-menu-horizontal > .ant-menu-item-selected > a':
case '.ant-menu-horizontal>.ant-menu-item-selected>a':
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a'
case '.ant-menu-horizontal > .ant-menu-item > a:hover':
case '.ant-menu-horizontal>.ant-menu-item>a:hover':
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover'
default:
return selector
}
}
}
const dynamicThemePlugin = () => new ThemeColorReplacer(themePluginOption)
module.exports = dynamicThemePlugin

View File

@ -1,6 +1,7 @@
const pkg = require('./package.json')
const { defineConfig } = require('@vue/cli-service')
const dynamicThemePlugin = require('./src/webpack/dynamicTheme.js')
module.exports = defineConfig({
publicPath: process.env.PUBLIC_PATH,
@ -12,6 +13,10 @@ module.exports = defineConfig({
})
},
configureWebpack: {
plugins: [dynamicThemePlugin()]
},
css: {
loaderOptions: {
less: {