seat-editor 1.2.6 → 1.2.7

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.
Files changed (54) hide show
  1. package/README.md +2 -0
  2. package/dist/app/layout.d.ts +1 -1
  3. package/dist/app/layout.jsx +27 -0
  4. package/dist/app/new-board/page.d.ts +1 -1
  5. package/dist/app/new-board/page.jsx +12 -0
  6. package/dist/app/old-board/page.d.ts +2 -1
  7. package/dist/app/old-board/page.jsx +515 -0
  8. package/dist/app/only-view/page.d.ts +1 -1
  9. package/dist/app/page.d.ts +1 -1
  10. package/dist/app/page.jsx +13 -0
  11. package/dist/components/button-tools/index.d.ts +1 -1
  12. package/dist/components/button-tools/index.jsx +17 -0
  13. package/dist/components/form-tools/label.d.ts +1 -1
  14. package/dist/components/form-tools/label.jsx +44 -0
  15. package/dist/components/form-tools/shape.d.ts +1 -1
  16. package/dist/components/form-tools/shape.jsx +43 -0
  17. package/dist/components/input/number-indicator.d.ts +1 -1
  18. package/dist/components/input/number-indicator.jsx +36 -0
  19. package/dist/components/layer/index.d.ts +3 -1
  20. package/dist/components/layer/index.jsx +22 -11
  21. package/dist/components/lib/index.d.ts +1 -1
  22. package/dist/components/lib/index.jsx +33 -0
  23. package/dist/components/modal-preview/index.d.ts +1 -1
  24. package/dist/components/modal-preview/index.jsx +11 -0
  25. package/dist/features/board/index.d.ts +1 -1
  26. package/dist/features/board/index.jsx +290 -0
  27. package/dist/features/navbar/index.d.ts +1 -1
  28. package/dist/features/navbar/index.jsx +5 -0
  29. package/dist/features/package/index.d.ts +1 -1
  30. package/dist/features/package/index.jsx +39 -0
  31. package/dist/features/panel/index.d.ts +1 -1
  32. package/dist/features/panel/index.jsx +91 -0
  33. package/dist/features/panel/select-tool.d.ts +1 -1
  34. package/dist/features/panel/select-tool.jsx +45 -0
  35. package/dist/features/panel/square-circle-tool.d.ts +1 -1
  36. package/dist/features/panel/square-circle-tool.jsx +10 -0
  37. package/dist/features/panel/table-seat-circle.d.ts +1 -1
  38. package/dist/features/panel/table-seat-circle.jsx +31 -0
  39. package/dist/features/panel/text-tool.d.ts +1 -1
  40. package/dist/features/panel/text-tool.jsx +22 -0
  41. package/dist/features/panel/upload-tool.d.ts +1 -1
  42. package/dist/features/panel/upload-tool.jsx +80 -0
  43. package/dist/features/side-tool/index.d.ts +1 -1
  44. package/dist/features/side-tool/index.jsx +211 -0
  45. package/dist/features/view/index.d.ts +1 -1
  46. package/dist/features/view/index.jsx +4 -5
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.js +1 -1
  49. package/dist/provider/antd-provider.jsx +30 -0
  50. package/dist/provider/redux-provider.d.ts +1 -1
  51. package/dist/provider/redux-provider.jsx +6 -0
  52. package/dist/provider/store-provider.d.ts +1 -1
  53. package/dist/provider/store-provider.jsx +8 -0
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -17,6 +17,8 @@ An interactive seat layout editor built with React (or your stack). Create, cust
17
17
 
18
18
  ---
19
19
 
20
+
21
+
20
22
  ## ✨ Comming SOOON!!
21
23
  - 🎨 actions upload image
22
24
 
@@ -3,4 +3,4 @@ import "./globals.css";
3
3
  export declare const metadata: Metadata;
