color selector

This commit is contained in:
pqcqaq 2024-07-18 12:16:41 +08:00
parent c6e1872253
commit 5e8d2506d3
8 changed files with 480 additions and 373 deletions

View File

@ -6,110 +6,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title> <title>Vite + React + TS</title>
<script src="/tailwindcss.js"></script> <script src="/tailwindcss.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
1: "var(--primary-1)",
2: "var(--primary-2)",
3: "var(--primary-3)",
4: "var(--primary-4)",
5: "var(--primary-5)",
6: "var(--primary-6)",
7: "var(--primary-7)",
},
success: {
1: "var(--success-1)",
2: "var(--success-2)",
3: "var(--success-3)",
4: "var(--success-4)",
5: "var(--success-5)",
6: "var(--success-6)",
7: "var(--success-7)",
},
warning: {
1: "var(--warning-1)",
2: "var(--warning-2)",
3: "var(--warning-3)",
4: "var(--warning-4)",
5: "var(--warning-5)",
6: "var(--warning-6)",
7: "var(--warning-7)",
},
danger: {
1: "var(--danger-1)",
2: "var(--danger-2)",
3: "var(--danger-3)",
4: "var(--danger-4)",
5: "var(--danger-5)",
6: "var(--danger-6)",
7: "var(--danger-7)",
},
link: {
1: "var(--link-1)",
2: "var(--link-2)",
3: "var(--link-3)",
4: "var(--link-4)",
5: "var(--link-5)",
6: "var(--link-6)",
7: "var(--link-7)",
},
background: {
1: "var(--color-bg-1)",
2: "var(--color-bg-2)",
3: "var(--color-bg-3)",
4: "var(--color-bg-4)",
5: "var(--color-bg-5)",
white: "var(--color-bg-white)",
},
text: {
1: "var(--color-text-1)",
2: "var(--color-text-2)",
3: "var(--color-text-3)",
4: "var(--color-text-4)",
},
border: {
1: "var(--color-border-1)",
2: "var(--color-border-2)",
3: "var(--color-border-3)",
4: "var(--color-border-4)",
},
fill: {
1: "var(--color-fill-1)",
2: "var(--color-fill-2)",
3: "var(--color-fill-3)",
4: "var(--color-fill-4)",
},
data: {
1: "var(--data-1)",
2: "var(--data-2)",
3: "var(--data-3)",
4: "var(--data-4)",
5: "var(--data-5)",
6: "var(--data-6)",
7: "var(--data-7)",
8: "var(--data-8)",
9: "var(--data-9)",
10: "var(--data-10)",
11: "var(--data-11)",
12: "var(--data-12)",
13: "var(--data-13)",
14: "var(--data-14)",
15: "var(--data-15)",
16: "var(--data-16)",
17: "var(--data-17)",
18: "var(--data-18)",
19: "var(--data-19)",
20: "var(--data-20)",
},
shadow: "--color-shadow"
},
},
}
}
</script>
</head> </head>
<body> <body>

View File

