color update al

This commit is contained in:
pqcqaq 2024-07-19 12:24:01 +08:00
parent a0317d3ddf
commit 3bdc3e2dfe
4 changed files with 172 additions and 38 deletions

View File

@ -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");
});

View File

@ -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;
}

View File

@ -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!);
}; };
/** /**

View File

@ -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;
};