@merchi/product-editor 0.1.9
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/.turbo/turbo-build.log +1 -0
- package/README.md +174 -0
- package/dist/components/AlignMenu.d.ts +3 -0
- package/dist/components/AlignMenu.js +61 -0
- package/dist/components/FloatingToolbar.d.ts +4 -0
- package/dist/components/FloatingToolbar.js +97 -0
- package/dist/components/FormatButtons.d.ts +2 -0
- package/dist/components/FormatButtons.js +22 -0
- package/dist/components/ImageNavButton.d.ts +7 -0
- package/dist/components/ImageNavButton.js +14 -0
- package/dist/components/ImageZoomModal.d.ts +12 -0
- package/dist/components/ImageZoomModal.js +129 -0
- package/dist/components/LayerPanel.d.ts +4 -0
- package/dist/components/LayerPanel.js +223 -0
- package/dist/components/LoadingOverlay.d.ts +9 -0
- package/dist/components/LoadingOverlay.js +17 -0
- package/dist/components/ProductEditor.d.ts +4 -0
- package/dist/components/ProductEditor.js +67 -0
- package/dist/components/ProductImageGallery.d.ts +6 -0
- package/dist/components/ProductImageGallery.js +148 -0
- package/dist/components/ProductPreviews.d.ts +7 -0
- package/dist/components/ProductPreviews.js +281 -0
- package/dist/components/TextToolbar.d.ts +4 -0
- package/dist/components/TextToolbar.js +117 -0
- package/dist/components/Toolbar.d.ts +3 -0
- package/dist/components/Toolbar.js +47 -0
- package/dist/config/colorConfig.d.ts +1 -0
- package/dist/config/colorConfig.js +10 -0
- package/dist/config/fontConfig.d.ts +5 -0
- package/dist/config/fontConfig.js +21 -0
- package/dist/context/ProductEditorContext.d.ts +60 -0
- package/dist/context/ProductEditorContext.js +743 -0
- package/dist/hooks/useSwipeNavigate.d.ts +11 -0
- package/dist/hooks/useSwipeNavigate.js +35 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +30 -0
- package/dist/styles/BottomPreviewDisplay.css +65 -0
- package/dist/styles/FloatingToolbar.css +41 -0
- package/dist/styles/ImageGallery.css +147 -0
- package/dist/styles/ImageNavButton.css +35 -0
- package/dist/styles/ImageZoomModal.css +101 -0
- package/dist/styles/LayerPanel.css +179 -0
- package/dist/styles/LoadingOverlay.css +48 -0
- package/dist/styles/ProductEditor.css +192 -0
- package/dist/styles/TextToolbar.css +327 -0
- package/dist/styles/Toolbar.css +125 -0
- package/dist/styles/index.css +5 -0
- package/dist/styles/textToolbarSelectStyles.d.ts +3 -0
- package/dist/styles/textToolbarSelectStyles.js +30 -0
- package/dist/types.d.ts +228 -0
- package/dist/types.js +17 -0
- package/dist/utils/canvasAddText.d.ts +11 -0
- package/dist/utils/canvasAddText.js +66 -0
- package/dist/utils/canvasUtils.d.ts +37 -0
- package/dist/utils/canvasUtils.js +342 -0
- package/dist/utils/deviceUtils.d.ts +5 -0
- package/dist/utils/deviceUtils.js +33 -0
- package/dist/utils/draftTemplateUtils.d.ts +23 -0
- package/dist/utils/draftTemplateUtils.js +66 -0
- package/dist/utils/grid.d.ts +32 -0
- package/dist/utils/grid.js +151 -0
- package/dist/utils/imageUtils.d.ts +12 -0
- package/dist/utils/imageUtils.js +178 -0
- package/dist/utils/job.d.ts +40 -0
- package/dist/utils/job.js +115 -0
- package/dist/utils/keyboard.d.ts +1 -0
- package/dist/utils/keyboard.js +26 -0
- package/dist/utils/previewUtils.d.ts +9 -0
- package/dist/utils/previewUtils.js +39 -0
- package/dist/utils/psdConverter.d.ts +40 -0
- package/dist/utils/psdConverter.js +516 -0
- package/dist/utils/psdRenderUtils.d.ts +12 -0
- package/dist/utils/psdRenderUtils.js +465 -0
- package/dist/utils/renderUtils.d.ts +2 -0
- package/dist/utils/renderUtils.js +85 -0
- package/package.json +66 -0
- package/src/components/AlignMenu.tsx +49 -0
- package/src/components/FloatingToolbar.tsx +83 -0
- package/src/components/FormatButtons.tsx +31 -0
- package/src/components/ImageNavButton.tsx +23 -0
- package/src/components/ImageZoomModal.tsx +163 -0
- package/src/components/LayerPanel.tsx +256 -0
- package/src/components/LoadingOverlay.tsx +27 -0
- package/src/components/ProductEditor.tsx +104 -0
- package/src/components/ProductImageGallery.tsx +181 -0
- package/src/components/ProductPreviews.tsx +243 -0
- package/src/components/TextToolbar.tsx +164 -0
- package/src/components/Toolbar.tsx +86 -0
- package/src/config/colorConfig.ts +7 -0
- package/src/config/fontConfig.ts +23 -0
- package/src/context/ProductEditorContext.tsx +829 -0
- package/src/hooks/useSwipeNavigate.ts +40 -0
- package/src/index.ts +6 -0
- package/src/styles/BottomPreviewDisplay.css +65 -0
- package/src/styles/FloatingToolbar.css +41 -0
- package/src/styles/ImageGallery.css +147 -0
- package/src/styles/ImageNavButton.css +35 -0
- package/src/styles/ImageZoomModal.css +101 -0
- package/src/styles/LayerPanel.css +179 -0
- package/src/styles/LoadingOverlay.css +48 -0
- package/src/styles/ProductEditor.css +192 -0
- package/src/styles/TextToolbar.css +327 -0
- package/src/styles/Toolbar.css +125 -0
- package/src/styles/index.css +5 -0
- package/src/styles/textToolbarSelectStyles.ts +60 -0
- package/src/types/ag-psd/index.d.ts +1 -0
- package/src/types/fabric.d.ts +14 -0
- package/src/types/lodash/index.d.ts +1 -0
- package/src/types/psd.d.ts +53 -0
- package/src/types.ts +247 -0
- package/src/utils/canvasAddText.ts +72 -0
- package/src/utils/canvasUtils.ts +406 -0
- package/src/utils/deviceUtils.ts +31 -0
- package/src/utils/draftTemplateUtils.ts +70 -0
- package/src/utils/grid.ts +154 -0
- package/src/utils/imageUtils.ts +218 -0
- package/src/utils/job.ts +128 -0
- package/src/utils/keyboard.ts +28 -0
- package/src/utils/previewUtils.ts +43 -0
- package/src/utils/psdConverter.ts +595 -0
- package/src/utils/psdRenderUtils.ts +453 -0
- package/src/utils/renderUtils.ts +44 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
26
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
27
|
+
if (ar || !(i in from)) {
|
|
28
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
29
|
+
ar[i] = from[i];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
var react_1 = __importStar(require("react"));
|
|
36
|
+
var ProductEditorContext_1 = require("../context/ProductEditorContext");
|
|
37
|
+
var grommet_icons_1 = require("grommet-icons");
|
|
38
|
+
require("../styles/LayerPanel.css");
|
|
39
|
+
var reorder = function (list, startIndex, endIndex) {
|
|
40
|
+
var result = Array.from(list);
|
|
41
|
+
var removed = result.splice(startIndex, 1)[0];
|
|
42
|
+
result.splice(endIndex, 0, removed);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
var LAYER_ITEM_HEIGHT_PX = 45;
|
|
46
|
+
var LayerPanel = function () {
|
|
47
|
+
var _a = (0, ProductEditorContext_1.useProductEditor)(), canvas = _a.canvas, toggleLayerPanel = _a.toggleLayerPanel, selectedObjectId = _a.selectedObjectId, selectObject = _a.selectObject, isMobileView = _a.isMobileView;
|
|
48
|
+
var _b = (0, react_1.useState)([]), layers = _b[0], setLayers = _b[1];
|
|
49
|
+
var dragItemIndex = (0, react_1.useRef)(null);
|
|
50
|
+
var dragOverItemIndex = (0, react_1.useRef)(null);
|
|
51
|
+
var _c = (0, react_1.useState)(false), isDraggingOver = _c[0], setIsDraggingOver = _c[1];
|
|
52
|
+
var _d = (0, react_1.useState)(null), dragOverIndexVisual = _d[0], setDragOverIndexVisual = _d[1];
|
|
53
|
+
(0, react_1.useEffect)(function () {
|
|
54
|
+
if (canvas) {
|
|
55
|
+
var updateLayers_1 = function () {
|
|
56
|
+
var filteredObjects = canvas.getObjects().filter(function (obj) {
|
|
57
|
+
return (obj.type === 'i-text' || obj.type === 'image') && obj.selectable;
|
|
58
|
+
});
|
|
59
|
+
setLayers(__spreadArray([], filteredObjects, true).reverse());
|
|
60
|
+
};
|
|
61
|
+
updateLayers_1();
|
|
62
|
+
var handleCanvasChange_1 = function () { return updateLayers_1(); };
|
|
63
|
+
canvas.on('object:added', handleCanvasChange_1);
|
|
64
|
+
canvas.on('object:removed', handleCanvasChange_1);
|
|
65
|
+
canvas.on('stack:changed', handleCanvasChange_1);
|
|
66
|
+
canvas.on('selection:created', handleCanvasChange_1);
|
|
67
|
+
canvas.on('selection:updated', handleCanvasChange_1);
|
|
68
|
+
canvas.on('selection:cleared', handleCanvasChange_1);
|
|
69
|
+
return function () {
|
|
70
|
+
canvas.off('object:added', handleCanvasChange_1);
|
|
71
|
+
canvas.off('object:removed', handleCanvasChange_1);
|
|
72
|
+
canvas.off('stack:changed', handleCanvasChange_1);
|
|
73
|
+
canvas.off('selection:created', handleCanvasChange_1);
|
|
74
|
+
canvas.off('selection:updated', handleCanvasChange_1);
|
|
75
|
+
canvas.off('selection:cleared', handleCanvasChange_1);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}, [canvas]);
|
|
79
|
+
var getLayerInfo = function (object) {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
if (object.type === 'i-text') {
|
|
82
|
+
return {
|
|
83
|
+
name: ((_a = object.text) === null || _a === void 0 ? void 0 : _a.substring(0, 20)) || 'Text',
|
|
84
|
+
icon: react_1.default.createElement(grommet_icons_1.TextAlignCenter, { size: "medium" })
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (object.type === 'image') {
|
|
88
|
+
var imageObject = object;
|
|
89
|
+
var src = imageObject.getSrc();
|
|
90
|
+
return {
|
|
91
|
+
name: object.name || (src ? (_b = src.split('/').pop()) === null || _b === void 0 ? void 0 : _b.substring(0, 20) : undefined) || 'Image',
|
|
92
|
+
icon: react_1.default.createElement("img", { src: src, alt: "layer thumb", className: "layer-thumbnail" })
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return { name: 'Unknown Layer', icon: react_1.default.createElement(react_1.default.Fragment, null) };
|
|
96
|
+
};
|
|
97
|
+
var handleDragStart = function (e, index) {
|
|
98
|
+
if (isMobileView)
|
|
99
|
+
return;
|
|
100
|
+
dragItemIndex.current = index;
|
|
101
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
102
|
+
setTimeout(function () { return setIsDraggingOver(true); }, 0);
|
|
103
|
+
};
|
|
104
|
+
var handleDragEnterItem = function (e, index) {
|
|
105
|
+
if (isMobileView)
|
|
106
|
+
return;
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
dragOverItemIndex.current = index;
|
|
109
|
+
setDragOverIndexVisual(index);
|
|
110
|
+
};
|
|
111
|
+
var handleDragLeaveList = function (e) {
|
|
112
|
+
if (isMobileView)
|
|
113
|
+
return;
|
|
114
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
115
|
+
dragOverItemIndex.current = null;
|
|
116
|
+
setDragOverIndexVisual(null);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var handleDragOverList = function (e) {
|
|
120
|
+
if (isMobileView)
|
|
121
|
+
return;
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
e.dataTransfer.dropEffect = 'move';
|
|
124
|
+
};
|
|
125
|
+
var handleDrop = function (e) {
|
|
126
|
+
if (isMobileView)
|
|
127
|
+
return;
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
var sourceIndex = dragItemIndex.current;
|
|
130
|
+
var destinationIndex = dragOverItemIndex.current;
|
|
131
|
+
setIsDraggingOver(false);
|
|
132
|
+
setDragOverIndexVisual(null);
|
|
133
|
+
dragItemIndex.current = null;
|
|
134
|
+
dragOverItemIndex.current = null;
|
|
135
|
+
if (sourceIndex === null || destinationIndex === null || sourceIndex === destinationIndex) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
var reorderedLayers = reorder(layers, sourceIndex, destinationIndex);
|
|
139
|
+
var objectToMove = layers[sourceIndex];
|
|
140
|
+
setLayers(reorderedLayers);
|
|
141
|
+
if (canvas && objectToMove) {
|
|
142
|
+
var totalObjects = canvas.getObjects().length;
|
|
143
|
+
var fabricTargetIndex = totalObjects - 1 - destinationIndex;
|
|
144
|
+
canvas.moveTo(objectToMove, fabricTargetIndex);
|
|
145
|
+
canvas.requestRenderAll();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
var handleDragEnd = function (e) {
|
|
149
|
+
if (isMobileView)
|
|
150
|
+
return;
|
|
151
|
+
setIsDraggingOver(false);
|
|
152
|
+
setDragOverIndexVisual(null);
|
|
153
|
+
dragItemIndex.current = null;
|
|
154
|
+
dragOverItemIndex.current = null;
|
|
155
|
+
};
|
|
156
|
+
var moveLayerUp = function (index) {
|
|
157
|
+
if (index <= 0 || !canvas)
|
|
158
|
+
return;
|
|
159
|
+
var objectToMove = layers[index];
|
|
160
|
+
var objectAbove = layers[index - 1];
|
|
161
|
+
var fabricIndexOfAbove = canvas.getObjects().indexOf(objectAbove);
|
|
162
|
+
if (fabricIndexOfAbove < 0) {
|
|
163
|
+
console.error("Could not find objectAbove in canvas stack for moveLayerUp");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
var targetFabricIndex = fabricIndexOfAbove;
|
|
167
|
+
canvas.moveTo(objectToMove, targetFabricIndex);
|
|
168
|
+
setLayers(function (prevLayers) { return reorder(prevLayers, index, index - 1); });
|
|
169
|
+
canvas.requestRenderAll();
|
|
170
|
+
};
|
|
171
|
+
var moveLayerDown = function (index) {
|
|
172
|
+
if (index >= layers.length - 1 || !canvas)
|
|
173
|
+
return;
|
|
174
|
+
var objectToMove = layers[index];
|
|
175
|
+
var objectBelow = layers[index + 1];
|
|
176
|
+
var fabricIndexOfBelow = canvas.getObjects().indexOf(objectBelow);
|
|
177
|
+
if (fabricIndexOfBelow < 0) {
|
|
178
|
+
console.error("Could not find objectBelow in canvas stack for moveLayerDown");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
var targetFabricIndex = fabricIndexOfBelow;
|
|
182
|
+
canvas.moveTo(objectToMove, targetFabricIndex);
|
|
183
|
+
setLayers(function (prevLayers) { return reorder(prevLayers, index, index + 1); });
|
|
184
|
+
canvas.requestRenderAll();
|
|
185
|
+
};
|
|
186
|
+
var handleLayerClick = function (layer) {
|
|
187
|
+
selectObject(layer);
|
|
188
|
+
};
|
|
189
|
+
return (react_1.default.createElement("div", { className: "layer-panel" },
|
|
190
|
+
react_1.default.createElement("div", { className: "layer-panel-header" },
|
|
191
|
+
react_1.default.createElement("h3", null, "Layers"),
|
|
192
|
+
react_1.default.createElement("button", { onClick: toggleLayerPanel, className: "close-button", title: "Close Panel" },
|
|
193
|
+
react_1.default.createElement(grommet_icons_1.Close, { size: "small" }))),
|
|
194
|
+
react_1.default.createElement("ul", { className: "layer-list ".concat(isDraggingOver ? 'is-dragging-active' : ''), onDragOver: handleDragOverList, onDrop: handleDrop, onDragLeave: handleDragLeaveList },
|
|
195
|
+
layers.map(function (layer, index) {
|
|
196
|
+
var layerInfo = getLayerInfo(layer);
|
|
197
|
+
var layerId = layer.id;
|
|
198
|
+
var isSelected = layerId && layerId === selectedObjectId;
|
|
199
|
+
var isDraggingThisItem = !isMobileView && isDraggingOver && dragItemIndex.current === index;
|
|
200
|
+
var transformStyle = 'translateY(0px)';
|
|
201
|
+
if (!isMobileView && isDraggingOver && dragItemIndex.current !== null && dragOverIndexVisual !== null && !isDraggingThisItem) {
|
|
202
|
+
var draggingFromIndex = dragItemIndex.current;
|
|
203
|
+
var hoveringOverIndex = dragOverIndexVisual;
|
|
204
|
+
if (index > draggingFromIndex && index <= hoveringOverIndex) {
|
|
205
|
+
transformStyle = "translateY(-".concat(LAYER_ITEM_HEIGHT_PX, "px)");
|
|
206
|
+
}
|
|
207
|
+
else if (index < draggingFromIndex && index >= hoveringOverIndex) {
|
|
208
|
+
transformStyle = "translateY(".concat(LAYER_ITEM_HEIGHT_PX, "px)");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return (react_1.default.createElement("li", { key: "layer-".concat(layerId || index), draggable: !isMobileView, onDragStart: function (e) { return handleDragStart(e, index); }, onDragEnter: function (e) { return handleDragEnterItem(e, index); }, onDragEnd: handleDragEnd, onClick: function () { return handleLayerClick(layer); }, className: "layer-item ".concat(isSelected ? 'selected' : '', " ").concat(isDraggingThisItem ? 'is-dragging-item' : ''), style: { transform: transformStyle } },
|
|
212
|
+
react_1.default.createElement("span", { className: "layer-icon" }, layerInfo.icon),
|
|
213
|
+
react_1.default.createElement("span", { className: "layer-name" }, layerInfo.name),
|
|
214
|
+
isMobileView ? (react_1.default.createElement("div", { className: "layer-mobile-controls" },
|
|
215
|
+
react_1.default.createElement("button", { className: "layer-move-button", onClick: function (e) { e.stopPropagation(); moveLayerUp(index); }, disabled: index === 0, title: "Move Up" },
|
|
216
|
+
react_1.default.createElement(grommet_icons_1.Up, { size: "small" })),
|
|
217
|
+
react_1.default.createElement("button", { className: "layer-move-button", onClick: function (e) { e.stopPropagation(); moveLayerDown(index); }, disabled: index === layers.length - 1, title: "Move Down" },
|
|
218
|
+
react_1.default.createElement(grommet_icons_1.Down, { size: "small" })))) : (react_1.default.createElement("span", { className: "layer-drag-indicator" },
|
|
219
|
+
react_1.default.createElement(grommet_icons_1.Drag, { size: "small" })))));
|
|
220
|
+
}),
|
|
221
|
+
layers.length === 0 && react_1.default.createElement("li", { className: "no-layers" }, "No layers found"))));
|
|
222
|
+
};
|
|
223
|
+
exports.default = LayerPanel;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import '../styles/LoadingOverlay.css';
|
|
3
|
+
interface LoadingOverlayProps {
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
message?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const LoadingOverlay: React.FC<LoadingOverlayProps>;
|
|
9
|
+
export default LoadingOverlay;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var react_1 = __importDefault(require("react"));
|
|
7
|
+
require("../styles/LoadingOverlay.css");
|
|
8
|
+
var LoadingOverlay = function (_a) {
|
|
9
|
+
var isLoading = _a.isLoading, _b = _a.message, message = _b === void 0 ? "Loading Canvas..." : _b, _c = _a.className, className = _c === void 0 ? "" : _c;
|
|
10
|
+
if (!isLoading) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return (react_1.default.createElement("div", { className: "loading-overlay ".concat(className) },
|
|
14
|
+
react_1.default.createElement("div", { className: "loading-spinner" }),
|
|
15
|
+
react_1.default.createElement("p", null, message)));
|
|
16
|
+
};
|
|
17
|
+
exports.default = LoadingOverlay;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
var react_1 = __importDefault(require("react"));
|
|
18
|
+
var ProductEditorContext_1 = require("../context/ProductEditorContext");
|
|
19
|
+
var FloatingToolbar_1 = __importDefault(require("./FloatingToolbar"));
|
|
20
|
+
var ProductPreviews_1 = __importDefault(require("./ProductPreviews"));
|
|
21
|
+
var Toolbar_1 = __importDefault(require("./Toolbar"));
|
|
22
|
+
var LoadingOverlay_1 = __importDefault(require("./LoadingOverlay"));
|
|
23
|
+
var TextToolbar_1 = __importDefault(require("./TextToolbar"));
|
|
24
|
+
var LayerPanel_1 = __importDefault(require("./LayerPanel"));
|
|
25
|
+
require("../styles/ProductEditor.css");
|
|
26
|
+
var ProductEditor = function () {
|
|
27
|
+
var _a = (0, ProductEditorContext_1.useProductEditor)(), canvasRef = _a.canvasRef, draftTemplates = _a.draftTemplates, groupIndex = _a.groupIndex, handleTemplateChange = _a.handleTemplateChange, isMobileView = _a.isMobileView, selectedTemplate = _a.selectedTemplate, showPreview = _a.showPreview, inputName = _a.inputName, isCanvasLoading = _a.isCanvasLoading, hookForm = _a.hookForm, selectedTextObject = _a.selectedTextObject, showLayerPanel = _a.showLayerPanel, renderedDraftPreviews = _a.renderedDraftPreviews;
|
|
28
|
+
var disableCanvasEvents = function (e) {
|
|
29
|
+
if (e.target.closest('.floating-toolbar') ||
|
|
30
|
+
e.target.closest('.bottom-preview-section') ||
|
|
31
|
+
e.target.closest('.mobile-bottom-toolbar')) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
};
|
|
36
|
+
var getTemplatePreviewImage = function (templateId) {
|
|
37
|
+
if (!templateId)
|
|
38
|
+
return null;
|
|
39
|
+
var renderedPreview = renderedDraftPreviews === null || renderedDraftPreviews === void 0 ? void 0 : renderedDraftPreviews.find(function (preview) { return preview.templateId === templateId; });
|
|
40
|
+
if (renderedPreview === null || renderedPreview === void 0 ? void 0 : renderedPreview.canvasPreview) {
|
|
41
|
+
return renderedPreview.canvasPreview;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
};
|
|
45
|
+
var register = hookForm === null || hookForm === void 0 ? void 0 : hookForm.register;
|
|
46
|
+
return (react_1.default.createElement("div", { className: "product-editor" },
|
|
47
|
+
register && (react_1.default.createElement("input", __assign({}, register(inputName), { type: 'hidden' }))),
|
|
48
|
+
!isCanvasLoading && draftTemplates.length > 0 && (react_1.default.createElement("div", { className: "template-buttons" }, draftTemplates.map(function (_a) {
|
|
49
|
+
var _b;
|
|
50
|
+
var template = _a.template;
|
|
51
|
+
return (react_1.default.createElement("div", { key: template.id, className: "template-button ".concat(selectedTemplate === template.id ? 'selected' : ''), onClick: function () { return handleTemplateChange(template); } },
|
|
52
|
+
!isMobileView && (getTemplatePreviewImage(template.id) || (template.file && template.file.viewUrl)) && (react_1.default.createElement("img", { src: getTemplatePreviewImage(template.id) || (((_b = template.file) === null || _b === void 0 ? void 0 : _b.viewUrl) || ''), alt: template.name || "Template ".concat(template.id), className: "template-thumbnail" })),
|
|
53
|
+
react_1.default.createElement("span", { className: "template-name" }, template.name || "Template ".concat(template.id))));
|
|
54
|
+
}))),
|
|
55
|
+
react_1.default.createElement("div", { className: "main-editor-layout", style: { position: 'relative' } },
|
|
56
|
+
react_1.default.createElement(LoadingOverlay_1.default, { isLoading: isCanvasLoading, className: "canvas-loading" }),
|
|
57
|
+
react_1.default.createElement("div", { className: "editor-container ".concat(isMobileView && showPreview ? 'has-bottom-padding' : '') },
|
|
58
|
+
selectedTextObject && react_1.default.createElement(TextToolbar_1.default, null),
|
|
59
|
+
react_1.default.createElement("div", { className: "canvas-area", onClick: disableCanvasEvents },
|
|
60
|
+
react_1.default.createElement("canvas", { ref: canvasRef })),
|
|
61
|
+
!isMobileView && !isCanvasLoading && react_1.default.createElement(FloatingToolbar_1.default, null),
|
|
62
|
+
showLayerPanel && react_1.default.createElement(LayerPanel_1.default, null)),
|
|
63
|
+
showPreview && react_1.default.createElement(ProductPreviews_1.default, null)),
|
|
64
|
+
isMobileView && !isCanvasLoading && (react_1.default.createElement("div", { className: "mobile-bottom-toolbar" },
|
|
65
|
+
react_1.default.createElement(Toolbar_1.default, null)))));
|
|
66
|
+
};
|
|
67
|
+
exports.default = ProductEditor;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
37
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
38
|
+
if (ar || !(i in from)) {
|
|
39
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
40
|
+
ar[i] = from[i];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
44
|
+
};
|
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
+
};
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
var react_1 = __importStar(require("react"));
|
|
50
|
+
var framer_motion_1 = require("framer-motion");
|
|
51
|
+
var ImageNavButton_1 = __importDefault(require("./ImageNavButton"));
|
|
52
|
+
var ImageZoomModal_1 = __importDefault(require("./ImageZoomModal"));
|
|
53
|
+
var grommet_icons_1 = require("grommet-icons");
|
|
54
|
+
var ProductEditorContext_1 = require("../context/ProductEditorContext");
|
|
55
|
+
var useSwipeNavigate_1 = require("../hooks/useSwipeNavigate");
|
|
56
|
+
var ProductImageGallery = function (_a) {
|
|
57
|
+
var _b;
|
|
58
|
+
var _c = _a.fallbackImageUrl, fallbackImageUrl = _c === void 0 ? '' : _c;
|
|
59
|
+
var product = (0, ProductEditorContext_1.useProductEditor)().product;
|
|
60
|
+
var _d = product.featureImage, featureImage = _d === void 0 ? null : _d, _e = product.images, images = _e === void 0 ? [] : _e, _f = product.name, productName = _f === void 0 ? 'Loading...' : _f;
|
|
61
|
+
var _images = featureImage ? __spreadArray([featureImage], images, true) : images;
|
|
62
|
+
var allImages = _images.map(function (image) {
|
|
63
|
+
if (!image)
|
|
64
|
+
return { viewUrl: '/blueman_white.png' };
|
|
65
|
+
return { viewUrl: image.viewUrl };
|
|
66
|
+
});
|
|
67
|
+
var totalImages = allImages.length;
|
|
68
|
+
// image browser related states
|
|
69
|
+
var _g = (0, react_1.useState)('right'), slideDirection = _g[0], setSlideDirection = _g[1];
|
|
70
|
+
var _h = (0, react_1.useState)(false), isZoomModalOpen = _h[0], setIsZoomModalOpen = _h[1];
|
|
71
|
+
var _j = (0, react_1.useState)(true), isImageLoading = _j[0], setIsImageLoading = _j[1];
|
|
72
|
+
var _k = (0, react_1.useState)(0), currentIndex = _k[0], setCurrentIndex = _k[1];
|
|
73
|
+
var _l = (0, react_1.useState)(((_b = allImages[currentIndex]) === null || _b === void 0 ? void 0 : _b.viewUrl) || fallbackImageUrl || '/blueman_white.png'), currentImageUrl = _l[0], setCurrentImageUrl = _l[1];
|
|
74
|
+
(0, react_1.useEffect)(function () {
|
|
75
|
+
var _a;
|
|
76
|
+
// set current image URL (for normal image mode)
|
|
77
|
+
if (allImages && allImages.length > 0) {
|
|
78
|
+
setCurrentImageUrl(((_a = allImages[currentIndex]) === null || _a === void 0 ? void 0 : _a.viewUrl) || '/blueman_white.png');
|
|
79
|
+
}
|
|
80
|
+
}, [allImages, currentIndex, fallbackImageUrl]);
|
|
81
|
+
var handleNavigation = function (newDirection) {
|
|
82
|
+
var _a;
|
|
83
|
+
if (!allImages || allImages.length <= 1)
|
|
84
|
+
return;
|
|
85
|
+
setSlideDirection(newDirection === 'left' ? 'left' : 'right');
|
|
86
|
+
var newIndex;
|
|
87
|
+
var actualTotalImages = Math.min(totalImages, allImages.length);
|
|
88
|
+
if (newDirection === 'left') {
|
|
89
|
+
newIndex = currentIndex === 0 ? actualTotalImages - 1 : currentIndex - 1;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
newIndex = currentIndex === actualTotalImages - 1 ? 0 : currentIndex + 1;
|
|
93
|
+
}
|
|
94
|
+
setCurrentIndex(newIndex);
|
|
95
|
+
setCurrentImageUrl(((_a = allImages[newIndex]) === null || _a === void 0 ? void 0 : _a.viewUrl) || '/blueman_white.png');
|
|
96
|
+
};
|
|
97
|
+
var handleThumbnailClick = function (index) {
|
|
98
|
+
var _a;
|
|
99
|
+
setCurrentIndex(index);
|
|
100
|
+
setCurrentImageUrl(((_a = allImages[index]) === null || _a === void 0 ? void 0 : _a.viewUrl) || '/blueman_white.png');
|
|
101
|
+
};
|
|
102
|
+
// Use the swipe hook
|
|
103
|
+
var swipeHandlers = (0, useSwipeNavigate_1.useSwipeNavigate)({
|
|
104
|
+
onSwipeLeft: function () { return handleNavigation('right'); },
|
|
105
|
+
onSwipeRight: function () { return handleNavigation('left'); },
|
|
106
|
+
});
|
|
107
|
+
var slideVariants = {
|
|
108
|
+
enter: function (direction) { return ({
|
|
109
|
+
x: direction === 'left' ? -1000 : 1000,
|
|
110
|
+
opacity: 0
|
|
111
|
+
}); },
|
|
112
|
+
center: {
|
|
113
|
+
zIndex: 1,
|
|
114
|
+
x: 0,
|
|
115
|
+
opacity: 1
|
|
116
|
+
},
|
|
117
|
+
exit: function (direction) { return ({
|
|
118
|
+
zIndex: 0,
|
|
119
|
+
x: direction === 'left' ? 1000 : -1000,
|
|
120
|
+
opacity: 0
|
|
121
|
+
}); }
|
|
122
|
+
};
|
|
123
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
124
|
+
react_1.default.createElement("div", { className: "image-gallery-container relative" },
|
|
125
|
+
react_1.default.createElement("div", { className: "image-container overflow-hidden" },
|
|
126
|
+
react_1.default.createElement(framer_motion_1.AnimatePresence, { initial: false, custom: slideDirection },
|
|
127
|
+
react_1.default.createElement(framer_motion_1.motion.div, __assign({ key: currentIndex, custom: slideDirection, variants: slideVariants, initial: "enter", animate: "center", exit: "exit", transition: {
|
|
128
|
+
x: { type: "spring", stiffness: 300, damping: 30 },
|
|
129
|
+
opacity: { duration: 0.2 }
|
|
130
|
+
}, className: "image-slide" }, swipeHandlers),
|
|
131
|
+
react_1.default.createElement("img", { src: currentImageUrl, alt: productName || "Product Image", className: "gallery-image ".concat(isImageLoading ? '' : 'image-loaded'), onLoad: function () { return setIsImageLoading(false); } }),
|
|
132
|
+
isImageLoading && (react_1.default.createElement("div", { className: "loading-indicator" },
|
|
133
|
+
react_1.default.createElement("div", { className: "loading-spinner" }))))),
|
|
134
|
+
react_1.default.createElement("button", { onClick: function () { return setIsZoomModalOpen(true); }, className: "zoom-button", type: "button" },
|
|
135
|
+
react_1.default.createElement(grommet_icons_1.ZoomIn, { className: "zoom-icon" }))),
|
|
136
|
+
allImages.length > 1 && (react_1.default.createElement("div", { className: "nav-buttons-container" },
|
|
137
|
+
react_1.default.createElement(ImageNavButton_1.default, { direction: "left", onClick: function () { return handleNavigation('left'); } }),
|
|
138
|
+
react_1.default.createElement(ImageNavButton_1.default, { direction: "right", onClick: function () { return handleNavigation('right'); } })))),
|
|
139
|
+
allImages.length > 1 && (react_1.default.createElement("div", { className: "thumbnails-container" },
|
|
140
|
+
react_1.default.createElement("div", { className: "thumbnails-row" }, allImages.slice(0, 5).map(function (image, index) {
|
|
141
|
+
var imageSrc = image.viewUrl || "/blueman_white.png";
|
|
142
|
+
var isSelected = index === currentIndex;
|
|
143
|
+
return (react_1.default.createElement("button", { key: index, onClick: function () { return handleThumbnailClick(index); }, className: "thumbnail-button ".concat(isSelected ? 'selected' : ''), type: "button" },
|
|
144
|
+
react_1.default.createElement("img", { src: imageSrc, loading: "lazy", alt: "Product Image ".concat(index + 1), className: "thumbnail-image" })));
|
|
145
|
+
})))),
|
|
146
|
+
react_1.default.createElement(ImageZoomModal_1.default, { isOpen: isZoomModalOpen, onClose: function () { return setIsZoomModalOpen(false); }, imageUrl: currentImageUrl, productName: productName, totalImages: allImages.length, currentIndex: currentIndex, allImages: allImages })));
|
|
147
|
+
};
|
|
148
|
+
exports.default = ProductImageGallery;
|