color selector
This commit is contained in:
parent
c6e1872253
commit
5e8d2506d3
104
index.html
104
index.html
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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: "",
|
||||||
|
|
|
||||||
|
|
@ -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)",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
Loading…
Reference in New Issue