4
4
  export default function RootLayout({ children, }: Readonly<{
5
5
  children: React.ReactNode;
6
- }>): import("react/jsx-runtime").JSX.Element;
6
+ }>): import("react").JSX.Element;
@@ -0,0 +1,27 @@
1
+ import localFont from "next/font/local";
2
+ import "./globals.css";
3
+ import { Layout } from "antd";
4
+ import { StoreProvider } from "../provider/store-provider";
5
+ const geistSans = localFont({
6
+ src: "./fonts/GeistVF.woff",
7
+ variable: "--font-geist-sans",
8
+ weight: "100 900",
9
+ });
10
+ const geistMono = localFont({
11
+ src: "./fonts/GeistMonoVF.woff",
12
+ variable: "--font-geist-mono",
13
+ weight: "100 900",
14
+ });
15
+ export const metadata = {
16
+ title: "Create Next App",
17
+ description: "Generated by create next app",
18
+ };
19
+ export default function RootLayout({ children, }) {
20
+ return (<html lang="en">
21
+ <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
22
+ <StoreProvider>
23
+ <Layout>{children}</Layout>
24
+ </StoreProvider>
25
+ </body>
26
+ </html>);
27
+ }
@@ -1 +1 @@
1
- export default function NewBoard(): import("react/jsx-runtime").JSX.Element;
1
+ export default function NewBoard(): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import Board from "../../features/board";
2
+ import SideTool from "../../features/side-tool";
3
+ import ControlPanels from "../../features/panel";
4
+ export default function NewBoard() {
5
+ return (<>
6
+ <div className="w-full h-screen flex relative">
7
+ <SideTool />
8
+ <Board />
9
+ <ControlPanels />
10
+ </div>
11
+ </>);
12
+ }
@@ -1,2 +1,3 @@
1
- declare const SeatEditor: () => import("react/jsx-runtime").JSX.Element;
1
+ import React from "react";
2
+ declare const SeatEditor: () => React.JSX.Element;
2
3
  export default SeatEditor;
