color update al
This commit is contained in:
parent
a0317d3ddf
commit
3bdc3e2dfe
|
|
@ -1,6 +1,7 @@
|
||||||
import { ColorSchema } from "../../../typings";
|
import { ColorSchema } from "../../../typings";
|
||||||
import { proxyWithHistory } from "valtio-history";
|
import { proxyWithHistory } from "valtio-history";
|
||||||
import { createDarkTheme, createLightTheme } from "../../utils/theme";
|
import { changeThemeSchema } from "../../utils/theme";
|
||||||
|
import { subscribe } from "valtio";
|
||||||
|
|
||||||
// // 模拟计算属性
|
// // 模拟计算属性
|
||||||
// watch((get) => {
|
// watch((get) => {
|
||||||
|
|
@ -8,23 +9,28 @@ import { createDarkTheme, createLightTheme } from "../../utils/theme";
|
||||||
// counterStore.double = counterStore.count * 2
|
// counterStore.double = counterStore.count * 2
|
||||||
// })
|
// })
|
||||||
|
|
||||||
const initString = `{"onLight": {}, "onDark": {}}`;
|
const initValue = {
|
||||||
|
onLight: {},
|
||||||
|
onDark: {},
|
||||||
|
};
|
||||||
|
|
||||||
export const useThemeStore = proxyWithHistory({
|
export const useThemeStore = proxyWithHistory({
|
||||||
// 取值的时候,本地存储有就从本地获取
|
// 取值的时候,本地存储有就从本地获取
|
||||||
colors: JSON.parse(
|
colors: JSON.parse(
|
||||||
localStorage.getItem("colors") || initString
|
localStorage.getItem("colors") || JSON.stringify(initValue)
|
||||||
) as ColorSchema,
|
) as ColorSchema,
|
||||||
init: () => {
|
init: () => {
|
||||||
createLightTheme(useThemeStore.value.colors.onLight);
|
changeThemeSchema(useThemeStore.value.colors);
|
||||||
createDarkTheme(useThemeStore.value.colors.onDark!);
|
|
||||||
},
|
},
|
||||||
updateColors: (value: ColorSchema) => {
|
updateColors: (value: ColorSchema) => {
|
||||||
// 更新的时候,订阅更新一下本地存储
|
|
||||||
localStorage.setItem("colors", JSON.stringify(value));
|
|
||||||
// 在更新的时候同步更新到style
|
|
||||||
createLightTheme(value.onLight);
|
|
||||||
createDarkTheme(value.onDark!);
|
|
||||||
useThemeStore.value.colors = value;
|
useThemeStore.value.colors = value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
subscribe(useThemeStore, () => {
|
||||||
|
// 更新的时候,订阅更新一下本地存储
|
||||||
|
localStorage.setItem("colors", JSON.stringify(useThemeStore.value.colors));
|
||||||
|
// 在更新的时候同步更新到style
|
||||||
|
changeThemeSchema(useThemeStore.value.colors);
|
||||||
|
console.log("useThemeStore updated");
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Change } from "../../../typings";
|
||||||
|
|
||||||
export const useDebounce = (fn: Function, delay: number) => {
|
export const useDebounce = (fn: Function, delay: number) => {
|
||||||
let timeout: any;
|
let timeout: any;
|
||||||
return (...args: any[]) => {
|
return (...args: any[]) => {
|
||||||
|
|
@ -5,3 +7,34 @@ export const useDebounce = (fn: Function, delay: number) => {
|
||||||
timeout = setTimeout(() => fn(...args), delay);
|
timeout = setTimeout(() => fn(...args), delay);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对象比较的结果
|
||||||
|
* @param obj1 原始对象
|
||||||
|
* @param obj2 目标对象
|
||||||
|
* @returns 返回修改的key
|
||||||
|
*/
|
||||||
|
export function compareObjects(
|
||||||
|
obj1: Record<string, any>,
|
||||||
|
obj2: Record<string, any>
|
||||||
|
): Change[] {
|
||||||
|
const changes: Change[] = [];
|
||||||
|
|
||||||
|
for (const key in obj1) {
|
||||||
|
if (obj1.hasOwnProperty(key)) {
|
||||||
|
if (!obj2.hasOwnProperty(key)) {
|
||||||
|
changes.push({ key, type: "remove" });
|
||||||
|
} else if (obj1[key] !== obj2[key]) {
|
||||||
|
changes.push({ key, type: "update" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in obj2) {
|
||||||
|
if (obj2.hasOwnProperty(key) && !obj1.hasOwnProperty(key)) {
|
||||||
|
changes.push({ key, type: "add" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@ import {
|
||||||
ReverseHandlerConfig,
|
ReverseHandlerConfig,
|
||||||
RGBString,
|
RGBString,
|
||||||
RGBValue,
|
RGBValue,
|
||||||
|
ThemeBlockCache,
|
||||||
|
ThemeMode,
|
||||||
ThemeSection,
|
ThemeSection,
|
||||||
ThemeVariables,
|
ThemeVariables,
|
||||||
UpdateThemeColor,
|
UpdateThemeColor,
|
||||||
} from "../../../typings";
|
} from "../../../typings";
|
||||||
import { themeColorSchema } from "../../data/colors";
|
import { themeColorSchema } from "../../data/colors";
|
||||||
import { useDebounce } from "../function";
|
import { compareObjects, useDebounce } from "../function";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新主题颜色
|
* 更新主题颜色
|
||||||
|
|
@ -30,6 +32,20 @@ export function updateThemeColor({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateCssText(
|
||||||
|
themeClass: string,
|
||||||
|
themeVariables: ThemeVariables
|
||||||
|
): string {
|
||||||
|
let cssRules = `.${themeClass} {`;
|
||||||
|
for (const variable in themeVariables) {
|
||||||
|
if (themeVariables.hasOwnProperty(variable)) {
|
||||||
|
cssRules += `--${variable}: ${themeVariables[variable]};`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cssRules += "}";
|
||||||
|
return cssRules;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建主题
|
* 创建主题
|
||||||
* @param themeClass 主题类名
|
* @param themeClass 主题类名
|
||||||
|
|
@ -48,14 +64,8 @@ export function createTheme(
|
||||||
//设置id属性,方便后面进行删除等操作
|
//设置id属性,方便后面进行删除等操作
|
||||||
styleSheet.id = id;
|
styleSheet.id = id;
|
||||||
|
|
||||||
// 构建 CSS 规则
|
// // 构建 CSS 规则
|
||||||
let cssRules = `.${themeClass} {`;
|
const cssRules = generateCssText(themeClass, themeVariables);
|
||||||
for (const variable in themeVariables) {
|
|
||||||
if (themeVariables.hasOwnProperty(variable)) {
|
|
||||||
cssRules += `--${variable}: ${themeVariables[variable]};`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cssRules += "}";
|
|
||||||
|
|
||||||
// 插入 CSS 规则到样式表中
|
// 插入 CSS 规则到样式表中
|
||||||
if ((styleSheet as any).styleSheet) {
|
if ((styleSheet as any).styleSheet) {
|
||||||
|
|
@ -68,6 +78,14 @@ export function createTheme(
|
||||||
// 将样式表添加到文档头部
|
// 将样式表添加到文档头部
|
||||||
document.head.appendChild(styleSheet);
|
document.head.appendChild(styleSheet);
|
||||||
|
|
||||||
|
if (themeClass === themeMap.light) {
|
||||||
|
themeLightCache.obj = themeVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (themeClass === themeMap.dark) {
|
||||||
|
themeDarkCache.obj = themeVariables;
|
||||||
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,10 +389,10 @@ const themeMap = {
|
||||||
*/
|
*/
|
||||||
export const createLightTheme = (themeVariables: ThemeVariables) => {
|
export const createLightTheme = (themeVariables: ThemeVariables) => {
|
||||||
return useDebounce(() => {
|
return useDebounce(() => {
|
||||||
if (themeLightId) {
|
if (themeLightCache.id) {
|
||||||
document.getElementById(themeLightId)?.remove();
|
document.getElementById(themeLightCache.id)?.remove();
|
||||||
}
|
}
|
||||||
themeLightId = createTheme(themeMap.light, themeVariables);
|
themeLightCache.id = createTheme(themeMap.light, themeVariables);
|
||||||
}, 50)();
|
}, 50)();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -385,10 +403,10 @@ export const createLightTheme = (themeVariables: ThemeVariables) => {
|
||||||
*/
|
*/
|
||||||
export const createDarkTheme = (themeVariables: ThemeVariables) => {
|
export const createDarkTheme = (themeVariables: ThemeVariables) => {
|
||||||
return useDebounce(() => {
|
return useDebounce(() => {
|
||||||
if (themeDarkId) {
|
if (themeDarkCache.id) {
|
||||||
document.getElementById(themeDarkId)?.remove();
|
document.getElementById(themeDarkCache.id)?.remove();
|
||||||
}
|
}
|
||||||
themeDarkId = createTheme(themeMap.dark, themeVariables);
|
themeDarkCache.id = createTheme(themeMap.dark, themeVariables);
|
||||||
}, 50)();
|
}, 50)();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -410,17 +428,23 @@ export const getColorAsync = async () => {
|
||||||
/**
|
/**
|
||||||
* 主题ID
|
* 主题ID
|
||||||
*/
|
*/
|
||||||
let themeLightId: string | null = null;
|
const themeLightCache: ThemeBlockCache = {
|
||||||
let themeDarkId: string | null = null;
|
id: "",
|
||||||
|
obj: {},
|
||||||
|
};
|
||||||
|
const themeDarkCache: ThemeBlockCache = {
|
||||||
|
id: "",
|
||||||
|
obj: {},
|
||||||
|
};
|
||||||
|
|
||||||
// 在退出的时候删除这两个主题,防止重复加载
|
// 在退出的时候删除这两个主题,防止重复加载
|
||||||
window.addEventListener("unload", () => {
|
window.addEventListener("unload", () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (themeLightId) {
|
if (themeLightCache.id) {
|
||||||
document.getElementById(themeLightId)?.remove();
|
document.getElementById(themeLightCache.id)?.remove();
|
||||||
}
|
}
|
||||||
if (themeDarkId) {
|
if (themeDarkCache.id) {
|
||||||
document.getElementById(themeDarkId)?.remove();
|
document.getElementById(themeDarkCache.id)?.remove();
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
@ -431,14 +455,71 @@ window.addEventListener("unload", () => {
|
||||||
*/
|
*/
|
||||||
export const changeThemeSchema = (schema: ColorSchema) => {
|
export const changeThemeSchema = (schema: ColorSchema) => {
|
||||||
// 通过id删除原有的主题,然后重新生成
|
// 通过id删除原有的主题,然后重新生成
|
||||||
if (themeLightId) {
|
if (themeLightCache.id) {
|
||||||
document.getElementById(themeLightId)?.remove();
|
// document.getElementById(themeLightId)?.remove();
|
||||||
|
updateThemeBlock("light", schema.onLight);
|
||||||
|
} else {
|
||||||
|
themeLightCache.id = createTheme(themeMap.light, schema.onLight);
|
||||||
}
|
}
|
||||||
if (themeDarkId) {
|
if (themeDarkCache.id) {
|
||||||
document.getElementById(themeDarkId)?.remove();
|
// document.getElementById(themeDarkId)?.remove();
|
||||||
|
updateThemeBlock("dark", schema.onDark!);
|
||||||
|
} else {
|
||||||
|
themeDarkCache.id = createTheme(themeMap.dark, schema.onDark!);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据对象更新关系检查来更新主题块
|
||||||
|
* @param mode 主题模式
|
||||||
|
* @param colors 主题颜色
|
||||||
|
* @returns 主题块
|
||||||
|
*/
|
||||||
|
export const updateThemeBlock = (mode: ThemeMode, colors: ThemeVariables) => {
|
||||||
|
// 通过id拿到block然后更新里面的内容
|
||||||
|
const id = mode == "light" ? themeLightCache.id : themeDarkCache.id;
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
throw new Error("Theme ID not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const block = document.getElementById(id);
|
||||||
|
if (block) {
|
||||||
|
const innerText = block.innerText;
|
||||||
|
let result;
|
||||||
|
if (mode == "light") {
|
||||||
|
result = compareObjects(themeLightCache.obj, colors);
|
||||||
|
} else {
|
||||||
|
result = compareObjects(themeDarkCache.obj, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(result && result.length)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newText = innerText;
|
||||||
|
|
||||||
|
result.forEach((item) => {
|
||||||
|
switch (item.type) {
|
||||||
|
case "update":
|
||||||
|
const regUpdate = new RegExp(`--${item.key}:.*?;`, "g");
|
||||||
|
newText = innerText.replace(
|
||||||
|
regUpdate,
|
||||||
|
`--${item.key}: ${colors[item.key]};`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "remove":
|
||||||
|
const regRemove = new RegExp(`--${item.key}:.*?;`, "g");
|
||||||
|
newText = innerText.replace(regRemove, "");
|
||||||
|
break;
|
||||||
|
case "add":
|
||||||
|
newText = `${innerText}\n--${item.key}: ${colors[item.key]};`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
block.innerText = newText;
|
||||||
}
|
}
|
||||||
themeLightId = createTheme(themeMap.light, schema.onLight);
|
|
||||||
themeDarkId = createTheme(themeMap.dark, schema.onDark!);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -43,4 +43,18 @@ export type ThemeSection = "dark" | "light" | "system";
|
||||||
|
|
||||||
export type ReverseHandlerType = "reverse" | "none" | "lighten" | "darken";
|
export type ReverseHandlerType = "reverse" | "none" | "lighten" | "darken";
|
||||||
|
|
||||||
export type ReverseHandlerConfig = Record<string, ReverseHandlerType>;
|
export type ReverseHandlerConfig = Record<string, ReverseHandlerType>;
|
||||||
|
|
||||||
|
export type ThemeMode = "dark" | "light";
|
||||||
|
|
||||||
|
export type ThemeBlockCache = {
|
||||||
|
id: string;
|
||||||
|
obj: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChangeType = "update" | "remove" | "add";
|
||||||
|
|
||||||
|
export type Change = {
|
||||||
|
key: string;
|
||||||
|
type: ChangeType;
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue