@lancom/shared 0.0.433 → 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.
@@ -26,7 +26,7 @@ export class Layer {
26
26
  cornerSize = 13;
27
27
  cornerStyle = 'circle';
28
28
  lockScalingFlip = true;
29
- padding = 0;
29
+ padding = 5;
30
30
  selectionDashArray = [10, 5];
31
31
  borderDashArray = [5, 3];
32
32
  cornerDashArray = [10, 5];
@@ -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
- // timelineLite: new TimelineLite()
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>
@@ -17,7 +17,9 @@
17
17
  active: amount >= range.min && ((range.max && amount <= range.max) || !range.max)
18
18
  }">
19
19
  <td>{{ (range.max >= 9999 || !range.max) ? `${range.min}+` : `${range.min}-${range.max}` }}</td>
20
- <td v-if="withGst">
20
+ <td
21
+ v-if="withGst"
22
+ class="PricingDiscountsTable__price">
21
23
  <span v-if="range.percent">
22
24
  {{ range.percent }}%
23
25
  </span>
@@ -25,7 +27,9 @@
25
27
  {{ range.price | priceWithTax(pricingSettings, currency) }}
26
28
  </span>
27
29
  </td>
28
- <td v-else>
30
+ <td
31
+ v-else
32
+ class="PricingDiscountsTable__price">
29
33
  <span v-if="range.percent">
30
34
  {{ range.percent }}%
31
35
  </span>
@@ -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
- get() {
176
- return prop
177
- ? this[`${field}_options`].find(o => o[prop] === this.layer[field])
178
- : this.layer[field];
179
- },
180
- set(v) {
181
- const value = prop && Object.prototype.hasOwnProperty.call(v, prop) ? v[prop] : v;
182
- this.$emit('set-layer-field', { field, value });
183
- this.textObject[field] = value;
184
- this.fabricCanvas.renderAll();
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: 300,
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.$nextTick(() => {
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
- @click="createTextLayer"
64
- class="EditorWorkspaceSide__placeholder-option">
65
- <span>Type here</span>
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
- return this.printAreaLayers.length > 0 ? {
241
- top: `${(top + height) * ratio}px`,
242
- left: `${left * ratio}px`
243
- } : {
244
- top: `${top * ratio}px`,
245
- left: `${left * ratio}px`,
246
- width: `${Math.max(60, width * ratio)}px`,
247
- height: `${height * ratio}px`,
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
- // todo center to print area
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: true });
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);
@@ -14,7 +14,7 @@
14
14
  </div>
15
15
  <div class="ProductCheckDelivery__postcode">
16
16
  <postcode-select
17
- v-model="postcode"
17
+ v-model="suburb.postcode"
18
18
  :suburb="suburb"
19
19
  :only-postcode="true"
20
20
  label-text="Postcode"
@@ -5,7 +5,7 @@
5
5
  </h3>
6
6
  <div class="ProductPricingTiers__tiers">
7
7
  <div
8
- v-for="(tier, index) in defaultSimpleProduct.pricing"
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.433",
3
+ "version": "0.0.435",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {