seat-editor 1.2.6 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -0
- package/dist/app/layout.d.ts +1 -1
- package/dist/app/layout.jsx +27 -0
- package/dist/app/new-board/page.d.ts +1 -1
- package/dist/app/new-board/page.jsx +12 -0
- package/dist/app/old-board/page.d.ts +2 -1
- package/dist/app/old-board/page.jsx +515 -0
- package/dist/app/only-view/page.d.ts +1 -1
- package/dist/app/page.d.ts +1 -1
- package/dist/app/page.jsx +13 -0
- package/dist/components/button-tools/index.d.ts +1 -1
- package/dist/components/button-tools/index.jsx +17 -0
- package/dist/components/form-tools/label.d.ts +1 -1
- package/dist/components/form-tools/label.jsx +44 -0
- package/dist/components/form-tools/shape.d.ts +1 -1
- package/dist/components/form-tools/shape.jsx +43 -0
- package/dist/components/input/number-indicator.d.ts +1 -1
- package/dist/components/input/number-indicator.jsx +36 -0
- package/dist/components/layer/index.d.ts +3 -1
- package/dist/components/layer/index.jsx +22 -11
- package/dist/components/lib/index.d.ts +1 -1
- package/dist/components/lib/index.jsx +33 -0
- package/dist/components/modal-preview/index.d.ts +1 -1
- package/dist/components/modal-preview/index.jsx +11 -0
- package/dist/features/board/index.d.ts +1 -1
- package/dist/features/board/index.jsx +290 -0
- package/dist/features/navbar/index.d.ts +1 -1
- package/dist/features/navbar/index.jsx +5 -0
- package/dist/features/package/index.d.ts +1 -1
- package/dist/features/package/index.jsx +39 -0
- package/dist/features/panel/index.d.ts +1 -1
- package/dist/features/panel/index.jsx +91 -0
- package/dist/features/panel/select-tool.d.ts +1 -1
- package/dist/features/panel/select-tool.jsx +45 -0
- package/dist/features/panel/square-circle-tool.d.ts +1 -1
- package/dist/features/panel/square-circle-tool.jsx +10 -0
- package/dist/features/panel/table-seat-circle.d.ts +1 -1
- package/dist/features/panel/table-seat-circle.jsx +31 -0
- package/dist/features/panel/text-tool.d.ts +1 -1
- package/dist/features/panel/text-tool.jsx +22 -0
- package/dist/features/panel/upload-tool.d.ts +1 -1
- package/dist/features/panel/upload-tool.jsx +80 -0
- package/dist/features/side-tool/index.d.ts +1 -1
- package/dist/features/side-tool/index.jsx +211 -0
- package/dist/features/view/index.d.ts +1 -1
- package/dist/features/view/index.jsx +4 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/provider/antd-provider.jsx +30 -0
- package/dist/provider/redux-provider.d.ts +1 -1
- package/dist/provider/redux-provider.jsx +6 -0
- package/dist/provider/store-provider.d.ts +1 -1
- package/dist/provider/store-provider.jsx +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Board from "../features/board";
|
|
2
|
+
import SideTool from "../features/side-tool";
|
|
3
|
+
import ControlPanels from "../features/panel";
|
|
4
|
+
const TableEditor = () => {
|
|
5
|
+
return (<>
|
|
6
|
+
<div className="w-full h-screen flex relative">
|
|
7
|
+
<SideTool />
|
|
8
|
+
<Board />
|
|
9
|
+
<ControlPanels />
|
|
10
|
+
</div>
|
|
11
|
+
</>);
|
|
12
|
+
};
|
|
13
|
+
export default TableEditor;
|
|
@@ -7,5 +7,5 @@ interface ButtonToolsProps {
|
|
|
7
7
|
}>;
|
|
8
8
|
popoverProps?: PopoverProps;
|
|
9
9
|
}
|
|
10
|
-
declare const ButtonTools: (props: ButtonToolsProps) => import("react
|
|
10
|
+
declare const ButtonTools: (props: ButtonToolsProps) => import("react").JSX.Element;
|
|
11
11
|
export default ButtonTools;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button, Popover } from "antd";
|
|
3
|
+
const ButtonTools = (props) => {
|
|
4
|
+
const { buttonProps, items, popoverProps } = props;
|
|
5
|
+
if (items.length === 0) {
|
|
6
|
+
return (<Popover trigger="hover" {...popoverProps}>
|
|
7
|
+
<Button {...buttonProps}/>
|
|
8
|
+
</Popover>);
|
|
9
|
+
}
|
|
10
|
+
return (<Popover content={<div>
|
|
11
|
+
<Button>Button 1</Button>
|
|
12
|
+
<Button>Button 2</Button>
|
|
13
|
+
</div>} trigger="click">
|
|
14
|
+
<Button {...buttonProps}/>
|
|
15
|
+
</Popover>);
|
|
16
|
+
};
|
|
17
|
+
export default ButtonTools;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const SectionLabel: () => import("react
|
|
1
|
+
declare const SectionLabel: () => import("react").JSX.Element;
|
|
2
2
|
export default SectionLabel;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button, ColorPicker, Flex, Form, Input, InputNumber } from "antd";
|
|
3
|
+
const SectionLabel = () => {
|
|
4
|
+
return (<div className="py-2">
|
|
5
|
+
<h1 className="heading-s">Section Labeling</h1>
|
|
6
|
+
<Form.Item label="Labels in square" name={"labels"}>
|
|
7
|
+
<Form.List name="labels">
|
|
8
|
+
{(fields, { add, remove }) => (<>
|
|
9
|
+
{fields.map((field) => (<div key={field.key}>
|
|
10
|
+
<Flex gap={2}>
|
|
11
|
+
<Form.Item name={[field.name, "label"]} label="Text">
|
|
12
|
+
<Input />
|
|
13
|
+
</Form.Item>
|
|
14
|
+
<Form.Item name={[field.name, "fontColor"]} label="Color" getValueFromEvent={(color) => color.toHexString()}>
|
|
15
|
+
<ColorPicker allowClear format="hex" defaultFormat="hex"/>
|
|
16
|
+
</Form.Item>
|
|
17
|
+
</Flex>
|
|
18
|
+
<Flex gap={2}>
|
|
19
|
+
<Form.Item name={[field.name, "x"]} label="X">
|
|
20
|
+
<InputNumber />
|
|
21
|
+
</Form.Item>
|
|
22
|
+
<Form.Item name={[field.name, "y"]} label="Y">
|
|
23
|
+
<InputNumber />
|
|
24
|
+
</Form.Item>
|
|
25
|
+
<Form.Item name={[field.name, "fontSize"]} label="Size">
|
|
26
|
+
<InputNumber suffix="px"/>
|
|
27
|
+
</Form.Item>
|
|
28
|
+
</Flex>
|
|
29
|
+
</div>))}
|
|
30
|
+
<Flex gap={2}>
|
|
31
|
+
<Button type="primary" onClick={() => add()} className="btn btn-primary">
|
|
32
|
+
Add
|
|
33
|
+
</Button>
|
|
34
|
+
<Button type="primary" onClick={() => remove(fields.length - 1)} className="btn btn-primary">
|
|
35
|
+
Remove
|
|
36
|
+
</Button>
|
|
37
|
+
</Flex>
|
|
38
|
+
</>)}
|
|
39
|
+
</Form.List>
|
|
40
|
+
</Form.Item>
|
|
41
|
+
<div className="divider-dashed"/>
|
|
42
|
+
</div>);
|
|
43
|
+
};
|
|
44
|
+
export default SectionLabel;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const SectionShape: () => import("react
|
|
1
|
+
declare const SectionShape: () => import("react").JSX.Element;
|
|
2
2
|
export default SectionShape;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { ColorPicker, Flex, Form, InputNumber } from "antd";
|
|
3
|
+
const SectionShape = () => {
|
|
4
|
+
return (<div className="py-2">
|
|
5
|
+
<h1 className="heading-s">Shape</h1>
|
|
6
|
+
<Flex gap={2} className="w-full">
|
|
7
|
+
<Form.Item label="Width" name="width" className="w-full">
|
|
8
|
+
<InputNumber suffix="px"/>
|
|
9
|
+
</Form.Item>
|
|
10
|
+
<Form.Item label="Height" name="height" className="w-full">
|
|
11
|
+
<InputNumber suffix="px"/>
|
|
12
|
+
</Form.Item>
|
|
13
|
+
</Flex>
|
|
14
|
+
<Flex gap={2}>
|
|
15
|
+
<Form.Item label="Position X" name="x" className="w-full">
|
|
16
|
+
<InputNumber />
|
|
17
|
+
</Form.Item>
|
|
18
|
+
<Form.Item label="Position Y" name="y" className="w-full">
|
|
19
|
+
<InputNumber />
|
|
20
|
+
</Form.Item>
|
|
21
|
+
<Form.Item label="Rotation" name="rotation" className="w-full">
|
|
22
|
+
<InputNumber />
|
|
23
|
+
</Form.Item>
|
|
24
|
+
</Flex>
|
|
25
|
+
<Flex gap={2}>
|
|
26
|
+
<Form.Item label="Fill" name={"fill"} getValueFromEvent={(color) => color.toHexString()} className="w-full ">
|
|
27
|
+
<ColorPicker allowClear format="hex" defaultFormat="hex"/>
|
|
28
|
+
</Form.Item>
|
|
29
|
+
<Form.Item label="Stroke" name={"stroke"} getValueFromEvent={(color) => color.toHexString()} className="w-full ">
|
|
30
|
+
<ColorPicker allowClear format="hex" defaultFormat="hex"/>
|
|
31
|
+
</Form.Item>
|
|
32
|
+
</Flex>
|
|
33
|
+
<Flex>
|
|
34
|
+
<Form.Item label="Stroke Width" name={"strokeWidth"} className="w-full">
|
|
35
|
+
<InputNumber />
|
|
36
|
+
</Form.Item>
|
|
37
|
+
<Form.Item label="opacity" name={"opacity"} className="w-full">
|
|
38
|
+
<InputNumber step={0.1} max={1} min={0}/>
|
|
39
|
+
</Form.Item>
|
|
40
|
+
</Flex>
|
|
41
|
+
</div>);
|
|
42
|
+
};
|
|
43
|
+
export default SectionShape;
|
|
@@ -3,5 +3,5 @@ interface NumberIndicatorProps {
|
|
|
3
3
|
defaultValue?: number;
|
|
4
4
|
onChange: (value: number) => void;
|
|
5
5
|
}
|
|
6
|
-
declare const NumberIndicator: ({ name, defaultValue, onChange }: NumberIndicatorProps) => import("react
|
|
6
|
+
declare const NumberIndicator: ({ name, defaultValue, onChange }: NumberIndicatorProps) => import("react").JSX.Element;
|
|
7
7
|
export default NumberIndicator;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Input, Button, Flex, Form } from "antd";
|
|
4
|
+
import { ArrowRight, ArrowLeft } from "lucide-react";
|
|
5
|
+
const NumberIndicator = ({ name, defaultValue, onChange }) => {
|
|
6
|
+
const [value, setValue] = useState(0);
|
|
7
|
+
const form = Form.useFormInstance();
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (defaultValue) {
|
|
10
|
+
setValue(defaultValue);
|
|
11
|
+
form.setFieldsValue({ [name]: defaultValue });
|
|
12
|
+
}
|
|
13
|
+
}, [defaultValue]);
|
|
14
|
+
const handlePrev = () => {
|
|
15
|
+
setValue(value - 1);
|
|
16
|
+
form.setFieldsValue({ [name]: value - 1 });
|
|
17
|
+
onChange(value - 1);
|
|
18
|
+
};
|
|
19
|
+
const handleNext = () => {
|
|
20
|
+
setValue(value + 1);
|
|
21
|
+
form.setFieldsValue({ [name]: value + 1 });
|
|
22
|
+
onChange(value + 1);
|
|
23
|
+
};
|
|
24
|
+
return (<Flex gap={2}>
|
|
25
|
+
<Button onClick={handlePrev}>
|
|
26
|
+
<ArrowLeft />
|
|
27
|
+
</Button>
|
|
28
|
+
<Form.Item name={name} noStyle>
|
|
29
|
+
<Input className="flex text-center" type="number" value={value} name={name} onChange={(e) => setValue(parseInt(e.target.value))}/>
|
|
30
|
+
</Form.Item>
|
|
31
|
+
<Button onClick={handleNext}>
|
|
32
|
+
<ArrowRight />
|
|
33
|
+
</Button>
|
|
34
|
+
</Flex>);
|
|
35
|
+
};
|
|
36
|
+
export default NumberIndicator;
|
|
@@ -9,6 +9,8 @@ interface LayersProps {
|
|
|
9
9
|
onBlur?: () => void;
|
|
10
10
|
selectedTable?: any;
|
|
11
11
|
selectedTableColor?: string;
|
|
12
|
+
style?: any;
|
|
13
|
+
mode?: "view" | "edit";
|
|
12
14
|
}
|
|
13
|
-
declare const Layers: ({ shadowShape, components, onClick, selectedComponent, selectedTable, activeTool, onMouseDown, onMouseUp, onBlur, selectedTableColor, }: LayersProps) => import("react
|
|
15
|
+
declare const Layers: ({ shadowShape, components, onClick, selectedComponent, selectedTable, activeTool, onMouseDown, onMouseUp, onBlur, selectedTableColor, mode, style }: LayersProps) => import("react").JSX.Element;
|
|
14
16
|
export default Layers;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { omit } from "lodash";
|
|
3
|
-
const Layers = ({ shadowShape, components, onClick, selectedComponent, selectedTable, activeTool, onMouseDown, onMouseUp, onBlur, selectedTableColor, }) => {
|
|
4
|
-
console.log({ components }, "this iss");
|
|
3
|
+
const Layers = ({ shadowShape, components, onClick, selectedComponent, selectedTable, activeTool, onMouseDown, onMouseUp, onBlur, selectedTableColor, mode = "edit", style }) => {
|
|
5
4
|
const renderShadowShape = (item) => {
|
|
6
5
|
const { id, x, y, width, height, fill, opacity, rotation, shape, fontColor, text, seatFill, labels, } = item;
|
|
7
6
|
const commonProps = { fill, opacity };
|
|
@@ -108,27 +107,33 @@ const Layers = ({ shadowShape, components, onClick, selectedComponent, selectedT
|
|
|
108
107
|
switch (shape) {
|
|
109
108
|
case "square":
|
|
110
109
|
return (<>
|
|
111
|
-
<rect key={id} x={x} y={y} width={width} height={height} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} opacity={id === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) ? 0.5 : opacity} {...omit(commonProps, "opacity")} transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`}/>
|
|
110
|
+
<rect key={id} x={x} y={y} width={width} height={height} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} style={Object.assign({ cursor: mode === "view" ? "pointer" : "default" }, style)} opacity={id === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) ? 0.5 : opacity} {...omit(commonProps, "opacity")} transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`}/>
|
|
112
111
|
{labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
113
112
|
var _a, _b, _c, _d;
|
|
114
|
-
return (<text key={`${id}-label-${index}`} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`}
|
|
113
|
+
return (<text key={`${id}-label-${index}`} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`} onClick={(e) => {
|
|
114
|
+
e.stopPropagation();
|
|
115
|
+
onClick(item);
|
|
116
|
+
}}>
|
|
115
117
|
{_ === null || _ === void 0 ? void 0 : _.label}
|
|
116
118
|
</text>);
|
|
117
119
|
})}
|
|
118
120
|
</>);
|
|
119
121
|
case "circle":
|
|
120
122
|
return (<>
|
|
121
|
-
<circle key={id} cx={x + width / 2} cy={y + height / 2} r={width / 2} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} opacity={id === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) ? 0.5 : opacity} {...omit(commonProps, "opacity")}/>
|
|
123
|
+
<circle key={id} cx={x + width / 2} cy={y + height / 2} r={width / 2} style={Object.assign({ cursor: mode === "view" ? "pointer" : "default" }, style)} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} opacity={id === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) ? 0.5 : opacity} {...omit(commonProps, "opacity")}/>
|
|
122
124
|
{labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
123
125
|
var _a, _b, _c, _d;
|
|
124
|
-
return (<text key={`${id}-label-${index}`} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`}
|
|
126
|
+
return (<text key={`${id}-label-${index}`} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`} onClick={(e) => {
|
|
127
|
+
e.stopPropagation();
|
|
128
|
+
onClick(item);
|
|
129
|
+
}}>
|
|
125
130
|
{_ === null || _ === void 0 ? void 0 : _.label}
|
|
126
131
|
</text>);
|
|
127
132
|
})}
|
|
128
133
|
</>);
|
|
129
134
|
case "diamond":
|
|
130
135
|
return (<>
|
|
131
|
-
<rect key={id} x={x} y={y} width={width} height={height} transform={`rotate(${rotation}, ${x}, ${y})`} {...commonProps} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill}/>
|
|
136
|
+
<rect key={id} x={x} y={y} width={width} height={height} style={Object.assign({ cursor: mode === "view" ? "pointer" : "default" }, style)} transform={`rotate(${rotation}, ${x}, ${y})`} {...commonProps} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill}/>
|
|
132
137
|
<text x={x + width / 2} y={y + height / 2} fill={fontColor !== null && fontColor !== void 0 ? fontColor : "black"} fontSize={`${fontSize !== null && fontSize !== void 0 ? fontSize : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
|
|
133
138
|
{label}
|
|
134
139
|
</text>
|
|
@@ -151,10 +156,13 @@ const Layers = ({ shadowShape, components, onClick, selectedComponent, selectedT
|
|
|
151
156
|
return { cx, cy };
|
|
152
157
|
});
|
|
153
158
|
return (<g key={id} transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`}>
|
|
154
|
-
<circle cx={centerX} cy={centerY} r={width - 15} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} {...commonProps} opacity={id === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) ? 0.5 : opacity}/>
|
|
159
|
+
<circle cx={centerX} style={Object.assign({ cursor: mode === "view" ? "pointer" : "default" }, style)} cy={centerY} r={width - 15} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill} {...commonProps} opacity={id === (selectedComponent === null || selectedComponent === void 0 ? void 0 : selectedComponent.id) ? 0.5 : opacity}/>
|
|
155
160
|
{labels === null || labels === void 0 ? void 0 : labels.map((_, index) => {
|
|
156
161
|
var _a, _b, _c, _d;
|
|
157
|
-
return (<text key={`${id}-label-${index}`} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`}
|
|
162
|
+
return (<text key={`${id}-label-${index}`} x={x + width / 2 + ((_a = _ === null || _ === void 0 ? void 0 : _.x) !== null && _a !== void 0 ? _a : 0)} y={y + height / 2 + ((_b = _ === null || _ === void 0 ? void 0 : _.y) !== null && _b !== void 0 ? _b : 0)} fill={(_c = _ === null || _ === void 0 ? void 0 : _.fontColor) !== null && _c !== void 0 ? _c : "black"} fontSize={`${(_d = _ === null || _ === void 0 ? void 0 : _.fontSize) !== null && _d !== void 0 ? _d : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle" transform={`rotate(${rotation} ${x + width / 2} ${y + height / 2})`} onClick={(e) => {
|
|
163
|
+
e.stopPropagation();
|
|
164
|
+
onClick(item);
|
|
165
|
+
}}>
|
|
158
166
|
{_ === null || _ === void 0 ? void 0 : _.label}
|
|
159
167
|
</text>);
|
|
160
168
|
})}
|
|
@@ -183,7 +191,7 @@ const Layers = ({ shadowShape, components, onClick, selectedComponent, selectedT
|
|
|
183
191
|
}));
|
|
184
192
|
return (<g key={id} transform={`rotate(${rotation}, ${x}, ${y})`}>
|
|
185
193
|
{/* Square Table */}
|
|
186
|
-
<rect x={x} y={y} width={width} height={height} {...commonProps} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill}/>
|
|
194
|
+
<rect x={x} y={y} style={Object.assign({ cursor: mode === "view" ? "pointer" : "default" }, style)} width={width} height={height} {...commonProps} fill={selectedTableColor !== null && selectedTableColor !== void 0 ? selectedTableColor : fill}/>
|
|
187
195
|
<text x={x + width / 2} y={y + height / 2} fill={fontColor !== null && fontColor !== void 0 ? fontColor : "black"} fontSize={`${fontSize !== null && fontSize !== void 0 ? fontSize : 10}px`} fontWeight="bold" textAnchor="middle" dominantBaseline="middle">
|
|
188
196
|
{label}
|
|
189
197
|
</text>
|
|
@@ -195,7 +203,10 @@ const Layers = ({ shadowShape, components, onClick, selectedComponent, selectedT
|
|
|
195
203
|
}
|
|
196
204
|
case "text":
|
|
197
205
|
return (<g key={id}>
|
|
198
|
-
<rect x={x} y={y} width={width} height={height} fill="transparent" opacity={opacity}
|
|
206
|
+
<rect x={x} y={y} width={width} height={height} fill="transparent" opacity={opacity} onClick={(e) => {
|
|
207
|
+
e.stopPropagation();
|
|
208
|
+
onClick(item);
|
|
209
|
+
}}/>
|
|
199
210
|
<text x={x + width / 2} y={y + height / 2} textAnchor="middle" dominantBaseline="middle" fill={fontColor} fontSize={fontSize !== null && fontSize !== void 0 ? fontSize : height * 0.6} opacity={opacity} {...omit(commonProps, ["fill", "opacity"])}>
|
|
200
211
|
{text}
|
|
201
212
|
</text>
|
|
@@ -3,6 +3,6 @@ export interface LayerViewProps {
|
|
|
3
3
|
componentProps: any[];
|
|
4
4
|
extraComponentProps: any[];
|
|
5
5
|
}
|
|
6
|
-
declare const TableEditor: ({ componentProps, extraComponentProps, }: LayerViewProps) => import("react
|
|
6
|
+
declare const TableEditor: ({ componentProps, extraComponentProps, }: LayerViewProps) => import("react").JSX.Element;
|
|
7
7
|
export default TableEditor;
|
|
8
8
|
export { LayerView };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import Board from "../../features/board";
|
|
4
|
+
import SideTool from "../../features/side-tool";
|
|
5
|
+
import ControlPanels from "../../features/panel";
|
|
6
|
+
import LayerView from "../../features/view";
|
|
7
|
+
import { useAppDispatch } from "../../hooks/use-redux";
|
|
8
|
+
const TableEditor = ({ componentProps = [], extraComponentProps = [], }) => {
|
|
9
|
+
const dispatch = useAppDispatch();
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (componentProps.length > 0) {
|
|
12
|
+
dispatch({
|
|
13
|
+
type: "board/setNewComponents",
|
|
14
|
+
payload: componentProps,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (extraComponentProps.length > 0) {
|
|
18
|
+
dispatch({
|
|
19
|
+
type: "board/setNewExtraComponent",
|
|
20
|
+
payload: extraComponentProps,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}, [componentProps, extraComponentProps]);
|
|
24
|
+
return (<>
|
|
25
|
+
<div className="w-full h-screen flex relative">
|
|
26
|
+
<SideTool />
|
|
27
|
+
<Board />
|
|
28
|
+
<ControlPanels />
|
|
29
|
+
</div>
|
|
30
|
+
</>);
|
|
31
|
+
};
|
|
32
|
+
export default TableEditor;
|
|
33
|
+
export { LayerView };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Modal } from "antd";
|
|
3
|
+
import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
|
|
4
|
+
const ModalPreview = ({ children }) => {
|
|
5
|
+
const { isPreview } = useAppSelector((state) => state.tool);
|
|
6
|
+
const dispatch = useAppDispatch();
|
|
7
|
+
return (<Modal open={isPreview} onCancel={() => dispatch({ type: "tool/setTooglePreview", payload: false })} width={700} title="Preview Board" centered footer={null}>
|
|
8
|
+
<div className="flex flex-col p-4 h-[500px]">{children}</div>
|
|
9
|
+
</Modal>);
|
|
10
|
+
};
|
|
11
|
+
export default ModalPreview;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
interface BoardTemplateProps {
|
|
2
2
|
onSelectComponent?: (items: any) => void;
|
|
3
3
|
}
|
|
4
|
-
declare const BoardTemplate: ({ onSelectComponent }: BoardTemplateProps) => import("react
|
|
4
|
+
declare const BoardTemplate: ({ onSelectComponent }: BoardTemplateProps) => import("react").JSX.Element;
|
|
5
5
|
export default BoardTemplate;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { TransformWrapper, TransformComponent, } from "react-zoom-pan-pinch";
|
|
4
|
+
import { useAppSelector, useAppDispatch } from "../../hooks/use-redux";
|
|
5
|
+
import Layers from "../../components/layer";
|
|
6
|
+
import { throttle } from "lodash";
|
|
7
|
+
import ModalPreview from "../../components/modal-preview";
|
|
8
|
+
import LayerView from "../view";
|
|
9
|
+
const BoardTemplate = ({ onSelectComponent }) => {
|
|
10
|
+
const dispatch = useAppDispatch();
|
|
11
|
+
const transformRef = useRef(null);
|
|
12
|
+
const containerRef = useRef(null);
|
|
13
|
+
const [widthBoard, setWidthBoard] = useState(0);
|
|
14
|
+
const [heightBoard, setHeightBoard] = useState(0);
|
|
15
|
+
const svgRef = useRef(null);
|
|
16
|
+
const [shadowShape, setShadowShape] = useState([]);
|
|
17
|
+
const [startPoint, setStartPoint] = useState(null);
|
|
18
|
+
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
|
19
|
+
const [moveComponent, setMoveComponent] = useState(false);
|
|
20
|
+
const [scale, setScale] = useState(1);
|
|
21
|
+
const activeTool = useAppSelector((state) => state.tool.active);
|
|
22
|
+
const { components, extraComponents } = useAppSelector((state) => state.board);
|
|
23
|
+
const backgroundColor = useAppSelector((state) => state.board.backgroundColor);
|
|
24
|
+
const selectedComponent = useAppSelector((state) => state.panel.selectedComponent);
|
|
25
|
+
// useEffect(() => {
|
|
26
|
+
// const handleKeyDown = (event: KeyboardEvent) => {
|
|
27
|
+
// if (event.key === 'Backspace' && selectedComponent) {
|
|
28
|
+
// dispatch({
|
|
29
|
+
// type:"board/removeComponent",
|
|
30
|
+
// payload:selectedComponent
|
|
31
|
+
// })
|
|
32
|
+
// dispatch({
|
|
33
|
+
// type:"panel/setUnSelectedComponent",
|
|
34
|
+
// })
|
|
35
|
+
// }
|
|
36
|
+
// };
|
|
37
|
+
// window.addEventListener('keydown', handleKeyDown);
|
|
38
|
+
// return () => {
|
|
39
|
+
// window.removeEventListener('keydown', handleKeyDown);
|
|
40
|
+
// };
|
|
41
|
+
// }, [selectedComponent]);
|
|
42
|
+
const handleAddComponent = (shape) => {
|
|
43
|
+
dispatch({
|
|
44
|
+
type: activeTool === "text"
|
|
45
|
+
? "board/setExtraComponent"
|
|
46
|
+
: "board/addComponent",
|
|
47
|
+
payload: Object.assign(Object.assign({}, shape), { fill: "#4A90E2" }),
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
const handleUpdateComponent = () => {
|
|
51
|
+
if (!selectedComponent)
|
|
52
|
+
return;
|
|
53
|
+
dispatch({
|
|
54
|
+
type: "board/updateComponent",
|
|
55
|
+
payload: Object.assign({}, (typeof selectedComponent === "object" && selectedComponent !== null
|
|
56
|
+
? selectedComponent
|
|
57
|
+
: {})),
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const getSvgCoords = (e) => {
|
|
61
|
+
var _a;
|
|
62
|
+
const svg = svgRef.current;
|
|
63
|
+
const point = svg.createSVGPoint();
|
|
64
|
+
point.x = e.clientX;
|
|
65
|
+
point.y = e.clientY;
|
|
66
|
+
const transformed = point.matrixTransform((_a = svg.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse());
|
|
67
|
+
return { x: transformed.x, y: transformed.y };
|
|
68
|
+
};
|
|
69
|
+
const createShape = (x, y, fill) => ({
|
|
70
|
+
x,
|
|
71
|
+
y,
|
|
72
|
+
width: 50,
|
|
73
|
+
height: 50,
|
|
74
|
+
shape: activeTool,
|
|
75
|
+
id: Date.now(),
|
|
76
|
+
fill,
|
|
77
|
+
rotation: activeTool === "diamond" ? 45 : 0,
|
|
78
|
+
seatCount: activeTool === "table-seat-circle" ? 6 : 0,
|
|
79
|
+
openSpace: activeTool === "table-seat-circle" ? 0 : undefined,
|
|
80
|
+
seatFill: activeTool === "table-seat-circle" ? "#DADADA" : undefined,
|
|
81
|
+
text: activeTool === "text" ? "Text" : "",
|
|
82
|
+
fontColor: activeTool === "text" ? "#DADADA" : undefined,
|
|
83
|
+
});
|
|
84
|
+
// console.log({ moveComponent})
|
|
85
|
+
const handleMouseDown = (e, item) => {
|
|
86
|
+
// console.log(" mouse down", item);
|
|
87
|
+
// if (!isEmpty(item)) {
|
|
88
|
+
// handleSelectComponent(item);
|
|
89
|
+
// }
|
|
90
|
+
if (activeTool === "select") {
|
|
91
|
+
if (e) {
|
|
92
|
+
dispatch({ type: "panel/setShow", payload: false });
|
|
93
|
+
setMoveComponent(true);
|
|
94
|
+
dispatch({ type: "panel/setSelectedComponent", payload: item });
|
|
95
|
+
const rectBox = (e === null || e === void 0 ? void 0 : e.target).getBoundingClientRect();
|
|
96
|
+
setDragOffset({
|
|
97
|
+
x: e.clientX - rectBox.left,
|
|
98
|
+
y: e.clientY - rectBox.top,
|
|
99
|
+
});
|
|
100
|
+
// dispatch({ type: "panel/setShow" , payload: false });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const handleMouseUp = () => {
|
|
105
|
+
if (activeTool === "select") {
|
|
106
|
+
setMoveComponent(false);
|
|
107
|
+
dispatch({ type: "panel/setShow", payload: false });
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const handleMouseEnter = () => {
|
|
111
|
+
if (![
|
|
112
|
+
"square",
|
|
113
|
+
"circle",
|
|
114
|
+
"diamond",
|
|
115
|
+
"table-seat-circle",
|
|
116
|
+
"table-seat-square",
|
|
117
|
+
"text",
|
|
118
|
+
].includes(activeTool))
|
|
119
|
+
return;
|
|
120
|
+
};
|
|
121
|
+
const handleMouseLeave = () => {
|
|
122
|
+
if (![
|
|
123
|
+
"square",
|
|
124
|
+
"circle",
|
|
125
|
+
"diamond",
|
|
126
|
+
"table-seat-circle",
|
|
127
|
+
"table-seat-square",
|
|
128
|
+
"text",
|
|
129
|
+
].includes(activeTool))
|
|
130
|
+
return;
|
|
131
|
+
setShadowShape([]);
|
|
132
|
+
};
|
|
133
|
+
const handleMouseClick = (e) => {
|
|
134
|
+
if (![
|
|
135
|
+
"square",
|
|
136
|
+
"circle",
|
|
137
|
+
"diamond",
|
|
138
|
+
"table-seat-circle",
|
|
139
|
+
"table-seat-square",
|
|
140
|
+
"text",
|
|
141
|
+
].includes(activeTool))
|
|
142
|
+
return;
|
|
143
|
+
const { x, y } = getSvgCoords(event);
|
|
144
|
+
setStartPoint({ x, y });
|
|
145
|
+
handleAddComponent(createShape(x, y, "#4A90E2"));
|
|
146
|
+
};
|
|
147
|
+
const throttledDispatch = useCallback(throttle((component) => {
|
|
148
|
+
dispatch({
|
|
149
|
+
type: "board/updateComponent",
|
|
150
|
+
payload: component,
|
|
151
|
+
});
|
|
152
|
+
}, 16), // 16ms ≈ 60fps
|
|
153
|
+
[dispatch]);
|
|
154
|
+
const handleMouseMove = (e) => {
|
|
155
|
+
if ([
|
|
156
|
+
"square",
|
|
157
|
+
"circle",
|
|
158
|
+
"diamond",
|
|
159
|
+
"table-seat-circle",
|
|
160
|
+
"table-seat-square",
|
|
161
|
+
"text",
|
|
162
|
+
].includes(activeTool)) {
|
|
163
|
+
const { x, y } = getSvgCoords(event);
|
|
164
|
+
setShadowShape([createShape(x, y, "white")]);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (activeTool === "select" &&
|
|
168
|
+
selectedComponent &&
|
|
169
|
+
moveComponent &&
|
|
170
|
+
dragOffset) {
|
|
171
|
+
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
172
|
+
const newX = e.clientX - workspaceRect.left - dragOffset.x;
|
|
173
|
+
const newY = e.clientY - workspaceRect.top - dragOffset.y;
|
|
174
|
+
let newPosition = {
|
|
175
|
+
x: newX,
|
|
176
|
+
y: newY,
|
|
177
|
+
};
|
|
178
|
+
throttledDispatch(Object.assign(Object.assign({}, (typeof selectedComponent === "object" && selectedComponent !== null
|
|
179
|
+
? selectedComponent
|
|
180
|
+
: {})), { x: newPosition.x, y: newPosition.y }));
|
|
181
|
+
// dispatch({
|
|
182
|
+
// type: "board/updateComponent",
|
|
183
|
+
// payload: {
|
|
184
|
+
// ...(typeof selectedComponent === "object" &&
|
|
185
|
+
// selectedComponent !== null
|
|
186
|
+
// ? selectedComponent
|
|
187
|
+
// : {}),
|
|
188
|
+
// x: newPosition.x,
|
|
189
|
+
// y: newPosition.y,
|
|
190
|
+
// },
|
|
191
|
+
// });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
// if (activeTool === "table-seat-circle") {
|
|
196
|
+
// shape = {
|
|
197
|
+
// x: Math.min(x, startPoint.x),
|
|
198
|
+
// y: Math.min(y, startPoint.y),
|
|
199
|
+
// width: Math.abs(x - startPoint.x),
|
|
200
|
+
// height: Math.abs(y - startPoint.y),
|
|
201
|
+
// shape: activeTool,
|
|
202
|
+
// id: Date.now(),
|
|
203
|
+
// fill: "#4A90E2",
|
|
204
|
+
// seats: 6,
|
|
205
|
+
// };
|
|
206
|
+
// }
|
|
207
|
+
// if (activeTool === "text") {
|
|
208
|
+
// shape = {
|
|
209
|
+
// x: Math.min(x, startPoint.x),
|
|
210
|
+
// y: Math.min(y, startPoint.y),
|
|
211
|
+
// width: Math.abs(x - startPoint.x),
|
|
212
|
+
// height: Math.abs(y - startPoint.y),
|
|
213
|
+
// shape: activeTool,
|
|
214
|
+
// id: Date.now(),
|
|
215
|
+
// fill: "#4A90E2",
|
|
216
|
+
// text: "Text",
|
|
217
|
+
// };
|
|
218
|
+
// }
|
|
219
|
+
// if (activeTool === "select" && selectedComponent) {
|
|
220
|
+
// shape = {
|
|
221
|
+
// ...selectedComponent,
|
|
222
|
+
// x: Math.min(x, startPoint.x),
|
|
223
|
+
// y: Math.min(y, startPoint.y),
|
|
224
|
+
// width: Math.abs(x - startPoint.x),
|
|
225
|
+
// height: Math.abs(y - startPoint.y),
|
|
226
|
+
// };
|
|
227
|
+
// setSelectedComponent(shape);
|
|
228
|
+
// return;
|
|
229
|
+
// }
|
|
230
|
+
// }
|
|
231
|
+
const handleSelectComponent = (items) => {
|
|
232
|
+
if (activeTool === "select") {
|
|
233
|
+
// if (isEmpty(items)) {
|
|
234
|
+
// dispatch({ type: "panel/setSelectedComponent", payload: null });
|
|
235
|
+
// setMoveComponent(false);
|
|
236
|
+
// } else {
|
|
237
|
+
onSelectComponent && onSelectComponent(items);
|
|
238
|
+
dispatch({ type: "panel/setSelectedComponent", payload: items });
|
|
239
|
+
dispatch({ type: "panel/setShow", payload: true });
|
|
240
|
+
// }
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (containerRef.current) {
|
|
245
|
+
setWidthBoard(containerRef.current.offsetWidth);
|
|
246
|
+
setHeightBoard(containerRef.current.offsetHeight);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
const handleUnSelectComponent = () => {
|
|
250
|
+
dispatch({ type: "panel/setSelectedComponent", payload: null });
|
|
251
|
+
};
|
|
252
|
+
return (<>
|
|
253
|
+
<ModalPreview>
|
|
254
|
+
<LayerView statusKey="status"/>
|
|
255
|
+
</ModalPreview>
|
|
256
|
+
<div className="relative w-full h-screen flex-1" ref={containerRef}>
|
|
257
|
+
<TransformWrapper ref={transformRef} panning={{ disabled: false }} centerZoomedOut={true} onTransformed={({ state: { scale } }) => setScale(scale)} minScale={1} // sangat kecil = bisa zoom out jauh
|
|
258
|
+
maxScale={1000} initialScale={1} pinch={{ step: 1 }} smooth={true}
|
|
259
|
+
// doubleClick={{ step: 2, mode: "zoomIn" }}
|
|
260
|
+
disablePadding>
|
|
261
|
+
<TransformComponent wrapperStyle={{
|
|
262
|
+
width: "100%",
|
|
263
|
+
height: "100%",
|
|
264
|
+
overflow: "hidden",
|
|
265
|
+
}} contentStyle={{
|
|
266
|
+
width: "100%",
|
|
267
|
+
height: "100%",
|
|
268
|
+
}}>
|
|
269
|
+
<svg id="workspace" ref={svgRef} width="100%" height="100%" viewBox={`0 0 ${widthBoard} ${heightBoard}`} className="h-screen" onMouseUp={handleMouseUp} onMouseMove={handleMouseMove} onMouseEnter={handleMouseEnter} onClick={(e) => {
|
|
270
|
+
e.stopPropagation();
|
|
271
|
+
handleMouseClick(e);
|
|
272
|
+
}} onMouseLeave={handleMouseLeave}
|
|
273
|
+
// onMouseDown={(e) => {
|
|
274
|
+
// e.stopPropagation();
|
|
275
|
+
// }}
|
|
276
|
+
// onFocus={(e) => {
|
|
277
|
+
// console.log(e.target);
|
|
278
|
+
// }}
|
|
279
|
+
xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" style={{
|
|
280
|
+
background: backgroundColor,
|
|
281
|
+
display: "block",
|
|
282
|
+
}}>
|
|
283
|
+
<Layers shadowShape={shadowShape} components={[...extraComponents, ...components]} onClick={handleSelectComponent} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} onBlur={handleUnSelectComponent} selectedComponent={selectedComponent} activeTool={activeTool}/>
|
|
284
|
+
</svg>
|
|
285
|
+
</TransformComponent>
|
|
286
|
+
</TransformWrapper>
|
|
287
|
+
</div>
|
|
288
|
+
</>);
|
|
289
|
+
};
|
|
290
|
+
export default BoardTemplate;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const Navbar: () => import("react
|
|
1
|
+
declare const Navbar: () => import("react").JSX.Element;
|
|
2
2
|
export default Navbar;
|