seat-editor 1.2.26 → 1.2.28
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/dist/app/layout.js +22 -0
- package/dist/app/new-board/page.js +7 -0
- package/dist/app/old-board/page.js +382 -0
- package/dist/app/only-view/page.js +40 -0
- package/dist/app/only-view/page.jsx +5 -2
- package/dist/app/page.js +8 -0
- package/dist/components/button-tools/index.js +11 -0
- package/dist/components/form-tools/label.js +7 -0
- package/dist/components/form-tools/shape.js +7 -0
- package/dist/components/input/number-indicator.js +27 -0
- package/dist/components/layer/index.js +168 -0
- package/dist/components/lib/index.js +28 -0
- package/dist/components/modal-preview/index.js +10 -0
- package/dist/features/board/index.js +297 -0
- package/dist/features/navbar/index.js +6 -0
- package/dist/features/package/index.js +41 -0
- package/dist/features/panel/index.js +78 -0
- package/dist/features/panel/select-tool.js +36 -0
- package/dist/features/panel/square-circle-tool.js +8 -0
- package/dist/features/panel/table-seat-circle.js +9 -0
- package/dist/features/panel/text-tool.js +7 -0
- package/dist/features/panel/upload-tool.js +119 -0
- package/dist/features/side-tool/index.js +197 -0
- package/dist/features/view/index.d.ts +2 -0
- package/dist/features/view/index.js +156 -0
- package/dist/features/view/index.jsx +15 -7
- package/dist/provider/antd-provider.js +27 -0
- package/dist/provider/redux-provider.js +7 -0
- package/dist/provider/store-provider.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import localFont from "next/font/local";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
import { Layout } from "antd";
|
|
5
|
+
import { StoreProvider } from "../provider/store-provider";
|
|
6
|
+
const geistSans = localFont({
|
|
7
|
+
src: "./fonts/GeistVF.woff",
|
|
8
|
+
variable: "--font-geist-sans",
|
|
9
|
+
weight: "100 900",
|
|
10
|
+
});
|
|
11
|
+
const geistMono = localFont({
|
|
12
|
+
src: "./fonts/GeistMonoVF.woff",
|
|
13
|
+
variable: "--font-geist-mono",
|
|
14
|
+
weight: "100 900",
|
|
15
|
+
});
|
|
16
|
+
export const metadata = {
|
|
17
|
+
title: "Create Next App",
|
|
18
|
+
description: "Generated by create next app",
|
|
19
|
+
};
|
|
20
|
+
export default function RootLayout({ children, }) {
|
|
21
|
+
return (_jsx("html", { lang: "en", children: _jsx("body", { className: `${geistSans.variable} ${geistMono.variable} antialiased`, children: _jsx(StoreProvider, { children: _jsx(Layout, { children: children }) }) }) }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import Board from "../../features/board";
|
|
3
|
+
import SideTool from "../../features/side-tool";
|
|
4
|
+
import ControlPanels from "../../features/panel";
|
|
5
|
+
export default function NewBoard() {
|
|
6
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { className: "w-full h-screen flex relative", children: [_jsx(SideTool, {}), _jsx(Board, {}), _jsx(ControlPanels, {})] }) }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Button, Input, Modal } from "antd"; //tes commit
|
|
5
|
+
// aduhuhhusd
|
|
6
|
+
import { Square, MousePointer2, Move3D, Trash, CopyPlusIcon, ZoomInIcon, ZoomOutIcon, DownloadIcon, UploadIcon, Circle, PenIcon, Pencil, } from "lucide-react";
|
|
7
|
+
import { SketchPicker } from "react-color";
|
|
8
|
+
const SeatEditor = () => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const [activeTool, setActiveTool] = useState(null);
|
|
11
|
+
const [rectangles, setRectangles] = useState([]);
|
|
12
|
+
const [selectedRectangle, setSelectedRectangle] = useState(null);
|
|
13
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
14
|
+
const [startPoint, setStartPoint] = useState(null);
|
|
15
|
+
const [shadowRect, setShadowRect] = useState(null);
|
|
16
|
+
const [showModal, setShowModal] = useState(false);
|
|
17
|
+
const [dragOffset, setDragOffset] = useState(null);
|
|
18
|
+
console.log({ rectangles });
|
|
19
|
+
const [zoom, setZoom] = useState(1);
|
|
20
|
+
const [resizeDirection, setResizeDirection] = useState(null);
|
|
21
|
+
const [images, setImages] = useState([]);
|
|
22
|
+
const [penPaths, setPenPaths] = useState([]);
|
|
23
|
+
const [currentPath, setCurrentPath] = useState(null);
|
|
24
|
+
const [isDrawing, setIsDrawing] = useState(false);
|
|
25
|
+
// upload image
|
|
26
|
+
const widthWorkspace = ((_a = document.getElementById("workspace")) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0;
|
|
27
|
+
const heightWorkspace = ((_b = document.getElementById("workspace")) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;
|
|
28
|
+
const handleImageUploadBackground = (e) => {
|
|
29
|
+
var _a;
|
|
30
|
+
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
31
|
+
if (!file)
|
|
32
|
+
return;
|
|
33
|
+
console.log({ file });
|
|
34
|
+
const reader = new FileReader();
|
|
35
|
+
reader.onload = () => {
|
|
36
|
+
const img = document.createElement("img");
|
|
37
|
+
img.src = reader.result;
|
|
38
|
+
console.log({ img });
|
|
39
|
+
let width = img.width > widthWorkspace ? img.width / 2 : img.width;
|
|
40
|
+
let height = img.height > heightWorkspace ? img.height / 2 : img.height;
|
|
41
|
+
console.log({ width, height }, img.width, img.height);
|
|
42
|
+
img.onload = () => {
|
|
43
|
+
setRectangles((prev) => [
|
|
44
|
+
...prev,
|
|
45
|
+
{
|
|
46
|
+
id: rectangles.length + 1,
|
|
47
|
+
x: 100,
|
|
48
|
+
y: 100,
|
|
49
|
+
width: width < 1 ? 100 : width,
|
|
50
|
+
height: height < 1 ? 100 : height,
|
|
51
|
+
rotation: 0,
|
|
52
|
+
shape: "image",
|
|
53
|
+
src: img.src,
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
reader.readAsDataURL(file);
|
|
59
|
+
};
|
|
60
|
+
const handleImageUpload = (e) => {
|
|
61
|
+
var _a;
|
|
62
|
+
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
63
|
+
if (!file)
|
|
64
|
+
return;
|
|
65
|
+
const reader = new FileReader();
|
|
66
|
+
reader.onload = () => {
|
|
67
|
+
const img = document.createElement("img");
|
|
68
|
+
img.src = reader.result;
|
|
69
|
+
let width = img.width > widthWorkspace ? img.width / 2 : img.width;
|
|
70
|
+
let height = img.height > heightWorkspace ? img.height / 2 : img.height;
|
|
71
|
+
img.onload = () => {
|
|
72
|
+
setRectangles((prev) => [
|
|
73
|
+
...prev,
|
|
74
|
+
{
|
|
75
|
+
id: rectangles.length + 1,
|
|
76
|
+
x: 100,
|
|
77
|
+
y: 100,
|
|
78
|
+
width: width < 1 ? 100 : width,
|
|
79
|
+
height: height < 1 ? 100 : height,
|
|
80
|
+
rotation: 0,
|
|
81
|
+
shape: "image-table",
|
|
82
|
+
src: img.src,
|
|
83
|
+
pax: "4 Pax",
|
|
84
|
+
highlightColor: "#C1443D",
|
|
85
|
+
status: "SOLD",
|
|
86
|
+
table: `V${rectangles.length + 1}`,
|
|
87
|
+
},
|
|
88
|
+
]);
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
reader.readAsDataURL(file);
|
|
92
|
+
};
|
|
93
|
+
// zoom in out
|
|
94
|
+
const zoomIn = () => setZoom((prev) => prev + 0.1);
|
|
95
|
+
const zoomOut = () => setZoom((prev) => Math.max(0.1, prev - 0.1));
|
|
96
|
+
const handleToolClick = (tool) => {
|
|
97
|
+
setActiveTool(tool);
|
|
98
|
+
setSelectedRectangle(null); // Deselect any rectangle when switching tools
|
|
99
|
+
};
|
|
100
|
+
// === Drawing Rectangle ===
|
|
101
|
+
const handleMouseDown = (e) => {
|
|
102
|
+
if (activeTool === "rectangle" ||
|
|
103
|
+
activeTool === "circle" ||
|
|
104
|
+
activeTool === "vip-seat") {
|
|
105
|
+
const rect = e.target.getBoundingClientRect();
|
|
106
|
+
setStartPoint({ x: e.clientX - rect.left, y: e.clientY - rect.top });
|
|
107
|
+
setIsDragging(true);
|
|
108
|
+
}
|
|
109
|
+
if (activeTool === "pen") {
|
|
110
|
+
const rect = e.target.getBoundingClientRect();
|
|
111
|
+
const newPoint = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
112
|
+
setCurrentPath({
|
|
113
|
+
id: penPaths.length + 1,
|
|
114
|
+
points: [newPoint],
|
|
115
|
+
color: "#fff", // Default white stroke
|
|
116
|
+
strokeWidth: 2, // Default stroke width
|
|
117
|
+
});
|
|
118
|
+
setIsDrawing(true);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
// rotate logic
|
|
122
|
+
const rotateRectangle = (direction) => {
|
|
123
|
+
if (selectedRectangle) {
|
|
124
|
+
const rotationChange = direction === "left" ? -5 : 5; // Rotate 5 degrees
|
|
125
|
+
const newRotation = (selectedRectangle.rotation + rotationChange) % 360;
|
|
126
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id
|
|
127
|
+
? Object.assign(Object.assign({}, rect), { rotation: newRotation }) : rect));
|
|
128
|
+
setSelectedRectangle((prev) => prev ? Object.assign(Object.assign({}, prev), { rotation: newRotation }) : null);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const handleMouseMove = (e) => {
|
|
132
|
+
// Resize logic for node tool
|
|
133
|
+
if (activeTool === "node" &&
|
|
134
|
+
isDragging &&
|
|
135
|
+
resizeDirection &&
|
|
136
|
+
selectedRectangle) {
|
|
137
|
+
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
138
|
+
const currentX = e.clientX - workspaceRect.left;
|
|
139
|
+
const currentY = e.clientY - workspaceRect.top;
|
|
140
|
+
let newRect = Object.assign({}, selectedRectangle);
|
|
141
|
+
switch (resizeDirection) {
|
|
142
|
+
case "top-left":
|
|
143
|
+
newRect.width += newRect.x - currentX;
|
|
144
|
+
newRect.height =
|
|
145
|
+
selectedRectangle.shape === "circle"
|
|
146
|
+
? newRect.width
|
|
147
|
+
: newRect.height + (newRect.y - currentY);
|
|
148
|
+
newRect.x = currentX;
|
|
149
|
+
newRect.y =
|
|
150
|
+
selectedRectangle.shape === "circle" ? newRect.y : currentY;
|
|
151
|
+
break;
|
|
152
|
+
case "top-right":
|
|
153
|
+
newRect.width = currentX - newRect.x;
|
|
154
|
+
newRect.height =
|
|
155
|
+
selectedRectangle.shape === "circle"
|
|
156
|
+
? newRect.width
|
|
157
|
+
: newRect.height + (newRect.y - currentY);
|
|
158
|
+
newRect.y =
|
|
159
|
+
selectedRectangle.shape === "circle" ? newRect.y : currentY;
|
|
160
|
+
break;
|
|
161
|
+
case "bottom-left":
|
|
162
|
+
newRect.width += newRect.x - currentX;
|
|
163
|
+
newRect.height =
|
|
164
|
+
selectedRectangle.shape === "circle"
|
|
165
|
+
? newRect.width
|
|
166
|
+
: currentY - newRect.y;
|
|
167
|
+
newRect.x = currentX;
|
|
168
|
+
break;
|
|
169
|
+
case "bottom-right":
|
|
170
|
+
newRect.width = currentX - newRect.x;
|
|
171
|
+
newRect.height =
|
|
172
|
+
selectedRectangle.shape === "circle"
|
|
173
|
+
? newRect.width
|
|
174
|
+
: currentY - newRect.y;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
// Ensure width and height are always positive
|
|
178
|
+
newRect.width = Math.max(10, newRect.width);
|
|
179
|
+
newRect.height = Math.max(10, newRect.height);
|
|
180
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id ? Object.assign({}, newRect) : rect));
|
|
181
|
+
setSelectedRectangle(newRect);
|
|
182
|
+
}
|
|
183
|
+
if ((activeTool === "rectangle" ||
|
|
184
|
+
activeTool === "circle" ||
|
|
185
|
+
activeTool === "vip-seat") &&
|
|
186
|
+
isDragging &&
|
|
187
|
+
startPoint) {
|
|
188
|
+
const rect = e.target.getBoundingClientRect();
|
|
189
|
+
const currentX = e.clientX - rect.left;
|
|
190
|
+
const currentY = e.clientY - rect.top;
|
|
191
|
+
// Update shadow rectangle dimensions dynamically
|
|
192
|
+
const newShadowRect = {
|
|
193
|
+
id: -1, // Temporary ID for preview
|
|
194
|
+
x: Math.min(startPoint.x, currentX),
|
|
195
|
+
y: Math.min(startPoint.y, currentY),
|
|
196
|
+
width: Math.abs(currentX - startPoint.x),
|
|
197
|
+
height: Math.abs(currentY - startPoint.y),
|
|
198
|
+
color: activeTool === "vip-seat" ? "#2D2D36" : "rgba(74, 144, 226, 0.4)", // Light blue with transparency
|
|
199
|
+
pax: "",
|
|
200
|
+
rotation: 0,
|
|
201
|
+
shape: activeTool === "vip-seat" ? "vip-seat" : activeTool, // Define shape type
|
|
202
|
+
highlightColor: activeTool === "vip-seat" ? "#C1443D" : undefined, // Red section in VIP
|
|
203
|
+
status: activeTool === "vip-seat" ? "SOLD" : undefined,
|
|
204
|
+
table: activeTool === "vip-seat" ? `V${rectangles.length + 1}` : undefined, // Table number for VIP
|
|
205
|
+
};
|
|
206
|
+
setShadowRect(newShadowRect);
|
|
207
|
+
}
|
|
208
|
+
// Dragging for select tool
|
|
209
|
+
if (activeTool === "select" &&
|
|
210
|
+
isDragging &&
|
|
211
|
+
selectedRectangle &&
|
|
212
|
+
dragOffset) {
|
|
213
|
+
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
214
|
+
const newX = e.clientX - workspaceRect.left - dragOffset.x;
|
|
215
|
+
const newY = e.clientY - workspaceRect.top - dragOffset.y;
|
|
216
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id
|
|
217
|
+
? Object.assign(Object.assign({}, rect), { x: newX, y: newY }) : rect));
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const handleMouseUp = () => {
|
|
221
|
+
setIsDragging(false);
|
|
222
|
+
setResizeDirection(null);
|
|
223
|
+
if ((activeTool === "rectangle" ||
|
|
224
|
+
activeTool === "circle" ||
|
|
225
|
+
activeTool === "vip-seat") &&
|
|
226
|
+
isDragging &&
|
|
227
|
+
shadowRect) {
|
|
228
|
+
// Finalize the rectangle on mouse release
|
|
229
|
+
const newRectangle = Object.assign(Object.assign({}, shadowRect), { id: rectangles.length + 1, color: "#4A90E2", pax: activeTool === "vip-seat" ? "4 Pax" : "Seat", highlightColor: activeTool === "vip-seat" ? "#C1443D" : undefined, status: activeTool === "vip-seat" ? "SOLD" : undefined, table: activeTool === "vip-seat" ? "V1" : undefined });
|
|
230
|
+
setRectangles([...rectangles, newRectangle]);
|
|
231
|
+
setImages((prev) => prev.map((img) => img.id === (selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id)
|
|
232
|
+
? Object.assign(Object.assign({}, img), { x: newRectangle.x, y: newRectangle.y }) : img));
|
|
233
|
+
setShadowRect(null); // Clear shadow preview
|
|
234
|
+
setIsDragging(false);
|
|
235
|
+
setStartPoint(null);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const handleRectangleMouseDown = (e, rect) => {
|
|
239
|
+
if (activeTool === "select" || activeTool === "node") {
|
|
240
|
+
setSelectedRectangle(rect);
|
|
241
|
+
const rectBox = e.target.getBoundingClientRect();
|
|
242
|
+
setDragOffset({
|
|
243
|
+
x: e.clientX - rectBox.left,
|
|
244
|
+
y: e.clientY - rectBox.top,
|
|
245
|
+
});
|
|
246
|
+
setIsDragging(true);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
const handleRectangleDoubleClick = (rect) => {
|
|
250
|
+
if (activeTool === "select" || activeTool === "node") {
|
|
251
|
+
setSelectedRectangle(rect);
|
|
252
|
+
setShowModal(true);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const updateRectangle = (updates) => {
|
|
256
|
+
if (selectedRectangle) {
|
|
257
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id ? Object.assign(Object.assign({}, rect), updates) : rect));
|
|
258
|
+
setSelectedRectangle((prev) => (prev ? Object.assign(Object.assign({}, prev), updates) : null));
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
const startResizing = (direction) => {
|
|
262
|
+
setResizeDirection(direction);
|
|
263
|
+
setIsDragging(true);
|
|
264
|
+
};
|
|
265
|
+
// Set the cursor style based on the active tool
|
|
266
|
+
const getCursorStyle = () => {
|
|
267
|
+
if (activeTool === "rectangle" ||
|
|
268
|
+
activeTool === "circle" ||
|
|
269
|
+
activeTool === "vip-seat")
|
|
270
|
+
return "cursor-crosshair";
|
|
271
|
+
if (activeTool === "select")
|
|
272
|
+
return "cursor-default";
|
|
273
|
+
if (activeTool === "node")
|
|
274
|
+
return "cursor-pointer";
|
|
275
|
+
return "cursor-default";
|
|
276
|
+
};
|
|
277
|
+
const deleteSelectedRectangle = () => {
|
|
278
|
+
if (selectedRectangle) {
|
|
279
|
+
setRectangles((prev) => prev.filter((rect) => rect.id !== selectedRectangle.id));
|
|
280
|
+
setSelectedRectangle(null);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
// duplicate
|
|
284
|
+
const duplicateRectangle = () => {
|
|
285
|
+
if (selectedRectangle) {
|
|
286
|
+
const newRectangle = Object.assign(Object.assign({}, selectedRectangle), { id: rectangles.length + 1, x: selectedRectangle.x + 20, y: selectedRectangle.y + 20 });
|
|
287
|
+
setRectangles([...rectangles, newRectangle]);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const exportJSON = () => {
|
|
291
|
+
console.log({ rectangles, images });
|
|
292
|
+
// const json = JSON.stringify(rectangles, null, 2);
|
|
293
|
+
// const blob = new Blob([json], { type: "application/json" });
|
|
294
|
+
// const link = document.createElement("a");
|
|
295
|
+
// link.href = URL.createObjectURL(blob);
|
|
296
|
+
// link.download = "seat_layout.json";
|
|
297
|
+
// document.body.appendChild(link);
|
|
298
|
+
// link.click();
|
|
299
|
+
// document.body.removeChild(link);
|
|
300
|
+
};
|
|
301
|
+
return (_jsxs("div", { className: "flex h-screen w-full", children: [_jsxs("div", { className: "w-16 bg-gray-800 text-white flex flex-col items-center py-4 space-y-4", children: [_jsx(Button, { type: activeTool === "select" ? "primary" : "default", shape: "circle", icon: _jsx(MousePointer2, {}), onClick: () => handleToolClick("select") }), _jsx(Button, { type: activeTool === "circle" ? "primary" : "default", shape: "circle", icon: _jsx(Circle, {}), onClick: () => handleToolClick("circle") }), _jsx(Button, { type: activeTool === "vip-seat" ? "primary" : "default", shape: "circle", icon: _jsx(PenIcon, {}), onClick: () => handleToolClick("vip-seat") }), _jsx(Button, { type: activeTool === "rectangle" ? "primary" : "default", shape: "circle", icon: _jsx(Square, {}), onClick: () => handleToolClick("rectangle") }), _jsx(Button, { type: activeTool === "node" ? "primary" : "default", shape: "circle", icon: _jsx(Move3D, {}), onClick: () => handleToolClick("node") }), _jsx(Button, { type: activeTool === "pen" ? "primary" : "default", shape: "circle", icon: _jsx(Pencil, {}), onClick: () => handleToolClick("pen") }), _jsx(Button, { type: "default", shape: "circle", icon: _jsx(Trash, {}), onClick: deleteSelectedRectangle }), _jsx(Button, { type: "default", shape: "circle", icon: _jsx(CopyPlusIcon, {}), onClick: duplicateRectangle }), _jsx(Button, { type: "default", shape: "circle", onClick: zoomIn, icon: _jsx(ZoomInIcon, {}) }), _jsx(Button, { type: "default", shape: "circle", onClick: zoomOut, icon: _jsx(ZoomOutIcon, {}) }), _jsx(UploadIcon, {}), _jsx("span", { children: "Image Seat" }), _jsx("input", { type: "file", accept: "image/*", onChange: handleImageUpload }), _jsx("span", { children: "Background Image" }), _jsx("input", { type: "file", accept: "image/*", onChange: handleImageUploadBackground }), _jsx(Button, { shape: "circle", icon: _jsx(DownloadIcon, {}), onClick: exportJSON })] }), _jsx("div", { className: "w-full flex items-center justify-center", id: "workspace", children: _jsxs("div", { className: `bg-gray-900 relative ${getCursorStyle()} w-full h-screen `, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, style: {
|
|
302
|
+
transform: `scale(${zoom})`,
|
|
303
|
+
transformOrigin: "0 0",
|
|
304
|
+
}, children: [shadowRect && (_jsx("div", { className: "absolute border-dashed border-2 border-blue-400", style: {
|
|
305
|
+
left: shadowRect.x,
|
|
306
|
+
top: shadowRect.y,
|
|
307
|
+
width: shadowRect.width,
|
|
308
|
+
height: shadowRect.height,
|
|
309
|
+
backgroundColor: shadowRect.color,
|
|
310
|
+
} })), rectangles.map((rect) => (_jsxs("div", { onMouseDown: (e) => handleRectangleMouseDown(e, rect), onDoubleClick: () => handleRectangleDoubleClick(rect), className: `absolute cursor-move border transition-transform ${(selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id) === rect.id
|
|
311
|
+
? "border-black"
|
|
312
|
+
: "border-gray-300"}`, style: {
|
|
313
|
+
left: rect.x,
|
|
314
|
+
top: rect.y,
|
|
315
|
+
width: rect.width,
|
|
316
|
+
height: rect.height,
|
|
317
|
+
backgroundColor: rect.color,
|
|
318
|
+
transform: `rotate(${rect.rotation}deg)`,
|
|
319
|
+
transformOrigin: "center",
|
|
320
|
+
borderRadius: rect.shape === "circle" ? "100%" : "0%",
|
|
321
|
+
}, children: [rect.shape === "image-table" && (_jsxs("div", { className: "w-full h-full relative", children: [_jsx("img", { src: rect.src, alt: "custom", className: "w-full h-full object-cover", draggable: false }), _jsx("div", { className: "absolute left-0 right-0 flex items-center justify-center", style: {
|
|
322
|
+
top: "10%",
|
|
323
|
+
height: "20%",
|
|
324
|
+
backgroundColor: rect.highlightColor || "transparent",
|
|
325
|
+
}, children: _jsx("span", { className: "text-white font-bold text-xs absolute", style: {
|
|
326
|
+
top: "10%",
|
|
327
|
+
left: "50%",
|
|
328
|
+
}, children: rect.table }) }), _jsx("span", { className: "text-xs text-white flex items-center justify-center absolute w-full", style: {
|
|
329
|
+
top: "85%",
|
|
330
|
+
left: "50%",
|
|
331
|
+
transform: "translate(-50%, -50%)",
|
|
332
|
+
backgroundColor: rect.highlightColor || "transparent"
|
|
333
|
+
}, children: rect.pax }), _jsx("div", { className: "absolute left-0 right-0 flex items-center justify-center", style: {
|
|
334
|
+
top: "40%",
|
|
335
|
+
height: "20%",
|
|
336
|
+
backgroundColor: rect.highlightColor || "transparent",
|
|
337
|
+
}, children: _jsx("span", { className: "text-white font-bold text-xs", children: rect.status }) })] })), rect.shape === "image" && (_jsx("img", { src: rect.src, alt: "custom", className: "w-full h-full object-cover", draggable: false })), rect.shape === "vip-seat" && (_jsx("div", { className: "absolute left-0 right-0 flex items-center justify-center", style: {
|
|
338
|
+
top: "10%",
|
|
339
|
+
height: "20%",
|
|
340
|
+
}, children: _jsx("span", { className: "text-white font-bold text-xs", children: rect.table }) })), rect.shape === "vip-seat" && (_jsx("div", { className: "absolute left-0 right-0 flex items-center justify-center", style: {
|
|
341
|
+
top: "40%",
|
|
342
|
+
height: "20%",
|
|
343
|
+
backgroundColor: rect.highlightColor || "transparent",
|
|
344
|
+
}, children: _jsx("span", { className: "text-white font-bold text-xs", children: rect.status }) })), _jsx("div", { className: "absolute bottom-2 left-0 right-0 text-center text-white text-sm", children: rect.shape === "vip-seat" ? "8 Pax" : "" }), activeTool === "node" && (selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id) === rect.id && (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute w-3 h-3 bg-white border border-gray-800", style: {
|
|
345
|
+
top: -6,
|
|
346
|
+
left: -6,
|
|
347
|
+
cursor: "nwse-resize",
|
|
348
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
349
|
+
}, onMouseDown: () => startResizing("top-left") }), _jsx("div", { className: "absolute w-3 h-3 bg-white border border-gray-800", style: {
|
|
350
|
+
top: -6,
|
|
351
|
+
right: -6,
|
|
352
|
+
cursor: "nesw-resize",
|
|
353
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
354
|
+
}, onMouseDown: () => startResizing("top-right") }), _jsx("div", { className: "absolute w-3 h-3 bg-white border border-gray-800", style: {
|
|
355
|
+
bottom: -6,
|
|
356
|
+
left: -6,
|
|
357
|
+
cursor: "nesw-resize",
|
|
358
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
359
|
+
}, onMouseDown: () => startResizing("bottom-left") }), _jsx("div", { className: "absolute w-3 h-3 bg-white border border-gray-800", style: {
|
|
360
|
+
bottom: -6,
|
|
361
|
+
right: -6,
|
|
362
|
+
cursor: "nwse-resize",
|
|
363
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
364
|
+
}, onMouseDown: () => startResizing("bottom-right") })] }))] }, rect.id)))] }) }), _jsx(Modal, { open: showModal, onCancel: () => setShowModal(false), onOk: () => setShowModal(false), title: "Edit Rectangle", children: selectedRectangle && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex gap-4 items-center", children: [_jsxs("div", { className: "flex flex-col", children: [_jsx("p", { className: "mb-2 font-semibold", children: "Change Color:" }), _jsx(SketchPicker, { color: selectedRectangle.color, onChangeComplete: (color) => updateRectangle({ color: color.hex }) })] }), _jsxs("div", { className: "flex flex-col", children: [_jsx("p", { className: "mt-4 mb-2 font-semibold", children: "Live Preview:" }), _jsxs("div", { className: "relative borderflex items-center justify-center", style: {
|
|
365
|
+
width: selectedRectangle.width,
|
|
366
|
+
height: selectedRectangle.height,
|
|
367
|
+
margin: "0 auto",
|
|
368
|
+
transform: `rotate(${selectedRectangle.rotation}deg)`,
|
|
369
|
+
backgroundColor: selectedRectangle.color,
|
|
370
|
+
transition: "all 0.3s ease",
|
|
371
|
+
scale: "0.5",
|
|
372
|
+
borderRadius: selectedRectangle.shape === "circle" ? "100%" : "0%",
|
|
373
|
+
}, children: [selectedRectangle.shape === "vip-seat" && (_jsx("div", { className: "absolute left-0 right-0 flex items-center justify-center", style: {
|
|
374
|
+
top: "10%",
|
|
375
|
+
height: "20%",
|
|
376
|
+
}, children: _jsxs("span", { className: "text-white font-bold text-xs", children: [selectedRectangle.status, "sfsdf"] }) })), selectedRectangle.shape === "vip-seat" && (_jsx("div", { className: "absolute left-0 right-0 flex items-center justify-center", style: {
|
|
377
|
+
top: "40%",
|
|
378
|
+
height: "20%",
|
|
379
|
+
backgroundColor: selectedRectangle.highlightColor || "transparent",
|
|
380
|
+
}, children: _jsxs("span", { className: "text-white font-bold text-xs", children: [selectedRectangle.status, " dsdsd"] }) }))] })] })] }), _jsx("p", { className: "mt-4 mb-2 font-semibold", children: "Edit Text:" }), _jsx(Input, { value: selectedRectangle.pax, onChange: (e) => updateRectangle({ pax: e.target.value }) }), _jsx("p", { className: "mt-4 mb-2 font-semibold", children: "Edit Label:" }), _jsx(Input, { value: selectedRectangle.table, onChange: (e) => updateRectangle({ table: e.target.value }) }), _jsx("p", { className: "mt-4 mb-2 font-semibold", children: "Edit Highlight:" }), _jsx(Input, { value: selectedRectangle.status, onChange: (e) => updateRectangle({ status: e.target.value }) }), _jsx("p", { className: "mt-4 mb-2 font-semibold", children: "Rotate:" }), _jsxs("div", { className: "flex gap-4 items-center", children: [_jsx(Button, { onClick: () => rotateRectangle("left"), children: "\u27F2 Rotate Left" }), _jsxs("span", { children: [selectedRectangle.rotation, "\u00B0"] }), _jsx(Button, { onClick: () => rotateRectangle("right"), children: "\u27F3 Rotate Right" })] })] })) })] }));
|
|
381
|
+
};
|
|
382
|
+
export default SeatEditor;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import LayerView from "@/features/view";
|
|
4
|
+
import { useState, useEffect } from "react";
|
|
5
|
+
const TouchScrollDetect = () => {
|
|
6
|
+
const [fingerCount, setFingerCount] = useState(0);
|
|
7
|
+
const [scrollType, setScrollType] = useState(""); // untuk kondisi tampilan
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const container = document.getElementById("scroll-container");
|
|
10
|
+
const handleTouchStart = (e) => {
|
|
11
|
+
const count = e.touches.length;
|
|
12
|
+
setFingerCount(count);
|
|
13
|
+
if (count === 1) {
|
|
14
|
+
setScrollType("one");
|
|
15
|
+
}
|
|
16
|
+
else if (count === 2) {
|
|
17
|
+
setScrollType("two");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
setScrollType("other");
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const handleTouchEnd = () => {
|
|
24
|
+
setFingerCount(0);
|
|
25
|
+
setScrollType(""); // reset saat tidak ada sentuhan
|
|
26
|
+
};
|
|
27
|
+
if (container) {
|
|
28
|
+
container.addEventListener("touchstart", handleTouchStart);
|
|
29
|
+
container.addEventListener("touchend", handleTouchEnd);
|
|
30
|
+
}
|
|
31
|
+
return () => {
|
|
32
|
+
if (container) {
|
|
33
|
+
container.removeEventListener("touchstart", handleTouchStart);
|
|
34
|
+
container.removeEventListener("touchend", handleTouchEnd);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
return (_jsxs("div", { id: "scroll-container", className: "h-screen overflow-y-scroll bg-gray-100 p-6 text-gray-800", children: [_jsx(LayerView, { statusKey: "status", defaultBackground: "#000000" }), _jsxs("div", { className: "sticky top-0 bg-white z-10 py-2", children: [scrollType === "one" && (_jsx("p", { className: "text-blue-600 font-medium", children: "\uD83D\uDC46 One-finger scroll" })), scrollType === "two" && (_jsx("p", { className: "text-green-600 font-medium", children: "\u270C\uFE0F Two-finger scroll" })), scrollType === "other" && (_jsxs("p", { className: "text-red-600 font-medium", children: ["\uD83D\uDD90\uFE0F ", fingerCount, " fingers on screen"] }))] }), _jsx("div", { className: "h-[2000px] bg-white mt-4 rounded p-4 shadow", children: _jsx("p", { children: "Scroll this page with 1 or 2 fingers." }) })] }));
|
|
39
|
+
};
|
|
40
|
+
export default TouchScrollDetect;
|
|
@@ -34,7 +34,10 @@ const TouchScrollDetect = () => {
|
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
36
|
}, []);
|
|
37
|
-
return (<div id="scroll-container" className="
|
|
37
|
+
return (<div id="scroll-container" className="bg-gray-100 p-6 text-gray-800">
|
|
38
|
+
<div className="h-[400px] bg-white mt-4 rounded p-4 shadow">
|
|
39
|
+
<p>Scroll this page with 1 or 2 fingers.</p>
|
|
40
|
+
</div>
|
|
38
41
|
<LayerView statusKey="status" defaultBackground="#000000"/>
|
|
39
42
|
<div className="sticky top-0 bg-white z-10 py-2">
|
|
40
43
|
{scrollType === "one" && (<p className="text-blue-600 font-medium">👆 One-finger scroll</p>)}
|
|
@@ -44,7 +47,7 @@ const TouchScrollDetect = () => {
|
|
|
44
47
|
</p>)}
|
|
45
48
|
</div>
|
|
46
49
|
|
|
47
|
-
<div className="h-[
|
|
50
|
+
<div className="h-[200px] bg-white mt-4 rounded p-4 shadow">
|
|
48
51
|
<p>Scroll this page with 1 or 2 fingers.</p>
|
|
49
52
|
</div>
|
|
50
53
|
</div>);
|
package/dist/app/page.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import Board from "../features/board";
|
|
3
|
+
import SideTool from "../features/side-tool";
|
|
4
|
+
import ControlPanels from "../features/panel";
|
|
5
|
+
const TableEditor = () => {
|
|
6
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { className: "w-full h-screen flex relative", children: [_jsx(SideTool, {}), _jsx(Board, {}), _jsx(ControlPanels, {})] }) }));
|
|
7
|
+
};
|
|
8
|
+
export default TableEditor;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button, Popover } from "antd";
|
|
4
|
+
const ButtonTools = (props) => {
|
|
5
|
+
const { buttonProps, items, popoverProps } = props;
|
|
6
|
+
if (items.length === 0) {
|
|
7
|
+
return (_jsx(Popover, Object.assign({ trigger: "hover" }, popoverProps, { children: _jsx(Button, Object.assign({}, buttonProps)) })));
|
|
8
|
+
}
|
|
9
|
+
return (_jsx(Popover, { content: _jsxs("div", { children: [_jsx(Button, { children: "Button 1" }), _jsx(Button, { children: "Button 2" })] }), trigger: "click", children: _jsx(Button, Object.assign({}, buttonProps)) }));
|
|
10
|
+
};
|
|
11
|
+
export default ButtonTools;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Button, ColorPicker, Flex, Form, Input, InputNumber } from "antd";
|
|
4
|
+
const SectionLabel = () => {
|
|
5
|
+
return (_jsxs("div", { className: "py-2", children: [_jsx("h1", { className: "heading-s", children: "Section Labeling" }), _jsx(Form.Item, { label: "Labels in square", name: "labels", children: _jsx(Form.List, { name: "labels", children: (fields, { add, remove }) => (_jsxs(_Fragment, { children: [fields.map((field) => (_jsxs("div", { children: [_jsxs(Flex, { gap: 2, children: [_jsx(Form.Item, { name: [field.name, "label"], label: "Text", children: _jsx(Input, {}) }), _jsx(Form.Item, { name: [field.name, "fontColor"], label: "Color", getValueFromEvent: (color) => color.toHexString(), children: _jsx(ColorPicker, { allowClear: true, format: "hex", defaultFormat: "hex" }) })] }), _jsxs(Flex, { gap: 2, children: [_jsx(Form.Item, { name: [field.name, "x"], label: "X", children: _jsx(InputNumber, {}) }), _jsx(Form.Item, { name: [field.name, "y"], label: "Y", children: _jsx(InputNumber, {}) }), _jsx(Form.Item, { name: [field.name, "fontSize"], label: "Size", children: _jsx(InputNumber, { suffix: "px" }) })] })] }, field.key))), _jsxs(Flex, { gap: 2, children: [_jsx(Button, { type: "primary", onClick: () => add(), className: "btn btn-primary", children: "Add" }), _jsx(Button, { type: "primary", onClick: () => remove(fields.length - 1), className: "btn btn-primary", children: "Remove" })] })] })) }) }), _jsx("div", { className: "divider-dashed" })] }));
|
|
6
|
+
};
|
|
7
|
+
export default SectionLabel;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ColorPicker, Flex, Form, InputNumber } from "antd";
|
|
4
|
+
const SectionShape = () => {
|
|
5
|
+
return (_jsxs("div", { className: "py-2", children: [_jsx("h1", { className: "heading-s", children: "Shape" }), _jsxs(Flex, { gap: 2, className: "w-full", children: [_jsx(Form.Item, { label: "Width", name: "width", className: "w-full", children: _jsx(InputNumber, { suffix: "px" }) }), _jsx(Form.Item, { label: "Height", name: "height", className: "w-full", children: _jsx(InputNumber, { suffix: "px" }) })] }), _jsxs(Flex, { gap: 2, children: [_jsx(Form.Item, { label: "Position X", name: "x", className: "w-full", children: _jsx(InputNumber, {}) }), _jsx(Form.Item, { label: "Position Y", name: "y", className: "w-full", children: _jsx(InputNumber, {}) }), _jsx(Form.Item, { label: "Rotation", name: "rotation", className: "w-full", children: _jsx(InputNumber, {}) })] }), _jsxs(Flex, { gap: 2, children: [_jsx(Form.Item, { label: "Fill", name: "fill", getValueFromEvent: (color) => color.toHexString(), className: "w-full ", children: _jsx(ColorPicker, { allowClear: true, format: "hex", defaultFormat: "hex" }) }), _jsx(Form.Item, { label: "Stroke", name: "stroke", getValueFromEvent: (color) => color.toHexString(), className: "w-full ", children: _jsx(ColorPicker, { allowClear: true, format: "hex", defaultFormat: "hex" }) })] }), _jsxs(Flex, { children: [_jsx(Form.Item, { label: "Stroke Width", name: "strokeWidth", className: "w-full", children: _jsx(InputNumber, {}) }), _jsx(Form.Item, { label: "opacity", name: "opacity", className: "w-full", children: _jsx(InputNumber, { step: 0.1, max: 1, min: 0 }) })] })] }));
|
|
6
|
+
};
|
|
7
|
+
export default SectionShape;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import { Input, Button, Flex, Form } from "antd";
|
|
5
|
+
import { ArrowRight, ArrowLeft } from "lucide-react";
|
|
6
|
+
const NumberIndicator = ({ name, defaultValue, onChange }) => {
|
|
7
|
+
const [value, setValue] = useState(0);
|
|
8
|
+
const form = Form.useFormInstance();
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (defaultValue) {
|
|
11
|
+
setValue(defaultValue);
|
|
12
|
+
form.setFieldsValue({ [name]: defaultValue });
|
|
13
|
+
}
|
|
14
|
+
}, [defaultValue]);
|
|
15
|
+
const handlePrev = () => {
|
|
16
|
+
setValue(value - 1);
|
|
17
|
+
form.setFieldsValue({ [name]: value - 1 });
|
|
18
|
+
onChange(value - 1);
|
|
19
|
+
};
|
|
20
|
+
const handleNext = () => {
|
|
21
|
+
setValue(value + 1);
|
|
22
|
+
form.setFieldsValue({ [name]: value + 1 });
|
|
23
|
+
onChange(value + 1);
|
|
24
|
+
};
|
|
25
|
+
return (_jsxs(Flex, { gap: 2, children: [_jsx(Button, { onClick: handlePrev, children: _jsx(ArrowLeft, {}) }), _jsx(Form.Item, { name: name, noStyle: true, children: _jsx(Input, { className: "flex text-center", type: "number", value: value, name: name, onChange: (e) => setValue(parseInt(e.target.value)) }) }), _jsx(Button, { onClick: handleNext, children: _jsx(ArrowRight, {}) })] }));
|
|
26
|
+
};
|
|
27
|
+
export default NumberIndicator;
|