store
This commit is contained in:
parent
51d65f9f45
commit
5c2012725b
|
|
@ -25,7 +25,9 @@
|
|||
"sort-by": "^1.2.0",
|
||||
"sucrase": "^3.31.0",
|
||||
"terser": "^5.31.3",
|
||||
"use-editable": "^2.3.3"
|
||||
"use-editable": "^2.3.3",
|
||||
"valtio": "^1.13.2",
|
||||
"valtio-history": "^0.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codemirror/autocomplete": "^6.17.0",
|
||||
|
|
|
|||
|
|
@ -1,105 +1,113 @@
|
|||
/* 下面是统一的颜色定义 */
|
||||
/* 默认的主题样式 */
|
||||
:root {
|
||||
background-color: var(--background-1);
|
||||
color: var(--text-1);
|
||||
font: 14px/1.5 "Helvetica Neue",Helvetica,Arial,"Microsoft Yahei","Hiragino Sans GB","Heiti SC","WenQuanYi Micro Hei",sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: var(--primary-6);
|
||||
color: var(--background-white);
|
||||
border: var(--border-1) solid var(--border-3);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3) var(--size-4);
|
||||
font-size: var(--font-size-body-3);
|
||||
box-shadow: var(--shadow1-center);
|
||||
}
|
||||
/* 默认的主题样式 */
|
||||
:root {
|
||||
background-color: var(--background-1);
|
||||
color: var(--text-1);
|
||||
font: 14px/1.5 "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei",
|
||||
"Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--primary-5);
|
||||
border-color: var(--border-4);
|
||||
}
|
||||
button {
|
||||
background-color: var(--primary-6);
|
||||
color: var(--background-white);
|
||||
border: var(--border-1) solid var(--border-3);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3) var(--size-4);
|
||||
font-size: var(--font-size-body-3);
|
||||
box-shadow: var(--shadow1-center);
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: var(--primary-7);
|
||||
border-color: var(--border-4);
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
background-color: var(--fill-1);
|
||||
color: var(--text-1);
|
||||
border: var(--border-1) solid var(--border-2);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
font-size: var(--font-size-body-3);
|
||||
box-shadow: var(--shadow1-center);
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--background-2);
|
||||
color: var(--text-1);
|
||||
border: var(--border-1) solid var(--border-1);
|
||||
border-radius: var(--border-radius-large);
|
||||
padding: var(--size-5);
|
||||
box-shadow: var(--shadow2-center);
|
||||
font-size: var(--font-size-body-3);
|
||||
}
|
||||
button:hover {
|
||||
background-color: var(--primary-5);
|
||||
border-color: var(--border-4);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-6);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--link-5);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: var(--text-1);
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--text-1);
|
||||
font-size: var(--font-size-body-3);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: var(--border-1) solid var(--border-2);
|
||||
padding: var(--size-3);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
thead {
|
||||
background-color: var(--background-2);
|
||||
}
|
||||
|
||||
.alert {
|
||||
background-color: var(--danger-1);
|
||||
color: var(--danger-6);
|
||||
border: var(--border-1) solid var(--danger-4);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: var(--success-1);
|
||||
color: var(--success-6);
|
||||
border: var(--border-1) solid var(--success-4);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: var(--warning-1);
|
||||
color: var(--warning-6);
|
||||
border: var(--border-1) solid var(--warning-4);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
}
|
||||
button:active {
|
||||
background-color: var(--primary-7);
|
||||
border-color: var(--border-4);
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
background-color: var(--fill-1);
|
||||
color: var(--text-1);
|
||||
border: var(--border-1) solid var(--border-2);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
font-size: var(--font-size-body-3);
|
||||
box-shadow: var(--shadow1-center);
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--background-2);
|
||||
color: var(--text-1);
|
||||
border: var(--border-1) solid var(--border-1);
|
||||
border-radius: var(--border-radius-large);
|
||||
padding: var(--size-5);
|
||||
box-shadow: var(--shadow2-center);
|
||||
font-size: var(--font-size-body-3);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-6);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--link-5);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: var(--text-1);
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--text-1);
|
||||
font-size: var(--font-size-body-3);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: var(--border-1) solid var(--border-2);
|
||||
padding: var(--size-3);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
thead {
|
||||
background-color: var(--background-2);
|
||||
}
|
||||
|
||||
.alert {
|
||||
background-color: var(--danger-1);
|
||||
color: var(--danger-6);
|
||||
border: var(--border-1) solid var(--danger-4);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: var(--success-1);
|
||||
color: var(--success-6);
|
||||
border: var(--border-1) solid var(--success-4);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: var(--warning-1);
|
||||
color: var(--warning-6);
|
||||
border: var(--border-1) solid var(--warning-4);
|
||||
border-radius: var(--border-radius-small);
|
||||
padding: var(--size-3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,6 @@ export const themeColorSchema: ColorSchema = {
|
|||
"background-7": "rgb(255, 255, 255)",
|
||||
"background-white": "rgb(255, 255, 255)",
|
||||
"background-black": "rgb(0, 0, 0)",
|
||||
"shadow": "rgba(255, 255, 255, 0.5)",
|
||||
"shadow": "rgb(255, 255, 255)",
|
||||
},
|
||||
};
|
||||
|
|
|
|||
16
src/main.tsx
16
src/main.tsx
|
|
@ -3,15 +3,23 @@ import ReactDOM from "react-dom/client";
|
|||
import "./index.scss";
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
import { router } from "./router";
|
||||
import { createDarkTheme, createLightTheme, generateTailwindProps, getColorAsync, setTailwindExtendProps } from "./utils/theme";
|
||||
import {
|
||||
generateTailwindProps,
|
||||
getColorAsync,
|
||||
setTailwindExtendProps,
|
||||
} from "./utils/theme";
|
||||
import { useThemeStore } from "./stores/theme";
|
||||
|
||||
// 当tailwindcss加载完毕,开始修改config
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
getColorAsync().then((colors) => {
|
||||
setTailwindExtendProps(generateTailwindProps(colors.onLight));
|
||||
createLightTheme(colors.onLight);
|
||||
createDarkTheme(colors.onDark!);
|
||||
})
|
||||
if (localStorage.getItem("colors")) {
|
||||
useThemeStore.value.init();
|
||||
return;
|
||||
}
|
||||
useThemeStore.value.updateColors(colors);
|
||||
});
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
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";
|
||||
import { ThemeVariables } from "../../../../typings";
|
||||
import { getColorAsync } from "../../../utils/theme";
|
||||
import { useThemeStore } from "../../../stores/theme";
|
||||
import { useSnapshot } from "valtio";
|
||||
|
||||
interface ColorPaletteProps {}
|
||||
|
||||
|
|
@ -17,16 +15,15 @@ interface VisibleColorPicker {
|
|||
}
|
||||
|
||||
const ColorPalette: React.FC<ColorPaletteProps> = () => {
|
||||
const [colors, setColors] = useState<ColorSchema>({
|
||||
onLight: {},
|
||||
onDark: {},
|
||||
});
|
||||
const themeStore = useSnapshot(useThemeStore);
|
||||
|
||||
useEffect(() => {
|
||||
getColorAsync().then((res) => {
|
||||
setColors(res);
|
||||
});
|
||||
}, []);
|
||||
const { colors, updateColors: update } = themeStore.value;
|
||||
|
||||
// useEffect(() => {
|
||||
// getColorAsync().then((res) => {
|
||||
// update(res);
|
||||
// });
|
||||
// }, []);
|
||||
|
||||
const [visibleColorPicker, setVisibleColorPicker] =
|
||||
useState<VisibleColorPicker | null>(null);
|
||||
|
|
@ -70,16 +67,16 @@ const ColorPalette: React.FC<ColorPaletteProps> = () => {
|
|||
};
|
||||
|
||||
const setLightColors = (newColor: ThemeVariables) => {
|
||||
setColors({ ...colors, onLight: newColor });
|
||||
createLightTheme(newColor);
|
||||
update({ ...colors, onLight: newColor });
|
||||
};
|
||||
|
||||
const setDarkColors = (newColor: ThemeVariables) => {
|
||||
setColors({ ...colors, onDark: newColor });
|
||||
createDarkTheme(newColor);
|
||||
update({ ...colors, onDark: newColor });
|
||||
};
|
||||
|
||||
const handleColorChange: IColorSelectorProps["onChange"] = ({ color }) => {
|
||||
const handleColorChange: IColorSelectorProps["onChange"] = ({
|
||||
rgb: color,
|
||||
}) => {
|
||||
if (visibleColorPicker) {
|
||||
if (visibleColorPicker.palette === "light") {
|
||||
setLightColors({ ...colors.onLight, [visibleColorPicker.key]: color });
|
||||
|
|
|
|||
|
|
@ -70,101 +70,101 @@ export const Creation = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<div className="p-4">
|
||||
<div className="mb-4">
|
||||
<label className="block mb-2 font-bold text-lg border-primary-1">
|
||||
组件名称
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={componentName}
|
||||
onChange={handleComponentNameChange}
|
||||
className="border border-text-1 rounded p-2 w-full"
|
||||
/>
|
||||
</div>
|
||||
<LiveProvider code={renderCode(code)} noInline>
|
||||
<div className="h-full grid lg:grid-cols-2 gap-4 border p-4 rounded shadow">
|
||||
<div className="border rounded p-2">
|
||||
<CodeMirror
|
||||
value={code}
|
||||
height="100%"
|
||||
theme={vscodeDark}
|
||||
extensions={[
|
||||
...extensions,
|
||||
basicSetup({
|
||||
autocompletion: true,
|
||||
lintKeymap: true,
|
||||
}),
|
||||
]}
|
||||
onChange={onChange}
|
||||
className="font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="border rounded p-2">
|
||||
<LivePreview {...componentsProps} />
|
||||
</div>
|
||||
</div>
|
||||
<LiveError className="text-danger-6 mt-2 p-2 rounded" />
|
||||
</LiveProvider>
|
||||
<div className="h-full grid lg:grid-cols-2 gap-4 border p-4 rounded shadow">
|
||||
<div className="p-4 border rounded shadow ">
|
||||
<h2 className="font-bold text-lg mb-2">Props 编辑器</h2>
|
||||
<div className="props-edit">
|
||||
<div className="mb-4">
|
||||
<label className="block mb-2 font-bold">新属性名</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
type="text"
|
||||
value={newPropKey}
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
<JsonViewEditor
|
||||
value={componentsProps}
|
||||
keyName="props"
|
||||
style={
|
||||
{
|
||||
"--w-rjv-background-color": "#ffffff",
|
||||
"--w-rjv-border-left": "1px dashed #ebebeb",
|
||||
"--w-rjv-update-color": "#ff6ffd",
|
||||
} as any
|
||||
}
|
||||
onEdit={(opts) => {
|
||||
const updateNestedProp = (
|
||||
obj: Record<string, any>,
|
||||
path: string[],
|
||||
value: unknown
|
||||
) => {
|
||||
if (path.length === 1) {
|
||||
obj[path[0]] = value;
|
||||
} else {
|
||||
if (!obj[path[0]]) {
|
||||
obj[path[0]] = {};
|
||||
}
|
||||
updateNestedProp(obj[path[0]], path.slice(1), value);
|
||||
}
|
||||
};
|
||||
const updatedProps = { ...componentsProps };
|
||||
updateNestedProp(
|
||||
updatedProps,
|
||||
(opts as any).namespace,
|
||||
opts.value
|
||||
);
|
||||
setComponentsProps(updatedProps);
|
||||
return true;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ColorPalette />
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="mb-4">
|
||||
<label className="block mb-2 font-bold text-lg border-primary-1">
|
||||
组件名称
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={componentName}
|
||||
onChange={handleComponentNameChange}
|
||||
className="border border-black rounded p-2 w-full"
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
<LiveProvider code={renderCode(code)} noInline>
|
||||
<div className="h-full grid lg:grid-cols-2 gap-4 border p-4 rounded shadow">
|
||||
<div className="border rounded p-2">
|
||||
<CodeMirror
|
||||
value={code}
|
||||
height="100%"
|
||||
theme={vscodeDark}
|
||||
extensions={[
|
||||
...extensions,
|
||||
basicSetup({
|
||||
autocompletion: true,
|
||||
lintKeymap: true,
|
||||
}),
|
||||
]}
|
||||
onChange={onChange}
|
||||
className="font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="border rounded p-2">
|
||||
<ThemeProvider>
|
||||
<LivePreview {...componentsProps} />
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
</div>
|
||||
<LiveError className="text-red-700 bg-gray-200 mt-2 p-2 rounded mb-2" />
|
||||
</LiveProvider>
|
||||
<div className="h-full grid lg:grid-cols-2 gap-4 border p-4 rounded shadow">
|
||||
<div className="p-4 border rounded shadow ">
|
||||
<h2 className="font-bold text-lg mb-2">Props 编辑器</h2>
|
||||
<div className="props-edit">
|
||||
<div className="mb-4">
|
||||
<label className="block mb-2 font-bold">新属性名</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
type="text"
|
||||
value={newPropKey}
|
||||
onChange={(e) => setNewPropKey(e.target.value)}
|
||||
className="border border-black rounded p-2 flex-grow"
|
||||
/>
|
||||
<button onClick={handleAddProp} className="p-2 rounded ml-2 border-gray-600">
|
||||
添加
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<JsonViewEditor
|
||||
value={componentsProps}
|
||||
keyName="props"
|
||||
style={
|
||||
{
|
||||
"--w-rjv-background-color": "#ffffff",
|
||||
"--w-rjv-border-left": "1px dashed #ebebeb",
|
||||
"--w-rjv-update-color": "#ff6ffd",
|
||||
} as any
|
||||
}
|
||||
onEdit={(opts) => {
|
||||
const updateNestedProp = (
|
||||
obj: Record<string, any>,
|
||||
path: string[],
|
||||
value: unknown
|
||||
) => {
|
||||
if (path.length === 1) {
|
||||
obj[path[0]] = value;
|
||||
} else {
|
||||
if (!obj[path[0]]) {
|
||||
obj[path[0]] = {};
|
||||
}
|
||||
updateNestedProp(obj[path[0]], path.slice(1), value);
|
||||
}
|
||||
};
|
||||
const updatedProps = { ...componentsProps };
|
||||
updateNestedProp(
|
||||
updatedProps,
|
||||
(opts as any).namespace,
|
||||
opts.value
|
||||
);
|
||||
setComponentsProps(updatedProps);
|
||||
return true;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ColorPalette />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { ColorSchema } from "../../../typings";
|
||||
import { proxyWithHistory } from "valtio-history";
|
||||
import { createDarkTheme, createLightTheme } from "../../utils/theme";
|
||||
|
||||
// // 模拟计算属性
|
||||
// watch((get) => {
|
||||
// get(counterStore)
|
||||
// counterStore.double = counterStore.count * 2
|
||||
// })
|
||||
|
||||
const initString = `{onLight: {}, onDark: {}}`;
|
||||
|
||||
export const useThemeStore = proxyWithHistory({
|
||||
// 取值的时候,本地存储有就从本地获取
|
||||
colors: JSON.parse(
|
||||
localStorage.getItem("colors") || initString
|
||||
) as ColorSchema,
|
||||
init: () => {
|
||||
createLightTheme(useThemeStore.value.colors.onLight);
|
||||
createDarkTheme(useThemeStore.value.colors.onDark!);
|
||||
},
|
||||
updateColors: (value: ColorSchema) => {
|
||||
// 更新的时候,订阅更新一下本地存储
|
||||
localStorage.setItem("colors", JSON.stringify(value));
|
||||
// 在更新的时候同步更新到style
|
||||
createLightTheme(value.onLight);
|
||||
createDarkTheme(value.onDark!);
|
||||
useThemeStore.value.colors = value;
|
||||
},
|
||||
});
|
||||
Loading…
Reference in New Issue