wip
This commit is contained in:
@@ -29,7 +29,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className={`${geistSans.variable} ${geistMono.variable} antialiased overflow-hidden`}
|
||||||
>
|
>
|
||||||
<StoreProvider initialData={initialState}>
|
<StoreProvider initialData={initialState}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
106
app/page.tsx
106
app/page.tsx
@@ -7,63 +7,64 @@ import Draggable from "@/components/Draggable/Draggable";
|
|||||||
import PreviewStore from "@/stores/previewStore";
|
import PreviewStore from "@/stores/previewStore";
|
||||||
import { useObserver } from "mobx-react-lite";
|
import { useObserver } from "mobx-react-lite";
|
||||||
import ComponentsStore from "@/stores/componentStore";
|
import ComponentsStore from "@/stores/componentStore";
|
||||||
|
import ComponentPaletteDrawer from "@/components/ComponentPaletteDrawer";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [isChangeSize, setIsSizeChangeSize] = useState(false);
|
const [isChangeSize, setIsSizeChangeSize] = useState(false);
|
||||||
const [isDraggable, setIsDraggable] = useState(false);
|
const [isDraggable, setIsDraggable] = useState(false);
|
||||||
const { components } = ComponentsStore;
|
const { components } = ComponentsStore;
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
ComponentsStore.initComponent([
|
// ComponentsStore.initComponent([
|
||||||
{
|
// {
|
||||||
id: "1",
|
// id: "1",
|
||||||
x: 0,
|
// x: 0,
|
||||||
y: 0,
|
// y: 0,
|
||||||
width: 320,
|
// width: 320,
|
||||||
height: 160,
|
// height: 160,
|
||||||
component: () => <Logo />
|
// component: () => <Logo />
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: "2",
|
// id: "2",
|
||||||
x: 336,
|
// x: 336,
|
||||||
y: 0,
|
// y: 0,
|
||||||
width: 160,
|
// width: 160,
|
||||||
height: 320,
|
// height: 320,
|
||||||
component: () => <Logo />
|
// component: () => <Logo />
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: "3",
|
// id: "3",
|
||||||
x: 336,
|
// x: 336,
|
||||||
y: 0,
|
// y: 0,
|
||||||
width: 160,
|
// width: 160,
|
||||||
height: 320,
|
// height: 320,
|
||||||
component: () => <Logo />
|
// component: () => <Logo />
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: "4",
|
// id: "4",
|
||||||
x: 336,
|
// x: 336,
|
||||||
y: 0,
|
// y: 0,
|
||||||
width: 160,
|
// width: 160,
|
||||||
height: 320,
|
// height: 320,
|
||||||
component: () => <Logo />
|
// component: () => <Logo />
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: "5",
|
// id: "5",
|
||||||
x: 336,
|
// x: 336,
|
||||||
y: 0,
|
// y: 0,
|
||||||
width: 160,
|
// width: 160,
|
||||||
height: 320,
|
// height: 320,
|
||||||
component: () => <Logo />
|
// component: () => <Logo />
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: "6",
|
// id: "6",
|
||||||
x: 336,
|
// x: 336,
|
||||||
y: 0,
|
// y: 0,
|
||||||
width: 160,
|
// width: 160,
|
||||||
height: 320,
|
// height: 320,
|
||||||
component: () => <Logo />
|
// component: () => <Logo />
|
||||||
},
|
// },
|
||||||
]);
|
// ]);
|
||||||
}, [])
|
// }, [])
|
||||||
|
|
||||||
return useObserver(() => (
|
return useObserver(() => (
|
||||||
<div className="h-screen w-screen p-4">
|
<div className="h-screen w-screen p-4">
|
||||||
@@ -83,6 +84,7 @@ export default function Home() {
|
|||||||
<div className="swap-on">拖拽</div>
|
<div className="swap-on">拖拽</div>
|
||||||
<div className="swap-off">锁定</div>
|
<div className="swap-off">锁定</div>
|
||||||
</label>
|
</label>
|
||||||
|
<ComponentPaletteDrawer />
|
||||||
<DraggablePanel draggable={isDraggable}>
|
<DraggablePanel draggable={isDraggable}>
|
||||||
{ComponentsStore.components.map((item) => (
|
{ComponentsStore.components.map((item) => (
|
||||||
<Draggable
|
<Draggable
|
||||||
|
|||||||
82
components/ComponentPaletteDrawer.tsx
Normal file
82
components/ComponentPaletteDrawer.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
"use client";
|
||||||
|
import "@/app/globals.css";
|
||||||
|
import { useRef } from "react";
|
||||||
|
export default function ComponentPaletteDrawer() {
|
||||||
|
const checkboxRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const onSubmit = (e: SubmitEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
checkboxRef.current?.click();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="drawer drawer-end">
|
||||||
|
<input
|
||||||
|
ref={checkboxRef}
|
||||||
|
id="ComponentPaletteDrawer"
|
||||||
|
type="checkbox"
|
||||||
|
className="drawer-toggle"
|
||||||
|
/>
|
||||||
|
<div className="drawer-content">
|
||||||
|
{/* Page content here */}
|
||||||
|
<label
|
||||||
|
htmlFor="ComponentPaletteDrawer"
|
||||||
|
className="drawer-button btn btn-primary"
|
||||||
|
>
|
||||||
|
Add Component
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="drawer-side">
|
||||||
|
<label
|
||||||
|
htmlFor="ComponentPaletteDrawer"
|
||||||
|
aria-label="close sidebar"
|
||||||
|
className="drawer-overlay"
|
||||||
|
></label>
|
||||||
|
<div className="menu min-h-full w-2/5 bg-base-200 p-0 text-base-content">
|
||||||
|
<div className="navbar bg-base-100 shadow-sm">
|
||||||
|
<a className="btn text-xl btn-ghost">daisyUI</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<div role="alert" className="alert alert-warning">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="h-6 w-6 shrink-0 stroke-current"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Warning: 内容处于开发阶段仅供参考!</span>
|
||||||
|
</div>
|
||||||
|
<form onSubmit={onSubmit} className="w-full">
|
||||||
|
<fieldset className="fieldset w-full">
|
||||||
|
<legend className="fieldset-legend">小部件</legend>
|
||||||
|
<select defaultValue="请选择小部件" className="select w-full">
|
||||||
|
<option disabled={true}>请选择小部件</option>
|
||||||
|
<option>文本</option>
|
||||||
|
<option>Logo</option>
|
||||||
|
</select>
|
||||||
|
<p className="fieldset-label">你可以选择一款你喜欢的小部件</p>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset className="fieldset w-full">
|
||||||
|
<legend className="fieldset-legend">配置信息</legend>
|
||||||
|
<textarea
|
||||||
|
className="textarea h-24 w-full"
|
||||||
|
placeholder="请输入 JSON 格式的配置信息"
|
||||||
|
></textarea>
|
||||||
|
<p className="fieldset-label">JSON格式的配置信息</p>
|
||||||
|
</fieldset>
|
||||||
|
<button className="btn w-full btn-primary">确认</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,15 +3,17 @@ import "@/app/globals.css";
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
|
||||||
import { useDraggable } from "@dnd-kit/core";
|
import { useDraggable } from "@dnd-kit/core";
|
||||||
import { ReactElement, useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { nearestMultiple } from "./utils";
|
import { nearestMultiple } from "./utils";
|
||||||
import PreviewStore from "@/stores/previewStore";
|
import PreviewStore from "@/stores/previewStore";
|
||||||
|
import Logo from "../Logo";
|
||||||
|
import Text from "../Text";
|
||||||
|
|
||||||
export default function Draggable(props: DraggablePropsType) {
|
export default function Draggable(props: DraggablePropsType) {
|
||||||
const targetRef = useRef<HTMLDivElement>(null);
|
const targetRef = useRef<HTMLDivElement>(null);
|
||||||
const timerRef = useRef<NodeJS.Timeout>(null);
|
const timerRef = useRef<NodeJS.Timeout>(null);
|
||||||
const [size, setSize] = useState({ width: 16, height: 16 });
|
const [size, setSize] = useState({ width: 16, height: 16 });
|
||||||
const { id, component, data, x, y, width:_width, height:_height } = props;
|
const { id, componentsId, data, x, y, width:_width, height:_height } = props;
|
||||||
const [width, setWidth] = useState(_width);
|
const [width, setWidth] = useState(_width);
|
||||||
const [height, setHeight] = useState(_height);
|
const [height, setHeight] = useState(_height);
|
||||||
|
|
||||||
@@ -23,7 +25,7 @@ export default function Draggable(props: DraggablePropsType) {
|
|||||||
const style = transform
|
const style = transform
|
||||||
? {
|
? {
|
||||||
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
||||||
opacity: 0.3,
|
opacity: 0.6,
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -48,12 +50,12 @@ export default function Draggable(props: DraggablePropsType) {
|
|||||||
clearTimeout(timerRef.current);
|
clearTimeout(timerRef.current);
|
||||||
}
|
}
|
||||||
timerRef.current = setTimeout(() => {
|
timerRef.current = setTimeout(() => {
|
||||||
console.log(PreviewStore.width, PreviewStore.height);
|
setWidth(nearestMultiple(width));
|
||||||
setWidth(PreviewStore.width);
|
setHeight(nearestMultiple(height));
|
||||||
setHeight(PreviewStore.height);
|
PreviewStore.clearPreview();
|
||||||
}, 2000);
|
}, 500);
|
||||||
}
|
}
|
||||||
}, 30),
|
}, 300),
|
||||||
);
|
);
|
||||||
|
|
||||||
observer.observe(element);
|
observer.observe(element);
|
||||||
@@ -74,7 +76,7 @@ export default function Draggable(props: DraggablePropsType) {
|
|||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
...style,
|
...style,
|
||||||
}} {...attributes} title={`${width}x${height}`}>
|
}} {...attributes}>
|
||||||
<button
|
<button
|
||||||
className="btn absolute top-1 right-1 z-50 btn-square btn-soft"
|
className="btn absolute top-1 right-1 z-50 btn-square btn-soft"
|
||||||
{...listeners}
|
{...listeners}
|
||||||
@@ -95,17 +97,22 @@ export default function Draggable(props: DraggablePropsType) {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
{component && component(data ?? {})}
|
{componentsLibrary[componentsId] && componentsLibrary[componentsId](data ?? {})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DraggablePropsType = {
|
export type DraggablePropsType = {
|
||||||
id: string;
|
id: string;
|
||||||
component: (data: Record<string, unknown>) => ReactElement;
|
componentsId: string;
|
||||||
data?: Record<string, unknown>;
|
data?: Record<string, unknown>;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const componentsLibrary = {
|
||||||
|
'logo': () => <Logo />,
|
||||||
|
'text': (data: DraggablePropsType["data"]) => <Text data={{ content: 'default',...data }} />,
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ export default function Preview(props: PreviewPropsType) {
|
|||||||
left: x,
|
left: x,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
// visibility: width * height === 0 ? 'hidden' : 'none'
|
display: width + height + x + y === 0 ? 'none' : 'block'
|
||||||
});
|
});
|
||||||
}, [props.height, props.width, props.x, props.y])
|
}, [props.height, props.width, props.x, props.y])
|
||||||
return (
|
return (
|
||||||
@@ -25,8 +25,16 @@ export default function Preview(props: PreviewPropsType) {
|
|||||||
className="absolute border-2 z-50 border-emerald-500 bg-gradient-to-br from-emerald-100/30 to-cyan-100/30 backdrop-blur-[2px] rounded-lg shadow-lg shadow-emerald-200/50 animate-pulse"
|
className="absolute border-2 z-50 border-emerald-500 bg-gradient-to-br from-emerald-100/30 to-cyan-100/30 backdrop-blur-[2px] rounded-lg shadow-lg shadow-emerald-200/50 animate-pulse"
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
{width * height === 0 || `${width} * ${height}`}
|
<span
|
||||||
{x * y === 0 || `${x}, ${y}`}
|
className="absolute text-2xl bg-emerald-500 border-emerald-500 text-white top-0 p-0.5"
|
||||||
|
>
|
||||||
|
{width * height === 0 || `${width} * ${height}`}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="absolute text-2xl bg-emerald-500 border-emerald-500 text-white bottom-0 p-0.5"
|
||||||
|
>
|
||||||
|
{x * y === 0 || `${x}, ${y}`}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
* @param [x=16] 推荐使用偶数
|
* @param [x=16] 推荐使用偶数
|
||||||
* @returns 最近的 x 的倍数
|
* @returns 最近的 x 的倍数
|
||||||
*/
|
*/
|
||||||
export function nearestMultiple(n: number, x: number = 16): number {
|
export function nearestMultiple(n: number, x: number = 32): number {
|
||||||
return Math.floor((n + x/2) / x) * x;
|
return Math.floor((n + x/2) / x) * x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,10 +40,7 @@ export default function DraggablePanel(props: DraggablePanelType) {
|
|||||||
const { width, height } = rect;
|
const { width, height } = rect;
|
||||||
const x = nearestMultiple(node.offsetLeft + event.delta.x);
|
const x = nearestMultiple(node.offsetLeft + event.delta.x);
|
||||||
const y = nearestMultiple(node.offsetTop + event.delta.y);
|
const y = nearestMultiple(node.offsetTop + event.delta.y);
|
||||||
PreviewStore.changePreviewX(0);
|
PreviewStore.clearPreview();
|
||||||
PreviewStore.changePreviewY(0);
|
|
||||||
PreviewStore.changePreviewWidth(0);
|
|
||||||
PreviewStore.changePreviewHeight(0);
|
|
||||||
ComponentStore.changeComponent({
|
ComponentStore.changeComponent({
|
||||||
id: event?.active?.data?.current?.id,
|
id: event?.active?.data?.current?.id,
|
||||||
component: event?.active?.data?.current?.component,
|
component: event?.active?.data?.current?.component,
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import "@/app/globals.css";
|
|||||||
|
|
||||||
export default function Logo() {
|
export default function Logo() {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full items-center justify-center bg-gray-300 text-5xl font-bold text-gray-900">
|
<div className="flex h-full w-full items-center justify-center text-5xl bg-base-200 font-bold">
|
||||||
<span className="whitespace-nowrap md:whitespace-normal">
|
<span className="whitespace-nowrap text-primary">
|
||||||
NEXUSHUB
|
NEXUSHUB
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
76
components/Text/index.tsx
Normal file
76
components/Text/index.tsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import React, { CSSProperties } from 'react';
|
||||||
|
import { DraggablePropsType } from '../Draggable/Draggable';
|
||||||
|
|
||||||
|
type FontData = {
|
||||||
|
content: string;
|
||||||
|
fontSize?: number; // 字体大小(px)
|
||||||
|
fontFamily?: string; // 字体类型
|
||||||
|
color?: string; // 字体颜色
|
||||||
|
fontWeight?: number; // 字重
|
||||||
|
lineHeight?: number; // 行高比例
|
||||||
|
textAlign?: 'left' | 'center' | 'right'; // 对齐方式
|
||||||
|
letterSpacing?: number; // 字间距(px)
|
||||||
|
customStyles?: CSSProperties; // 自定义CSS扩展
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ResponsiveTextProps {
|
||||||
|
data: DraggablePropsType["data"] & FontData;
|
||||||
|
className?: string; // 外部容器类名
|
||||||
|
}
|
||||||
|
|
||||||
|
const Text: React.FC<ResponsiveTextProps> = ({
|
||||||
|
data,
|
||||||
|
className
|
||||||
|
}) => {
|
||||||
|
// 合并默认样式与传入样式
|
||||||
|
const textStyles: CSSProperties = {
|
||||||
|
fontSize: `${data.fontSize || 16}px`,
|
||||||
|
fontFamily: data.fontFamily || 'Arial, sans-serif',
|
||||||
|
color: data.color || '#333',
|
||||||
|
fontWeight: data.fontWeight || 400,
|
||||||
|
lineHeight: data.lineHeight ? `${data.lineHeight}em` : '1.5',
|
||||||
|
textAlign: data.textAlign || 'left',
|
||||||
|
letterSpacing: `${data.letterSpacing || 0}px`,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: data.textAlign === 'center' ? 'center' :
|
||||||
|
data.textAlign === 'right' ? 'flex-end' : 'flex-start',
|
||||||
|
...data.customStyles
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
style={{
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
minWidth: '50px', // 防止容器坍缩
|
||||||
|
minHeight: '1em' // 最小高度保障
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
...textStyles,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
padding: '0.2em' // 防止文本贴边
|
||||||
|
}}
|
||||||
|
title={data.content} // 添加tooltip
|
||||||
|
>
|
||||||
|
{data.content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Text;
|
||||||
@@ -1,29 +1,69 @@
|
|||||||
import { DraggablePropsType } from "@/components/Draggable/Draggable";
|
import { DraggablePropsType } from "@/components/Draggable/Draggable";
|
||||||
import { makeAutoObservable } from "mobx";
|
import { makeAutoObservable, reaction } from "mobx";
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
class ComponentsStore {
|
class ComponentsStore {
|
||||||
components:DraggablePropsType[] = [];
|
components: DraggablePropsType[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
|
this.loadFromLocalStorage(); // 初始化加载
|
||||||
|
|
||||||
|
// 监听 components 变化自动保存(防抖版)
|
||||||
|
reaction(
|
||||||
|
() => this.components.slice(), // 深度监听变化
|
||||||
|
debounce(() => this.saveToLocalStorage(), 500)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
initComponent(componentsList:DraggablePropsType[]) {
|
// 初始化时从本地存储加载
|
||||||
|
private loadFromLocalStorage() {
|
||||||
|
if (window === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const data = localStorage.getItem("componentsStore");
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
this.components = JSON.parse(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse stored components", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防抖保存到本地存储
|
||||||
|
private saveToLocalStorage = debounce(() => {
|
||||||
|
localStorage.setItem("componentsStore", JSON.stringify(this.components));
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// 以下方法会触发自动保存
|
||||||
|
initComponent(componentsList: DraggablePropsType[]) {
|
||||||
this.components = componentsList || [];
|
this.components = componentsList || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
changeComponent(componentsList:DraggablePropsType) {
|
changeComponent(updatedComponent: DraggablePropsType) {
|
||||||
this.components = this.components.map(item => {
|
this.components = this.components.map(item =>
|
||||||
if (item.id !== componentsList.id) {
|
item.id === updatedComponent.id ? updatedComponent : item
|
||||||
return item;
|
);
|
||||||
}
|
|
||||||
return componentsList;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delectComponent(componentsList:DraggablePropsType) {
|
deleteComponent(targetComponent: DraggablePropsType) {
|
||||||
this.components = this.components.filter(item => item.id !== componentsList.id);
|
this.components = this.components.filter(
|
||||||
|
item => item.id !== targetComponent.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponent(componentsId: string, data:Record<string, unknown>) {
|
||||||
|
this.components.push({
|
||||||
|
id: String(this.components.length),
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
componentsId,
|
||||||
|
data,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new ComponentsStore();
|
export default new ComponentsStore();
|
||||||
|
|||||||
Reference in New Issue
Block a user