-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8a06136
commit 8f3f4fc
Showing
23 changed files
with
670 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import colorPalette from '../colorPalette'; | ||
|
||
describe('colorPalette test', () => { | ||
beforeAll(() => {}); | ||
|
||
it('colorPalette', done => { | ||
const res = colorPalette('#fff', 2); | ||
expect(res).toBe('#fff2f0'); | ||
done(); | ||
}); | ||
|
||
afterAll(() => {}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import tinycolor from 'tinycolor2'; | ||
|
||
const hueStep = 2; | ||
const saturationStep = 16; | ||
const saturationStep2 = 5; | ||
const brightnessStep1 = 5; | ||
const brightnessStep2 = 15; | ||
const lightColorCount = 5; | ||
const darkColorCount = 4; | ||
|
||
function getHue(hsv: any, i: number, isLight: boolean): number { | ||
let hue; | ||
if (hsv.h >= 60 && hsv.h <= 240) { | ||
hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i; | ||
} else { | ||
hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i; | ||
} | ||
if (hue < 0) { | ||
hue += 360; | ||
} else if (hue >= 360) { | ||
hue -= 360; | ||
} | ||
return Math.round(hue); | ||
} | ||
|
||
function getSaturation(hsv: any, i: number, isLight: boolean): number { | ||
let saturation: number; | ||
if (isLight) { | ||
saturation = Math.round(hsv.s * 100) - saturationStep * i; | ||
} else if (i === darkColorCount) { | ||
saturation = Math.round(hsv.s * 100) + saturationStep; | ||
} else { | ||
saturation = Math.round(hsv.s * 100) + saturationStep2 * i; | ||
} | ||
if (saturation > 100) { | ||
saturation = 100; | ||
} | ||
if (isLight && i === lightColorCount && saturation > 10) { | ||
saturation = 10; | ||
} | ||
if (saturation < 6) { | ||
saturation = 6; | ||
} | ||
return Math.round(saturation); | ||
} | ||
|
||
function getValue(hsv: any, i: number, isLight: boolean): number { | ||
if (isLight) { | ||
return Math.round(hsv.v * 100) + brightnessStep1 * i; | ||
} | ||
return Math.round(hsv.v * 100) - brightnessStep2 * i; | ||
} | ||
|
||
export default function colorPalette(color: string, index: number): string { | ||
const isLight = index <= 6; | ||
const hsv = tinycolor(color).toHsv(); | ||
const i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1; | ||
return tinycolor({ | ||
h: getHue(hsv, i, isLight), | ||
s: getSaturation(hsv, i, isLight), | ||
v: getValue(hsv, i, isLight) | ||
}).toHexString(false); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
import colorPalette from 'vue-iclient-core/utils/style/color/colorPalette'; | ||
import themeFactory from 'vue-iclient-core/utils/style/theme/theme.json'; | ||
import { getColorWithOpacity, getDarkenColor, getDataType } from 'vue-iclient-core/utils/util'; | ||
import cssVars from 'css-vars-ponyfill'; | ||
|
||
export interface styleConfigParams { | ||
styleConfig: { | ||
id?: string; | ||
className?: string; | ||
include?: string; | ||
}; | ||
} | ||
|
||
const lightTheme = themeFactory[1]; | ||
export type ThemeStyleParams = typeof lightTheme & styleConfigParams; | ||
|
||
export interface FunctionColorParams { | ||
successColor?: string | string[]; | ||
infoColor?: string | string[]; | ||
warningColor?: string | string[]; | ||
dangerColor?: string | string[]; | ||
} | ||
|
||
export interface ExtraColorParams { | ||
[prop: string]: string; | ||
} | ||
export interface ColorGroupExtraColorParams { | ||
colorGroup: string[]; | ||
[prop: string]: any; | ||
} | ||
|
||
export interface StyleReplacerParams { | ||
themeStyle: ThemeStyleParams; | ||
primarySerialColors?: string[]; | ||
functionSerialColors?: FunctionColorParams; | ||
extraSerialColors: ExtraColorParams; | ||
} | ||
|
||
const $blue6 = '#1890ff'; | ||
const $green6 = '#52c41a'; | ||
const $glod6 = '#faad14'; | ||
const $red6 = '#f5222d'; | ||
|
||
const antdPrimaryColor = $blue6; | ||
const antdFunctionColors: FunctionColorParams = { | ||
infoColor: $blue6, | ||
successColor: $green6, | ||
warningColor: $glod6, | ||
dangerColor: $red6 | ||
}; | ||
|
||
const isBrowser = typeof window !== 'undefined'; | ||
const isNativeSupport = isBrowser && window.CSS && window.CSS.supports && window.CSS.supports('(--a: 0)'); | ||
|
||
export function getPrimarySerialColors(nextThemeInfo?: ThemeStyleParams | ColorGroupExtraColorParams): string[] { | ||
const series = []; | ||
const nextThemeStyle = nextThemeInfo; | ||
let prevPrimaryColor: string; | ||
if (nextThemeStyle && nextThemeStyle.colorGroup && nextThemeStyle.colorGroup[0]) { | ||
prevPrimaryColor = nextThemeStyle.colorGroup[0]; | ||
} | ||
const acceptColor: string = prevPrimaryColor || antdPrimaryColor; | ||
for (let index = 1; index <= 10; index++) { | ||
let nextColor: string; | ||
switch (index) { | ||
case 2: | ||
nextColor = nextThemeStyle.selectedColor || getColorWithOpacity(acceptColor, 0.15); | ||
break; | ||
case 5: | ||
nextColor = nextThemeStyle.hoverColor || colorPalette(acceptColor, index); | ||
break; | ||
case 6: | ||
nextColor = acceptColor; | ||
break; | ||
case 7: | ||
nextColor = nextThemeStyle.clickColor || colorPalette(acceptColor, index); | ||
break; | ||
default: | ||
nextColor = colorPalette(acceptColor, index); | ||
break; | ||
} | ||
series.push(nextColor); | ||
} | ||
return series; | ||
} | ||
|
||
export function getFunctionSerialColors(functionColors?: ThemeStyleParams): FunctionColorParams { | ||
const seriesIndex = [1, 2, 3, 4, 5, 6, 7]; | ||
const acceptFunctionColors = functionColors || antdFunctionColors; | ||
const nextFunctionSerialColors: FunctionColorParams = {}; | ||
for (const key in acceptFunctionColors) { | ||
if (Object.prototype.hasOwnProperty.call(antdFunctionColors, key)) { | ||
const color = acceptFunctionColors[key] || antdFunctionColors[key]; | ||
nextFunctionSerialColors[key] = []; | ||
seriesIndex.forEach(item => { | ||
const nextColor = item === 6 ? color : colorPalette(color, item); | ||
nextFunctionSerialColors[key].push(nextColor); | ||
}); | ||
} | ||
} | ||
return nextFunctionSerialColors; | ||
} | ||
|
||
export function getExtralColors( | ||
themeStyleData: ThemeStyleParams, | ||
primarySerialColors: string[], | ||
functionColors: FunctionColorParams | ||
): ExtraColorParams { | ||
const tableHeaderSortActiveBg = getDarkenColor(themeStyleData.backgroundLight, 3); | ||
const extraSerialColors: ExtraColorParams = { | ||
textColorWithoutOpacity: getColorWithOpacity(themeStyleData.textColor, 1, false), | ||
backgroundWithoutOpacity: getColorWithOpacity(themeStyleData.background, 1, false), | ||
componentBackgroundWithoutOpacity: getColorWithOpacity(themeStyleData.componentBackground, 1, false), | ||
primaryShadowColor: getColorWithOpacity(primarySerialColors[4], 0.25), | ||
dangerShadowColor: getColorWithOpacity(functionColors.dangerColor[4], 0.25), | ||
disabledDarkenBgColor10: getDarkenColor(themeStyleData.containerDisabled, 10), | ||
tableHeaderSortActiveBg, | ||
tableHeaderFilterActiveBg: getDarkenColor(tableHeaderSortActiveBg, 5) | ||
}; | ||
return extraSerialColors; | ||
} | ||
|
||
export function dealWithTheme(nextThemeStyle: ThemeStyleParams): StyleReplacerParams { | ||
const defaultThemeStyle = nextThemeStyle.style || 'light'; | ||
const defaultTheme = themeFactory.find((item: ThemeStyleParams) => item.label === defaultThemeStyle); | ||
// 合并 lightTheme 是因为可能其他 theme 没有完整的参数,如 disableColor | ||
const serialColorsReplacer = getPrimarySerialColors( | ||
Object.assign({ colorGroup: defaultTheme && defaultTheme.colorGroup }, nextThemeStyle) | ||
); | ||
const themeStyleData = Object.assign({}, lightTheme, defaultTheme, nextThemeStyle); | ||
const functionSerialColorsReplacer = getFunctionSerialColors(themeStyleData); | ||
const nextThemeStyleData = Object.assign({}, themeStyleData, { | ||
selectedColor: serialColorsReplacer[1], | ||
hoverColor: serialColorsReplacer[4], | ||
clickColor: serialColorsReplacer[6] | ||
}); | ||
const nextThemeData = { | ||
themeStyle: nextThemeStyleData, | ||
primarySerialColors: serialColorsReplacer, | ||
functionSerialColors: functionSerialColorsReplacer, | ||
extraSerialColors: getExtralColors(themeStyleData, serialColorsReplacer, functionSerialColorsReplacer) | ||
}; | ||
setRootStyle(nextThemeData); | ||
return nextThemeData; | ||
} | ||
|
||
export function toStyleVariable(variable) { | ||
return `--${variable.replace(/[A-Z]/g, '-$&').toLowerCase()}`; | ||
} | ||
|
||
export function getRootStyleSelector(themeStyle: ThemeStyleParams) { | ||
return themeStyle.styleConfig?.className && isNativeSupport ? `.${themeStyle.styleConfig.className}` : ':root'; | ||
} | ||
|
||
function setRootStyle(themeData: StyleReplacerParams): void { | ||
const { themeStyle, primarySerialColors, functionSerialColors, extraSerialColors } = themeData; | ||
const primaryColor = themeStyle.colorGroup[0]; | ||
const variables = { | ||
'--antd-wave-shadow-color': primaryColor, | ||
'--primary-color': primaryColor | ||
}; | ||
const themeInfo = Object.assign({}, themeStyle, extraSerialColors); | ||
const themeKeys = Object.keys(themeInfo); | ||
primarySerialColors.forEach((color: string, index: number) => { | ||
const varKey = `--primary-${index + 1}`; | ||
variables[varKey] = color; | ||
}); | ||
for (const key in functionSerialColors) { | ||
functionSerialColors[key].forEach((color: string, index: number) => { | ||
const varKey = `--${key.replace('Color', '')}-${index + 1}`; | ||
variables[varKey] = color; | ||
}); | ||
} | ||
themeKeys.forEach((key: string) => { | ||
if (!['[object Object]', '[object Array]'].includes(getDataType(themeInfo[key]))) { | ||
const varKey = toStyleVariable(key); | ||
variables[varKey] = themeInfo[key] || 'rgba(0, 0, 0, 0)'; | ||
} | ||
}); | ||
const rootStyleSelector = getRootStyleSelector(themeStyle); | ||
const antdStyleId = themeStyle.styleConfig?.id || 'sm-component-style'; | ||
const rootStyle = `${rootStyleSelector} ${JSON.stringify(variables, null, 2) | ||
.replace(/(:.+),/g, '$1;') | ||
.replace(/"/g, '')}`; | ||
let antStyleTag = document.getElementById(antdStyleId); | ||
if (!antStyleTag) { | ||
antStyleTag = document.createElement('style'); | ||
antStyleTag.setAttribute('id', antdStyleId); | ||
antStyleTag.setAttribute('type', 'text/css'); | ||
document.head.insertBefore(antStyleTag, document.head.firstChild); | ||
} | ||
const defaultInclude = 'style#sm-component-style, link[href*=vue-iclient-mapboxgl]'; | ||
const options = { | ||
include: themeStyle.styleConfig?.include || defaultInclude, | ||
silent: true, | ||
onlyLegacy: true, | ||
variables: {}, | ||
watch: false | ||
}; | ||
if (!isNativeSupport) { | ||
options.onlyLegacy = false; | ||
options.watch = true; | ||
options.variables = variables; | ||
} | ||
cssVars(options); | ||
antStyleTag.innerHTML = rootStyle; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import globalEvent from 'vue-iclient-core/utils/global-event'; | ||
import themeFactory from 'vue-iclient-core/utils/style/theme/theme.json'; | ||
import { dealWithTheme, ThemeStyleParams } from 'vue-iclient-core/utils/style/color/serialColors'; | ||
import { objectWithoutProperties } from 'vue-iclient-core/utils/util'; | ||
|
||
interface triggerParams { | ||
triggerEvent: boolean; | ||
ignoreElements: string[]; | ||
} | ||
|
||
export const setTheme = (themeStyle: any = {}, triggerInfo?: triggerParams) => { | ||
let acceptedThemeStyle = themeStyle; | ||
if (typeof themeStyle === 'string') { | ||
acceptedThemeStyle = themeFactory.find((item: ThemeStyleParams) => item.label === themeStyle) || themeFactory[1]; | ||
} else if (acceptedThemeStyle.componentBackground) { | ||
if (!acceptedThemeStyle.collapseCardHeaderBg) { | ||
acceptedThemeStyle.collapseCardHeaderBg = acceptedThemeStyle.componentBackground; | ||
} | ||
if (!acceptedThemeStyle.collapseCardBackground) { | ||
acceptedThemeStyle.collapseCardBackground = acceptedThemeStyle.componentBackground; | ||
} | ||
} | ||
const nextThemeData = dealWithTheme(acceptedThemeStyle); | ||
const nextTheme = { | ||
...nextThemeData.themeStyle | ||
}; | ||
if (themeStyle && (typeof themeStyle === 'string' || 'componentBackground' in themeStyle)) { | ||
nextTheme.background = nextTheme.componentBackground; | ||
} | ||
globalEvent.theme = nextTheme; | ||
if (!triggerInfo || triggerInfo.triggerEvent === true) { | ||
globalEvent.changeTheme(objectWithoutProperties(nextTheme, (triggerInfo || {}).ignoreElements || [])); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.