Skip to content

Commit

Permalink
feat(color): remove built-in theme and get palette from tvision color (
Browse files Browse the repository at this point in the history
…#218)

* feat(color): remove built-in theme and get palette from tvision color

* feat: card with default nobordered
  • Loading branch information
uyarn authored Jan 10, 2023
1 parent 368b7ce commit cb945db
Show file tree
Hide file tree
Showing 31 changed files with 162 additions and 533 deletions.
6 changes: 3 additions & 3 deletions src/components/color/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div :style="style" class="color-container" />
</template>
<script lang="ts">
import { getBrandColor } from '@/config/color';
import { DEFAULT_COLOR_OPTIONS } from '@/config/color';
const panelColor =
'conic-gradient(from 90deg at 50% 50%, #FF0000 -19.41deg, #FF0000 18.76deg, #FF8A00 59.32deg, #FFE600 99.87deg, #14FF00 141.65deg, #00A3FF 177.72deg, #0500FF 220.23deg, #AD00FF 260.13deg, #FF00C7 300.69deg, #FF0000 340.59deg, #FF0000 378.76deg)';
Expand All @@ -17,9 +17,9 @@ export default {
},
computed: {
style() {
const { colorList } = this.$store.state.setting;
const { value } = this;
return {
background: this.value !== 'dynamic' ? getBrandColor(this.value, colorList)['--td-brand-color'] : panelColor,
background: DEFAULT_COLOR_OPTIONS.indexOf(value) > -1 ? value : panelColor,
};
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/product-card/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<t-card theme="poster2">
<t-card theme="poster2" :bordered="false">
<template #avatar>
<t-avatar size="56px">
<template #icon>
Expand Down
232 changes: 17 additions & 215 deletions src/config/color.ts
Original file line number Diff line number Diff line change
@@ -1,228 +1,30 @@
import { Color } from 'tvision-color';
/* eslint-disable indent */
export type ColorToken = Record<string, string>;
export type ColorSeries = Record<string, ColorToken>;
export type TColorToken = Record<string, string>;
export type TColorSeries = Record<string, TColorToken>;

export const defaultLightColor = [
'#0052d9',
'#0594fa',
'#00a870',
'#ebb105',
'#ed7b2f',
'#e34d59',
'#ed49b4',
'#834ec2',
];
export const defaultDarkColor = [
'#4582e6',
'#29a4fb',
'#03a56f',
'#ca8d03',
'#ed7b2f',
'#ea7b84',
'#f172c5',
'#ab87d5',
];

export const COLOR_TOKEN: ColorSeries = {
DEFAULT: {
'--td-brand-color': '#0052d9',
'--td-brand-color-1': '#f2f3ff',
'--td-brand-color-2': '#d9e1ff',
'--td-brand-color-3': '#b5c7ff',
'--td-brand-color-4': '#8eabff',
'--td-brand-color-5': '#618dff',
'--td-brand-color-6': '#366ef4',
'--td-brand-color-7': '#0052d9',
'--td-brand-color-8': '#003cab',
'--td-brand-color-9': '#002a7c',
'--td-brand-color-10': '#001a57',
},

CYAN: {
'--td-brand-color': '#0594FA',
'--td-brand-color-1': '#d7eefe',
'--td-brand-color-2': '#aeddfd',
'--td-brand-color-3': '#84cafd',
'--td-brand-color-4': '#58b8fc',
'--td-brand-color-5': '#29a4fb',
'--td-brand-color-6': '#0594FA',
'--td-brand-color-7': '#29a4fb',
'--td-brand-color-8': '#0594FA',
'--td-brand-color-9': '#0378df',
'--td-brand-color-10': '#01409b',
},
GREEN: {
'--td-brand-color': '#00A870',
'--td-brand-color-1': '#8dffd9',
'--td-brand-color-2': '#00f2a2',
'--td-brand-color-3': '#00dc92',
'--td-brand-color-4': '#00c583',
'--td-brand-color-5': '#00A870',
'--td-brand-color-6': '#009a5d',
'--td-brand-color-7': '#00c583',
'--td-brand-color-8': '#00A870',
'--td-brand-color-9': '#009a5d',
'--td-brand-color-10': '#004a14',
},
ORANGE: {
'--td-brand-color': '#ED7B2F',
'--td-brand-color-1': '#fce5d7',
'--td-brand-color-2': '#f8cdaf',
'--td-brand-color-3': '#f4b285',
'--td-brand-color-4': '#f19659',
'--td-brand-color-5': '#ED7B2F',
'--td-brand-color-6': '#e75510',
'--td-brand-color-7': '#f19659',
'--td-brand-color-8': '#ED7B2F',
'--td-brand-color-9': '#e75510',
'--td-brand-color-10': '#7f0a02',
},
RED: {
'--td-brand-color': '#E34D59',
'--td-brand-color-1': '#fbe5e7',
'--td-brand-color-2': '#f7ccd0',
'--td-brand-color-3': '#f3b2b8',
'--td-brand-color-4': '#ef989f',
'--td-brand-color-5': '#ea7b84',
'--td-brand-color-6': '#E34D59',
'--td-brand-color-7': '#ea7b84',
'--td-brand-color-8': '#E34D59',
'--td-brand-color-9': '#e42c3a',
'--td-brand-color-10': '#8d0309',
},
PINK: {
'--td-brand-color': '#ED49B4',
'--td-brand-color-1': '#fce5f4',
'--td-brand-color-2': '#facae9',
'--td-brand-color-3': '#f7aede',
'--td-brand-color-4': '#f491d2',
'--td-brand-color-5': '#f172c5',
'--td-brand-color-6': '#ED49B4',
'--td-brand-color-7': '#f172c5',
'--td-brand-color-8': '#ED49B4',
'--td-brand-color-9': '#e80f9d',
'--td-brand-color-10': '#8f025e',
},
PURPLE: {
'--td-brand-color': '#834EC2',
'--td-brand-color-1': '#eee6f7',
'--td-brand-color-2': '#ddceee',
'--td-brand-color-3': '#ccb6e6',
'--td-brand-color-4': '#bb9edc',
'--td-brand-color-5': '#ab87d5',
'--td-brand-color-6': '#9a6fce',
'--td-brand-color-7': '#9a6fce',
'--td-brand-color-8': '#834EC2',
'--td-brand-color-9': '#783ac3',
'--td-brand-color-10': '#4c1397',
},
YELLOW: {
'--td-brand-color': '#EBB105',
'--td-brand-color-1': '#fde9ab',
'--td-brand-color-2': '#fbd152',
'--td-brand-color-3': '#EBB105',
'--td-brand-color-4': '#dda204',
'--td-brand-color-5': '#ca8d03',
'--td-brand-color-6': '#b67803',
'--td-brand-color-7': '#fbd152',
'--td-brand-color-8': '#EBB105',
'--td-brand-color-9': '#dda204',
'--td-brand-color-10': '#603100',
},
};

export const LIGHT_CHART_COLORS: ColorToken = {
// TODO: 中性色暂时固定 待tvision-color生成带色彩倾向的中性色
export const LIGHT_CHART_COLORS = {
textColor: 'rgba(0, 0, 0, 0.9)',
placeholderColor: 'rgba(0, 0, 0, 0.35)',
borderColor: '#dcdcdc',
containerColor: '#fff',
};

export const DARK_CHART_COLORS: ColorToken = {
export const DARK_CHART_COLORS = {
textColor: 'rgba(255, 255, 255, 0.9)',
placeholderColor: 'rgba(255, 255, 255, 0.35)',
borderColor: '#5e5e5e',
containerColor: '#242424',
};

function toUnderline(name: string): string {
return name.replace(/([A-Z])/g, '_$1').toUpperCase();
}

export function getBrandColor(type: string, colorList: ColorSeries): ColorToken {
const name = /^#[A-F\d]{6}$/i.test(type) ? type : toUnderline(type);
return colorList[name || 'DEFAULT'];
}

export function getColorList(colorArray: Array<ColorToken>): Array<string> {
const pureColorList = [];
colorArray.map((colorToken) => Object.keys(colorToken).map((key) => pureColorList.push(colorToken[key])));

return pureColorList;
}
// inspired by https://stackoverflow.com/questions/36721830/convert-hsl-to-rgb-and-hex
export function hslToHex(h: number, s: number, l: number) {
l /= 100;
const a = (s * Math.min(l, 1 - l)) / 100;
const f = (n: number) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color)
.toString(16)
.padStart(2, '0');
};
return `#${f(0)}${f(8)}${f(4)}`;
}

export function generateColorMap(theme: string, colorPalette: Array<string>, mode: 'light' | 'dark') {
const isDarkMode = mode === 'dark';
let brandColorIdx = colorPalette.indexOf(theme);

if (isDarkMode) {
// eslint-disable-next-line no-use-before-define
colorPalette.reverse().map((color) => {
const [h, s, l] = Color.colorTransform(color, 'hex', 'hsl');
return Color.colorTransform([h, Number(s) - 4, l], 'hsl', 'hex');
});
brandColorIdx = 5;
colorPalette[0] = `${colorPalette[brandColorIdx]}20`;
}

const colorMap = {
'--td-brand-color': colorPalette[brandColorIdx], // 主题色
'--td-brand-color-1': colorPalette[0], // light
'--td-brand-color-2': colorPalette[1], // focus
'--td-brand-color-3': colorPalette[2], // disabled
'--td-brand-color-4': colorPalette[3],
'--td-brand-color-5': colorPalette[4],
'--td-brand-color-6': colorPalette[5],
'--td-brand-color-7': brandColorIdx > 0 ? colorPalette[brandColorIdx - 1] : theme, // hover
'--td-brand-color-8': colorPalette[brandColorIdx], // 主题色
'--td-brand-color-9': brandColorIdx > 8 ? theme : colorPalette[brandColorIdx + 1], // click
'--td-brand-color-10': colorPalette[9],
};
return colorMap;
}
export function insertThemeStylesheet(theme: string, colorMap: ColorToken, mode: 'light' | 'dark') {
const isDarkMode = mode === 'dark';
const root = !isDarkMode ? `:root[theme-color='${theme}']` : `:root[theme-color='${theme}'][theme-mode='dark']`;

const styleSheet = document.createElement('style');
styleSheet.type = 'text/css';
styleSheet.innerText = `${root}{
--td-brand-color: ${colorMap['--td-brand-color']};
--td-brand-color-1: ${colorMap['--td-brand-color-1']};
--td-brand-color-2: ${colorMap['--td-brand-color-2']};
--td-brand-color-3: ${colorMap['--td-brand-color-3']};
--td-brand-color-4: ${colorMap['--td-brand-color-4']};
--td-brand-color-5: ${colorMap['--td-brand-color-5']};
--td-brand-color-6: ${colorMap['--td-brand-color-6']};
--td-brand-color-7: ${colorMap['--td-brand-color-7']};
--td-brand-color-8: ${colorMap['--td-brand-color-8']};
--td-brand-color-9: ${colorMap['--td-brand-color-9']};
--td-brand-color-10: ${colorMap['--td-brand-color-10']};
}`;

document.head.appendChild(styleSheet);
}
export type TChartColor = typeof LIGHT_CHART_COLORS;

export const DEFAULT_COLOR_OPTIONS = [
'#0052D9',
'#0594FA',
'#00A870',
'#EBB105',
'#ED7B2F',
'#E34D59',
'#ED49B4',
'#834EC2',
];
3 changes: 1 addition & 2 deletions src/config/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ export default {
isHeaderFixed: true,
isUseTabsRouter: false,
showHeader: true,
backgroundTheme: 'blueGrey',
brandTheme: 'default',
brandTheme: '#0052D9',
};
36 changes: 18 additions & 18 deletions src/layouts/setting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@
</t-radio-group>
<div class="setting-group-title">主题色</div>
<t-radio-group v-model="formData.brandTheme">
<div
v-for="(item, index) in COLOR_OPTIONS.slice(0, COLOR_OPTIONS.length - 1)"
:key="index"
class="setting-layout-drawer"
>
<div v-for="(item, index) in DEFAULT_COLOR_OPTIONS" :key="index" class="setting-layout-drawer">
<t-radio-button :key="index" :value="item" class="setting-layout-color-group">
<color-container :value="item" />
</t-radio-button>
Expand All @@ -50,11 +46,8 @@
format="HEX"
:swatch-colors="[]"
/></template>
<t-radio-button
:value="COLOR_OPTIONS[COLOR_OPTIONS.length - 1]"
class="setting-layout-color-group dynamic-color-btn"
>
<color-container :value="COLOR_OPTIONS[COLOR_OPTIONS.length - 1]" />
<t-radio-button :value="dynamicColor" :class="['setting-layout-color-group', 'dynamic-color-btn']">
<color-container :value="dynamicColor" />
</t-radio-button>
</t-popup>
</div>
Expand Down Expand Up @@ -113,7 +106,8 @@ import { Color } from 'tvision-color';
import { PopupVisibleChangeContext } from 'tdesign-vue';
import STYLE_CONFIG from '@/config/style';
import { insertThemeStylesheet, generateColorMap } from '@/config/color';
import { insertThemeStylesheet, generateColorMap } from '@/utils/color';
import { DEFAULT_COLOR_OPTIONS } from '@/config/color';
import Thumbnail from '@/components/thumbnail/index.vue';
import ColorContainer from '@/components/color/index.vue';
Expand All @@ -123,7 +117,7 @@ import SettingLightIcon from '@/assets/assets-setting-light.svg';
import SettingAutoIcon from '@/assets/assets-setting-auto.svg';
const LAYOUT_OPTION = ['side', 'top', 'mix'];
const COLOR_OPTIONS = ['default', 'cyan', 'green', 'yellow', 'orange', 'red', 'pink', 'purple', 'dynamic'];
const MODE_OPTIONS = [
{ type: 'light', text: '明亮' },
{ type: 'dark', text: '暗黑' },
Expand All @@ -140,7 +134,7 @@ export default {
},
MODE_OPTIONS,
LAYOUT_OPTION,
COLOR_OPTIONS,
DEFAULT_COLOR_OPTIONS,
visible: false,
formData: { ...STYLE_CONFIG },
isColoPickerDisplay: false,
Expand All @@ -162,10 +156,15 @@ export default {
showOthers() {
return (this.formData.showFooter && !this.formData.isSidebarFixed) || !this.formData.splitMenu;
},
dynamicColor() {
const isDynamic = DEFAULT_COLOR_OPTIONS.indexOf(this.formData.brandTheme) === -1;
return isDynamic ? this.formData.brandTheme : '';
},
},
watch: {
formData: {
handler(newVal) {
if (!newVal.brandTheme) return;
// 没有在formData中 需要从store中同步过来
const { isSidebarCompact } = this.$store.state.setting;
this.$store.dispatch('setting/changeTheme', { ...newVal, isSidebarCompact });
Expand Down Expand Up @@ -224,19 +223,20 @@ export default {
changeColor(hex: string) {
const { setting } = this.$store.state;
// hex 主题色
const newPalette = Color.getPaletteByGradation({
const { colors: newPalette, primary: brandColorIndex } = Color.getColorGradations({
colors: [hex],
step: 10,
remainInput: false, // 是否保留输入 不保留会矫正不合适的主题色
})[0];
const { mode } = this.$store.state.setting;
const colorMap = generateColorMap(hex, newPalette, mode);
const colorMap = generateColorMap(hex, newPalette, mode, brandColorIndex);
this.formData.brandTheme = hex;
this.$store.commit('setting/addColor', { [hex]: colorMap });
this.$store.dispatch('setting/changeTheme', { ...setting, brandTheme: hex });
insertThemeStylesheet(hex, colorMap, mode);
this.$store.dispatch('setting/changeTheme', { ...setting, brandTheme: hex });
},
},
};
Expand Down
4 changes: 2 additions & 2 deletions src/pages/dashboard/base/components/MiddleChart.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<t-row :gutter="[16, 16]">
<t-col :xs="12" :xl="9">
<t-card title="统计数据" subtitle="(万元)" class="dashboard-chart-card">
<t-card title="统计数据" subtitle="(万元)" class="dashboard-chart-card" :bordered="false">
<template #actions>
<div class="dashboard-chart-title-container">
<t-date-range-picker
Expand All @@ -21,7 +21,7 @@
</t-card>
</t-col>
<t-col :xs="12" :xl="3">
<t-card title="销售渠道" :subtitle="currentMonth" class="dashboard-chart-card">
<t-card title="销售渠道" :subtitle="currentMonth" class="dashboard-chart-card" :bordered="false">
<div
id="countContainer"
ref="countContainer"
Expand Down
Loading

0 comments on commit cb945db

Please sign in to comment.