@designcrowd/fe-shared-lib 1.6.2-eng-4039-freemode → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/css/tailwind-brandCrowd.css +9 -0
  2. package/dist/css/tailwind-brandPage.css +9 -0
  3. package/dist/css/tailwind-crazyDomains.css +9 -0
  4. package/dist/css/tailwind-designCom.css +9 -0
  5. package/dist/css/tailwind-designCrowd.css +9 -0
  6. package/docs/plans/DY-957-plan-phase-2-fe-shared-lib.md +382 -0
  7. package/package.json +1 -1
  8. package/src/atoms/components/Carousel/Carousel.vue +5 -0
  9. package/src/atoms/components/Icon/Icon.vue +4 -0
  10. package/src/atoms/components/Icon/icons/history.vue +12 -0
  11. package/src/atoms/components/Icon/icons/save.vue +6 -0
  12. package/src/bundles/bundled-translations.de-DE.json +3 -1
  13. package/src/bundles/bundled-translations.es-ES.json +3 -1
  14. package/src/bundles/bundled-translations.fr-CA.json +3 -1
  15. package/src/bundles/bundled-translations.fr-FR.json +3 -1
  16. package/src/bundles/bundled-translations.json +3 -1
  17. package/src/bundles/bundled-translations.pt-BR.json +3 -1
  18. package/src/bundles/bundled-translations.pt-PT.json +3 -1
  19. package/src/experiences/clients/brand-crowd-api.client.js +18 -0
  20. package/src/experiences/components/UploadYourLogoApplication/UploadYourLogoApplication.stories.js +49 -0
  21. package/src/experiences/components/UploadYourLogoApplication/UploadYourLogoApplication.vue +28 -0
  22. package/src/experiences/components/UploadYourLogoOnBoarding/LogoKeywords.stories.js +65 -0
  23. package/src/experiences/components/UploadYourLogoOnBoarding/LogoKeywords.vue +156 -0
  24. package/src/experiences/components/UploadYourLogoOnBoarding/UploadYourLogoOnBoarding.vue +61 -9
  25. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.de-DE.json +34 -31
  26. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.es-ES.json +34 -31
  27. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.fr-CA.json +34 -31
  28. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.fr-FR.json +34 -31
  29. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.json +3 -1
  30. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.pt-BR.json +34 -31
  31. package/src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.pt-PT.json +34 -31
  32. package/src/experiences/constants/api.js +1 -0