@@ -0,0 +1,515 @@
1
+ "use client";
2
+ import React, { useState } from "react";
3
+ import { Button, Input, Modal } from "antd"; //tes commit
4
+ // aduhuhhusd
5
+ import { Square, MousePointer2, Move3D, Trash, CopyPlusIcon, ZoomInIcon, ZoomOutIcon, DownloadIcon, UploadIcon, Circle, PenIcon, Pencil, } from "lucide-react";
6
+ import { SketchPicker } from "react-color";
7
+ const SeatEditor = () => {
8
+ var _a, _b;
9
+ const [activeTool, setActiveTool] = useState(null);
10
+ const [rectangles, setRectangles] = useState([]);
11
+ const [selectedRectangle, setSelectedRectangle] = useState(null);
12
+ const [isDragging, setIsDragging] = useState(false);
13
+ const [startPoint, setStartPoint] = useState(null);
14
+ const [shadowRect, setShadowRect] = useState(null);
15
+ const [showModal, setShowModal] = useState(false);
16
+ const [dragOffset, setDragOffset] = useState(null);
17
+ console.log({ rectangles });
18
+ const [zoom, setZoom] = useState(1);
19
+ const [resizeDirection, setResizeDirection] = useState(null);
20
+ const [images, setImages] = useState([]);
21
+ const [penPaths, setPenPaths] = useState([]);
22
+ const [currentPath, setCurrentPath] = useState(null);
23
+ const [isDrawing, setIsDrawing] = useState(false);
24
+ // upload image
25
+ const widthWorkspace = ((_a = document.getElementById("workspace")) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0;
26
+ const heightWorkspace = ((_b = document.getElementById("workspace")) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;
27
+ const handleImageUploadBackground = (e) => {
28
+ var _a;
29
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
30
+ if (!file)
31
+ return;
32
+ console.log({ file });
33
+ const reader = new FileReader();
34
+ reader.onload = () => {
35
+ const img = document.createElement("img");
36
+ img.src = reader.result;
37
+ console.log({ img });
38
+ let width = img.width > widthWorkspace ? img.width / 2 : img.width;
39
+ let height = img.height > heightWorkspace ? img.height / 2 : img.height;
40
+ console.log({ width, height }, img.width, img.height);
41
+ img.onload = () => {
42
+ setRectangles((prev) => [
43
+ ...prev,
44
+ {
45
+ id: rectangles.length + 1,
46
+ x: 100,
47
+ y: 100,
48
+ width: width < 1 ? 100 : width,
49
+ height: height < 1 ? 100 : height,
50
+ rotation: 0,
51
+ shape: "image",
52
+ src: img.src,
53
+ },
54
+ ]);
55
+ };
56
+ };
57
+ reader.readAsDataURL(file);
58
+ };
59
+ const handleImageUpload = (e) => {
60
+ var _a;
61
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
62
+ if (!file)
63
+ return;
64
+ const reader = new FileReader();
65
+ reader.onload = () => {
66
+ const img = document.createElement("img");
67
+ img.src = reader.result;
68
+ let width = img.width > widthWorkspace ? img.width / 2 : img.width;
69
+ let height = img.height > heightWorkspace ? img.height / 2 : img.height;
70
+ img.onload = () => {
71
+ setRectangles((prev) => [
72
+ ...prev,
73
+ {
74
+ id: rectangles.length + 1,
75
+ x: 100,
76
+ y: 100,
77
+ width: width < 1 ? 100 : width,
78
+ height: height < 1 ? 100 : height,
79
+ rotation: 0,
80
+ shape: "image-table",
81
+ src: img.src,
82
+ pax: "4 Pax",
83
+ highlightColor: "#C1443D",
84
+ status: "SOLD",
85
+ table: `V${rectangles.length + 1}`,
86
+ },
87
+ ]);
88
+ };
89
+ };
90
+ reader.readAsDataURL(file);
91
+ };
92
+ // zoom in out
93
+ const zoomIn = () => setZoom((prev) => prev + 0.1);
94
+ const zoomOut = () => setZoom((prev) => Math.max(0.1, prev - 0.1));
95
+ const handleToolClick = (tool) => {
96
+ setActiveTool(tool);
97
+ setSelectedRectangle(null); // Deselect any rectangle when switching tools
98
+ };
99
+ // === Drawing Rectangle ===
100
+ const handleMouseDown = (e) => {
101
+ if (activeTool === "rectangle" ||
102
+ activeTool === "circle" ||
103
+ activeTool === "vip-seat") {
104
+ const rect = e.target.getBoundingClientRect();
105
+ setStartPoint({ x: e.clientX - rect.left, y: e.clientY - rect.top });
106
+ setIsDragging(true);
107
+ }
108
+ if (activeTool === "pen") {
109
+ const rect = e.target.getBoundingClientRect();
110
+ const newPoint = { x: e.clientX - rect.left, y: e.clientY - rect.top };
111
+ setCurrentPath({
112
+ id: penPaths.length + 1,
113
+ points: [newPoint],
114
+ color: "#fff", // Default white stroke
115
+ strokeWidth: 2, // Default stroke width
116
+ });
117
+ setIsDrawing(true);
118
+ }
119
+ };
120
+ // rotate logic
121
+ const rotateRectangle = (direction) => {
122
+ if (selectedRectangle) {
123
+ const rotationChange = direction === "left" ? -5 : 5; // Rotate 5 degrees
124
+ const newRotation = (selectedRectangle.rotation + rotationChange) % 360;
125
+ setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id
126
+ ? Object.assign(Object.assign({}, rect), { rotation: newRotation }) : rect));
127
+ setSelectedRectangle((prev) => prev ? Object.assign(Object.assign({}, prev), { rotation: newRotation }) : null);
128
+ }
129
+ };
130
+ const handleMouseMove = (e) => {
131
+ // Resize logic for node tool
132
+ if (activeTool === "node" &&
133
+ isDragging &&
134
+ resizeDirection &&
135
+ selectedRectangle) {
136
+ const workspaceRect = e.currentTarget.getBoundingClientRect();
137
+ const currentX = e.clientX - workspaceRect.left;
138
+ const currentY = e.clientY - workspaceRect.top;
139
+ let newRect = Object.assign({}, selectedRectangle);
140
+ switch (resizeDirection) {
141
+ case "top-left":
142
+ newRect.width += newRect.x - currentX;
143
+ newRect.height =
144
+ selectedRectangle.shape === "circle"
145
+ ? newRect.width
146
+ : newRect.height + (newRect.y - currentY);
147
+ newRect.x = currentX;
148
+ newRect.y =
149
+ selectedRectangle.shape === "circle" ? newRect.y : currentY;
150
+ break;
151
+ case "top-right":
152
+ newRect.width = currentX - newRect.x;
153
+ newRect.height =
154
+ selectedRectangle.shape === "circle"
155
+ ? newRect.width
156
+ : newRect.height + (newRect.y - currentY);
157
+ newRect.y =
158
+ selectedRectangle.shape === "circle" ? newRect.y : currentY;
159
+ break;
160
+ case "bottom-left":
161
+ newRect.width += newRect.x - currentX;
162
+ newRect.height =
163
+ selectedRectangle.shape === "circle"
164
+ ? newRect.width
165
+ : currentY - newRect.y;
166
+ newRect.x = currentX;
167
+ break;
168
+ case "bottom-right":
169
+ newRect.width = currentX - newRect.x;
170
+ newRect.height =
171
+ selectedRectangle.shape === "circle"
172
+ ? newRect.width
173
+ : currentY - newRect.y;
174
+ break;
175
+ }
176
+ // Ensure width and height are always positive
177
+ newRect.width = Math.max(10, newRect.width);
178
+ newRect.height = Math.max(10, newRect.height);
179
+ setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id ? Object.assign({}, newRect) : rect));
180
+ setSelectedRectangle(newRect);
181
+ }
182
+ if ((activeTool === "rectangle" ||
183
+ activeTool === "circle" ||
184
+ activeTool === "vip-seat") &&
185
+ isDragging &&
186
+ startPoint) {
187
+ const rect = e.target.getBoundingClientRect();
188
+ const currentX = e.clientX - rect.left;
189
+ const currentY = e.clientY - rect.top;
190
+ // Update shadow rectangle dimensions dynamically
191
+ const newShadowRect = {
192
+ id: -1, // Temporary ID for preview
193
+ x: Math.min(startPoint.x, currentX),
194
+ y: Math.min(startPoint.y, currentY),
195
+ width: Math.abs(currentX - startPoint.x),
196
+ height: Math.abs(currentY - startPoint.y),
197
+ color: activeTool === "vip-seat" ? "#2D2D36" : "rgba(74, 144, 226, 0.4)", // Light blue with transparency
198
+ pax: "",
199
+ rotation: 0,
200
+ shape: activeTool === "vip-seat" ? "vip-seat" : activeTool, // Define shape type
201
+ highlightColor: activeTool === "vip-seat" ? "#C1443D" : undefined, // Red section in VIP
202
+ status: activeTool === "vip-seat" ? "SOLD" : undefined,
203
+ table: activeTool === "vip-seat" ? `V${rectangles.length + 1}` : undefined, // Table number for VIP
204
+ };
205
+ setShadowRect(newShadowRect);
206
+ }
207
+ // Dragging for select tool
208
+ if (activeTool === "select" &&
209
+ isDragging &&
210
+ selectedRectangle &&
211
+ dragOffset) {
212
+ const workspaceRect = e.currentTarget.getBoundingClientRect();
213
+ const newX = e.clientX - workspaceRect.left - dragOffset.x;
214
+ const newY = e.clientY - workspaceRect.top - dragOffset.y;
215
+ setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id
216
+ ? Object.assign(Object.assign({}, rect), { x: newX, y: newY }) : rect));
217
+ }
218
+ };
219
+ const handleMouseUp = () => {
220
+ setIsDragging(false);
221
+ setResizeDirection(null);
222
+ if ((activeTool === "rectangle" ||
223
+ activeTool === "circle" ||
224
+ activeTool === "vip-seat") &&
225
+ isDragging &&
226
+ shadowRect) {
227
+ // Finalize the rectangle on mouse release
228
+ 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 });
229
+ setRectangles([...rectangles, newRectangle]);
230
+ setImages((prev) => prev.map((img) => img.id === (selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id)
231
+ ? Object.assign(Object.assign({}, img), { x: newRectangle.x, y: newRectangle.y }) : img));
232
+ setShadowRect(null); // Clear shadow preview
233
+ setIsDragging(false);
234
+ setStartPoint(null);
235
+ }
236
+ };
237
+ const handleRectangleMouseDown = (e, rect) => {
238
+ if (activeTool === "select" || activeTool === "node") {
239
+ setSelectedRectangle(rect);
240
+ const rectBox = e.target.getBoundingClientRect();
241
+ setDragOffset({
242
+ x: e.clientX - rectBox.left,
243
+ y: e.clientY - rectBox.top,
244
+ });
245
+ setIsDragging(true);
246
+ }
247
+ };
248
+ const handleRectangleDoubleClick = (rect) => {
249
+ if (activeTool === "select" || activeTool === "node") {
250
+ setSelectedRectangle(rect);
251
+ setShowModal(true);
252
+ }
253
+ };
254
+ const updateRectangle = (updates) => {
255
+ if (selectedRectangle) {
256
+ setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id ? Object.assign(Object.assign({}, rect), updates) : rect));
257
+ setSelectedRectangle((prev) => (prev ? Object.assign(Object.assign({}, prev), updates) : null));
258
+ }
259
+ };
260
+ const startResizing = (direction) => {
261
+ setResizeDirection(direction);
262
+ setIsDragging(true);
263
+ };
264
+ // Set the cursor style based on the active tool
265
+ const getCursorStyle = () => {
266
+ if (activeTool === "rectangle" ||
267
+ activeTool === "circle" ||
268
+ activeTool === "vip-seat")
269
+ return "cursor-crosshair";
270
+ if (activeTool === "select")
271
+ return "cursor-default";
272
+ if (activeTool === "node")
273
+ return "cursor-pointer";
274
+ return "cursor-default";
275
+ };
276
+ const deleteSelectedRectangle = () => {
277
+ if (selectedRectangle) {
278
+ setRectangles((prev) => prev.filter((rect) => rect.id !== selectedRectangle.id));
279
+ setSelectedRectangle(null);
280
+ }
281
+ };
282
+ // duplicate
283
+ const duplicateRectangle = () => {
284
+ if (selectedRectangle) {
285
+ const newRectangle = Object.assign(Object.assign({}, selectedRectangle), { id: rectangles.length + 1, x: selectedRectangle.x + 20, y: selectedRectangle.y + 20 });
286
+ setRectangles([...rectangles, newRectangle]);
287
+ }
288
+ };
289
+ const exportJSON = () => {
290
+ console.log({ rectangles, images });
291
+ // const json = JSON.stringify(rectangles, null, 2);
292
+ // const blob = new Blob([json], { type: "application/json" });
293
+ // const link = document.createElement("a");
294
+ // link.href = URL.createObjectURL(blob);
295
+ // link.download = "seat_layout.json";
296
+ // document.body.appendChild(link);
297
+ // link.click();
298
+ // document.body.removeChild(link);
299
+ };
300
+ return (<div className="flex h-screen w-full">
301
+ {/* Toolbar */}
302
+ <div className="w-16 bg-gray-800 text-white flex flex-col items-center py-4 space-y-4">
303
+ {/* Select Tool */}
304
+ <Button type={activeTool === "select" ? "primary" : "default"} shape="circle" icon={<MousePointer2 />} onClick={() => handleToolClick("select")}/>
305
+ <Button type={activeTool === "circle" ? "primary" : "default"} shape="circle" icon={<Circle />} onClick={() => handleToolClick("circle")}/>
306
+ <Button type={activeTool === "vip-seat" ? "primary" : "default"} shape="circle" icon={<PenIcon />} // Use any icon you prefer
307
+ onClick={() => handleToolClick("vip-seat")}/>
308
+ {/* Rectangle Tool */}
309
+ <Button type={activeTool === "rectangle" ? "primary" : "default"} shape="circle" icon={<Square />} onClick={() => handleToolClick("rectangle")}/>
310
+ {/* Node Tool */}
311
+ <Button type={activeTool === "node" ? "primary" : "default"} shape="circle" icon={<Move3D />} onClick={() => handleToolClick("node")}/>
312
+ <Button type={activeTool === "pen" ? "primary" : "default"} shape="circle" icon={<Pencil />} onClick={() => handleToolClick("pen")}/>
313
+
314
+ {/* delete */}
315
+ <Button type="default" shape="circle" icon={<Trash />} onClick={deleteSelectedRectangle}/>
316
+ {/* duplicate */}
317
+ <Button type="default" shape="circle" icon={<CopyPlusIcon />} // You can use a copy icon
318
+ onClick={duplicateRectangle}/>
319
+ {/* zoomIn/out */}
320
+ <Button type="default" shape="circle" onClick={zoomIn} icon={<ZoomInIcon />}/>
321
+ <Button type="default" shape="circle" onClick={zoomOut} icon={<ZoomOutIcon />}/>
322
+ {/* {activeTool === "image" && ( */}
323
+ <UploadIcon />
324
+ <span>Image Seat</span>
325
+ <input type="file" accept="image/*" onChange={handleImageUpload}/>
326
+ <span>Background Image</span>
327
+ <input type="file" accept="image/*" onChange={handleImageUploadBackground}/>
328
+ {/* )} */}
329
+ <Button shape="circle" icon={<DownloadIcon />} onClick={exportJSON}/>
330
+ </div>
331
+
332
+ {/* Workspace */}
333
+ <div className="w-full flex items-center justify-center" id={"workspace"}>
334
+ <div className={`bg-gray-900 relative ${getCursorStyle()} w-full h-screen `} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} style={{
335
+ transform: `scale(${zoom})`,
336
+ transformOrigin: "0 0",
337
+ }}>
338
+
339
+ {shadowRect && (<div className="absolute border-dashed border-2 border-blue-400" style={{
340
+ left: shadowRect.x,
341
+ top: shadowRect.y,
342
+ width: shadowRect.width,
343
+ height: shadowRect.height,
344
+ backgroundColor: shadowRect.color,
345
+ }}/>)}
346
+ {/* Render rectangles */}
347
+ {rectangles.map((rect) => (<div key={rect.id} 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
348
+ ? "border-black"
349
+ : "border-gray-300"}`} style={{
350
+ left: rect.x,
351
+ top: rect.y,
352
+ width: rect.width,
353
+ height: rect.height,
354
+ backgroundColor: rect.color,
355
+ transform: `rotate(${rect.rotation}deg)`,
356
+ transformOrigin: "center",
357
+ borderRadius: rect.shape === "circle" ? "100%" : "0%",
358
+ }}>
359
+ {rect.shape === "image-table" && (<div className="w-full h-full relative">
360
+ <img src={rect.src} alt="custom" className="w-full h-full object-cover" draggable={false}/>
361
+ <div className="absolute left-0 right-0 flex items-center justify-center" style={{
362
+ top: "10%",
363
+ height: "20%",
364
+ backgroundColor: rect.highlightColor || "transparent",
365
+ }}>
366
+ <span className="text-white font-bold text-xs absolute" style={{
367
+ top: "10%",
368
+ left: "50%",
369
+ }}>
370
+ {rect.table}
371
+ </span>
372
+ </div>
373
+ <span className="text-xs text-white flex items-center justify-center absolute w-full" style={{
374
+ top: "85%",
375
+ left: "50%",
376
+ transform: "translate(-50%, -50%)",
377
+ backgroundColor: rect.highlightColor || "transparent"
378
+ }}>
379
+ {rect.pax}
380
+ </span>
381
+ <div className="absolute left-0 right-0 flex items-center justify-center" style={{
382
+ top: "40%",
383
+ height: "20%",
384
+ backgroundColor: rect.highlightColor || "transparent",
385
+ }}>
386
+ <span className="text-white font-bold text-xs">
387
+ {rect.status}
388
+ </span>
389
+ </div>
390
+ </div>)}
391
+ {rect.shape === "image" && (<img src={rect.src} alt="custom" className="w-full h-full object-cover" draggable={false}/>)}
392
+ {rect.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
393
+ top: "10%",
394
+ height: "20%",
395
+ }}>
396
+ <span className="text-white font-bold text-xs">
397
+ {rect.table}
398
+ </span>
399
+ </div>)}
400
+ {rect.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
401
+ top: "40%",
402
+ height: "20%",
403
+ backgroundColor: rect.highlightColor || "transparent",
404
+ }}>
405
+ <span className="text-white font-bold text-xs">
406
+ {rect.status}
407
+ </span>
408
+ </div>)}
409
+
410
+ {/* Bottom Text */}
411
+ <div className="absolute bottom-2 left-0 right-0 text-center text-white text-sm">
412
+ {rect.shape === "vip-seat" ? "8 Pax" : ""}
413
+ </div>
414
+
415
+ {/* Resize Nodes */}
416
+ {/* Resize Nodes (Only Show When in Node Mode and Item is Selected) */}
417
+ {activeTool === "node" && (selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id) === rect.id && (<>
418
+ {/* Top Left */}
419
+ <div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
420
+ top: -6,
421
+ left: -6,
422
+ cursor: "nwse-resize",
423
+ borderRadius: rect.shape === "circle" ? "50%" : "0%",
424
+ }} onMouseDown={() => startResizing("top-left")}/>
425
+ {/* Top Right */}
426
+ <div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
427
+ top: -6,
428
+ right: -6,
429
+ cursor: "nesw-resize",
430
+ borderRadius: rect.shape === "circle" ? "50%" : "0%",
431
+ }} onMouseDown={() => startResizing("top-right")}/>
432
+ {/* Bottom Left */}
433
+ <div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
434
+ bottom: -6,
435
+ left: -6,
436
+ cursor: "nesw-resize",
437
+ borderRadius: rect.shape === "circle" ? "50%" : "0%",
438
+ }} onMouseDown={() => startResizing("bottom-left")}/>
439
+ {/* Bottom Right */}
440
+ <div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
441
+ bottom: -6,
442
+ right: -6,
443
+ cursor: "nwse-resize",
444
+ borderRadius: rect.shape === "circle" ? "50%" : "0%",
445
+ }} onMouseDown={() => startResizing("bottom-right")}/>
446
+ </>)}
447
+ </div>))}
448
+ </div>
449
+ </div>
450
+
451
+ {/* Rectangle Customization Modal */}
452
+ <Modal open={showModal} onCancel={() => setShowModal(false)} onOk={() => setShowModal(false)} title="Edit Rectangle">
453
+ {selectedRectangle && (<>
454
+ <div className="flex gap-4 items-center">
455
+ <div className="flex flex-col">
456
+ <p className="mb-2 font-semibold">Change Color:</p>
457
+ <SketchPicker color={selectedRectangle.color} onChangeComplete={(color) => updateRectangle({ color: color.hex })}/>
458
+ </div>
459
+ <div className="flex flex-col">
460
+ <p className="mt-4 mb-2 font-semibold">Live Preview:</p>
461
+ <div className="relative borderflex items-center justify-center" style={{
462
+ width: selectedRectangle.width,
463
+ height: selectedRectangle.height,
464
+ margin: "0 auto",
465
+ transform: `rotate(${selectedRectangle.rotation}deg)`,
466
+ backgroundColor: selectedRectangle.color,
467
+ transition: "all 0.3s ease",
468
+ scale: "0.5",
469
+ borderRadius: selectedRectangle.shape === "circle" ? "100%" : "0%",
470
+ }}>
471
+ {selectedRectangle.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
472
+ top: "10%",
473
+ height: "20%",
474
+ }}>
475
+ <span className="text-white font-bold text-xs">
476
+ {selectedRectangle.status}sfsdf
477
+ </span>
478
+ </div>)}
479
+ {selectedRectangle.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
480
+ top: "40%",
481
+ height: "20%",
482
+ backgroundColor: selectedRectangle.highlightColor || "transparent",
483
+ }}>
484
+ <span className="text-white font-bold text-xs">
485
+ {selectedRectangle.status} dsdsd
486
+ </span>
487
+ </div>)}
488
+ </div>
489
+ </div>
490
+ </div>
491
+
492
+ {/* Preview Section */}
493
+
494
+ <p className="mt-4 mb-2 font-semibold">Edit Text:</p>
495
+ <Input value={selectedRectangle.pax} onChange={(e) => updateRectangle({ pax: e.target.value })}/>
496
+ <p className="mt-4 mb-2 font-semibold">Edit Label:</p>
497
+ <Input value={selectedRectangle.table} onChange={(e) => updateRectangle({ table: e.target.value })}/>
498
+ <p className="mt-4 mb-2 font-semibold">Edit Highlight:</p>
499
+ <Input value={selectedRectangle.status} onChange={(e) => updateRectangle({ status: e.target.value })}/>
500
+ {/* Rotation Controls */}
501
+ <p className="mt-4 mb-2 font-semibold">Rotate:</p>
502
+ <div className="flex gap-4 items-center">
503
+ <Button onClick={() => rotateRectangle("left")}>
504
+ ⟲ Rotate Left
505
+ </Button>
506
+ <span>{selectedRectangle.rotation}°</span>
507
+ <Button onClick={() => rotateRectangle("right")}>
508
+ ⟳ Rotate Right
509
+ </Button>
510
+ </div>
511
+ </>)}
512
+ </Modal>
513
+ </div>);
514
+ };
515
+ export default SeatEditor;
@@ -1,2 +1,2 @@
1
- declare const OnlyView: () => import("react/jsx-runtime").JSX.Element;
1
+ declare const OnlyView: () => import("react").JSX.Element;
2
2
  export default OnlyView;
@@ -1,2 +1,2 @@
1
- declare const TableEditor: () => import("react/jsx-runtime").JSX.Element;
1
+ declare const TableEditor: () => import("react").JSX.Element;
2
2
  export default TableEditor;
@@ -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/jsx-runtime").JSX.Element;
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/jsx-runtime").JSX.Element;
1
+ declare const SectionLabel: () => import("react").JSX.Element;
2
2
  export default SectionLabel;