@lancom/shared 0.0.449 → 0.0.450
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/api/index.js +4 -1
- package/assets/js/utils/export-print-to-svg.js +1 -1
- package/assets/js/utils/fabric/selection-style.js +145 -44
- package/assets/js/utils/fabric-helper.js +11 -34
- package/components/common/file_uploader.vue +5 -4
- package/components/common/postcode_select/postcode-select.vue +1 -1
- package/components/common/product_side_with_print/product-side-with-print.vue +6 -2
- package/components/editor/editor_colors/editor-colors.vue +1 -0
- package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.vue +1 -2
- package/components/editor/editor_layers/editor_layers_layer/editor-layers-layer.scss +1 -0
- package/components/editor/editor_layers/editor_layers_layer/editor-layers-layer.vue +2 -2
- package/components/editor/editor_layers/editor_layers_toolbar/editor-layers-toolbar.vue +1 -0
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +3 -20
- package/components/modals/failed_conversion_modal/failed-conversion-modal.vue +1 -0
- package/components/product/product_check_delivery/product-check-delivery.vue +8 -1
- package/components/product/wizard/wizard_print_layers/wizard_print_layer/wizard-print-layer.vue +1 -0
- package/components/product/wizard/wizard_print_text_or_logo/wizard_text_or_logo_form/wizard-text-or-logo-form.vue +1 -0
- package/feeds/google-shopping.js +22 -13
- package/nuxt.config.js +1 -1
- package/package.json +1 -1
package/assets/js/api/index.js
CHANGED
|
@@ -161,7 +161,7 @@ const api = {
|
|
|
161
161
|
subscribe(data, shop) {
|
|
162
162
|
return _post(`shop/${shop}/subscribe`, data);
|
|
163
163
|
},
|
|
164
|
-
uploadImage(file, progressCallback = Function.prototype, requestUrl = 'image/upload') {
|
|
164
|
+
uploadImage(file, progressCallback = Function.prototype, requestUrl = 'image/upload', convert = false) {
|
|
165
165
|
const config = {
|
|
166
166
|
onUploadProgress: ({ loaded, total }) => {
|
|
167
167
|
progressCallback(Math.round((loaded * 100) / total));
|
|
@@ -169,6 +169,9 @@ const api = {
|
|
|
169
169
|
};
|
|
170
170
|
const formData = new FormData();
|
|
171
171
|
formData.set('file', file);
|
|
172
|
+
if (convert) {
|
|
173
|
+
requestUrl += (requestUrl.includes('?') ? '&' : '?') + 'convert=true';
|
|
174
|
+
}
|
|
172
175
|
return _post(requestUrl, formData, config);
|
|
173
176
|
},
|
|
174
177
|
sendFailedConversionFile(data, shop) {
|
|
@@ -11,7 +11,7 @@ export function convertPrintToSVG(layers, printSize) {
|
|
|
11
11
|
return new Promise(resolve => {
|
|
12
12
|
const svgSize = getSVGSize(printSize);
|
|
13
13
|
console.log('svgSize: ', svgSize);
|
|
14
|
-
const canvas = new fabric.Canvas(document.createElement('canvas'), { ...svgSize
|
|
14
|
+
const canvas = new fabric.Canvas(document.createElement('canvas'), { ...svgSize });
|
|
15
15
|
Promise.all(
|
|
16
16
|
layers
|
|
17
17
|
.map(layer => {
|
|
@@ -1,59 +1,160 @@
|
|
|
1
1
|
import { fabric } from 'fabric';
|
|
2
2
|
|
|
3
|
-
let
|
|
3
|
+
let rotateImg;
|
|
4
|
+
let centerImg;
|
|
4
5
|
|
|
5
6
|
export function loadRotateImage(cb = Function.prototype) {
|
|
6
7
|
const image = new Image();
|
|
7
|
-
image.src =
|
|
8
|
+
image.src = '/icons/rotate.png';
|
|
8
9
|
image.onload = () => {
|
|
9
|
-
|
|
10
|
+
rotateImg = image;
|
|
10
11
|
cb();
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const top = -(height + scaleOffset) / 2;
|
|
23
|
-
const methodName = this.transparentCorners ? 'stroke' : 'fill';
|
|
15
|
+
export function loadCenterImage(cb = Function.prototype) {
|
|
16
|
+
const image = new Image();
|
|
17
|
+
image.src = '/icons/center.png';
|
|
18
|
+
image.onload = () => {
|
|
19
|
+
centerImg = image;
|
|
20
|
+
cb();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
24
23
|
|
|
24
|
+
function renderIcon(ctx, left, top, styleOverride, fabricObject, icon) {
|
|
25
|
+
const size = 20;
|
|
25
26
|
ctx.save();
|
|
27
|
+
ctx.translate(left, top);
|
|
28
|
+
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
|
29
|
+
ctx.drawImage(icon, -size / 2, -size / 2, size, size);
|
|
30
|
+
ctx.restore();
|
|
31
|
+
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!this.get('lockUniScaling')) {
|
|
39
|
-
this._drawControl('mt', ctx, methodName, left + width / 2, top);
|
|
40
|
-
this._drawControl('mb', ctx, methodName, left + width / 2, top + height);
|
|
41
|
-
this._drawControl('mr', ctx, methodName, left + width, top + height / 2);
|
|
42
|
-
this._drawControl('ml', ctx, methodName, left, top + height / 2);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (this.hasRotatingPoint) {
|
|
46
|
-
const rotateLeft = left + width / 2 - 4;
|
|
47
|
-
const rotateTop = top - this.rotatingPointOffset - 5;
|
|
48
|
-
const drawRotateIcon = () => ctx.drawImage(rotate, rotateLeft, rotateTop, 20, 20);
|
|
49
|
-
if (!rotate) {
|
|
50
|
-
loadRotateImage(drawRotateIcon);
|
|
51
|
-
} else {
|
|
52
|
-
drawRotateIcon();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
33
|
+
export function setupCustomControls(fabricHelper) {
|
|
34
|
+
fabric.Object.prototype.set({
|
|
35
|
+
padding: 20,
|
|
36
|
+
cornerSize: 8,
|
|
37
|
+
cornerStyle: 'circle',
|
|
38
|
+
borderColor: '#7D6AEF',
|
|
39
|
+
cornerColor: '#7D6AEF',
|
|
40
|
+
cornerStrokeColor: '#fff',
|
|
41
|
+
transparentCorners: false
|
|
42
|
+
});
|
|
55
43
|
|
|
56
|
-
|
|
44
|
+
delete fabric.Object.prototype.controls.ml;
|
|
45
|
+
delete fabric.Object.prototype.controls.mr;
|
|
46
|
+
delete fabric.Object.prototype.controls.mt;
|
|
47
|
+
delete fabric.Object.prototype.controls.mb;
|
|
57
48
|
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
['tl', 'bl', 'br'].forEach(key => {
|
|
50
|
+
fabric.Object.prototype.controls[key].sizeX = 7;
|
|
51
|
+
fabric.Object.prototype.controls[key].sizeY = 7;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
fabric.Object.prototype.controls.tr = new fabric.Control({
|
|
55
|
+
x: 0.5,
|
|
56
|
+
y: -0.5,
|
|
57
|
+
cursorStyle: 'pointer',
|
|
58
|
+
mouseUpHandler: function(eventData, transform) {
|
|
59
|
+
const target = transform.target;
|
|
60
|
+
fabricHelper.dispatch('removeLayer', target.layer);
|
|
61
|
+
fabricHelper.editor.remove(target);
|
|
62
|
+
fabricHelper.editor.renderAll();
|
|
63
|
+
return true;
|
|
64
|
+
},
|
|
65
|
+
render: function(ctx, left, top, styleOverride, fabricObject) {
|
|
66
|
+
const size = 10;
|
|
67
|
+
ctx.save();
|
|
68
|
+
ctx.translate(left, top);
|
|
69
|
+
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
|
70
|
+
ctx.fillStyle = '#FF4444';
|
|
71
|
+
ctx.beginPath();
|
|
72
|
+
ctx.arc(0, 0, size / 2, 0, 2 * Math.PI, false);
|
|
73
|
+
ctx.fill();
|
|
74
|
+
ctx.strokeStyle = '#fff';
|
|
75
|
+
ctx.lineWidth = 2;
|
|
76
|
+
ctx.beginPath();
|
|
77
|
+
ctx.moveTo(-4, -4);
|
|
78
|
+
ctx.lineTo(4, 4);
|
|
79
|
+
ctx.moveTo(4, -4);
|
|
80
|
+
ctx.lineTo(-4, 4);
|
|
81
|
+
ctx.stroke();
|
|
82
|
+
ctx.restore();
|
|
83
|
+
},
|
|
84
|
+
cornerSize: 10
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
fabric.Object.prototype.controls.mtr = new fabric.Control({
|
|
88
|
+
x: 0,
|
|
89
|
+
y: -0.5,
|
|
90
|
+
offsetY: -30,
|
|
91
|
+
cursorStyle: 'pointer',
|
|
92
|
+
actionHandler: fabric.controlsUtils.rotationWithSnapping,
|
|
93
|
+
actionName: 'rotate',
|
|
94
|
+
render: function(ctx, left, top, styleOverride, fabricObject) {
|
|
95
|
+
if (rotateImg) {
|
|
96
|
+
renderIcon(ctx, left, top, styleOverride, fabricObject, rotateImg);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
cornerSize: 20,
|
|
100
|
+
withConnection: true
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
fabric.Object.prototype.controls.centerControl = new fabric.Control({
|
|
104
|
+
x: 0,
|
|
105
|
+
y: -0.5,
|
|
106
|
+
offsetY: -30,
|
|
107
|
+
offsetX: 30,
|
|
108
|
+
cursorStyle: 'pointer',
|
|
109
|
+
mouseUpHandler: function(eventData, transform) {
|
|
110
|
+
const target = transform.target;
|
|
111
|
+
const helper = fabricHelper;
|
|
112
|
+
|
|
113
|
+
if (helper && helper.printAreaRect) {
|
|
114
|
+
const printArea = helper.printAreaRect;
|
|
115
|
+
const scaleX = printArea.width / target.width;
|
|
116
|
+
const scaleY = printArea.height / target.height;
|
|
117
|
+
const scale = Math.min(scaleX, scaleY) * 0.8;
|
|
118
|
+
|
|
119
|
+
target.set({
|
|
120
|
+
scaleX: scale,
|
|
121
|
+
scaleY: scale,
|
|
122
|
+
left: printArea.left + printArea.width / 2,
|
|
123
|
+
top: printArea.top + printArea.height / 2
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
target.setCoords();
|
|
127
|
+
helper.editor.renderAll();
|
|
128
|
+
helper.dispatch('setField', { field: 'scaleX', value: scale });
|
|
129
|
+
helper.dispatch('setField', { field: 'scaleY', value: scale });
|
|
130
|
+
helper.dispatch('setField', { field: 'left', value: target.left });
|
|
131
|
+
helper.dispatch('setField', { field: 'top', value: target.top });
|
|
132
|
+
helper.dispatch('setField', { field: 'boundingRect', value: target.getBoundingRect() });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return true;
|
|
136
|
+
},
|
|
137
|
+
render: function(ctx, left, top, styleOverride, fabricObject) {
|
|
138
|
+
if (centerImg) {
|
|
139
|
+
renderIcon(ctx, left, top, styleOverride, fabricObject, centerImg);
|
|
140
|
+
} else {
|
|
141
|
+
const size = 20;
|
|
142
|
+
ctx.save();
|
|
143
|
+
ctx.translate(left, top);
|
|
144
|
+
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
|
145
|
+
ctx.fillStyle = '#7D6AEF';
|
|
146
|
+
ctx.beginPath();
|
|
147
|
+
ctx.arc(0, 0, size / 2, 0, 2 * Math.PI, false);
|
|
148
|
+
ctx.fill();
|
|
149
|
+
ctx.fillStyle = '#fff';
|
|
150
|
+
ctx.font = '14px Arial';
|
|
151
|
+
ctx.textAlign = 'center';
|
|
152
|
+
ctx.textBaseline = 'middle';
|
|
153
|
+
ctx.fillText('⊙', 0, 0);
|
|
154
|
+
ctx.restore();
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
cornerSize: 20,
|
|
158
|
+
withConnection: true
|
|
159
|
+
});
|
|
160
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { fabric } from 'fabric';
|
|
3
3
|
import { getPrintAreaByName } from '../models/print-area';
|
|
4
|
-
import { loadRotateImage } from './fabric/selection-style';
|
|
4
|
+
import { loadRotateImage, loadCenterImage, setupCustomControls } from './fabric/selection-style';
|
|
5
5
|
import EventDispatcher from './event-dispatcher';
|
|
6
6
|
import { createText, createArt } from './fabric/object-factory';
|
|
7
7
|
import { buildWireframe } from './fabric/wireframe';
|
|
@@ -14,7 +14,7 @@ class Background {
|
|
|
14
14
|
backgroundImage = null;
|
|
15
15
|
|
|
16
16
|
constructor({ background, size }) {
|
|
17
|
-
this.canvas = new fabric.Canvas(background, { ...size
|
|
17
|
+
this.canvas = new fabric.Canvas(background, { ...size });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
clear() {
|
|
@@ -68,7 +68,7 @@ export default class FabricHelper {
|
|
|
68
68
|
|
|
69
69
|
constructor({ editor, background, size }) {
|
|
70
70
|
this.size = size;
|
|
71
|
-
this.editor = new fabric.Canvas(editor, { ...size
|
|
71
|
+
this.editor = new fabric.Canvas(editor, { ...size });
|
|
72
72
|
if (background) {
|
|
73
73
|
this.background = new Background({ background, size });
|
|
74
74
|
}
|
|
@@ -88,8 +88,10 @@ export default class FabricHelper {
|
|
|
88
88
|
// return -this.height / 2 + this.getHeightOfLine(0) / this.lineHeight;
|
|
89
89
|
// };
|
|
90
90
|
|
|
91
|
-
this.setDeleteButtonListeners();
|
|
92
91
|
loadRotateImage();
|
|
92
|
+
loadCenterImage();
|
|
93
|
+
setupCustomControls(this);
|
|
94
|
+
this.setDeleteButtonListeners();
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
clear() {
|
|
@@ -209,7 +211,6 @@ export default class FabricHelper {
|
|
|
209
211
|
obj.hiddenTextarea.focus();
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
|
-
obj.setControlsVisibility({ tr: false });
|
|
213
214
|
|
|
214
215
|
if (initial) {
|
|
215
216
|
this.dispatch('setField', { field: 'boundingRect', value: obj.getBoundingRect() });
|
|
@@ -264,28 +265,6 @@ export default class FabricHelper {
|
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
setDeleteButtonListeners() {
|
|
267
|
-
this.editor.on('object:selected', ({ target }) => {
|
|
268
|
-
this.dispatch('setDeleteButtonPosition', target.oCoords.tr);
|
|
269
|
-
});
|
|
270
|
-
this.editor.on('object:modified', ({ target }) => {
|
|
271
|
-
this.dispatch('setDeleteButtonPosition', target.oCoords.tr);
|
|
272
|
-
target.setControlsVisibility({ tr: false });
|
|
273
|
-
});
|
|
274
|
-
this.editor.on('object:moving', ({ target }) => {
|
|
275
|
-
target.setControlsVisibility({ tr: true });
|
|
276
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
277
|
-
});
|
|
278
|
-
this.editor.on('object:scaling', ({ target }) => {
|
|
279
|
-
target.setControlsVisibility({ tr: true });
|
|
280
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
281
|
-
});
|
|
282
|
-
this.editor.on('object:rotating', ({ target }) => {
|
|
283
|
-
target.setControlsVisibility({ tr: true });
|
|
284
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
285
|
-
});
|
|
286
|
-
this.editor.on('selection:cleared', () => {
|
|
287
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
288
|
-
});
|
|
289
268
|
}
|
|
290
269
|
|
|
291
270
|
handleListeners(object, type) {
|
|
@@ -293,13 +272,12 @@ export default class FabricHelper {
|
|
|
293
272
|
** COMMON EVENTS
|
|
294
273
|
*/
|
|
295
274
|
object.on('selected', () => this.dispatch('selectLayer', object.layer));
|
|
296
|
-
object.on('rotating', (
|
|
297
|
-
this.dispatch('setField', { field: 'angle', value: parseInt(angle) });
|
|
275
|
+
object.on('rotating', () => {
|
|
276
|
+
this.dispatch('setField', { field: 'angle', value: parseInt(object.angle) });
|
|
298
277
|
});
|
|
299
|
-
object.on('moved', (
|
|
300
|
-
|
|
301
|
-
this.dispatch('setField', { field: '
|
|
302
|
-
this.dispatch('setField', { field: 'left', value: Math.round(left) });
|
|
278
|
+
object.on('moved', () => {
|
|
279
|
+
this.dispatch('setField', { field: 'top', value: Math.round(object.top) });
|
|
280
|
+
this.dispatch('setField', { field: 'left', value: Math.round(object.left) });
|
|
303
281
|
});
|
|
304
282
|
object.on('moving', () => this.checkBoundingIntersection(object));
|
|
305
283
|
object.on('scaling', () => {
|
|
@@ -339,7 +317,6 @@ export default class FabricHelper {
|
|
|
339
317
|
object.on('changed', () => {
|
|
340
318
|
this.dispatch('setField', { field: 'copy', value: object.text });
|
|
341
319
|
this.dispatch('setField', { field: 'boundingRect', value: object.getBoundingRect() });
|
|
342
|
-
this.dispatch('setDeleteButtonPosition', object.oCoords.tr);
|
|
343
320
|
// if (/\n/g.test(object.text || '')) {
|
|
344
321
|
// this.discardActiveObjects();
|
|
345
322
|
// object.text = object.text.replace(/\n/g, '');
|
|
@@ -48,6 +48,7 @@ export default {
|
|
|
48
48
|
name: 'FileUploader',
|
|
49
49
|
props: {
|
|
50
50
|
required: { type: Boolean, default: false },
|
|
51
|
+
convert: { type: Boolean, default: false },
|
|
51
52
|
disabled: { type: Boolean, default: false },
|
|
52
53
|
multiple: { type: Boolean, default: false },
|
|
53
54
|
hasUploadLink: { type: Boolean, default: false },
|
|
@@ -113,18 +114,18 @@ export default {
|
|
|
113
114
|
},
|
|
114
115
|
async upload() {
|
|
115
116
|
try {
|
|
116
|
-
const image = await api.uploadImage(this.file, this.onProgress, this.url);
|
|
117
|
+
const image = await api.uploadImage(this.file, this.onProgress, this.url, this.convert);
|
|
117
118
|
this.onProgress(0);
|
|
118
119
|
const url = image && staticLink(image.thumb || image.origin);
|
|
119
120
|
this.$emit('onuploaded', { ...image, url });
|
|
120
121
|
} catch (e) {
|
|
121
122
|
console.dir(e);
|
|
122
123
|
this.onProgress(0);
|
|
123
|
-
const { message, data } = e.response
|
|
124
|
-
if (message
|
|
124
|
+
const { message, error, data } = e.response?.data || {};
|
|
125
|
+
if ([message, error].includes('Conversion failed') && this.hasConversionErrorModal) {
|
|
125
126
|
this.showConversionFailedModal(data);
|
|
126
127
|
} else if (this.showErrorMessage) {
|
|
127
|
-
this.$toastr.e(e);
|
|
128
|
+
this.$toastr.e(error || message || e.message || e);
|
|
128
129
|
} else {
|
|
129
130
|
this.$emit('onerror', e);
|
|
130
131
|
}
|
|
@@ -177,7 +177,7 @@ export default {
|
|
|
177
177
|
if (this.suburb) {
|
|
178
178
|
const option = this.createOptionFromSuburb(this.suburb);
|
|
179
179
|
this.selected = option;
|
|
180
|
-
await this.handleSearch(this.selected.value.trim())
|
|
180
|
+
// await this.handleSearch(this.selected.value.trim());
|
|
181
181
|
}
|
|
182
182
|
},
|
|
183
183
|
methods: {
|
|
@@ -59,6 +59,10 @@ export default {
|
|
|
59
59
|
defaultPreview: {
|
|
60
60
|
type: Boolean,
|
|
61
61
|
default: true
|
|
62
|
+
},
|
|
63
|
+
allowCoverImage: {
|
|
64
|
+
type: Boolean,
|
|
65
|
+
default: true
|
|
62
66
|
}
|
|
63
67
|
},
|
|
64
68
|
computed: {
|
|
@@ -80,7 +84,7 @@ export default {
|
|
|
80
84
|
},
|
|
81
85
|
colorBackground() {
|
|
82
86
|
const color = this.color || this.product.color;
|
|
83
|
-
return this.fillBackground && getColorBackgroundStyle(color, false, this.originBackground);
|
|
87
|
+
return (this.fillBackground || (!this.allowCoverImage && !this.image)) && getColorBackgroundStyle(color, false, this.originBackground);
|
|
84
88
|
},
|
|
85
89
|
imageBackground() {
|
|
86
90
|
return this.image && this.getImageBackground(this.image);
|
|
@@ -91,7 +95,7 @@ export default {
|
|
|
91
95
|
image() {
|
|
92
96
|
const color = this.defaultPreview ? null : (this.color || this.product.color || (this.product.colors || [])[0]);
|
|
93
97
|
const product = this.product?.product || this.product;
|
|
94
|
-
return getColorImage(product, this.size, this.side, color) || getProductCover(product, this.size, this.side, color);
|
|
98
|
+
return getColorImage(product, this.size, this.side, color) || (this.allowCoverImage ? getProductCover(product, this.size, this.side, color) : null);
|
|
95
99
|
},
|
|
96
100
|
print() {
|
|
97
101
|
const { printsThumbnails = {} } = this.product || {};
|
|
@@ -310,8 +310,7 @@ export default {
|
|
|
310
310
|
if (this.$refs.previewCanvas) {
|
|
311
311
|
this.fabricCanvas = new fabric.Canvas(this.$refs.previewCanvas, {
|
|
312
312
|
width: this.$refs.previewCanvas.parentElement.offsetWidth - 100,
|
|
313
|
-
height: 200
|
|
314
|
-
uniScaleTransform: false
|
|
313
|
+
height: 200
|
|
315
314
|
});
|
|
316
315
|
this.fabricCanvas.renderOnAddRemove = false;
|
|
317
316
|
this.setupCanvasListeners();
|
|
@@ -145,8 +145,8 @@ export default {
|
|
|
145
145
|
break;
|
|
146
146
|
}
|
|
147
147
|
return {
|
|
148
|
-
class: quality ? quality.replace(' ', '_') : null,
|
|
149
|
-
value: isVector ? null : `${quality} / ${this.layer.dpi} DPI`
|
|
148
|
+
class: null, // quality ? quality.replace(' ', '_') : null,
|
|
149
|
+
value: isVector ? null : `${this.layer.dpi} DPI` // isVector ? null : `${quality} / ${this.layer.dpi} DPI`
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
},
|
|
@@ -34,13 +34,6 @@
|
|
|
34
34
|
{{ visibleOnpress ? 'Real product photo' : 'Press for real product photo' }}
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
|
-
<div
|
|
38
|
-
v-if="deleteButtonPos"
|
|
39
|
-
:style="deleteButtonPosition"
|
|
40
|
-
class="EditorWorkspaceSide__delete-object"
|
|
41
|
-
@click="removeSelected">
|
|
42
|
-
<i class="icon-cancel"></i>
|
|
43
|
-
</div>
|
|
44
37
|
<div>
|
|
45
38
|
<div class="EditorWorkspaceSide__background-container">
|
|
46
39
|
<canvas ref="background"></canvas>
|
|
@@ -78,6 +71,7 @@
|
|
|
78
71
|
}">
|
|
79
72
|
<file-uploader
|
|
80
73
|
:multiple="false"
|
|
74
|
+
:convert="true"
|
|
81
75
|
:url="`image/editor/${shop._id}/${product._id}`"
|
|
82
76
|
@onuploaded="handleUploaded">
|
|
83
77
|
<template #toggle>
|
|
@@ -114,7 +108,7 @@
|
|
|
114
108
|
class="EditorWorkspaceSide__overlay"
|
|
115
109
|
@mousedown="$emit('zoom-in')"></div>
|
|
116
110
|
<div class="EditorWorkspaceSide__alert-container">
|
|
117
|
-
<div
|
|
111
|
+
<!-- <div
|
|
118
112
|
v-if="showErrorAboutSmallImage"
|
|
119
113
|
class="EditorWorkspaceSide__alert-error"
|
|
120
114
|
@click="adjustSelectedArtDPI">
|
|
@@ -132,7 +126,7 @@
|
|
|
132
126
|
class="EditorWorkspaceSide__alert-error">
|
|
133
127
|
<i class="icon-attention-circled"></i>
|
|
134
128
|
Part of your design layer is outside the print area.
|
|
135
|
-
</div>
|
|
129
|
+
</div> -->
|
|
136
130
|
</div>
|
|
137
131
|
</div>
|
|
138
132
|
</template>
|
|
@@ -190,7 +184,6 @@ export default {
|
|
|
190
184
|
backgroundImage: null,
|
|
191
185
|
backgroundImageUrl: null,
|
|
192
186
|
backgroundImageLoaded: false,
|
|
193
|
-
deleteButtonPos: null,
|
|
194
187
|
drawingInProcess: false,
|
|
195
188
|
breakpoints: new Breakpoints()
|
|
196
189
|
};
|
|
@@ -239,12 +232,6 @@ export default {
|
|
|
239
232
|
const layers = this.editableLayers.filter(l => !paId || (l.printArea === paId));
|
|
240
233
|
return layers;
|
|
241
234
|
},
|
|
242
|
-
deleteButtonPosition() {
|
|
243
|
-
return this.deleteButtonPos ? {
|
|
244
|
-
top: `${this.deleteButtonPos.y}px`,
|
|
245
|
-
left: `${this.deleteButtonPos.x}px`
|
|
246
|
-
} : null;
|
|
247
|
-
},
|
|
248
235
|
positionPlaceholder() {
|
|
249
236
|
const { center, left, top, width, height } = this.fabricHelper.printAreaRect;
|
|
250
237
|
const ratio = this.calcWorkspaceSize() / this.editorSize.width;
|
|
@@ -403,7 +390,6 @@ export default {
|
|
|
403
390
|
}
|
|
404
391
|
}, 100);
|
|
405
392
|
});
|
|
406
|
-
this.fabricHelper.on('setDeleteButtonPosition', this.setDeleteButtonPosition);
|
|
407
393
|
this.fabricHelper.on('outOfPrintArea', this.setOffsetWarningVisibility);
|
|
408
394
|
|
|
409
395
|
this.updateBackgroundImage();
|
|
@@ -488,9 +474,6 @@ export default {
|
|
|
488
474
|
await this.createLayer({ type: 'art', url, size, fileName });
|
|
489
475
|
this.visibleWireframe = true;
|
|
490
476
|
},
|
|
491
|
-
setDeleteButtonPosition(pos) {
|
|
492
|
-
this.deleteButtonPos = pos;
|
|
493
|
-
},
|
|
494
477
|
setOffsetWarningVisibility(visible) {
|
|
495
478
|
this.setOffsetWarningVisible(visible);
|
|
496
479
|
},
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<span>Detected:</span>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="ProductCheckDelivery__detected-position">
|
|
12
|
-
|
|
12
|
+
{{ suburbInfo }}
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
<div class="ProductCheckDelivery__postcode">
|
|
@@ -119,6 +119,13 @@ export default {
|
|
|
119
119
|
},
|
|
120
120
|
suppliersWithRates() {
|
|
121
121
|
return this.pricing?.shipping?.suppliersWithRates || [];
|
|
122
|
+
},
|
|
123
|
+
suburbInfo() {
|
|
124
|
+
const { locality, state } = this.suburb || {};
|
|
125
|
+
if (locality && state) {
|
|
126
|
+
return `${locality}, ${state}`;
|
|
127
|
+
}
|
|
128
|
+
return 'London, Greater London';
|
|
122
129
|
}
|
|
123
130
|
},
|
|
124
131
|
watch: {
|
package/feeds/google-shopping.js
CHANGED
|
@@ -20,6 +20,13 @@ const COUNTRIES_SIZE_SYSTEMS = {
|
|
|
20
20
|
GB: 'UK'
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
function replaceVariables(text, product, sp) {
|
|
24
|
+
return (text || '')
|
|
25
|
+
.replace(/{colour}/g, sp.color?.name)
|
|
26
|
+
.replace(/{size}/g, sp.size?.name)
|
|
27
|
+
.replace(/{brand}/g, product.brand?.name);
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
async function googleShoppingFeed(axios, config, availableStores, country, isEditor, params) {
|
|
24
31
|
const { allowSameDayDelivery } = params || {};
|
|
25
32
|
const { data } = await axios.get(`${config.LOCAL_API_URL}/feed/products?host=${config.HOST_NAME}&country=${country || ''}`);
|
|
@@ -38,23 +45,22 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
38
45
|
return !availableStores || availableStores.includes(sp.storeCode);
|
|
39
46
|
})
|
|
40
47
|
.map(sp => {
|
|
41
|
-
const filterImagesByType = imgType => (product.images || []).filter(i => (i.types || []).includes(imgType) && sp.color._id === i.color).map(i => i.image);
|
|
48
|
+
const filterImagesByType = (imgType, skipColor) => (product.images || []).filter(i => (i.types || []).includes(imgType) && (skipColor || sp.color._id === i.color)).map(i => i.image);
|
|
42
49
|
const feedImages = filterImagesByType('feed_primary');
|
|
43
50
|
const frontImages = filterImagesByType('front');
|
|
44
51
|
const backImages = filterImagesByType('back');
|
|
45
52
|
const additionalImages = filterImagesByType('additional_image_link');
|
|
46
|
-
const catalogFrontImages = (
|
|
53
|
+
const catalogFrontImages = filterImagesByType('catalog_front');
|
|
54
|
+
const catalogBackImages = filterImagesByType('catalog_back');
|
|
47
55
|
const feedImage = spliceFirstImage(feedImages);
|
|
48
|
-
const image = feedImage || spliceFirstImage(
|
|
56
|
+
const image = feedImage || spliceFirstImage(catalogFrontImages) || spliceFirstImage(frontImages) || spliceFirstImage(backImages) || null;
|
|
49
57
|
const images = [
|
|
58
|
+
...catalogBackImages,
|
|
50
59
|
...additionalImages,
|
|
51
60
|
...((!backImages?.includes(image) && getImages(backImages)) || (!frontImages?.includes(image) && getImages(frontImages)) || [])
|
|
52
|
-
.filter(image => !additionalImages.includes(image))
|
|
61
|
+
.filter(image => !additionalImages.includes(image) && !catalogBackImages.includes(image))
|
|
53
62
|
];
|
|
54
|
-
const feedTitle =
|
|
55
|
-
.replace(/{colour}/g, sp.color.name)
|
|
56
|
-
.replace(/{size}/g, sp.size.name)
|
|
57
|
-
.replace(/{brand}/g, product.brand.name)
|
|
63
|
+
const feedTitle = product.feedTitle;
|
|
58
64
|
const title = feedTitle || `${product.name} ${sp.color.name}`;
|
|
59
65
|
const description = `${product.description || product.fabricInfoShort || product.name || ''}`
|
|
60
66
|
.replace(/ /g, ' ')
|
|
@@ -66,11 +72,10 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
66
72
|
if (sp.multipackQty) {
|
|
67
73
|
link = link.includes('?') ? `${link}&multipack=${sp.SKU}` : `${link}?multipack=${sp.SKU}`;
|
|
68
74
|
}
|
|
69
|
-
|
|
70
75
|
const productWeight = +((product.weight || 0) * (sp.multipackQty || 1)).toFixed(3);
|
|
71
76
|
const info = {
|
|
72
|
-
'g:title': { _text: sp.title || title },
|
|
73
|
-
'g:description': { _text: sp.description || description },
|
|
77
|
+
'g:title': { _text: replaceVariables(sp.title || title, product, sp) },
|
|
78
|
+
'g:description': { _text: replaceVariables(sp.description || description, product, sp) },
|
|
74
79
|
link: { _text: link },
|
|
75
80
|
'g:canonical_link': { _text: link.split('?')[0] },
|
|
76
81
|
'g:id': { _text: sp.SKU },
|
|
@@ -143,7 +148,7 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
143
148
|
info['g:local_shipping_label'] = { _text: 'sameday' };
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
const productHighlight = `${product.feedProductHighlight || ''}
|
|
151
|
+
const productHighlight = replaceVariables(`${product.feedProductHighlight || ''}`, product, sp)
|
|
147
152
|
.trim()
|
|
148
153
|
.split(/\n+/g)
|
|
149
154
|
.map(highlight => `${highlight || ''}`.trim())
|
|
@@ -183,7 +188,11 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
183
188
|
}
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
|
|
191
|
+
if (isClearance) {
|
|
192
|
+
info['g:custom_label_4'] = { _text: 'clearance' };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const feedLifestyleImage = filterImagesByType('model')[0] || product.feedLifestyleImage || filterImagesByType('model', true)[0];
|
|
187
196
|
if (feedLifestyleImage) {
|
|
188
197
|
info['g:lifestyle_image_link'] = { _text: staticLink(feedLifestyleImage, config) };
|
|
189
198
|
}
|
package/nuxt.config.js
CHANGED
|
@@ -49,7 +49,7 @@ module.exports = (config, axios, { raygunClient, publicPath, productUrlToEditor
|
|
|
49
49
|
},
|
|
50
50
|
plugins: [
|
|
51
51
|
'@/node_modules/@lancom/shared/plugins/jsonld',
|
|
52
|
-
'@/node_modules/@lancom/shared/plugins/vue-fragment',
|
|
52
|
+
{ src: '@/node_modules/@lancom/shared/plugins/vue-fragment', ssr: false },
|
|
53
53
|
'@/node_modules/@lancom/shared/plugins/global-components',
|
|
54
54
|
'@/node_modules/@lancom/shared/plugins/directives',
|
|
55
55
|
'@/node_modules/@lancom/shared/plugins/vue-js-modal',
|