@@ -551,6 +551,9 @@ video {
551
551
  .tw-relative {
552
552
  position: relative;
553
553
  }
554
+ .tw-inset-0 {
555
+ inset: 0px;
556
+ }
554
557
  .tw--left-16 {
555
558
  left: -4rem;
556
559
  }
@@ -1400,6 +1403,9 @@ video {
1400
1403
  --tw-border-opacity: 1;
1401
1404
  border-color: rgb(255 255 255 / var(--tw-border-opacity));
1402
1405
  }
1406
+ .tw-border-t-transparent {
1407
+ border-top-color: transparent;
1408
+ }
1403
1409
  .tw-bg-black {
1404
1410
  --tw-bg-opacity: 1;
1405
1411
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1515,6 +1521,9 @@ video {
1515
1521
  --tw-bg-opacity: 1;
1516
1522
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1517
1523
  }
1524
+ .tw-bg-white\/50 {
1525
+ background-color: rgb(255 255 255 / 0.5);
1526
+ }
1518
1527
  .tw-bg-opacity-75 {
1519
1528
  --tw-bg-opacity: 0.75;
1520
1529
  }
@@ -551,6 +551,9 @@ video {
551
551
  .tw-relative {
552
552
  position: relative;
553
553
  }
554
+ .tw-inset-0 {
555
+ inset: 0px;
556
+ }
554
557
  .tw--left-16 {
555
558
  left: -4rem;
556
559
  }
@@ -1332,6 +1335,9 @@ video {
1332
1335
  --tw-border-opacity: 1;
1333
1336
  border-color: rgb(255 255 255 / var(--tw-border-opacity));
1334
1337
  }
1338
+ .tw-border-t-transparent {
1339
+ border-top-color: transparent;
1340
+ }
1335
1341
  .tw-bg-black {
1336
1342
  --tw-bg-opacity: 1;
1337
1343
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1363,6 +1369,9 @@ video {
1363
1369
  --tw-bg-opacity: 1;
1364
1370
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1365
1371
  }
1372
+ .tw-bg-white\/50 {
1373
+ background-color: rgb(255 255 255 / 0.5);
1374
+ }
1366
1375
  .tw-bg-opacity-75 {
1367
1376
  --tw-bg-opacity: 0.75;
1368
1377
  }
@@ -551,6 +551,9 @@ video {
551
551
  .tw-relative {
552
552
  position: relative;
553
553
  }
554
+ .tw-inset-0 {
555
+ inset: 0px;
556
+ }
554
557
  .tw--left-16 {
555
558
  left: -4rem;
556
559
  }
@@ -1400,6 +1403,9 @@ video {
1400
1403
  --tw-border-opacity: 1;
1401
1404
  border-color: rgb(255 255 255 / var(--tw-border-opacity));
1402
1405
  }
1406
+ .tw-border-t-transparent {
1407
+ border-top-color: transparent;
1408
+ }
1403
1409
  .tw-bg-black {
1404
1410
  --tw-bg-opacity: 1;
1405
1411
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1515,6 +1521,9 @@ video {
1515
1521
  --tw-bg-opacity: 1;
1516
1522
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1517
1523
  }
1524
+ .tw-bg-white\/50 {
1525
+ background-color: rgb(255 255 255 / 0.5);
1526
+ }
1518
1527
  .tw-bg-opacity-75 {
1519
1528
  --tw-bg-opacity: 0.75;
1520
1529
  }
@@ -551,6 +551,9 @@ video {
551
551
  .tw-relative {
552
552
  position: relative;
553
553
  }
554
+ .tw-inset-0 {
555
+ inset: 0px;
556
+ }
554
557
  .tw--left-16 {
555
558
  left: -4rem;
556
559
  }
@@ -1400,6 +1403,9 @@ video {
1400
1403
  --tw-border-opacity: 1;
1401
1404
  border-color: rgb(255 255 255 / var(--tw-border-opacity));
1402
1405
  }
1406
+ .tw-border-t-transparent {
1407
+ border-top-color: transparent;
1408
+ }
1403
1409
  .tw-bg-black {
1404
1410
  --tw-bg-opacity: 1;
1405
1411
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1515,6 +1521,9 @@ video {
1515
1521
  --tw-bg-opacity: 1;
1516
1522
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1517
1523
  }
1524
+ .tw-bg-white\/50 {
1525
+ background-color: rgb(255 255 255 / 0.5);
1526
+ }
1518
1527
  .tw-bg-opacity-75 {
1519
1528
  --tw-bg-opacity: 0.75;
1520
1529
  }
@@ -551,6 +551,9 @@ video {
551
551
  .tw-relative {
552
552
  position: relative;
553
553
  }
554
+ .tw-inset-0 {
555
+ inset: 0px;
556
+ }
554
557
  .tw--left-16 {
555
558
  left: -4rem;
556
559
  }
@@ -1400,6 +1403,9 @@ video {
1400
1403
  --tw-border-opacity: 1;
1401
1404
  border-color: rgb(255 255 255 / var(--tw-border-opacity));
1402
1405
  }
1406
+ .tw-border-t-transparent {
1407
+ border-top-color: transparent;
1408
+ }
1403
1409
  .tw-bg-black {
1404
1410
  --tw-bg-opacity: 1;
1405
1411
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1515,6 +1521,9 @@ video {
1515
1521
  --tw-bg-opacity: 1;
1516
1522
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1517
1523
  }
1524
+ .tw-bg-white\/50 {
1525
+ background-color: rgb(255 255 255 / 0.5);
1526
+ }
1518
1527
  .tw-bg-opacity-75 {
1519
1528
  --tw-bg-opacity: 0.75;
1520
1529
  }
@@ -0,0 +1,382 @@
1
+ # DY-957 Phase 2: fe-shared-lib Wizard Changes
2
+
3
+ ## Goal
4
+
5
+ Add an optional keywords step to the BYO upload wizard in `@designcrowd/fe-shared-lib`. The step fetches AI keyword suggestions, displays them in an editable textbox, and emits the keywords for the consumer to use. The step is opt-in via a `showKeywordsStep` prop (default `false`).
6
+
7
+ ## Repo
8
+
9
+ `fe-shared-lib`
10
+
11
+ ## Prerequisites
12
+
13
+ - Phase 1 backend endpoint deployed (needed for integration testing, not for Storybook development)
14
+
15
+ ## Implementation Decisions (Confirmed)
16
+
17
+ - The keyword suggestions endpoint path is `/api/ai-keyword-suggestion` (this is intentionally **not** maker-prefixed).
18
+ - `templateType` is required end-to-end; consumers must pass a non-null default value.
19
+ - Continue action in the keywords step must be disabled while suggestions are loading.
20
+ - Storybook coverage for `LogoKeywords` is required for this task (not optional).
21
+ - Publishing/version bump and final validation are human-owned follow-up steps, not coding-agent scope.
22
+
23
+ ---
24
+
25
+ ## Tasks
26
+
27
+ ### 1. Add API constant
28
+
29
+ **File**: `src/experiences/constants/api.js`
30
+
31
+ Add one line to the exported object:
32
+
33
+ ```js
34
+ KEYWORD_SUGGESTIONS_API_URL: '/api/ai-keyword-suggestion',
35
+ ```
36
+
37
+ ### 2. Add `getKeywordSuggestionsAsync` to API client
38
+
39
+ **File**: `src/experiences/clients/brand-crowd-api.client.js`
40
+
41
+ Add a new async method following the `searchDomainNamesByKeywordAsync` pattern (lines 71-117):
42
+
43
+ ```js
44
+ const getKeywordSuggestionsAsync = async ({ businessName, templateType }) => {
45
+ try {
46
+ const url = `${API.KEYWORD_SUGGESTIONS_API_URL}?businessName=${encodeURIComponent(businessName)}&templateType=${encodeURIComponent(templateType)}`;
47
+ const response = await getAxios()({
48
+ method: 'get',
49
+ url,
50
+ });
51
+ return response.data;
52
+ } catch (error) {
53
+ return false;
54
+ }
55
+ };
56
+ ```
57
+
58
+ Behavior note: if `businessName` is empty, still call the endpoint with `businessName=` and continue normally (expected to return empty suggestions).
59
+
60
+ Add `getKeywordSuggestionsAsync` to the default export object (lines 119-124).
61
+
62
+ ### 3. Create `LogoKeywords.vue` component
63
+
64
+ **File**: Create `src/experiences/components/UploadYourLogoOnBoarding/LogoKeywords.vue`
65
+
66
+ Clone the structure from `LogoBusinessText.vue` (same directory). The component should:
67
+
68
+ **Props:**
69
+ - `progressLabel` (String, required) — "Step X of Y"
70
+ - `eventCategory` (String, required) — for analytics tracking
71
+ - `savedKeywords` (String, optional, default: `null`) — restored keywords if user navigated back then forward
72
+ - `businessName` (String, optional, default: `''`) — from previous step (may be empty)
73
+ - `templateType` (String, required) — e.g. "business card"
74
+
75
+ Behavior note: keep current wizard behavior where empty business name is allowed; do not block navigation if no business name is entered.
76
+
77
+ **Data:**
78
+ - `keywordsText: ''` — the editable comma-separated keywords string
79
+ - `isLoading: false`
80
+
81
+ **Mounted lifecycle:**
82
+ ```js
83
+ async mounted() {
84
+ if (this.savedKeywords !== null) {
85
+ this.keywordsText = this.savedKeywords;
86
+ return;
87
+ }
88
+ this.isLoading = true;
89
+ try {
90
+ const result = await brandCrowdClient.getKeywordSuggestionsAsync({
91
+ businessName: this.businessName,
92
+ templateType: this.templateType,
93
+ });
94
+ if (result && result.keywords && result.keywords.length > 0) {
95
+ this.keywordsText = result.keywords.join(', ');
96
+ }
97
+ } catch {
98
+ // leave keywordsText as empty string
99
+ } finally {
100
+ this.isLoading = false;
101
+ }
102
+ },
103
+ ```
104
+
105
+ **Methods:**
106
+ - `back()` — emits `on-go-back`
107
+ - `save()` — no-op if `isLoading` is true; otherwise tracks event with `eventAction: 'keywords'`, `eventLabel: 'Clicked_Continue'`, then emits `on-save` with `{ keywords: this.keywordsText }`
108
+ - `onKeywordsKeyUp(e)` — if `e.key === 'Enter'` and `!isLoading`, call `this.save()`
109
+
110
+ **Template:** Mirror `LogoBusinessText.vue` layout:
111
+ - Progress label header: `{{ progressLabel }}`
112
+ - Heading: `{{ uploadYourLogoTr('keywords') }}`
113
+ - Description: `{{ uploadYourLogoTr('keywordsDescription') }}`
114
+ - Single `<input>` or `<textarea>` bound to `keywordsText`, disabled while `isLoading`, with `@keyup="onKeywordsKeyUp"`
115
+ - Show a loading indicator (spinner or skeleton) when `isLoading` is true
116
+ - Footer with Back button (emits `on-go-back`) and Continue button (calls `save()`)
117
+ - Continue button must be disabled while `isLoading` is `true`
118
+
119
+ **i18n:** Use the `uploadYourLogoTr` mixin (same as `LogoBusinessText.vue`).
120
+
121
+ ### 4. Add i18n translation keys
122
+
123
+ **Files**: All 7 locale files in `src/experiences/components/UploadYourLogoOnBoarding/i18n/`
124
+
125
+ Add two new keys inside the `"uploadYourLogo"` object in **every** locale file, using the **English text** in all of them:
126
+
127
+ ```json
128
+ "keywords": "Keywords",
129
+ "keywordsDescription": "Add keywords related to your business and logo"
130
+ ```
131
+
132
+ Add this identical English text to:
133
+ - `upload-your-logo.json` (English)
134
+ - `upload-your-logo.de-DE.json`
135
+ - `upload-your-logo.es-ES.json`
136
+ - `upload-your-logo.fr-CA.json`
137
+ - `upload-your-logo.fr-FR.json`
138
+ - `upload-your-logo.pt-BR.json`
139
+ - `upload-your-logo.pt-PT.json`
140
+
141
+ **Do not translate** — a separate process will sweep the codebase and replace the English placeholders with proper translations.
142
+
143
+ After editing all files, run `npm run bundle-translation` to regenerate bundled translation files.
144
+
145
+ ### 5. Update `UploadYourLogoOnBoarding.vue` orchestrator
146
+
147
+ **File**: `src/experiences/components/UploadYourLogoOnBoarding/UploadYourLogoOnBoarding.vue`
148
+
149
+ #### 5a. Add new props (after existing props at lines 115-136)
150
+
151
+ ```js
152
+ showKeywordsStep: {
153
+ type: Boolean,
154
+ required: false,
155
+ default: false,
156
+ },
157
+ templateType: {
158
+ type: String,
159
+ required: true,
160
+ },
161
+ ```
162
+
163
+ Note: `templateType` must be provided by the consumer (fallback/defaulting happens in consumer app config, not in this component).
164
+
165
+ #### 5b. Update `data()` (lines 142-154)
166
+
167
+ Change `totalNumSteps` to be dynamic:
168
+ ```js
169
+ totalNumSteps: this.useDropzone
170
+ ? (this.showKeywordsStep ? 6 : 5)
171
+ : (this.showKeywordsStep ? 5 : 4),
172
+ ```
173
+
174
+ Add new data property:
175
+ ```js
176
+ savedKeywords: null,
177
+ ```
178
+
179
+ #### 5c. Add computed property for brand colours step number
180
+
181
+ ```js
182
+ brandColoursStep() {
183
+ return this.showKeywordsStep ? 5 : 4;
184
+ },
185
+ ```
186
+
187
+ #### 5d. Update `currentStepProgressLabel` (lines 157-163)
188
+
189
+ Replace hard-coded totals with `this.totalNumSteps`:
190
+ ```js
191
+ currentStepProgressLabel() {
192
+ if (this.includeDropzoneInModal) {
193
+ const currentStepDisplay = this.currentStep === 0 ? 1 : this.currentStep;
194
+ return this.uploadYourLogoTr('stepOf', { CURRENT: currentStepDisplay, TOTAL: this.totalNumSteps });
195
+ }
196
+ return this.uploadYourLogoTr('stepOf', { CURRENT: this.currentStep - 1, TOTAL: this.totalNumSteps });
197
+ },
198
+ ```
199
+
200
+ #### 5e. Update `currentStepTrackingLabel` (lines 170-176)
201
+
202
+ Make it keyword-step aware:
203
+ ```js
204
+ currentStepTrackingLabel() {
205
+ const stepTwoLabel = this.currentStep === 2 && !this.canCropImage ? 'previewLogo' : 'cropLogo';
206
+ const steps = this.showKeywordsStep
207
+ ? ['logoUploader', stepTwoLabel, 'businessName', 'keywords', 'brandColors']
208
+ : ['logoUploader', stepTwoLabel, 'businessName', 'brandColors'];
209
+ return steps[this.currentStep - 1];
210
+ },
211
+ ```
212
+
213
+ #### 5f. Import LogoKeywords component
214
+
215
+ Add import at top of script:
216
+ ```js
217
+ import LogoKeywords from './LogoKeywords.vue';
218
+ ```
219
+
220
+ Register in `components: { ... }`.
221
+
222
+ #### 5g. Update `onSaveBusinessText` method (lines 251-255)
223
+
224
+ No change needed — it already sets `currentStep = 4`. When `showKeywordsStep` is true, step 4 shows LogoKeywords. When false, step 4 shows LogoBusinessBrandColours (via `brandColoursStep` computed).
225
+
226
+ #### 5h. Add `onSaveKeywords` method
227
+
228
+ ```js
229
+ onSaveKeywords(payload) {
230
+ this.$emit('on-save-keywords', { keywords: payload.keywords });
231
+ this.savedKeywords = payload.keywords;
232
+ this.currentStep = this.brandColoursStep;
233
+ },
234
+ ```
235
+
236
+ #### 5i. Add `onGoBackFromBrandColours` method (or rename existing `onGoBackToBusinessText` usage on brand colours)
237
+
238
+ ```js
239
+ onGoBackFromBrandColours() {
240
+ this.$emit('on-back', { currentStepTrackingLabel: this.currentStepTrackingLabel });
241
+ this.currentStep = this.showKeywordsStep ? 4 : 3;
242
+ },
243
+ ```
244
+
245
+ **Important**: The brand colours component currently uses `@on-go-back="onGoBackToBusinessText"` (which sets `currentStep = 3`). Change this to `@on-go-back="onGoBackFromBrandColours"` so it goes back to keywords (step 4) when the keywords step is enabled.
246
+
247
+ #### 5j. Update template — add LogoKeywords between BusinessText and BrandColours
248
+
249
+ Add after the LogoBusinessText block and before LogoBusinessBrandColours:
250
+
251
+ ```vue
252
+ <LogoKeywords
253
+ v-if="showKeywordsStep && !isAttemptingToExit && currentStep === 4 && uploadedLogoData"
254
+ :progress-label="currentStepProgressLabel"
255
+ :event-category="eventCategory"
256
+ :saved-keywords="savedKeywords"
257
+ :business-name="(savedBusinessText && savedBusinessText.businessText) || ''"
258
+ :template-type="templateType"
259
+ @on-go-back="onGoBackToBusinessText"
260
+ @on-save="onSaveKeywords"
261
+ />
262
+ ```
263
+
264
+ #### 5k. Update template — change BrandColours step condition
265
+
266
+ Change `currentStep === 4` to `currentStep === brandColoursStep`:
267
+
268
+ ```vue
269
+ <LogoBusinessBrandColours
270
+ v-if="!isAttemptingToExit && currentStep === brandColoursStep && uploadedLogoData && !isCurrentlySaving"
271
+ ...
272
+ @on-go-back="onGoBackFromBrandColours"
273
+ ...
274
+ />
275
+ ```
276
+
277
+ #### 5l. Update `reset()` method (lines 290-299)
278
+
279
+ Add:
280
+ ```js
281
+ this.savedKeywords = null;
282
+ ```
283
+
284
+ ### 6. Update `UploadYourLogoApplication.vue` wrapper
285
+
286
+ **File**: `src/experiences/components/UploadYourLogoApplication/UploadYourLogoApplication.vue`
287
+
288
+ #### 6a. Add pass-through props (after existing props at lines 29-45)
289
+
290
+ ```js
291
+ showKeywordsStep: {
292
+ type: Boolean,
293
+ required: false,
294
+ default: false,
295
+ },
296
+ templateType: {
297
+ type: String,
298
+ required: true,
299
+ },
300
+ ```
301
+
302
+ Note: `templateType` must be provided by the consumer (fallback/defaulting happens in consumer app config, not in this component).
303
+
304
+ #### 6b. Pass props to `UploadYourLogoOnBoarding` in template
305
+
306
+ Add to the existing `<UploadYourLogoOnBoarding>` tag:
307
+ ```vue
308
+ :show-keywords-step="showKeywordsStep"
309
+ :template-type="templateType"
310
+ @on-save-keywords="onSaveKeywords"
311
+ ```
312
+
313
+ #### 6c. Add event handler method
314
+
315
+ ```js
316
+ onSaveKeywords(payload) {
317
+ this.$emit('on-save-keywords', payload);
318
+ },
319
+ ```
320
+
321
+ ### 7. Add Storybook story (required)
322
+
323
+ **File**: Create `src/experiences/components/UploadYourLogoOnBoarding/LogoKeywords.stories.js`
324
+
325
+ Create a story following standard Storybook patterns covering:
326
+ - Loading state (mock delayed API)
327
+ - Populated state (mock successful response with keywords)
328
+ - Empty state (mock failed response)
329
+ - Pre-populated state (savedKeywords prop set)
330
+
331
+ ### 8. Publish package
332
+
333
+ After all changes are verified (human release process; **not** a coding-agent task):
334
+ 1. Bump package version in `package.json`
335
+ 2. Run `npm run bundle-translation` to regenerate i18n bundles
336
+ 3. Perform manual validation in Storybook/integration context (no automated test runner in this repo)
337
+ 4. Publish the new version of `@designcrowd/fe-shared-lib`
338
+
339
+ ---
340
+
341
+ ## Step Number Reference Table
342
+
343
+ ### When `showKeywordsStep = false` (default, unchanged):
344
+
345
+ | currentStep | Component | Progress Display |
346
+ |---|---|---|
347
+ | 1 | LogoUploader | Step 0 of 4 |
348
+ | 2 | LogoCropper/Preview | Step 1 of 4 |
349
+ | 3 | LogoBusinessText | Step 2 of 4 |
350
+ | 4 | LogoBusinessBrandColours | Step 3 of 4 |
351
+
352
+ ### When `showKeywordsStep = true`:
353
+
354
+ | currentStep | Component | Progress Display |
355
+ |---|---|---|
356
+ | 1 | LogoUploader | Step 0 of 5 |
357
+ | 2 | LogoCropper/Preview | Step 1 of 5 |
358
+ | 3 | LogoBusinessText | Step 2 of 5 |
359
+ | **4** | **LogoKeywords (NEW)** | **Step 3 of 5** |
360
+ | 5 | LogoBusinessBrandColours | Step 4 of 5 |
361
+
362
+ Note: The `useDropzone` variant adds step 0 (dropzone) and shifts totals by +1. The same logic applies — `totalNumSteps` handles this via the ternary in `data()`.
363
+
364
+ ---
365
+
366
+ ## Files Changed
367
+
368
+ | File | Change |
369
+ |---|---|
370
+ | `src/experiences/constants/api.js` | Add `KEYWORD_SUGGESTIONS_API_URL` |
371
+ | `src/experiences/clients/brand-crowd-api.client.js` | Add `getKeywordSuggestionsAsync` method + export |
372
+ | `src/experiences/components/UploadYourLogoOnBoarding/LogoKeywords.vue` | **New file** — keywords step component |
373
+ | `src/experiences/components/UploadYourLogoOnBoarding/UploadYourLogoOnBoarding.vue` | New props, step routing, computed properties, methods, template |
374
+ | `src/experiences/components/UploadYourLogoApplication/UploadYourLogoApplication.vue` | Pass-through props + event |
375
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.json` | Add `keywords`, `keywordsDescription` |
376
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.de-DE.json` | Add `keywords`, `keywordsDescription` (English placeholder) |
377
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.es-ES.json` | Add `keywords`, `keywordsDescription` (English placeholder) |
378
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.fr-CA.json` | Add `keywords`, `keywordsDescription` (English placeholder) |
379
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.fr-FR.json` | Add `keywords`, `keywordsDescription` (English placeholder) |
380
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.pt-BR.json` | Add `keywords`, `keywordsDescription` (English placeholder) |
381
+ | `src/experiences/components/UploadYourLogoOnBoarding/i18n/upload-your-logo.pt-PT.json` | Add `keywords`, `keywordsDescription` (English placeholder) |
382
+ | `src/experiences/components/UploadYourLogoOnBoarding/LogoKeywords.stories.js` | **New file** (required) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@designcrowd/fe-shared-lib",
3
- "version": "1.6.2-eng-4039-freemode",
3
+ "version": "1.6.3",
4
4
  "scripts": {
5
5
  "start": "run-p storybook watch:translation",
6
6
  "build": "npm run build:css --production",
@@ -233,6 +233,11 @@ export default {
233
233
 
234
234
  const options = merge(defaultOptions, this.options || {});
235
235
 
236
+ // loop and freeMode are incompatible in Swiper 11 — loop takes priority
237
+ if (options.loop) {
238
+ options.freeMode = false;
239
+ }
240
+
236
241
  options.initialSlide = this.slideIndex || options.initialSlide;
237
242
 
238
243
  options.keyboard = defaultOptions.keyboard || {
@@ -138,6 +138,7 @@ import IconHamburger2 from './icons/hamburger-2.vue';
138
138
  import IconHamburger3 from './icons/hamburger-3.vue';
139
139
  import IconHamburger4 from './icons/hamburger-4.vue';
140
140
  import IconHamburger from './icons/hamburger.vue';
141
+ import IconHistory from './icons/history.vue';
141
142
  import IconHome from './icons/home.vue';
142
143
  import IconImageGalleryCarousel from './icons/image-gallery-carousel.vue';
143
144
  import IconImageGalleryGrid from './icons/image-gallery-grid.vue';
@@ -264,6 +265,7 @@ import IconReload from './icons/reload.vue';
264
265
  import IconReorderable from './icons/reorderable.vue';
265
266
  import IconRequestPayment from './icons/request-payment.vue';
266
267
  import IconResize from './icons/resize.vue';
268
+ import IconSave from './icons/save.vue';
267
269
  import IconSearch from './icons/search.vue';
268
270
  import IconSecure from './icons/secure.vue';
269
271
  import IconSend from './icons/send.vue';
@@ -580,6 +582,7 @@ export default {
580
582
  IconFooterCentered,
581
583
  IconFooterLeft,
582
584
 
585
+ IconHistory,
583
586
  IconHome,
584
587
  IconHomeOutline,
585
588
  IconHomeCrazyDomains,
@@ -664,6 +667,7 @@ export default {
664
667
  IconRequestPayment,
665
668
  IconShieldTick,
666
669
  IconShop,
670
+ IconSave,
667
671
  IconSearch,
668
672
  IconSecure,
669
673
  IconSend,
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <g fill="none" transform="translate(0.25, 1.5) scale(1.1)">
3
+ <path d="M0.500244 3.85742L1.50022 6.35742" stroke="currentColor" stroke-linecap="round" />
4
+ <path d="M1.50031 6.3574L4.00037 5.35742" stroke="currentColor" stroke-linecap="round" />
5
+ <path
6
+ d="M7.46411 0C10.9158 0 13.7139 2.79836 13.7141 6.25C13.7141 9.70178 10.9159 12.5 7.46411 12.5C5.66342 12.4999 4.04145 11.7379 2.9014 10.5192C2.46116 10.0485 2.84585 9.35742 3.4903 9.35742C3.73353 9.35742 3.96191 9.46606 4.13532 9.63662C4.9923 10.4795 6.16711 10.9999 7.46411 11C10.0875 11 12.2141 8.87335 12.2141 6.25C12.2139 3.62679 10.0874 1.5 7.46411 1.5C4.84108 1.50026 2.71428 3.62695 2.71411 6.25C2.71411 6.30896 2.66854 6.35742 2.60957 6.35742H1.32451C1.26487 6.35742 1.21411 6.30964 1.21411 6.25C1.21428 2.79852 4.01266 0.000262284 7.46411 0Z"
7
+ fill="currentColor"
8
+ />
9
+ <path d="M7.00024 4.35742V6.85742" stroke="currentColor" stroke-linecap="round" />
10
+ <line x1="7.00024" y1="6.85742" x2="9.00024" y2="6.85742" stroke="currentColor" stroke-linecap="round" />
11
+ </g>
12
+ </template>
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <path
3
+ d="M9.32715 8.01665C9.32689 8.01352 9.32545 8.01066 9.3252 8.00786C9.32271 8.00764 9.32012 8.00711 9.31738 8.00689C9.23966 8.00054 9.13128 8.00005 8.93359 8.00005H4.40039C4.20271 8.00005 4.09433 8.00054 4.0166 8.00689C4.0135 8.00714 4.01058 8.00761 4.00781 8.00786C4.00756 8.01063 4.00709 8.01355 4.00684 8.01665C4.00049 8.09437 4 8.20276 4 8.40044V12H9.33398V8.40044C9.33398 8.20276 9.3335 8.09437 9.32715 8.01665ZM0 3.86724C0 3.31819 0.000292534 2.86602 0.0302734 2.49907C0.0608946 2.12439 0.126173 1.77963 0.291016 1.4561C0.546643 0.954538 0.954488 0.546693 1.45605 0.291066C1.77958 0.126223 2.12434 0.0609446 2.49902 0.0303234C2.7322 0.0112719 2.99977 0.00535884 3.30469 0.00297968C3.31432 0.00256653 3.32425 4.99914e-05 3.33398 4.99914e-05C3.34251 5.40638e-05 3.35092 0.00265814 3.35938 0.00297968C3.51849 0.00200758 3.68774 4.99914e-05 3.86719 4.99914e-05H8.4502C8.74443 4.81347e-05 9.00014 -0.00377018 9.24805 0.0557141C9.45204 0.104689 9.64728 0.185377 9.82617 0.294972C10.0436 0.42821 10.2216 0.612265 10.4297 0.820363L12.5137 2.90435C12.7218 3.11244 12.9058 3.29044 13.0391 3.50786C13.1487 3.68675 13.2293 3.88199 13.2783 4.08599C13.3378 4.3339 13.334 4.58961 13.334 4.88384V9.46685C13.334 10.0159 13.3337 10.4681 13.3037 10.835C13.2731 11.2097 13.2078 11.5545 13.043 11.878C12.7873 12.3795 12.3795 12.7874 11.8779 13.043C11.5544 13.2079 11.2096 13.2731 10.835 13.3038C10.6015 13.3228 10.3336 13.3287 10.0283 13.3311C10.019 13.3315 10.0094 13.334 10 13.334C9.99114 13.334 9.98241 13.3315 9.97363 13.3311C9.8148 13.3321 9.64588 13.334 9.4668 13.334H3.86719C3.68774 13.334 3.51849 13.3321 3.35938 13.3311C3.35092 13.3314 3.34251 13.334 3.33398 13.334C3.32425 13.334 3.31432 13.3315 3.30469 13.3311C2.99977 13.3287 2.7322 13.3228 2.49902 13.3038C2.12434 13.2731 1.77958 13.2079 1.45605 13.043C0.954488 12.7874 0.546643 12.3795 0.291016 11.878C0.126173 11.5545 0.0608946 11.2097 0.0302734 10.835C0.000292534 10.4681 0 10.0159 0 9.46685V3.86724ZM1.33398 9.46685C1.33398 10.0379 1.33388 10.4266 1.3584 10.7266C1.38228 11.0187 1.42542 11.1683 1.47852 11.2725C1.60635 11.5234 1.81064 11.7277 2.06152 11.8555C2.16576 11.9086 2.31537 11.9518 2.60742 11.9756C2.62679 11.9772 2.64687 11.9772 2.66699 11.9786V8.40044C2.66699 8.22476 2.6669 8.05287 2.67871 7.90825C2.69116 7.75586 2.7203 7.57553 2.8125 7.39458C2.94027 7.14405 3.14401 6.94032 3.39453 6.81255C3.57548 6.72035 3.75581 6.69121 3.9082 6.67876C4.05282 6.66695 4.22471 6.66704 4.40039 6.66704H8.93359C9.10928 6.66704 9.28117 6.66695 9.42578 6.67876C9.57818 6.69121 9.7585 6.72035 9.93945 6.81255C10.19 6.94032 10.3937 7.14405 10.5215 7.39458C10.6137 7.57553 10.6428 7.75586 10.6553 7.90825C10.6671 8.05287 10.667 8.22476 10.667 8.40044V11.9786C10.6871 11.9772 10.7072 11.9772 10.7266 11.9756C11.0186 11.9518 11.1682 11.9086 11.2725 11.8555C11.5233 11.7277 11.7276 11.5234 11.8555 11.2725C11.9086 11.1683 11.9517 11.0187 11.9756 10.7266C12.0001 10.4266 12 10.0379 12 9.46685V4.88384C12 4.52686 11.9955 4.45631 11.9814 4.39751C11.9651 4.32949 11.9389 4.2638 11.9023 4.20415C11.8707 4.15253 11.8233 4.09975 11.5703 3.84673L10.666 2.94243C10.666 3.11508 10.6669 3.28361 10.6553 3.42583C10.6428 3.57823 10.6137 3.75856 10.5215 3.9395C10.3937 4.19003 10.19 4.39377 9.93945 4.52153C9.7585 4.61373 9.57818 4.64287 9.42578 4.65532C9.28117 4.66714 9.10928 4.66704 8.93359 4.66704H4.40039C4.22471 4.66704 4.05282 4.66714 3.9082 4.65532C3.75581 4.64287 3.57548 4.61373 3.39453 4.52153C3.14401 4.39377 2.94027 4.19003 2.8125 3.9395C2.7203 3.75856 2.69116 3.57823 2.67871 3.42583C2.6669 3.28122 2.66699 3.10933 2.66699 2.93364V1.35454C2.64684 1.35593 2.62681 1.35686 2.60742 1.35845C2.31537 1.38233 2.16576 1.42547 2.06152 1.47857C1.81064 1.6064 1.60635 1.81069 1.47852 2.06157C1.42542 2.16581 1.38228 2.31542 1.3584 2.60747C1.33388 2.90753 1.33398 3.29618 1.33398 3.86724V9.46685ZM4.00684 3.31743C4.00706 3.32017 4.00759 3.32276 4.00781 3.32525C4.01061 3.3255 4.01347 3.32694 4.0166 3.3272C4.09433 3.33355 4.20271 3.33403 4.40039 3.33403H8.93359C9.13128 3.33403 9.23966 3.33355 9.31738 3.3272C9.32016 3.32697 9.32269 3.32547 9.3252 3.32525C9.32542 3.32274 9.32692 3.32021 9.32715 3.31743C9.3335 3.23971 9.33398 3.13133 9.33398 2.93364V1.61333C9.20748 1.48941 9.16893 1.45562 9.12988 1.43169C9.07023 1.39514 9.00455 1.36892 8.93652 1.35259C8.87773 1.33852 8.80717 1.33404 8.4502 1.33403H4V2.93364C4 3.13133 4.00049 3.23971 4.00684 3.31743Z"
4
+ fill="currentColor"
5
+ />
6
+ </template>
@@ -96,7 +96,9 @@
96
96
  "dropYourFileHere": "Legen Sie Ihre Datei hier ab oder",
97
97
  "clickToUpload": "Klicken zum Hochladen",
98
98
  "acceptedFiles": "Wir akzeptieren PNG-, JPG-, SVG- und EPS-Dateien bis zu 25 MB.",
99
- "wrongUploadType": "Sie können Dateien dieses Typs nicht hochladen."
99
+ "wrongUploadType": "Sie können Dateien dieses Typs nicht hochladen.",
100
+ "keywords": "Schlüsselwörter",
101
+ "keywordsDescription": "Fügen Sie Schlüsselwörter hinzu, die relevant für Ihr Unternehmen und Ihr Logo sind"
100
102
  },
101
103
  "uploadLogoSearchResultCard": {
102
104
  "replace": "Ersetzen",
@@ -96,7 +96,9 @@
96
96
  "dropYourFileHere": "Suelta el archivo aquí o",
97
97
  "clickToUpload": "haz clic para subirlo",
98
98
  "acceptedFiles": "Aceptamos archivos PNG, JPG, SVG o EPS de hasta 25 MB",
99
- "wrongUploadType": "No puedes subir archivos de este tipo."
99
+ "wrongUploadType": "No puedes subir archivos de este tipo.",
100
+ "keywords": "Palabras clave",
101
+ "keywordsDescription": "Añade palabras clave relacionadas con tu negocio y logo"
100
102
  },
101
103
  "uploadLogoSearchResultCard": {
102
104
  "replace": "Sustituir",
@@ -96,7 +96,9 @@
96
96
  "dropYourFileHere": "Déposez votre fichier ici ou",
97
97
  "clickToUpload": "cliquez pour télécharger",
98
98
  "acceptedFiles": "Nous acceptons les fichiers PNG, JPG, SVG ou EPS jusqu'à 25 Mo",
99
- "wrongUploadType": "Vous ne pouvez pas télécharger des fichiers de ce type."
99
+ "wrongUploadType": "Vous ne pouvez pas télécharger des fichiers de ce type.",
100
+ "keywords": "Mots-clés",
101
+ "keywordsDescription": "Ajoutez des mots-clés liés à votre entreprise et à votre logo."
100
102
  },
101
103
  "uploadLogoSearchResultCard": {
102
104
  "replace": "Remplacer",
@@ -96,7 +96,9 @@
96
96
  "dropYourFileHere": "Déposez votre fichier ici ou",
97
97
  "clickToUpload": "cliquez pour télécharger",
98
98
  "acceptedFiles": "Nous acceptons les fichiers PNG, JPG, SVG ou EPS jusqu'à 25 Mo",
99
- "wrongUploadType": "Vous ne pouvez pas télécharger des fichiers de ce type."
99
+ "wrongUploadType": "Vous ne pouvez pas télécharger des fichiers de ce type.",
100
+ "keywords": "Mots-clés",
101
+ "keywordsDescription": "Ajoutez des mots-clés liés à votre entreprise et à votre logo"
100
102
  },
101
103
  "uploadLogoSearchResultCard": {
102
104
  "replace": "Remplacer",
@@ -96,7 +96,9 @@
96
96
  "dropYourFileHere": "Drop your file here or",
97
97
  "clickToUpload": "click to upload",
98
98
  "acceptedFiles": "We accept PNG, JPG, SVG or EPS files up to 25MB",
99
- "wrongUploadType": "You can't upload files of this type."
99
+ "wrongUploadType": "You can't upload files of this type.",
100
+ "keywords": "Keywords",
101
+ "keywordsDescription": "Add keywords related to your business and logo"
100
102
  },
101
103
  "uploadLogoSearchResultCard": {
102
104
  "replace": "Replace",