@cataract6545/tmui
Version:
tm-vuetify是一个新势力由主题驱动的UI组件库,相比其它优势大,组件全,设计趋势紧跟未来。具有主题生成,主题实时切换,暗黑实时切换,lottie动画,图表等新颖功能,tmui TMUI
534 lines (488 loc) • 17.1 kB
text/typescript
/**
* 主题工具
* @author tmzdy tmui3.0
* @description 主题样式生成工具
* @copyright tmzdy|tmui|https://tmui.design
*/
import { colortool } from './colortool';
import { ssrRef } from '@dcloudio/uni-app'
import { cssStyleConfig, cssstyle, colorThemeType, cssDirection, linearDirection, linearDeep, linearDirectionType } from '../lib/interface';
//导入用户自定义的主题色值。
// import { theme } from '../../../theme/index';
let localTheme = {};
// #ifdef APP
try {
localTheme = JSON.parse(uni.getStorageSync("$tmTheme"))
} catch (e) {
//TODO handle the exception
}
// #endif
let theme = uni?.$tm?.config?.theme ? { ...uni.$tm.config.theme } : localTheme;
var colors: Array<colorThemeType> = [];
var colorObj: any = {
red: '#FE1C00',
pink: '#CA145D',
purple: '#A61BC3',
'deep-purple': '#6A0E81',
indigo: '#652DF4',
blue: '#0163FF',
'light-blue': '#0889FF',
cyan: '#11CDE8',
teal: '#00998a',
green: '#5DBD1F',
'light-green': '#83D54A',
lime: '#D4ED00',
yellow: '#FFC400',
amber: '#FFFB01',
orange: '#FEA600',
'deep-orange': '#FE5C00',
brown: '#795548',
'blue-grey': '#607D8B',
grey: '#9E9E9E',
black: '#000000',
white: '#FFFFFF',
primary: '#0163FF',
'grey-5': '#fafafa',
'grey-4': '#f5f5f5',
'grey-3': '#eeeeee',
'grey-2': '#e0e0e0',
'grey-1': '#bdbdbd',
'grey-darken-1': '#757575',
'grey-darken-2': '#616161',
'grey-darken-3': '#404044',
'grey-darken-4': '#202022',
'grey-darken-5': '#111112',
'grey-darken-6': '#0A0A0B',
...theme
};
for (const key in colorObj) {
if (Object.prototype.hasOwnProperty.call(colorObj, key)) {
const element: string = String(colorObj[key]);
if (isCssColor(element)) {
let rgba = colortool.cssToRgba(element);
colors.push({
name: key,
value: element,
hsva: colortool.rgbaToHsva(colortool.cssToRgba(element)),
rgba: colortool.cssToRgba(element),
hsla: colortool.rgbaToHsla(rgba),
csscolor: `rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`
});
}
}
}
function isCssColor(color: string) {
const reg1 = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
const reg2 = /^(rgb|RGB|rgba|RGBA)/;
return reg1.test(color) || reg2.test(color);
}
function getColor(colorName: string) {
let isHand: number = colors.findIndex(function (el, index) {
return el.name == colorName;
});
if (isHand == -1) {
colorName = "primary";
isHand = colors.findIndex(function (el, index) {
return el.name == colorName;
});
console.warn('主题中不存在相关名称的主题。');
}
return colors[isHand];
}
class themeColors {
colors: Array<colorThemeType> = [];
constructor(c: Array<colorThemeType> = colors) {
this.colors = c;
}
public hasColors(colorName: string = "") {
let isHand: Array<colorThemeType> = this.colors.filter(function (el, index) {
return el.name == colorName;
});
return isHand.length > 0;
}
public add(colorName: string = "", value: string = "") {
let isHand: Array<colorThemeType> = this.colors.filter(function (el, index) {
return el.name == colorName;
});
if (isHand.length > 0) {
// console.error('已存在相关颜色名称!!!');
return this.colors;
}
if (!value) {
console.error('颜色值必填!!!');
return this.colors;
}
let rgba = colortool.cssToRgba(value);
let color: colorThemeType = {
csscolor: "",
hsva: { h: 0, s: 0, v: 0, a: 0 },
hsla: { h: 0, s: 0, l: 0, a: 0 },
rgba: { r: 0, g: 0, b: 0, a: 0 },
name: colorName, value: value
};
color.csscolor = colortool.rgbaToCss(rgba);
color.hsva = colortool.rgbaToHsva(rgba);
color.rgba = rgba;
color.hsla = colortool.rgbaToHsla(rgba);
this.colors.push(color);
return this.colors;
}
public del(colorName: string) {
let isHand: number = this.colors.findIndex(function (el, index) {
return el.name == colorName;
});
if (isHand == -1) {
console.error('删除失败,主题中不存在相关名称的主题。');
return;
}
this.colors.splice(isHand, 1);
}
public getColor(colorName: string): colorThemeType {
let isHand: number = this.colors.findIndex(function (el, index) {
return el.name == colorName;
});
if (isHand == -1) {
colorName = "primary";
isHand = this.colors.findIndex(function (el, index) {
return el.name == colorName;
});
console.error('主题中不存在相关名称的主题。');
}
return this.colors[isHand];
}
/**
* 计算主题
* @author tmui3.0|tmzdy
* @param config 样式的细化
* @returns cssstyle 返回一个计算好的主题系。
*/
public getTheme(config: cssStyleConfig = { colorname: 'primary', dark: false }): cssstyle {
if (!config['colorname']) {
console.error('颜色名称必填');
config.colorname = 'primary';
}
let index = this.colors.findIndex(el => el.name == config.colorname);
if (index == -1) {
console.error('主题不存在,默认为primary');
config.colorname = 'primary';
}
//当前颜色对象。
let nowColor = { ...this.colors[index] };
config.borderWidth = isNaN(parseInt(String(config['borderWidth']))) ? 0 : config['borderWidth'] ?? 0;
config.borderStyle = config['borderStyle'] ? config['borderStyle'] : 'solid';
config.borderColor = config['borderColor'] || '';
config.borderDirection = config['borderDirection'] || cssDirection.all;
config.linearDirection = config['linearDirection'] || linearDirection.none;
config.linearDeep = config['linearDeep'] || linearDeep.light;
config.shadow = isNaN(parseInt(String(config['shadow']))) ? 6 : config['shadow'];
config.round = isNaN(parseInt(String(config['round']))) ? 4 : config['round'];
config.opaticy = isNaN(parseInt(String(config['opaticy']))) ? 1 : config['opaticy'];
config.outlined = typeof config['outlined'] == 'boolean' ? config['outlined'] : false;
config.text = typeof config['text'] == 'boolean' ? config['text'] : false;
config.blur = typeof config['blur'] == 'boolean' ? config['blur'] : false;
// 确定一个颜色值是明亮的还是深色的,
//以方便确定文本颜色是亮还是深来区别,否则颜色看不清.
function isDarkColorFun(r: number, g: number, b: number) {
const yiq = (r * 2126 + g * 7152 + b * 722) / 10000;
return yiq < 180;
}
/**是否是黑色 */
let isBlack = false;
/**是否是白色 */
let isWhite = false;
/**黑或者白 */
let isBlackAndWhite = false;
/**是否是灰色 */
let isGrey = false
/**该颜色在人眼中属于深,还是浅,以适配文本色 */
let isDarkColor = false;
isDarkColor = isDarkColorFun(nowColor.rgba.r, nowColor.rgba.g, nowColor.rgba.b)
//黑
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0 && nowColor.hsla.l == 0) {
isBlack = true;
}
//白
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0 && nowColor.hsla.l == 100) {
isWhite = true;
}
//灰
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0 && nowColor.hsla.l < 100) {
isGrey = true;
}
//黑或者白
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0) {
isBlackAndWhite = true;
}
let css: cssstyle = {};
css.color = nowColor.value;
css.config = { ...config };
css.isBlackAndWhite = isBlackAndWhite;
css.gradientColor = []
css.colorname = config.colorname;
let borderhsl = { ...nowColor.hsla };
let borderDir = "all";
css.borderCss = {};
//背景颜色。
let bghsl = { ...nowColor.hsla };
/**非黑非白,h,s不变,只要降10%的亮度即可。 */
if (config.dark && !isBlackAndWhite) {
bghsl.l = 40;
}
if (config.blur) {
bghsl.a = 0.85
}
css.backgroundColor = colortool.rgbaToCss(colortool.hslaToRgba({ ...bghsl }));
if (isBlackAndWhite && config.dark) {
css.backgroundColor = colortool.rgbaToCss(colortool.hslaToRgba({ ...bghsl, h: 240, s: 3, l: 8 }));
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...borderhsl, h: 240, s: 3, l: 12 }));
}
if (isWhite && !config.dark) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...borderhsl, l: 90 }));
}
if (isBlack && !config.dark) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...borderhsl, l: 12 }));
}
css.backgroundColorCss = { 'background-color': css.backgroundColor }
//文字颜色。
let txcolor = { ...nowColor.hsla };
//当亮度小于(含)50需要降低文本颜色的亮度,即加深。,否则加亮,即变浅色。
if (config.dark) {
txcolor.l = 95;
} else {
if (isDarkColor) {
txcolor.l = 95;
} else {
if (isGrey) {
txcolor.l = 10;
} else {
txcolor.l = 20;
}
}
}
//外边框轮廓时
//outlined
if (config.outlined) {
txcolor.l = nowColor.hsla.l;
if (config.dark) {
txcolor.l = 55;
} else {
if (nowColor.hsla.h != 0 && nowColor.hsla.s != 0 && !isDarkColorFun(nowColor.rgba.r, nowColor.rgba.g, nowColor.rgba.b)) {
txcolor.l = 20;
}
}
if ((isBlack || isWhite) && config.dark) {
txcolor.l = 100
}
config.borderWidth = config['borderWidth'] || 2;
let n_hsl = { h: nowColor.hsla.h, s: nowColor.hsla.s, l: 0, a: 0 };
let o_bgcss = colortool.rgbaToCss(colortool.hslaToRgba(n_hsl));
css.backgroundColor = o_bgcss;
css.backgroundColorCss = { 'background-color': o_bgcss }
css.textColor = colortool.rgbaToCss(colortool.hslaToRgba(txcolor));
}
//text
if (config.text) {
txcolor.l = nowColor.hsla.l;
if (isGrey) {
txcolor.l = 15;
} else {
// txcolor.l = 55;
if (nowColor.hsla.h != 0 && nowColor.hsla.s != 0 && !isDarkColorFun(nowColor.rgba.r, nowColor.rgba.g, nowColor.rgba.b)) {
txcolor.l = 20;
}
}
if (config.dark) {
txcolor.l = 60;
if (!isBlackAndWhite) {
txcolor.s = 100;
}
}
if (isBlack) {
txcolor.l = 90
}
if (isWhite) {
txcolor.l = 15
}
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0 && config.dark) {
txcolor.l = 90;
}
css.textColor = colortool.rgbaToCss(colortool.hslaToRgba(txcolor));
css.border = css.textColor;
let o_now_bgColor = nowColor.csscolor;
let n_hsl = { h: nowColor.hsla.h, s: nowColor.hsla.s, l: 96, a: nowColor.hsla.a };
if (config.dark) {
if (nowColor.hsla.h != 0 && nowColor.hsla.s != 0) {
n_hsl.l = 12;
n_hsl.s = 35;
} else {
n_hsl.l = 12;
n_hsl.s = 0;
}
}
if (config.blur) {
n_hsl.a = 0.85
}
o_now_bgColor = colortool.rgbaToCss(colortool.hslaToRgba(n_hsl));
css.backgroundColor = o_now_bgColor;
css.backgroundColorCss = { 'background-color': o_now_bgColor }
}
//shadow
if (config.shadow) {
let n_hsl = { h: nowColor.hsla.h, s: 100, l: 50, a: 0.2 };
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0) {
//黑白要反转。
n_hsl = { h: 0, s: 0, l: 20, a: 0.07 };
}
let o_bgcss = colortool.rgbaToCss(colortool.hslaToRgba(n_hsl));
css.shadowColor = {
boxShadow: `0rpx ${config.shadow * 2.5}rpx ${config.shadow * 6}rpx ${o_bgcss}`
}
}
//处理渐变色
if (config.linearDirection) {
let liner_color_1 = { h: 0, s: 0, l: 0, a: nowColor.hsla.a };
let liner_color_2 = { h: 0, s: 0, l: 0, a: nowColor.hsla.a };
let dir_str = linearDirection[config.linearDirection];
// 增减控制参数。
let addling = 0;
if (nowColor.hsla.h < 180 && nowColor.hsla.h > 0) {
addling = 20
} else {
addling = -37
}
//先计算渐变的亮色系。
// 先算白或者黑
// 如果是白
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0 && nowColor.hsla.l == 100) {
//白。
if (config.linearDeep == 'light') {
liner_color_1.l = 80;
liner_color_2.l = 20;
} else {
liner_color_1.l = 50;
liner_color_2.l = 40;
}
} else if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0 && nowColor.hsla.l == 0) {
//黑。
if (config.linearDeep == 'light') {
liner_color_1.l = 40;
liner_color_2.l = 10;
} else {
liner_color_1.l = 30;
liner_color_2.l = 0;
}
} else {
liner_color_2.h = nowColor.hsla.h;
liner_color_2.s = nowColor.hsla.s;
liner_color_1.h = nowColor.hsla.h;
liner_color_1.s = nowColor.hsla.s;
if (config.linearDeep == 'light') {
liner_color_1.h = liner_color_1.h;//色相需要往前偏移加强色系
liner_color_1.s = 90;//饱和度需要加强
liner_color_1.l = 70;
liner_color_2.l = 44;
} else if (config.linearDeep == 'dark') {
liner_color_2.s = 90;
liner_color_2.l = 26;
liner_color_1.s = 90;
liner_color_1.l = 50;
} else if (config.linearDeep == 'accent') {
liner_color_1.h -= 0;//色相需要往前偏移加强色系
liner_color_1.s = 90;//饱和度需要加强
liner_color_1.l = 54;
liner_color_2.h -= addling;//偏移30度的色相搭配色进行渐变
liner_color_2.s = 90;//饱和度需要加强
liner_color_2.l = 54;
}
}
if (config.dark) {
liner_color_1.l = 40
liner_color_2.l = 40
txcolor.l = 90;
}
// 背景颜色取中间。
let color_t_1 = colortool.rgbaToCss(colortool.hslaToRgba(liner_color_1));
let color_t_2 = colortool.rgbaToCss(colortool.hslaToRgba(liner_color_2));
if (!config.text && !config.outlined) {
css.backgroundColorCss = { 'background-image': `linear-gradient(${dir_str},${color_t_1},${color_t_2})` }
let newBgcolor = {
h: (liner_color_1.h + liner_color_2.h) / 2,
s: (liner_color_1.s + liner_color_2.s) / 2,
l: (liner_color_1.l + liner_color_2.l) / 2,
a: (liner_color_1.a + liner_color_2.a) / 2
}
let newBgcolorRgb = colortool.hslaToRgba(newBgcolor)
if (!config.dark) {
if (!isDarkColorFun(newBgcolorRgb.r, newBgcolorRgb.g, newBgcolorRgb.b) && nowColor.hsla.h != 0 && nowColor.hsla.s != 0) {
txcolor.l = 20;
}
}
css.backgroundColor = colortool.rgbaToCss(colortool.hslaToRgba(newBgcolor));
css.gradientColor = [color_t_1, color_t_2]
css.linearDirectionStr = dir_str;
}
}
if (config.dark == true) {
// css.cardcolor = '#0A0A0B'; //项目
// css.inputcolor = '#111112';//输入框,表单等
// css.bodycolor = 'rgba(5,5,5, 1.0)';//背景
// css.disablecolor = 'rgba(30, 30, 30, 1.0)';//禁用的项目或者表单
// css.textDisableColor = 'rgba(100, 100, 100, 1.0)';//文本禁用色.
css = { ...css, ...uni.$tm.config?.themeConfig?.dark ?? {} }
}
css.textColor = colortool.rgbaToCss(colortool.hslaToRgba(txcolor));
if (config.dark) {
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...nowColor.hsla, l: 12 }));
} else {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...nowColor.hsla, l: bghsl.l + 10 }));
}
} else {
if (nowColor.hsla.h == 0 && nowColor.hsla.s == 0) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...nowColor.hsla, l: 90 }));
} else {
// text时,使用浅色线条,outlined时与颜色相同
if ((config.text && config.outlined)) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...nowColor.hsla, l: 90 }));
} else if (!config.text && config.outlined) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...txcolor }));
} else if (!config.text && !config.outlined && config.borderWidth > 0) {
css.border = colortool.rgbaToCss(colortool.hslaToRgba({ ...nowColor.hsla, l: bghsl.l - 3 }));
}
}
css.border = config.borderColor || css.border
}
//设置边线样式。
let bcss = `${config.borderWidth}rpx ${config.borderStyle} ${css.border}`;
if (config.borderDirection == 'all') {
css.borderCss[`border`] = bcss;
} else if (config.borderDirection == 'x' || config.borderDirection == "leftright") {
css.borderCss[`border-left`] = bcss;
css.borderCss[`border-right`] = bcss;
} else if (config.borderDirection == 'y' || config.borderDirection == "topbottom") {
css.borderCss[`border-top`] = bcss;
css.borderCss[`border-bottom`] = bcss;
} else if (config.borderDirection == 'bottomleft') {
css.borderCss[`border-left`] = bcss;
css.borderCss[`border-bottom`] = bcss;
} else if (config.borderDirection == 'bottomright') {
css.borderCss[`border-right`] = bcss;
css.borderCss[`border-bottom`] = bcss;
} else if (config.borderDirection == 'topleft') {
css.borderCss[`border-left`] = bcss;
css.borderCss[`border-top`] = bcss;
} else if (config.borderDirection == 'topright') {
css.borderCss[`border-right`] = bcss;
css.borderCss[`border-top`] = bcss;
} else {
let str = '-' + config.borderDirection;
css.borderCss[`border${str}`] = bcss;
}
return css;
}
}
export default {
isCssColor,
themeColors,
getColor
};