@ -12,8 +12,10 @@
"dependencies": { "dependencies": {
"@uiw/codemirror-extensions-color": "^4.23.0", "@uiw/codemirror-extensions-color": "^4.23.0",
"@uiw/codemirror-extensions-langs": "^4.23.0", "@uiw/codemirror-extensions-langs": "^4.23.0",
"@uiw/codemirror-theme-vscode": "^4.23.0",
"@uiw/react-codemirror": "^4.23.0", "@uiw/react-codemirror": "^4.23.0",
"@uiw/react-json-view": "1.12.0", "@uiw/react-json-view": "1.12.0",
"color-selector-react": "0.3.0-beta.4",
"localforage": "^1.10.0", "localforage": "^1.10.0",
"match-sorter": "^6.3.4", "match-sorter": "^6.3.4",
"react": "^18.2.0", "react": "^18.2.0",

View File

@ -1,35 +1,7 @@
import { createContext, useContext, useEffect, useRef, useState } from "react"; import { createContext, useContext, useEffect, useRef, useState } from "react";
import { createTheme, reverseColor } from "../../utils/theme"; import { ThemeSection } from "../../../typings";
import { getColorAsync } from "../../data/colors";
type ThemeSection = "dark" | "light" | "system"; const themeMap = {
let themeLightId: string | null = null;
let themeDarkId: string | null = null;
getColorAsync().then((color) => {
themeLightId = createTheme(
"theme-color-light",
color
)
const rev = reverseColor(color)
themeDarkId = createTheme(
"theme-color-dark",
rev
)
})
// 在退出的时候删除这两个主题
window.addEventListener("beforeunload", () => {
if (themeLightId) {
document.getElementById(themeLightId)?.remove();
}
if (themeDarkId) {
document.getElementById(themeDarkId)?.remove();
}
});
const themeMap: Record<ThemeSection, string> = {
dark: "theme-color-dark", dark: "theme-color-dark",
light: "theme-color-light", light: "theme-color-light",
system: "", system: "",

View File

@ -1,94 +1,92 @@
const themeColorLight = { import { ColorSchema } from "../../typings";
"primary-7": "rgb(14, 66, 210)",
"primary-6": "rgb(22, 93, 255)",
"primary-5": "rgb(64, 128, 255)",
"primary-4": "rgb(106, 161, 255)",
"primary-3": "rgb(148, 191, 255)",
"primary-2": "rgb(190, 218, 255)",
"primary-1": "rgb(232, 243, 255)",
"success-7": "rgb(0, 154, 41)",
"success-6": "rgb(0, 180, 42)",
"success-5": "rgb(35, 195, 67)",
"success-4": "rgb(76, 210, 99)",
"success-3": "rgb(123, 225, 136)",
"success-2": "rgb(175, 240, 181)",
"success-1": "rgb(232, 255, 234)",
"warning-7": "rgb(210, 95, 0)",
"warning-6": "rgb(255, 125, 0)",
"warning-5": "rgb(255, 154, 46)",
"warning-4": "rgb(255, 182, 93)",
"warning-3": "rgb(255, 207, 139)",
"warning-2": "rgb(255, 228, 186)",
"warning-1": "rgb(255, 247, 232)",
"danger-7": "rgb(203, 39, 45)",
"danger-6": "rgb(245, 63, 63)",
"danger-5": "rgb(247, 101, 96)",
"danger-4": "rgb(249, 137, 129)",
"danger-3": "rgb(251, 172, 163)",
"danger-2": "rgb(253, 205, 197)",
"danger-1": "rgb(255, 236, 232)",
"link-7": "rgb(14, 66, 210)",
"link-6": "rgb(22, 93, 255)",
"link-5": "rgb(64, 128, 255)",
"link-4": "rgb(106, 161, 255)",
"link-3": "rgb(148, 191, 255)",
"link-2": "rgb(190, 218, 255)",
"link-1": "rgb(232, 243, 255)",
"data-1": "rgb(64, 128, 255)",
"data-2": "rgb(190, 218, 255)",
"data-3": "rgb(85, 197, 253)",
"data-4": "rgb(156, 220, 252)",
"data-5": "rgb(255, 125, 0)",
"data-6": "rgb(255, 207, 139)",
"data-7": "rgb(76, 210, 99)",
"data-8": "rgb(175, 240, 181)",
"data-9": "rgb(168, 113, 227)",
"data-10": "rgb(221, 190, 246)",
"data-11": "rgb(247, 186, 30)",
"data-12": "rgb(250, 220, 109)",
"data-13": "rgb(159, 219, 29)",
"data-14": "rgb(201, 233, 104)",
"data-15": "rgb(249, 121, 183)",
"data-16": "rgb(251, 157, 199)",
"data-17": "rgb(20, 201, 201)",
"data-18": "rgb(137, 233, 224)",
"data-19": "rgb(232, 101, 223)",
"data-20": "rgb(247, 186, 239)",
"color-border-1": "rgb(242, 243, 245)",
"color-border-2": "rgb(229, 230, 235)",
"color-border-3": "rgb(201, 205, 212)",
"color-border-4": "rgb(134, 144, 156)",
"color-border-5": "rgb(78, 89, 105)",
"color-border-6": "rgb(29, 33, 41)",
"color-border-7": "rgb(14, 16, 20)",
"color-fill-1": "rgb(247, 248, 250)",
"color-fill-2": "rgb(242, 243, 245)",
"color-fill-3": "rgb(229, 230, 235)",
"color-fill-4": "rgb(201, 205, 212)",
"color-fill-5": "rgb(134, 144, 156)",
"color-fill-6": "rgb(78, 89, 105)",
"color-fill-7": "rgb(29, 33, 41)",
"color-text-1": "rgb(29, 33, 41)",
"color-text-2": "rgb(78, 89, 105)",
"color-text-3": "rgb(134, 144, 156)",
"color-text-4": "rgb(201, 205, 212)",
"color-text-5": "rgb(229, 230, 235)",
"color-text-6": "rgb(242, 243, 245)",
"color-text-7": "rgb(247, 248, 250)",
"color-bg-1": "rgb(255, 255, 255)",
"color-bg-2": "rgb(255, 255, 255)",
"color-bg-3": "rgb(255, 255, 255)",
"color-bg-4": "rgb(255, 255, 255)",
"color-bg-5": "rgb(255, 255, 255)",
"color-bg-6": "rgb(255, 255, 255)",
"color-bg-7": "rgb(255, 255, 255)",
"color-bg-white": "rgb(255, 255, 255)",
"color-bg-black": "rgb(0, 0, 0)",
"color-shadow": "rgba(255, 255, 255, 0.5)",
};
export const getColorAsync = async () => { export const themeColorSchema: ColorSchema = {
return await Promise.resolve({ onLight: {
...themeColorLight, "primary-7": "rgb(14, 66, 210)",
}); "primary-6": "rgb(22, 93, 255)",
"primary-5": "rgb(64, 128, 255)",
"primary-4": "rgb(106, 161, 255)",
"primary-3": "rgb(148, 191, 255)",
"primary-2": "rgb(190, 218, 255)",
"primary-1": "rgb(232, 243, 255)",
"success-7": "rgb(0, 154, 41)",
"success-6": "rgb(0, 180, 42)",
"success-5": "rgb(35, 195, 67)",
"success-4": "rgb(76, 210, 99)",
"success-3": "rgb(123, 225, 136)",
"success-2": "rgb(175, 240, 181)",
"success-1": "rgb(232, 255, 234)",
"warning-7": "rgb(210, 95, 0)",
"warning-6": "rgb(255, 125, 0)",
"warning-5": "rgb(255, 154, 46)",
"warning-4": "rgb(255, 182, 93)",
"warning-3": "rgb(255, 207, 139)",
"warning-2": "rgb(255, 228, 186)",
"warning-1": "rgb(255, 247, 232)",
"danger-7": "rgb(203, 39, 45)",
"danger-6": "rgb(245, 63, 63)",
"danger-5": "rgb(247, 101, 96)",
"danger-4": "rgb(249, 137, 129)",
"danger-3": "rgb(251, 172, 163)",
"danger-2": "rgb(253, 205, 197)",
"danger-1": "rgb(255, 236, 232)",
"link-7": "rgb(14, 66, 210)",
"link-6": "rgb(22, 93, 255)",
"link-5": "rgb(64, 128, 255)",
"link-4": "rgb(106, 161, 255)",
"link-3": "rgb(148, 191, 255)",
"link-2": "rgb(190, 218, 255)",
"link-1": "rgb(232, 243, 255)",
"data-1": "rgb(64, 128, 255)",
"data-2": "rgb(190, 218, 255)",
"data-3": "rgb(85, 197, 253)",
"data-4": "rgb(156, 220, 252)",
"data-5": "rgb(255, 125, 0)",
"data-6": "rgb(255, 207, 139)",
"data-7": "rgb(76, 210, 99)",
"data-8": "rgb(175, 240, 181)",
"data-9": "rgb(168, 113, 227)",
"data-10": "rgb(221, 190, 246)",
"data-11": "rgb(247, 186, 30)",
"data-12": "rgb(250, 220, 109)",
"data-13": "rgb(159, 219, 29)",
"data-14": "rgb(201, 233, 104)",
"data-15": "rgb(249, 121, 183)",
"data-16": "rgb(251, 157, 199)",
"data-17": "rgb(20, 201, 201)",
"data-18": "rgb(137, 233, 224)",
"data-19": "rgb(232, 101, 223)",
"data-20": "rgb(247, 186, 239)",
"color-border-1": "rgb(242, 243, 245)",
"color-border-2": "rgb(229, 230, 235)",
"color-border-3": "rgb(201, 205, 212)",
"color-border-4": "rgb(134, 144, 156)",
"color-border-5": "rgb(78, 89, 105)",
"color-border-6": "rgb(29, 33, 41)",
"color-border-7": "rgb(14, 16, 20)",
"color-fill-1": "rgb(247, 248, 250)",
"color-fill-2": "rgb(242, 243, 245)",
"color-fill-3": "rgb(229, 230, 235)",
"color-fill-4": "rgb(201, 205, 212)",
"color-fill-5": "rgb(134, 144, 156)",
"color-fill-6": "rgb(78, 89, 105)",
"color-fill-7": "rgb(29, 33, 41)",
"color-text-1": "rgb(29, 33, 41)",
"color-text-2": "rgb(78, 89, 105)",
"color-text-3": "rgb(134, 144, 156)",
"color-text-4": "rgb(201, 205, 212)",
"color-text-5": "rgb(229, 230, 235)",
"color-text-6": "rgb(242, 243, 245)",
"color-text-7": "rgb(247, 248, 250)",
"color-bg-1": "rgb(255, 255, 255)",
"color-bg-2": "rgb(255, 255, 255)",
"color-bg-3": "rgb(255, 255, 255)",
"color-bg-4": "rgb(255, 255, 255)",
"color-bg-5": "rgb(255, 255, 255)",
"color-bg-6": "rgb(255, 255, 255)",
"color-bg-7": "rgb(255, 255, 255)",
"color-bg-white": "rgb(255, 255, 255)",
"color-bg-black": "rgb(0, 0, 0)",
"color-shadow": "rgba(255, 255, 255, 0.5)",
},
}; };

View File

@ -0,0 +1,150 @@
import React, { useEffect, useState, useRef } from "react";
import { ColorSelector, IColorSelectorProps } from "color-selector-react";
import "color-selector-react/dist/es/index.css";
import { ColorSchema, ThemeVariables } from "../../../../typings";
import {
createDarkTheme,
createLightTheme,
getColorAsync,
} from "../../../utils/theme";
interface ColorPaletteProps {}
interface VisibleColorPicker {
key: string;
palette: "light" | "dark";
position: { top: number; left: number };
}
const ColorPalette: React.FC<ColorPaletteProps> = () => {
const [colors, setColors] = useState<ColorSchema>({
onLight: {},
onDark: {},
});
useEffect(() => {
getColorAsync().then((res) => {
setColors(res);
});
}, []);
const [visibleColorPicker, setVisibleColorPicker] =
useState<VisibleColorPicker | null>(null);
const [currentColor, setCurrentColor] = useState<string>("");
const paletteRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
paletteRef.current &&
!paletteRef.current.contains(event.target as Node)
) {
setVisibleColorPicker(null);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [paletteRef]);
const handleColorClick = (
key: string,
palette: "light" | "dark",
event: React.MouseEvent
) => {
const { clientX, clientY } = event;
const rect = paletteRef.current?.getBoundingClientRect();
const adjustedX = clientX - (rect?.left ?? 0);
const adjustedY = clientY - (rect?.top ?? 0);
setCurrentColor(
palette === "light" ? colors.onLight[key] : colors.onDark![key]
);
setVisibleColorPicker({
key,
palette,
position: { top: adjustedY, left: adjustedX },
});
};
const setLightColors = (newColor: ThemeVariables) => {
setColors({ ...colors, onLight: newColor });
createLightTheme(newColor);
};
const setDarkColors = (newColor: ThemeVariables) => {
setColors({ ...colors, onDark: newColor });
createDarkTheme(newColor);
};
const handleColorChange: IColorSelectorProps["onChange"] = ({ color }) => {
if (visibleColorPicker) {
if (visibleColorPicker.palette === "light") {
setLightColors({ ...colors.onLight, [visibleColorPicker.key]: color });
} else {
setDarkColors({ ...colors.onDark, [visibleColorPicker.key]: color });
}
setCurrentColor(color);
}
};
return (
<div ref={paletteRef} className="p-4 border rounded shadow relative">
<div className="font-bold text-lg mb-4"></div>
<div className="grid grid-cols-2 gap-4">
<div>
<div className="font-semibold mb-2">Light Colors</div>
<div className="grid grid-cols-2 gap-2">
{Object.keys(colors.onLight).map((key) => (
<div key={key} className="flex items-center space-x-2">
<span>{`${key}:`}</span>
<div
onClick={(event) => handleColorClick(key, "light", event)}
className="w-5 h-5 cursor-pointer border"
style={{
backgroundColor: `${colors.onLight[key]}`,
}}
></div>
</div>
))}
</div>
</div>
<div>
<div className="font-semibold mb-2">Dark Colors</div>
<div className="grid grid-cols-2 gap-2">
{Object.keys(colors.onDark!).map((key) => (
<div key={key} className="flex items-center space-x-2">
<span>{`${key}:`}</span>
<div
onClick={(event) => handleColorClick(key, "dark", event)}
className="w-5 h-5 cursor-pointer border"
style={{
backgroundColor: `${colors.onDark![key]}`,
}}
></div>
</div>
))}
</div>
</div>
</div>
{visibleColorPicker && (
<ColorSelector
style={{
position: "absolute",
top: visibleColorPicker.position.top,
left: visibleColorPicker.position.left,
backgroundColor: `rgb( 255, 255, 255)`,
}}
color={currentColor}
visible={true}
onChange={handleColorChange}
onVisibleChange={(v: boolean) => !v && setVisibleColorPicker(null)}
/>
)}
</div>
);
};
export default ColorPalette;

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import CodeMirror, { basicSetup } from "@uiw/react-codemirror"; import CodeMirror, { basicSetup } from "@uiw/react-codemirror";
import { loadLanguage, langs } from "@uiw/codemirror-extensions-langs"; import { loadLanguage, langs } from "@uiw/codemirror-extensions-langs";
import LiveProvider from "../../components/Live/LiveProvider"; import LiveProvider from "../../components/Live/LiveProvider";
@ -9,6 +9,9 @@ import JsonViewEditor from "@uiw/react-json-view/editor";
import { ThemeProvider } from "../../components/Theme/ThemePrivider"; import { ThemeProvider } from "../../components/Theme/ThemePrivider";
import { plugin as colorCom } from "./completions"; import { plugin as colorCom } from "./completions";
import { functionBlockList } from "../../data/functionBlocks"; import { functionBlockList } from "../../data/functionBlocks";
import { vscodeDark } from "@uiw/codemirror-theme-vscode";
import { ColorSchema } from "../../../typings";
import ColorPalette from "./components/colorPalette";
loadLanguage("tsx"); loadLanguage("tsx");
const extensions = [color, langs.tsx(), colorView(false), colorTheme, colorCom]; const extensions = [color, langs.tsx(), colorView(false), colorTheme, colorCom];
@ -87,6 +90,7 @@ export const Creation = () => {
<CodeMirror <CodeMirror
value={code} value={code}
height="100%" height="100%"
theme={vscodeDark}
extensions={[ extensions={[
...extensions, ...extensions,
basicSetup({ basicSetup({
@ -104,59 +108,62 @@ export const Creation = () => {
</div> </div>
<LiveError className="text-danger-6 mt-2 p-2 rounded" /> <LiveError className="text-danger-6 mt-2 p-2 rounded" />
</LiveProvider> </LiveProvider>
<div className="mt-4 p-4 border rounded shadow w-2/4"> <div className="h-full grid lg:grid-cols-2 gap-4 border p-4 rounded shadow">
<h2 className="font-bold text-lg mb-2">Props </h2> <div className="p-4 border rounded shadow ">
<div className="props-edit"> <h2 className="font-bold text-lg mb-2">Props </h2>
<div className="mb-4"> <div className="props-edit">
<label className="block mb-2 font-bold"></label> <div className="mb-4">
<div className="flex"> <label className="block mb-2 font-bold"></label>
<input <div className="flex">
type="text" <input
value={newPropKey} type="text"
onChange={(e) => setNewPropKey(e.target.value)} value={newPropKey}
className="border border-text-1 rounded p-2 flex-grow" onChange={(e) => setNewPropKey(e.target.value)}
/> className="border border-text-1 rounded p-2 flex-grow"
<button onClick={handleAddProp} className="p-2 rounded ml-2"> />
<button onClick={handleAddProp} className="p-2 rounded ml-2">
</button>
</button>
</div>
</div> </div>
</div> <JsonViewEditor
<JsonViewEditor value={componentsProps}
value={componentsProps} keyName="props"
keyName="props" style={
style={ {
{ "--w-rjv-background-color": "#ffffff",
"--w-rjv-background-color": "#ffffff", "--w-rjv-border-left": "1px dashed #ebebeb",
"--w-rjv-border-left": "1px dashed #ebebeb", "--w-rjv-update-color": "#ff6ffd",
"--w-rjv-update-color": "#ff6ffd", } as any
} as any }
} onEdit={(opts) => {
onEdit={(opts) => { const updateNestedProp = (
const updateNestedProp = ( obj: Record<string, any>,
obj: Record<string, any>, path: string[],
path: string[], value: unknown
value: unknown ) => {
) => { if (path.length === 1) {
if (path.length === 1) { obj[path[0]] = value;
obj[path[0]] = value; } else {
} else { if (!obj[path[0]]) {
if (!obj[path[0]]) { obj[path[0]] = {};
obj[path[0]] = {}; }
updateNestedProp(obj[path[0]], path.slice(1), value);
} }
updateNestedProp(obj[path[0]], path.slice(1), value); };
} const updatedProps = { ...componentsProps };
}; updateNestedProp(
const updatedProps = { ...componentsProps }; updatedProps,
updateNestedProp( (opts as any).namespace,
updatedProps, opts.value
(opts as any).namespace, );
opts.value setComponentsProps(updatedProps);
); return true;
setComponentsProps(updatedProps); }}
return true; />
}} </div>
/>
</div> </div>
<ColorPalette />
</div> </div>
</div> </div>
</ThemeProvider> </ThemeProvider>

View File

@ -1,9 +1,12 @@
import { import {
ColorSchema,
RGBString, RGBString,
RGBValue, RGBValue,
ThemeSection,
ThemeVariables, ThemeVariables,
UpdateThemeColor, UpdateThemeColor,
} from "../../../typings"; } from "../../../typings";
import { themeColorSchema } from "../../data/colors";
export function updateThemeColor({ export function updateThemeColor({
themeClass, themeClass,
@ -217,108 +220,180 @@ export const setTailwindExtendProps = (colors: Record<string, string>) => {
if (!tailwind) { if (!tailwind) {
throw new Error("Tailwind CSS not found"); throw new Error("Tailwind CSS not found");
} }
console.log(tailwind);
tailwind.config = { tailwind.config = {
theme: { theme: {
extend: { extend: {
colors: { colors: {
primary: { // primary: {
1: "var(--primary-1)", // 1: "var(--primary-1)",
2: "var(--primary-2)", // 2: "var(--primary-2)",
3: "var(--primary-3)", // 3: "var(--primary-3)",
4: "var(--primary-4)", // 4: "var(--primary-4)",
5: "var(--primary-5)", // 5: "var(--primary-5)",
6: "var(--primary-6)", // 6: "var(--primary-6)",
7: "var(--primary-7)", // 7: "var(--primary-7)",
}, // },
success: { // success: {
1: "var(--success-1)", // 1: "var(--success-1)",
2: "var(--success-2)", // 2: "var(--success-2)",
3: "var(--success-3)", // 3: "var(--success-3)",
4: "var(--success-4)", // 4: "var(--success-4)",
5: "var(--success-5)", // 5: "var(--success-5)",
6: "var(--success-6)", // 6: "var(--success-6)",
7: "var(--success-7)", // 7: "var(--success-7)",
}, // },
warning: { // warning: {
1: "var(--warning-1)", // 1: "var(--warning-1)",
2: "var(--warning-2)", // 2: "var(--warning-2)",
3: "var(--warning-3)", // 3: "var(--warning-3)",
4: "var(--warning-4)", // 4: "var(--warning-4)",
5: "var(--warning-5)", // 5: "var(--warning-5)",
6: "var(--warning-6)", // 6: "var(--warning-6)",
7: "var(--warning-7)", // 7: "var(--warning-7)",
}, // },
danger: { // danger: {
1: "var(--danger-1)", // 1: "var(--danger-1)",
2: "var(--danger-2)", // 2: "var(--danger-2)",
3: "var(--danger-3)", // 3: "var(--danger-3)",
4: "var(--danger-4)", // 4: "var(--danger-4)",
5: "var(--danger-5)", // 5: "var(--danger-5)",
6: "var(--danger-6)", // 6: "var(--danger-6)",
7: "var(--danger-7)", // 7: "var(--danger-7)",
}, // },
link: { // link: {
1: "var(--link-1)", // 1: "var(--link-1)",
2: "var(--link-2)", // 2: "var(--link-2)",
3: "var(--link-3)", // 3: "var(--link-3)",
4: "var(--link-4)", // 4: "var(--link-4)",
5: "var(--link-5)", // 5: "var(--link-5)",
6: "var(--link-6)", // 6: "var(--link-6)",
7: "var(--link-7)", // 7: "var(--link-7)",
}, // },
background: { // background: {
1: "var(--color-bg-1)", // 1: "var(--color-bg-1)",
2: "var(--color-bg-2)", // 2: "var(--color-bg-2)",
3: "var(--color-bg-3)", // 3: "var(--color-bg-3)",
4: "var(--color-bg-4)", // 4: "var(--color-bg-4)",
5: "var(--color-bg-5)", // 5: "var(--color-bg-5)",
white: "var(--color-bg-white)", // white: "var(--color-bg-white)",
}, // },
text: { // text: {
1: "var(--color-text-1)", // 1: "var(--color-text-1)",
2: "var(--color-text-2)", // 2: "var(--color-text-2)",
3: "var(--color-text-3)", // 3: "var(--color-text-3)",
4: "var(--color-text-4)", // 4: "var(--color-text-4)",
}, // },
border: { // border: {
1: "var(--color-border-1)", // 1: "var(--color-border-1)",
2: "var(--color-border-2)", // 2: "var(--color-border-2)",
3: "var(--color-border-3)", // 3: "var(--color-border-3)",
4: "var(--color-border-4)", // 4: "var(--color-border-4)",
}, // },
fill: { // fill: {
1: "var(--color-fill-1)", // 1: "var(--color-fill-1)",
2: "var(--color-fill-2)", // 2: "var(--color-fill-2)",
3: "var(--color-fill-3)", // 3: "var(--color-fill-3)",
4: "var(--color-fill-4)", // 4: "var(--color-fill-4)",
}, // },
data: { // data: {
1: "var(--data-1)", // 1: "var(--data-1)",
2: "var(--data-2)", // 2: "var(--data-2)",
3: "var(--data-3)", // 3: "var(--data-3)",
4: "var(--data-4)", // 4: "var(--data-4)",
5: "var(--data-5)", // 5: "var(--data-5)",
6: "var(--data-6)", // 6: "var(--data-6)",
7: "var(--data-7)", // 7: "var(--data-7)",
8: "var(--data-8)", // 8: "var(--data-8)",
9: "var(--data-9)", // 9: "var(--data-9)",
10: "var(--data-10)", // 10: "var(--data-10)",
11: "var(--data-11)", // 11: "var(--data-11)",
12: "var(--data-12)", // 12: "var(--data-12)",
13: "var(--data-13)", // 13: "var(--data-13)",
14: "var(--data-14)", // 14: "var(--data-14)",
15: "var(--data-15)", // 15: "var(--data-15)",
16: "var(--data-16)", // 16: "var(--data-16)",
17: "var(--data-17)", // 17: "var(--data-17)",
18: "var(--data-18)", // 18: "var(--data-18)",
19: "var(--data-19)", // 19: "var(--data-19)",
20: "var(--data-20)", // 20: "var(--data-20)",
}, // },
shadow: "--color-shadow", // shadow: "--color-shadow",
// TODO: 这里使用传入的颜色
...colors,
}, },
}, },
}, },
}; };
}; };
const themeMap = {
dark: "theme-color-dark",
light: "theme-color-light",
system: "",
} as const;
export const createLightTheme = (themeVariables: ThemeVariables) => {
return createTheme(themeMap.light, themeVariables);
};
export const createDarkTheme = (themeVariables: ThemeVariables) => {
return createTheme(themeMap.dark, themeVariables);
};
export const getColorAsync = async () => {
if (!themeColorSchema.onDark) {
themeColorSchema.onDark = reverseColor(themeColorSchema.onLight);
}
return await Promise.resolve({
onLight: themeColorSchema.onLight,
onDark: themeColorSchema.onDark,
});
};
let themeLightId: string | null = null;
let themeDarkId: string | null = null;
getColorAsync().then((color) => {
themeLightId = createLightTheme(color.onLight);
themeDarkId = createDarkTheme(color.onDark!);
});
// 在退出的时候删除这两个主题,防止重复加载
window.addEventListener("unload", () => {
setTimeout(() => {
if (themeLightId) {
document.getElementById(themeLightId)?.remove();
}
if (themeDarkId) {
document.getElementById(themeDarkId)?.remove();
}
}, 0);
});
export const changeThemeSchema = (schema: ColorSchema) => {
// 通过id删除原有的主题然后重新生成
if (themeLightId) {
document.getElementById(themeLightId)?.remove();
}
if (themeDarkId) {
document.getElementById(themeDarkId)?.remove();
}
themeLightId = createTheme(themeMap.light, schema.onLight);
themeDarkId = createTheme(themeMap.dark, schema.onDark!);
};
export const overrideColor = (
theme: ThemeSection,
color: Record<string, string>
) => {
const themeElement = document.querySelector(`.${themeMap[theme]}`);
if (themeElement) {
for (const key in color) {
if (color.hasOwnProperty(key)) {
const value = color[key];
(themeElement as HTMLElement).style.setProperty(`--${key}`, value);
}
}
}
};

View File

@ -24,3 +24,10 @@ export type RGBValue = {
export type ThemeVariables = { export type ThemeVariables = {
[key: string]: string; [key: string]: string;
}; };
export type ColorSchema = {
onLight: Record<string, string>,
onDark?: Record<string, string>,
}
export type ThemeSection = "dark" | "light" | "system";