@lancom/shared 0.0.434 → 0.0.435
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/assets/js/models/product-layers.js +1 -1
- package/components/common/file_uploader.vue +19 -3
- package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.scss +11 -0
- package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.vue +42 -18
- package/components/editor/editor_layers/editor_layers_toolbar/editor-layers-toolbar.vue +2 -3
- package/components/editor/editor_workspace/editor-workspace.vue +7 -2
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.scss +25 -2
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +41 -20
- package/components/product/product_check_delivery/product-check-delivery.vue +1 -1
- package/components/product/product_pricing_tiers/product-pricing-tiers.vue +7 -3
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
<slot name="toggle" :uploading="uploading"></slot>
|
|
12
12
|
<slot name="progress" :progress="progress"></slot>
|
|
13
13
|
<input
|
|
14
|
+
:id="'fileUpload' + uniqueKey"
|
|
14
15
|
ref="fileUploaderField"
|
|
15
16
|
class="FileUploader__input"
|
|
16
17
|
type="file"
|
|
@@ -20,6 +21,10 @@
|
|
|
20
21
|
:required="required"
|
|
21
22
|
:disabled="disabled || uploading"
|
|
22
23
|
@change="fileChange" />
|
|
24
|
+
<label
|
|
25
|
+
:for="'fileUpload' + uniqueKey"
|
|
26
|
+
class="FileUploader__input-label">
|
|
27
|
+
</label>
|
|
23
28
|
</div>
|
|
24
29
|
</div>
|
|
25
30
|
<div v-if="hasUploadLink">
|
|
@@ -59,14 +64,14 @@ export default {
|
|
|
59
64
|
rendered: null,
|
|
60
65
|
error: null,
|
|
61
66
|
progress: 0,
|
|
62
|
-
|
|
67
|
+
uniqueKey: Math.random()
|
|
63
68
|
};
|
|
64
69
|
},
|
|
65
70
|
methods: {
|
|
66
71
|
async onPastLink(event) {
|
|
67
72
|
const url = event.target.value?.trim();
|
|
68
73
|
if (!url) return;
|
|
69
|
-
|
|
74
|
+
|
|
70
75
|
try {
|
|
71
76
|
const response = await fetch(url);
|
|
72
77
|
const blob = await response.blob();
|
|
@@ -167,7 +172,9 @@ export default {
|
|
|
167
172
|
display: inline-block;
|
|
168
173
|
position: relative;
|
|
169
174
|
width: inherit;
|
|
175
|
+
cursor: pointer !important;
|
|
170
176
|
&:before {
|
|
177
|
+
cursor: pointer !important;
|
|
171
178
|
content: '';
|
|
172
179
|
position: absolute;
|
|
173
180
|
width: 100%;
|
|
@@ -209,10 +216,19 @@ export default {
|
|
|
209
216
|
width: 100%;
|
|
210
217
|
height: 100%;
|
|
211
218
|
position: absolute;
|
|
212
|
-
cursor: pointer;
|
|
213
219
|
&.disabled {
|
|
214
220
|
cursor: default;
|
|
215
221
|
}
|
|
222
|
+
|
|
223
|
+
&-label {
|
|
224
|
+
opacity: 0;
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
position: absolute;
|
|
227
|
+
top: 0;
|
|
228
|
+
right: 0;
|
|
229
|
+
bottom: 0;
|
|
230
|
+
left: 0;
|
|
231
|
+
}
|
|
216
232
|
}
|
|
217
233
|
}
|
|
218
234
|
</style>
|
|
@@ -19,6 +19,17 @@
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
&__placeholder {
|
|
23
|
+
position: absolute;
|
|
24
|
+
text-transform: uppercase;
|
|
25
|
+
font-size: 22px;
|
|
26
|
+
font-weight: 800px;
|
|
27
|
+
left: 0;
|
|
28
|
+
right: 0;
|
|
29
|
+
text-align: center;
|
|
30
|
+
top: 50%;
|
|
31
|
+
z-index: 1;
|
|
32
|
+
}
|
|
22
33
|
&__content {
|
|
23
34
|
padding-top: 24px;
|
|
24
35
|
}
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
</slot>
|
|
8
8
|
|
|
9
9
|
<div class="EditorLayerFormText__preview">
|
|
10
|
+
<div
|
|
11
|
+
v-if="isVisiblePlaceholder"
|
|
12
|
+
class="EditorLayerFormText__placeholder"
|
|
13
|
+
@click="editText()">
|
|
14
|
+
Add Text
|
|
15
|
+
</div>
|
|
10
16
|
<canvas ref="previewCanvas"></canvas>
|
|
11
17
|
</div>
|
|
12
18
|
|
|
@@ -171,19 +177,23 @@ import ColorPicker from '@lancom/shared/components/common/color-picker';
|
|
|
171
177
|
import EditorLayerCommonFields from '../editor_layer_common_fields/editor-layer-common-fields';
|
|
172
178
|
import FontFamilySelect from './font-family_select/font-family-select';
|
|
173
179
|
|
|
174
|
-
const editableModel = (field, prop)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
180
|
+
const editableModel = function (field, prop) {
|
|
181
|
+
return {
|
|
182
|
+
get() {
|
|
183
|
+
return prop
|
|
184
|
+
? this[`${field}_options`].find(o => o[prop] === this.layer[field])
|
|
185
|
+
: this.layer[field];
|
|
186
|
+
},
|
|
187
|
+
set(v) {
|
|
188
|
+
const value = prop && Object.prototype.hasOwnProperty.call(v, prop) ? v[prop] : v;
|
|
189
|
+
this.$emit('set-layer-field', { field, value });
|
|
190
|
+
if (field !== 'copy') {
|
|
191
|
+
this.textObject[field] = value;
|
|
192
|
+
}
|
|
193
|
+
this.fabricCanvas.renderAll();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
};
|
|
187
197
|
export default {
|
|
188
198
|
name: 'EditorLayerFormText',
|
|
189
199
|
components: {
|
|
@@ -249,6 +259,9 @@ export default {
|
|
|
249
259
|
},
|
|
250
260
|
fontFamily_options() {
|
|
251
261
|
return availableFonts.map(({ label, alias }) => ({ label, value: alias }));
|
|
262
|
+
},
|
|
263
|
+
isVisiblePlaceholder() {
|
|
264
|
+
return !this.copy?.trim() && !this.isEditing;
|
|
252
265
|
}
|
|
253
266
|
},
|
|
254
267
|
mounted() {
|
|
@@ -261,6 +274,14 @@ export default {
|
|
|
261
274
|
}
|
|
262
275
|
},
|
|
263
276
|
methods: {
|
|
277
|
+
editText() {
|
|
278
|
+
if (!this.isEditing) {
|
|
279
|
+
this.fabricCanvas.setActiveObject(this.textObject);
|
|
280
|
+
this.textObject.enterEditing();
|
|
281
|
+
this.textObject.hiddenTextarea.focus();
|
|
282
|
+
this.isEditing = true;
|
|
283
|
+
}
|
|
284
|
+
},
|
|
264
285
|
async selectFont({ value }) {
|
|
265
286
|
const font = await loadFont(value);
|
|
266
287
|
Object.keys(font).forEach(field => this.$emit('set-layer-field', {
|
|
@@ -288,7 +309,7 @@ export default {
|
|
|
288
309
|
initFabricCanvas() {
|
|
289
310
|
if (this.$refs.previewCanvas) {
|
|
290
311
|
this.fabricCanvas = new fabric.Canvas(this.$refs.previewCanvas, {
|
|
291
|
-
width:
|
|
312
|
+
width: this.$refs.previewCanvas.parentElement.offsetWidth,
|
|
292
313
|
height: 200,
|
|
293
314
|
uniScaleTransform: false
|
|
294
315
|
});
|
|
@@ -311,6 +332,11 @@ export default {
|
|
|
311
332
|
this.syncTextFromCanvas();
|
|
312
333
|
}
|
|
313
334
|
});
|
|
335
|
+
this.fabricCanvas.on('mouse:down', options => {
|
|
336
|
+
if (options.target === this.textObject) {
|
|
337
|
+
this.editText();
|
|
338
|
+
}
|
|
339
|
+
});
|
|
314
340
|
},
|
|
315
341
|
async renderLayer() {
|
|
316
342
|
try {
|
|
@@ -347,12 +373,10 @@ export default {
|
|
|
347
373
|
|
|
348
374
|
this.fabricCanvas.add(textObj);
|
|
349
375
|
this.fabricCanvas.renderAll();
|
|
376
|
+
|
|
350
377
|
this.textObject = textObj;
|
|
351
378
|
|
|
352
|
-
this
|
|
353
|
-
this.fabricCanvas.setActiveObject(textObj);
|
|
354
|
-
textObj.enterEditing();
|
|
355
|
-
});
|
|
379
|
+
this.editText();
|
|
356
380
|
} catch (error) {
|
|
357
381
|
console.error('Error rendering layer:', error);
|
|
358
382
|
}
|
|
@@ -21,12 +21,11 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<file-uploader
|
|
24
|
+
class="EditorLayersToolbar__option"
|
|
24
25
|
:multiple="false"
|
|
25
26
|
:url="`image/editor/${shop._id}/${product._id}`"
|
|
26
27
|
@onuploaded="handleUploaded">
|
|
27
|
-
<div
|
|
28
|
-
slot="toggle"
|
|
29
|
-
class="EditorLayersToolbar__option">
|
|
28
|
+
<div slot="toggle">
|
|
30
29
|
<i class="icon-layer-art EditorLayersToolbar__option-icon"></i>
|
|
31
30
|
<div class="lc_black">
|
|
32
31
|
Add art
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
<editor-workspace-side
|
|
30
30
|
ref="editor"
|
|
31
31
|
:key="side"
|
|
32
|
+
:is-edit-mode="isEditMode"
|
|
32
33
|
:side="side"
|
|
33
34
|
:print-area="editablePrintArea"
|
|
34
35
|
:zoom-size="sideZoomSize"
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
<editor-workspace-side
|
|
66
67
|
ref="editor"
|
|
67
68
|
:key="editableSide.id"
|
|
69
|
+
:is-edit-mode="isEditMode"
|
|
68
70
|
:side="editableSide.id"
|
|
69
71
|
:print-area="editablePrintArea"
|
|
70
72
|
:print-area-size="selectedPrintArea"
|
|
@@ -113,8 +115,7 @@
|
|
|
113
115
|
:side="editableSide.id"
|
|
114
116
|
:layers="editableLayers"
|
|
115
117
|
@select="selectPrintArea"
|
|
116
|
-
@option-mouseover="toogleBoundBox(true, $event)"
|
|
117
|
-
@option-mouseleave="toogleBoundBox(false, $event)">
|
|
118
|
+
@option-mouseover="toogleBoundBox(true, $event)">
|
|
118
119
|
</editor-print-area-options>
|
|
119
120
|
</div>
|
|
120
121
|
</div>
|
|
@@ -153,6 +154,10 @@ export default {
|
|
|
153
154
|
visibleBackgroundImage: {
|
|
154
155
|
type: Boolean,
|
|
155
156
|
default: true
|
|
157
|
+
},
|
|
158
|
+
isEditMode: {
|
|
159
|
+
type: Boolean,
|
|
160
|
+
default: true
|
|
156
161
|
}
|
|
157
162
|
},
|
|
158
163
|
data() {
|
|
@@ -64,6 +64,24 @@
|
|
|
64
64
|
bottom: 0;
|
|
65
65
|
z-index: 1000;
|
|
66
66
|
}
|
|
67
|
+
&__add-btn {
|
|
68
|
+
background-color: white;
|
|
69
|
+
opacity: 0.8;
|
|
70
|
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
71
|
+
border-radius: 3px;
|
|
72
|
+
box-shadow: 0px 0px 0px rgba(75, 75, 75, 0.2);
|
|
73
|
+
margin: 3px 0;
|
|
74
|
+
padding: 5px;
|
|
75
|
+
min-width: 73px;
|
|
76
|
+
&:nth-child(3) {
|
|
77
|
+
padding: 5px 5px 3px 5px;
|
|
78
|
+
}
|
|
79
|
+
&:hover {
|
|
80
|
+
opacity: 1;
|
|
81
|
+
transform: translateY(-1px);
|
|
82
|
+
box-shadow: 0px 5px 15px rgba(75, 75, 75, 0.2);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
67
85
|
&__placeholder {
|
|
68
86
|
position: absolute;
|
|
69
87
|
z-index: 999;
|
|
@@ -72,6 +90,7 @@
|
|
|
72
90
|
align-items: center;
|
|
73
91
|
justify-content: center;
|
|
74
92
|
flex-direction: column;
|
|
93
|
+
font-size: 12px;
|
|
75
94
|
|
|
76
95
|
// @media (max-width: $bp-extra-small-max) {
|
|
77
96
|
// font-size: 10px;
|
|
@@ -86,8 +105,8 @@
|
|
|
86
105
|
letter-spacing: -0.5px;
|
|
87
106
|
&-option {
|
|
88
107
|
cursor: pointer;
|
|
89
|
-
margin: 5px 0;
|
|
90
108
|
text-transform: uppercase;
|
|
109
|
+
display: inline-block;
|
|
91
110
|
span {
|
|
92
111
|
&:last-child {
|
|
93
112
|
display: none;
|
|
@@ -102,6 +121,10 @@
|
|
|
102
121
|
}
|
|
103
122
|
&-divider {
|
|
104
123
|
color: $grey_1;
|
|
124
|
+
padding: 2px;
|
|
125
|
+
background-color: white;
|
|
126
|
+
border-radius: 2px;
|
|
127
|
+
opacity: 0.7;
|
|
105
128
|
}
|
|
106
129
|
&-progress {
|
|
107
130
|
position: absolute;
|
|
@@ -185,4 +208,4 @@
|
|
|
185
208
|
background-color: #EB5757;
|
|
186
209
|
}
|
|
187
210
|
}
|
|
188
|
-
}
|
|
211
|
+
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
}"
|
|
8
8
|
v-click-outside="onOutsideClick"
|
|
9
9
|
@mouseover="toogleBoundBox(true)"
|
|
10
|
-
@mouseleave="toogleBoundBox(false)"
|
|
11
10
|
@mouseup="toggleOnpressImage(false)">
|
|
12
11
|
<div
|
|
13
12
|
v-if="hasOnpressImage || hasWireframeImage"
|
|
@@ -60,15 +59,23 @@
|
|
|
60
59
|
ignore-document-click
|
|
61
60
|
:style="positionPlaceholder">
|
|
62
61
|
<div
|
|
63
|
-
|
|
64
|
-
class="
|
|
65
|
-
|
|
62
|
+
class="EditorWorkspaceSide__placeholder-option"
|
|
63
|
+
:class="{
|
|
64
|
+
'EditorWorkspaceSide__add-btn': !printAreaLayers.length
|
|
65
|
+
}"
|
|
66
|
+
@click="createTextLayer">
|
|
67
|
+
<span>
|
|
68
|
+
<i class="icon-layer-text"></i> Add Text
|
|
69
|
+
</span>
|
|
66
70
|
<span style="margin-top: -0.5px;">Text</span>
|
|
67
71
|
</div>
|
|
68
72
|
<div class="EditorWorkspaceSide__placeholder-divider">
|
|
69
73
|
or
|
|
70
74
|
</div>
|
|
71
|
-
<div
|
|
75
|
+
<div
|
|
76
|
+
:class="{
|
|
77
|
+
'EditorWorkspaceSide__add-btn': !printAreaLayers.length
|
|
78
|
+
}">
|
|
72
79
|
<file-uploader
|
|
73
80
|
:multiple="false"
|
|
74
81
|
:url="`image/editor/${shop._id}/${product._id}`"
|
|
@@ -165,6 +172,10 @@ export default {
|
|
|
165
172
|
visibleBackgroundImage: {
|
|
166
173
|
type: Boolean,
|
|
167
174
|
default: true
|
|
175
|
+
},
|
|
176
|
+
isEditMode: {
|
|
177
|
+
type: Boolean,
|
|
178
|
+
default: true
|
|
168
179
|
}
|
|
169
180
|
},
|
|
170
181
|
data() {
|
|
@@ -235,16 +246,22 @@ export default {
|
|
|
235
246
|
},
|
|
236
247
|
positionPlaceholder() {
|
|
237
248
|
const { center, left, top, width, height } = this.fabricHelper.printAreaRect;
|
|
238
|
-
// console.log('this.fabricHelper.printAreaRect: ', this.fabricHelper.printAreaRect);
|
|
239
249
|
const ratio = this.calcWorkspaceSize() / this.editorSize.width;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
250
|
+
if (this.printAreaLayers.length > 0) {
|
|
251
|
+
return {
|
|
252
|
+
top: `${(top + height) * ratio}px`,
|
|
253
|
+
left: `${left * ratio}px`
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
const centerX = center?.x ?? (left + width / 2);
|
|
257
|
+
const centerY = center?.y ?? (top + height / 2);
|
|
258
|
+
const placeholderWidth = Math.max(100, width * ratio);
|
|
259
|
+
const placeholderHeight = height * ratio;
|
|
260
|
+
return {
|
|
261
|
+
top: `${(centerY * ratio) - (placeholderHeight / 2)}px`,
|
|
262
|
+
left: `${(centerX * ratio) - (placeholderWidth / 2)}px`,
|
|
263
|
+
width: `${placeholderWidth}px`,
|
|
264
|
+
height: `${placeholderHeight}px`
|
|
248
265
|
};
|
|
249
266
|
},
|
|
250
267
|
printAreaIsSmall() {
|
|
@@ -346,15 +363,12 @@ export default {
|
|
|
346
363
|
this.$emit('workspace', { size: this.calcWorkspaceSize(true), fabricHelper: this.fabricHelper });
|
|
347
364
|
},
|
|
348
365
|
initEventsListeners() {
|
|
349
|
-
// document.addEventListener('mousedown', this.onDocumentStartClick);
|
|
350
366
|
window.addEventListener('resize', this.onResize);
|
|
351
367
|
},
|
|
352
368
|
clearEventsListeners() {
|
|
353
|
-
// document.removeEventListener('mousedown', this.onDocumentStartClick);
|
|
354
369
|
window.removeEventListener('resize', this.onResize);
|
|
355
370
|
},
|
|
356
371
|
onDocumentStartClick({ target }) {
|
|
357
|
-
// todo: replace by click outside plugin?
|
|
358
372
|
console.log('target: ', target);
|
|
359
373
|
const isCanvasElement = target.tagName === 'CANVAS';
|
|
360
374
|
const isIgnoreClick = !!findParentByPredicate(target, element => element.hasAttribute('ignore-document-click'));
|
|
@@ -386,7 +400,7 @@ export default {
|
|
|
386
400
|
});
|
|
387
401
|
this.fabricHelper.on('setDeleteButtonPosition', this.setDeleteButtonPosition);
|
|
388
402
|
this.fabricHelper.on('outOfPrintArea', this.setOffsetWarningVisibility);
|
|
389
|
-
|
|
403
|
+
|
|
390
404
|
this.updateBackgroundImage();
|
|
391
405
|
this.redrawWithThrottle();
|
|
392
406
|
},
|
|
@@ -451,11 +465,18 @@ export default {
|
|
|
451
465
|
const image = this.fabricHelper.getLayersAsImage();
|
|
452
466
|
this.setLayersThumbnail({ side: this.side, value: image });
|
|
453
467
|
},
|
|
454
|
-
createTextLayer() {
|
|
468
|
+
async createTextLayer() {
|
|
455
469
|
this.addedFromCanvas = true;
|
|
456
470
|
window.scrollTo(0, 0);
|
|
457
|
-
this.createLayer({ type: 'text', isEditMode:
|
|
471
|
+
const layer = await this.createLayer({ type: 'text', isEditMode: this.isEditMode });
|
|
458
472
|
this.visibleWireframe = true;
|
|
473
|
+
if (!this.isEditMode) {
|
|
474
|
+
setTimeout(() => {
|
|
475
|
+
this.setSelectedLayer(layer);
|
|
476
|
+
this.setEditModeSelectedLayer(true);
|
|
477
|
+
this.toogleBoundBox(true);
|
|
478
|
+
});
|
|
479
|
+
}
|
|
459
480
|
},
|
|
460
481
|
async handleUploaded({ url, size, fileName }) {
|
|
461
482
|
window.scrollTo(0, 0);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</h3>
|
|
6
6
|
<div class="ProductPricingTiers__tiers">
|
|
7
7
|
<div
|
|
8
|
-
v-for="(tier, index) in
|
|
8
|
+
v-for="(tier, index) in visibleTiers"
|
|
9
9
|
:key="index"
|
|
10
10
|
class="ProductPricingTiers__tier"
|
|
11
11
|
@click="selectTier(tier)">
|
|
@@ -41,8 +41,12 @@ export default {
|
|
|
41
41
|
},
|
|
42
42
|
mixins: [MultipackMixin],
|
|
43
43
|
computed: {
|
|
44
|
-
...mapGetters('product', ['product', 'editableColor', 'priceIncludeGST', 'defaultSimpleProduct']),
|
|
45
|
-
...mapGetters(['pricingSettings', 'currency'])
|
|
44
|
+
...mapGetters('product', ['product', 'editableColor', 'priceIncludeGST', 'isPrintPricing', 'printsPrice', 'defaultSimpleProduct']),
|
|
45
|
+
...mapGetters(['pricingSettings', 'currency']),
|
|
46
|
+
visibleTiers() {
|
|
47
|
+
const pricing = this.defaultSimpleProduct.pricing;
|
|
48
|
+
return pricing.map(p => ({ ...p, price: p.price + this.printsPrice }));
|
|
49
|
+
}
|
|
46
50
|
},
|
|
47
51
|
methods: {
|
|
48
52
|
selectTier(tier) {
|