@searchstax-inc/searchstudio-ux-vue 0.0.13 → 0.1.1

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 (27) hide show
  1. package/README.md +599 -121
  2. package/dist/@searchstax-inc/components/SearchstaxExternalPromotionsWidget.vue.d.ts +11 -0
  3. package/dist/@searchstax-inc/components/SearchstaxExternalPromotionsWidget.vue.d.ts.map +1 -0
  4. package/dist/@searchstax-inc/components/SearchstaxFacetsWidget.vue.d.ts +7818 -0
  5. package/dist/@searchstax-inc/components/SearchstaxFacetsWidget.vue.d.ts.map +1 -0
  6. package/dist/@searchstax-inc/components/SearchstaxInputWidget.vue.d.ts +10 -19
  7. package/dist/@searchstax-inc/components/SearchstaxInputWidget.vue.d.ts.map +1 -1
  8. package/dist/@searchstax-inc/components/SearchstaxPaginationWidget.vue.d.ts +14 -0
  9. package/dist/@searchstax-inc/components/SearchstaxPaginationWidget.vue.d.ts.map +1 -0
  10. package/dist/@searchstax-inc/components/SearchstaxRelatedSearchesWidget.vue.d.ts +30 -0
  11. package/dist/@searchstax-inc/components/SearchstaxRelatedSearchesWidget.vue.d.ts.map +1 -0
  12. package/dist/@searchstax-inc/components/SearchstaxResultWidget.vue.d.ts +7667 -19
  13. package/dist/@searchstax-inc/components/SearchstaxResultWidget.vue.d.ts.map +1 -1
  14. package/dist/@searchstax-inc/components/SearchstaxSearchFeedbackWidget.vue.d.ts +11 -0
  15. package/dist/@searchstax-inc/components/SearchstaxSearchFeedbackWidget.vue.d.ts.map +1 -0
  16. package/dist/@searchstax-inc/components/SearchstaxSortingWidget.vue.d.ts +12 -0
  17. package/dist/@searchstax-inc/components/SearchstaxSortingWidget.vue.d.ts.map +1 -0
  18. package/dist/@searchstax-inc/components/SearchstaxWrapper.vue.d.ts +36 -0
  19. package/dist/@searchstax-inc/components/SearchstaxWrapper.vue.d.ts.map +1 -1
  20. package/dist/@searchstax-inc/main.d.ts +7 -1
  21. package/dist/@searchstax-inc/searchstudio-ux-vue.cjs +213 -61
  22. package/dist/@searchstax-inc/searchstudio-ux-vue.d.cts +7 -1
  23. package/dist/@searchstax-inc/searchstudio-ux-vue.d.mts +7 -1
  24. package/dist/@searchstax-inc/searchstudio-ux-vue.iife.js +213 -61
  25. package/dist/@searchstax-inc/searchstudio-ux-vue.mjs +2710 -647
  26. package/dist/@searchstax-inc/stores/searchstaxStore.d.ts +7665 -17
  27. package/package.json +2 -2
package/README.md CHANGED
@@ -3,9 +3,8 @@
3
3
  Library to build searchstudio search page
4
4
 
5
5
  ## Installation
6
- npm install following packages
6
+ npm install following package
7
7
  `npm install --save @searchstax-inc/searchstudio-ux-vue`
8
- `npm install --save @searchstax-inc/searchstudio-ux-js`
9
8
 
10
9
  Add following code to `<head>`
11
10
 
@@ -22,98 +21,150 @@ Add following code to `<head>`
22
21
  })();
23
22
  </script>
24
23
  ```
24
+ ## Usage
25
25
 
26
- ## imports
27
- types can be imported from
28
-
29
- `import type { ISearchstaxParsedResult, ISearchstaxSearchProps, ISearchstaxSuggestProps, ISearchstaxSuggestResponse, Searchstax } from '@searchstax-inc/searchstudio-ux-js'`
26
+ After importing SearchstaxWrapper component needs to wrap all other components:
30
27
 
31
- component import
28
+ ```
32
29
 
33
- `import {SearchstaxWrapper, SearchstaxInputWidget, SearchstaxResultWidget} from "@searchstax-inc/searchstudio-ux-vue"`
34
- ## Usage
30
+ <SearchstaxWrapper
31
+ :language="sampleConfig.language"
32
+ :searchURL="sampleConfig.searchURL"
33
+ :suggesterURL="sampleConfig.suggesterURL"
34
+ :trackApiKey="sampleConfig.trackApiKey"
35
+ :searchAuth="sampleConfig.searchAuth"
36
+ :authType="sampleConfig.authType"
37
+ :router="sampleConfig.router"
38
+ :beforeSearch="sampleConfig.hooks.beforeSearch" // callback function to intercept search object before search is fired
39
+ :afterSearch="sampleConfig.hooks.afterSearch" // callback function to handle results after search is fired
35
40
 
36
- Following components are experted by this library:
41
+ >
42
+ // other components will go there
37
43
 
38
- ```
39
- SearchstaxWrapper
40
- SearchstaxInputWidget
41
- SearchstaxResultWidget
44
+ </SearchstaxWrapper>
42
45
  ```
43
46
 
44
47
  ## Initialization
45
- JS
46
- ```
47
- const config = {
48
- searchURL: '', // - SeachStudio select endpoint
49
- suggesterURL: '', // - SeachStudio suggest endpoint
50
- trackApiKey: '', // - Api key used for tracking events
51
- searchAuth: '', // - Authentication value. based on authType it's either a token value or basic auth value
52
- authType: '', // - Type of authentication
53
- }
48
+ Initialization object needs to be of type: [ISearchstaxConfig](https://github.com/searchstax/searchstudio-ux-js/blob/main/src/interfaces/connector.interface.ts#L5)
54
49
 
55
-
56
- function initialized(searchstax: Searchstax){ // - optional function that returns an instance of Searchstax class. can be used for advanced workflows
57
-
58
- }
50
+ Initialization example
59
51
  ```
60
-
61
- HTML
52
+ sampleConfig = {
53
+ language: "en",
54
+ searchURL: "",
55
+ suggesterURL: "",
56
+ trackApiKey: "",
57
+ searchAuth: "",
58
+ authType: "basic",
59
+ router: {
60
+ enabled: true,
61
+ routeName: "searchstax",
62
+ title: (result: ISearchObject) => {
63
+ return "Search results for: " + result.query;
64
+ },
65
+ ignoredKeys: [],
66
+ },
67
+ hooks: {
68
+ beforeSearch: function (props: ISearchObject) {
69
+ const propsCopy = { ...props };
70
+ return propsCopy;
71
+ },
72
+ afterSearch: function (results: ISearchstaxParsedResult[]) {
73
+ const copy = [...results];
74
+ return copy;
75
+ },
76
+ }
77
+ };
62
78
  ```
63
79
 
80
+ ## Initial layout
81
+ Our base theme is designed with this layout in mind but it is optional as all widgets have id parameters and can be attached to any element.
82
+ ```
64
83
  <SearchstaxWrapper
65
- :searchURL="config.searchURL"
66
- :suggesterURL="config.suggesterURL"
67
- :trackApiKey="config.trackApiKey"
68
- :searchAuth="config.searchAuth"
69
- :authType="config.authType"
70
- @initialized="initialized"
71
- >
84
+ :language="sampleConfig.language"
85
+ :searchURL="sampleConfig.searchURL"
86
+ :suggesterURL="sampleConfig.suggesterURL"
87
+ :trackApiKey="sampleConfig.trackApiKey"
88
+ :searchAuth="sampleConfig.searchAuth"
89
+ :authType="sampleConfig.authType"
90
+ :router="sampleConfig.router"
91
+ :beforeSearch="sampleConfig.hooks.beforeSearch" // callback function to intercept search object before search is fired
92
+ :afterSearch="sampleConfig.hooks.afterSearch" // callback function to handle results after search is fired
93
+ >
72
94
  <template #default>
73
- // other widgets go here
95
+ <div class="searchstax-page-layout-container">
96
+ <SearchstaxInputWidget
97
+ :afterAutosuggest="afterAutosuggest"
98
+ :beforeAutosuggest="beforeAutosuggest"
99
+ :suggestAfterMinChars="3"
100
+ >
101
+ </SearchstaxInputWidget>
102
+ <div class="search-details-container">
103
+ <SearchstaxSearchFeedbackWidget></SearchstaxSearchFeedbackWidget>
104
+ <SearchstaxSortingWidget></SearchstaxSortingWidget>
105
+ </div>
106
+ <div class="searchstax-page-layout-facet-result-container">
107
+ <div class="searchstax-page-layout-facet-container">
108
+ <SearchstaxFacetsWidget
109
+ :facetingType="'or'"
110
+ :itemsPerPageDesktop="3"
111
+ :itemsPerPageMobile="99"
112
+ >
113
+ </SearchstaxFacetsWidget>
114
+ </div>
115
+ <div class="searchstax-page-layout-result-container">
116
+ <div id="searchstax-external-promotions-layout-container"></div>
117
+ <SearchstaxResultWidget :afterLinkClick="afterLinkClick">
118
+ </SearchstaxResultWidget>
119
+ <div id="searchstax-related-searches-container"></div>
120
+ <SearchstaxPaginationWidget>
121
+ </SearchstaxPaginationWidget>
122
+ </div>
123
+ </div>
124
+ </div>
74
125
  </template>
75
- </SearchstaxWrapper>
76
-
126
+ </SearchstaxWrapper>
77
127
  ```
78
128
 
79
- ## Input widget
80
- JS
81
- ```
82
- function beforeSearch(props: ISearchstaxSearchProps) {
83
- // - this function gets called before firing search. searchProps are being passed as a property and can be modified, if passed along further search will execute with modified properties, if null is returned then event gets canceled and search never fires.
84
- const propsCopy = { ...props }
85
- return propsCopy
86
- }
87
- function afterSearch(results: ISearchstaxParsedResult[]) {
88
- //- this function gets called after firing search and before rendering. It needs to return array of results that are either modified or untouched.
89
- const copy = [...results]
90
- return copy
91
- }
92
- function afterAutosuggest(result: ISearchstaxSuggestResponse) {
93
- // - this function gets called before firing autosuggest. autosuggestProps are being passed as a property and can be modified, if passed along further search will execute with modified properties, if null is returned then event gets canceled and search never fires.
94
- const copy = { ...result }
95
- return copy
96
- }
97
- function beforeAutosuggest(props: ISearchstaxSuggestProps) {
98
- // - this function gets called after autosuggest has values but before rendering. It needs to return same type of data but it can be modified.
99
- const propsCopy = { ...props }
100
- return propsCopy
101
- }
129
+ ### widgets
130
+ Following widgets are available:
131
+
132
+ [Input Widget](#input-widget)
133
+
134
+ [Result Widget](#result-widget)
135
+
136
+ [Facets Widget](#facets-widget)
137
+
138
+ [Pagination Widget](#pagination-widget)
139
+
140
+ [SearchFeedback Widget](#searchfeedback-widget)
141
+
142
+ [RelatedSearches Widget](#relatedsearches-widget)
143
+
144
+ [ExternalPromotions Widget](#externalpromotions-widget)
102
145
 
103
- const suggestAfterMinChars = 3; // - controls how many characters the UI should accept at the minimum before showing suggestions
146
+ [sorting Widget](#sorting-widget)
147
+
148
+ ### Input Widget ###
149
+
150
+ example of input widget initialization with minimum options
151
+ ```
152
+ <SearchstaxInputWidget
153
+ :afterAutosuggest="afterAutosuggest"
154
+ :beforeAutosuggest="beforeAutosuggest"
155
+ :suggestAfterMinChars="3"
156
+ ></SearchstaxInputWidget>
104
157
  ```
105
158
 
106
- HTML example with input override
107
159
 
160
+ example of input widget initialization with template override
108
161
  ```
109
162
  <SearchstaxInputWidget
110
- :beforeSearch="beforeSearch"
111
- :afterSearch="afterSearch"
112
163
  :afterAutosuggest="afterAutosuggest"
113
164
  :beforeAutosuggest="beforeAutosuggest"
114
- :suggestAfterMinChars="suggestAfterMinChars"
165
+ :suggestAfterMinChars="3"
115
166
  >
116
- <template #input>
167
+ <template #input="{ suggestions, onMouseLeave, onMouseOver, onMouseClick }">
117
168
  <div class="searchstax-search-input-wrapper">
118
169
  <input
119
170
  type="text"
@@ -121,81 +172,508 @@ HTML example with input override
121
172
  class="searchstax-search-input"
122
173
  placeholder="SEARCH FOR..."
123
174
  />
175
+ <div
176
+ class="searchstax-autosuggest-container"
177
+ :class="{ 'hidden': suggestions.length === 0 }"
178
+ @mouseleave="onMouseLeave"
179
+ >
180
+ <div
181
+ class="searchstax-autosuggest-item"
182
+ v-for="suggestion in suggestions"
183
+ :key="suggestion.term"
184
+ >
185
+ <div
186
+ class="searchstax-autosuggest-item-term-container"
187
+ v-html="suggestion.term"
188
+ @mouseover="onMouseOver(suggestion)"
189
+ @click.stop="onMouseClick()"
190
+ ></div>
191
+ </div>
192
+ </div>
124
193
  <button
125
194
  class="searchstax-spinner-icon"
126
195
  id="searchstax-search-input-action-button"
127
- ></button>
196
+ >
197
+ </button>
128
198
  </div>
129
199
  </template>
130
200
  </SearchstaxInputWidget>
131
201
  ```
132
- ## Result widget
202
+ ### Result Widget ###
133
203
 
134
- JS
204
+ example of results widget initialization with minimum options
205
+ ```
206
+ <SearchstaxResultWidget :afterLinkClick="afterLinkClick"></SearchstaxResultWidget>
135
207
  ```
136
- function afterLinkClick(result: ISearchstaxParsedResult) {
137
- // - function is called after user clicks result and passes that result as a property. when result is passed along tracking will execute and user will be navigated if null is returned events are canceled and nothing happens.
138
- const propsCopy = { ...result }
139
208
 
140
- return propsCopy
141
- }
209
+ example of result widget initialization with template override
210
+ ```
211
+ <SearchstaxResultWidget :afterLinkClick="afterLinkClick">
212
+ <template #results="{ searchResults, resultClicked }">
213
+ <div
214
+ class="searchstax-search-results"
215
+ v-if="searchResults && searchResults.length"
216
+ >
217
+ <div
218
+ class="searchstax-search-result"
219
+ :class="{ 'has-thumbnail': searchResult.thumbnail }"
220
+ :key="searchResult.uniqueId"
221
+ v-for="searchResult in searchResults"
222
+ >
223
+ <div
224
+ v-if="searchResult.promoted"
225
+ class="searchstax-search-result-promoted"
226
+ ></div>
227
+ <a
228
+ v-if="searchResult.url"
229
+ :href="searchResult.url"
230
+ :data-searchstax-unique-result-id="searchResult.uniqueId"
231
+ @click="resultClicked(searchResult, $event)"
232
+ class="searchstax-result-item-link"
233
+ ></a>
234
+ <div
235
+ v-if="searchResult.ribbon"
236
+ class="searchstax-search-result-ribbon"
237
+ > {{ searchResult.ribbon }} </div>
238
+ <img
239
+ v-if="searchResult.thumbnail"
240
+ :src="searchResult.thumbnail"
241
+ class="searchstax-thumbnail"
242
+ />
243
+ <div class="searchstax-search-result-title-container">
244
+ <span class="searchstax-search-result-title">{{ searchResult.title }}</span>
245
+ </div>
246
+ <p
247
+ v-if="searchResult.paths"
248
+ class="searchstax-search-result-common"
249
+ > {{ searchResult.paths }} </p>
250
+ <p
251
+ v-if="searchResult.description"
252
+ class="searchstax-search-result-description searchstax-search-result-common"
253
+ > {{ searchResult.description }} </p>
254
+ <div
255
+ :key="unmappedField.key"
256
+ v-for="unmappedField in searchResult.unmappedFields"
257
+ >
258
+ <div
259
+ v-if="unmappedField.isImage && typeof unmappedField.value === 'string'"
260
+ class="searchstax-search-result-image-container"
261
+ >
262
+ <img
263
+ :src="unmappedField.value"
264
+ class="searchstax-result-image"
265
+ />
266
+ </div>
267
+ <div v-else>
268
+ <p class="searchstax-search-result-common"> {{ unmappedField.value }} </p>
269
+ </div>
270
+ </div>
271
+ </div>
272
+ </div>
273
+ </template>
274
+ </SearchstaxResultWidget>
142
275
  ```
143
276
 
144
- HTML
277
+ ### Pagination Widget ###
145
278
 
279
+
280
+ example of pagination widget initialization with minimum options
281
+ ```
282
+ <SearchstaxPaginationWidget></SearchstaxPaginationWidget>
283
+ ```
284
+
285
+ example of pagination widget initialization with various options
286
+ ```
287
+ <template #pagination="{ paginationData, previousPage, nextPage }">
288
+ <div
289
+ class="searchstax-pagination-container"
290
+ v-if="paginationData"
291
+ >
292
+ <div class="searchstax-pagination-content">
293
+ <a
294
+ class="searchstax-pagination-previous"
295
+ :disabled="paginationData?.isFirstPage"
296
+ @click="previousPage"
297
+ id="searchstax-pagination-previous"
298
+ > &lt; Previous </a>
299
+ <div class="searchstax-pagination-details"> {{ paginationData?.startResultIndex }} - {{
300
+ paginationData?.endResultIndex }} of {{ paginationData?.totalResults }} </div>
301
+ <a
302
+ class="searchstax-pagination-next"
303
+ :disabled="paginationData?.isLastPage"
304
+ @click="nextPage"
305
+ id="searchstax-pagination-next"
306
+ >Next ></a>
307
+ </div>
308
+ </div>
309
+ </template>
146
310
  ```
147
- - possible template overrides are: #results, #noResult
148
- - searchResults are passed to the template and contains an array of results to render
149
- <SearchstaxResultWidget :afterLinkClick="afterLinkClick">
150
- <template #results="{ searchResults, resultClicked }">
151
- <div
152
- class="searchstax-search-result"
153
- :key="searchResult.uniqueId"
154
- v-for="searchResult in searchResults"
311
+
312
+ ### Facets Widget ###
313
+
314
+ example of facets widget initialization with minimum options
315
+ ```
316
+ <SearchstaxFacetsWidget
317
+ :facetingType="'or'"
318
+ :itemsPerPageDesktop="3"
319
+ :itemsPerPageMobile="99"
320
+ ></SearchstaxFacetsWidget>
321
+ ```
322
+
323
+
324
+ example of facets widget initialization with template overrides
325
+ ```
326
+ <SearchstaxFacetsWidget
327
+ :facetingType="'or'"
328
+ :itemsPerPageDesktop="3"
329
+ :itemsPerPageMobile="99"
155
330
  >
156
- <a
157
- v-if="searchResult.url"
158
- :href="searchResult.url"
159
- :data-searchstax-unique-result-id="searchResult.uniqueId"
160
- @click="resultClicked(searchResult, $event)"
161
- class="searchstax-result-item-link"
162
- ></a>
163
- <div v-if="searchResult.ribbon" class="searchstax-search-result-ribbon">
164
- {{ searchResult.ribbon }}
165
- </div>
166
- <img
167
- v-if="searchResult.thumbnail"
168
- :src="searchResult.thumbnail"
169
- class="searchstax-thumbnail"
170
- />
171
- <div class="searchstax-search-result-title-container">
172
- <span class="searchstax-search-result-title">{{ searchResult.title }}dddd</span>
173
- </div>
174
- <p v-if="searchResult.paths" class="searchstax-search-result-common">
175
- {{ searchResult.paths }}
176
- </p>
177
- <p
178
- v-if="searchResult.description"
179
- class="searchstax-search-result-description searchstax-search-result-common"
331
+ <template
332
+ #desktopFacets="{ facetsTemplateDataDesktop, isNotDeactivated, toggleFacetGroup, isChecked, selectFacet, showMoreLessDesktop, facetContainers }"
180
333
  >
181
- {{ searchResult.description }}
182
- </p>
334
+ <div
335
+ v-if="facetsTemplateDataDesktop?.hasResultsOrExternalPromotions"
336
+ class="searchstax-facets-container-desktop"
337
+ >
338
+ <div
339
+ v-for="facet in facetsTemplateDataDesktop.facets"
340
+ :key="facet"
341
+ class="searchstax-facet-container"
342
+ :class="{ 'active': isNotDeactivated(facet.name) }"
343
+ >
344
+ <div>
345
+ <div
346
+ class="searchstax-facet-title-container"
347
+ @click="toggleFacetGroup(facet.name)"
348
+ >
349
+ <div class="searchstax-facet-title"> {{ facet.label }} </div>
350
+ <div class="searchstax-facet-title-arrow active"></div>
351
+ </div>
352
+ <div class="searchstax-facet-values-container">
353
+ <div
354
+ v-for="(facetValue, key) in facet.values"
355
+ :key="facetValue.value + facetValue.parentName"
356
+ class="searchstax-facet-value-container"
357
+ :class="{ 'searchstax-facet-value-disabled': facetValue.disabled }"
358
+ :ref="el => { facetContainers[key + facet.name] = el }"
359
+ >
360
+ <div class="searchstax-facet-input">
361
+ <input
362
+ type="checkbox"
363
+ class="searchstax-facet-input-checkbox"
364
+ :checked="isChecked(facetValue)"
365
+ :disabled="facetValue.disabled"
366
+ @click="selectFacet(key + facet.name, $event, facetValue, true)"
367
+ />
368
+ </div>
369
+ <div
370
+ class="searchstax-facet-value-label"
371
+ @click="selectFacet(key + facet.name, $event, facetValue, false)"
372
+ >{{ facetValue.value }}</div>
373
+ <div
374
+ class="searchstax-facet-value-count"
375
+ @click="selectFacet(key + facet.name, $event, facetValue, false)"
376
+ >({{ facetValue.count }})</div>
377
+ </div>
378
+ <div
379
+ class="searchstax-facet-show-more-container"
380
+ v-if="facet.hasMoreFacets"
381
+ >
382
+ <div
383
+ class="searchstax-facet-show-more-container"
384
+ @click="showMoreLessDesktop($event, facet)"
385
+ >
386
+ <div
387
+ v-if="facet.showingAllFacets"
388
+ class="searchstax-facet-show-less-button searchstax-facet-show-button"
389
+ >less</div>
390
+ <div
391
+ v-else
392
+ class="searchstax-facet-show-more-button searchstax-facet-show-button"
393
+ >more</div>
394
+ </div>
395
+ </div>
396
+ </div>
397
+ </div>
398
+ </div>
399
+ </div>
400
+ </template>
401
+ <template
402
+ #mobileFacets="{ facetsTemplateDataMobile, selectedFacetsCheckboxes, isNotDeactivated, toggleFacetGroup, isChecked, selectFacet, showMoreLessDesktop, facetContainers, openOverlay, unselectFacet, unselectAll, closeOverlay }"
403
+ >
404
+ <div
405
+ class="searchstax-facets-container-mobile"
406
+ v-if="facetsTemplateDataMobile?.hasResultsOrExternalPromotions"
407
+ >
408
+ <div class="searchstax-facets-pills-container">
409
+ <div
410
+ class="searchstax-facets-pill searchstax-facets-pill-filter-by"
411
+ @click="openOverlay"
412
+ >
413
+ <div class="searchstax-facets-pill-label">Filter By</div>
414
+ </div>
415
+ <div class="searchstax-facets-pills-selected">
416
+ <div
417
+ class="searchstax-facets-pill searchstax-facets-pill-facets"
418
+ v-for="facet in selectedFacetsCheckboxes"
419
+ :key="facet.value"
420
+ @click="unselectFacet(facet)"
421
+ >
422
+ <div class="searchstax-facets-pill-label">{{ facet.value }} ({{ facet.count }})</div>
423
+ <div class="searchstax-facets-pill-icon-close"></div>
424
+ </div>
425
+ </div>
426
+ <div
427
+ class="searchstax-facets-pill searchstax-clear-filters searchstax-facets-pill-clear-all"
428
+ v-if="selectedFacetsCheckboxes.length"
429
+ @click="unselectAll"
430
+ >
431
+ <div class="searchstax-facets-pill-label">Clear Filters</div>
432
+ </div>
433
+ </div>
434
+ <div
435
+ class="searchstax-facets-mobile-overlay"
436
+ :class="{ 'searchstax-show': facetsTemplateDataMobile?.overlayOpened }"
437
+ >
438
+ <div class="searchstax-facets-mobile-overlay-header">
439
+ <div class="searchstax-facets-mobile-overlay-header-title">Filter By</div>
440
+ <div
441
+ class="searchstax-search-close"
442
+ @click="closeOverlay"
443
+ ></div>
444
+ </div>
445
+ <div class="searchstax-facets-container-mobile">
446
+ <div
447
+ v-for="facet in facetsTemplateDataMobile?.facets"
448
+ :key="facet"
449
+ class="searchstax-facet-container"
450
+ :class="{ 'active': isNotDeactivated(facet.name) }"
451
+ >
452
+ <div>
453
+ <div
454
+ class="searchstax-facet-title-container"
455
+ @click="toggleFacetGroup(facet.name)"
456
+ >
457
+ <div class="searchstax-facet-title"> {{ facet.label }} </div>
458
+ <div class="searchstax-facet-title-arrow active"></div>
459
+ </div>
460
+ <div class="searchstax-facet-values-container">
461
+ <div
462
+ v-for="(facetValue, key) in facet.values"
463
+ :key="facetValue.value + facetValue.parentName"
464
+ class="searchstax-facet-value-container"
465
+ :class="{ 'searchstax-facet-value-disabled': facetValue.disabled }"
466
+ :ref="el => { facetContainers[key + facet.name] = el }"
467
+ >
468
+ <div class="searchstax-facet-input">
469
+ <input
470
+ type="checkbox"
471
+ class="searchstax-facet-input-checkbox"
472
+ :checked="isChecked(facetValue)"
473
+ :disabled="facetValue.disabled"
474
+ @click="selectFacet(key + facet.name, $event, facetValue, true)"
475
+ />
476
+ </div>
477
+ <div
478
+ class="searchstax-facet-value-label"
479
+ @click="selectFacet(key + facet.name, $event, facetValue, false)"
480
+ >{{ facetValue.value }}</div>
481
+ <div
482
+ class="searchstax-facet-value-count"
483
+ @click="selectFacet(key + facet.name, $event, facetValue, false)"
484
+ >({{ facetValue.count }})</div>
485
+ </div>
486
+ <div
487
+ class="searchstax-facet-show-more-container"
488
+ v-if="facet.hasMoreFacets"
489
+ >
490
+ <div
491
+ class="searchstax-facet-show-more-container"
492
+ @click="showMoreLessDesktop($event, facet)"
493
+ >
494
+ <div
495
+ v-if="facet.showingAllFacets"
496
+ class="searchstax-facet-show-less-button searchstax-facet-show-button"
497
+ >less</div>
498
+ <div
499
+ v-else
500
+ class="searchstax-facet-show-more-button searchstax-facet-show-button"
501
+ >more</div>
502
+ </div>
503
+ </div>
504
+ </div>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ <button
509
+ class="searchstax-facets-mobile-overlay-done"
510
+ @click="closeOverlay"
511
+ >Done</button>
512
+ </div>
513
+ </div>
514
+ </template>
515
+ </SearchstaxFacetsWidget>
516
+ ```
517
+
518
+ ### SearchFeedback Widget ###
519
+
520
+ example of search feedback widget initialization with minimum options
521
+ ```
522
+ <SearchstaxSearchFeedbackWidget></SearchstaxSearchFeedbackWidget>
523
+ ```
524
+
183
525
 
184
- <div :key="unmappedField" v-for="unmappedField in searchResult.unmappedFields">
185
- <div v-if="unmappedField.isImage" class="searchstax-search-result-image-container">
186
- <img :src="unmappedField.value" class="searchstax-result-image" />
526
+ example of search feedback widget initialization with template overrides
527
+ ```
528
+ <SearchstaxSearchFeedbackWidget>
529
+ <template #searchFeedback="{ searchFeedbackData, onOriginalQueryClick }">
530
+ <div
531
+ class="searchstax-feedback-container"
532
+ v-if="searchFeedbackData && searchFeedbackData?.searchExecuted"
533
+ > Showing <b>{{ searchFeedbackData.startResultIndex }} - {{ searchFeedbackData.endResultIndex }}</b> of
534
+ <b>{{ searchFeedbackData.totalResults }}</b> results <span v-if="searchFeedbackData.searchTerm">for "<b>{{
535
+ searchFeedbackData.searchTerm }}</b>" </span>
536
+ <div class="searchstax-feedback-container-suggested">
537
+ <div v-if="searchFeedbackData.autoCorrectedQuery"> Search instead for <a
538
+ href="#"
539
+ @click.prevent="onOriginalQueryClick($event)"
540
+ class="searchstax-feedback-original-query"
541
+ >{{ searchFeedbackData.originalQuery }}</a>
542
+ </div>
187
543
  </div>
188
- <div v-else>
189
- <p class="searchstax-search-result-common">
190
- {{ unmappedField.value }}
191
- </p>
544
+ </div>
545
+ </template>
546
+ </SearchstaxSearchFeedbackWidget>
547
+ ```
548
+
549
+ ## RelatedSearches widget
550
+
551
+
552
+
553
+ example of search feedback widget initialization with minimum options
554
+ ```
555
+ <SearchstaxRelatedSearchesWidget
556
+ :relatedSearchesURL="config.relatedSearchesURL"
557
+ :relatedSearchesAPIKey="config.relatedSearchesAPIKey"
558
+ ></SearchstaxRelatedSearchesWidget>
559
+ ```
560
+
561
+
562
+ example of search feedback widget initialization with template overrides
563
+ ```
564
+ <SearchstaxRelatedSearchesWidget
565
+ :relatedSearchesURL="config.relatedSearchesURL"
566
+ :relatedSearchesAPIKey="config.relatedSearchesAPIKey"
567
+ >
568
+ <template #related="{ relatedData, executeSearch }">
569
+ <div
570
+ class="searchstax-related-searches-container"
571
+ id="searchstax-related-searches-container"
572
+ v-if="relatedData && relatedData?.searchExecuted && relatedData?.hasRelatedSearches"
573
+ > Related searches: <span id="searchstax-related-searches"></span>
574
+ <span
575
+ class="searchstax-related-search"
576
+ v-if="relatedData.relatedSearches"
577
+ >
578
+ <span
579
+ v-for="related in relatedData.relatedSearches"
580
+ :key="related.related_search"
581
+ @click="executeSearch(related)"
582
+ class="searchstax-related-search searchstax-related-search-item"
583
+ > {{ related.related_search }}<span v-if="!related.last">,</span>
584
+ </span>
585
+ </span>
586
+ </div>
587
+ </template>
588
+ </SearchstaxRelatedSearchesWidget>
589
+ ```
590
+
591
+ ### ExternalPromotions widget ###
592
+
593
+ example of search feedback widget initialization with minimum options
594
+ ```
595
+ <SearchstaxExternalPromotionsWidget></SearchstaxExternalPromotionsWidget>
596
+ ```
597
+
598
+
599
+ example of search feedback widget initialization with template overrides
600
+ ```
601
+ <SearchstaxExternalPromotionsWidget>
602
+ <template #externalPromotions="{ externalPromotionsData, trackClick }">
603
+ <div
604
+ class="searchstax-external-promotions-container"
605
+ id="searchstax-external-promotions-container"
606
+ v-if="externalPromotionsData && externalPromotionsData?.searchExecuted && externalPromotionsData?.hasExternalPromotions"
607
+ >
608
+ <div
609
+ class="searchstax-external-promotion searchstax-search-result"
610
+ v-for="externalPromotion in externalPromotionsData.externalPromotions"
611
+ :key="externalPromotion.id"
612
+ >
613
+ <div class="icon-elevated"></div>
614
+ <a
615
+ v-if="externalPromotion.url"
616
+ href="{{externalPromotion.url}}"
617
+ @click="trackClick(externalPromotion, $event)"
618
+ class="searchstax-result-item-link"
619
+ ></a>
620
+ <div class="searchstax-search-result-title-container">
621
+ <span class="searchstax-search-result-title">{{ externalPromotion.name }}</span>
622
+ </div>
623
+ <p
624
+ v-if="externalPromotion.description"
625
+ class="searchstax-search-result-description searchstax-search-result-common"
626
+ > {{ externalPromotion.description }} </p>
627
+ <p
628
+ v-if="externalPromotion.url"
629
+ class="searchstax-search-result-description searchstax-search-result-common"
630
+ > {{ externalPromotion.url }} </p>
631
+ </div>
192
632
  </div>
633
+ </template>
634
+ </SearchstaxExternalPromotionsWidget>
635
+ ```
636
+
637
+
638
+ ### Sorting Widget ###
639
+
640
+ example of sorting widget initialization with minimum options
641
+ ```
642
+ <SearchstaxSortingWidget></SearchstaxSortingWidget>
643
+ ```
644
+
645
+
646
+ example of sorting widget initialization with template override
647
+ ```
648
+ <SearchstaxSortingWidget>
649
+ <template #sorting="{ sortingData, orderChange, selectedSorting }">
650
+ <div
651
+ class="searchstax-sorting-container"
652
+ v-if="sortingData && sortingData?.searchExecuted && sortingData?.hasResultsOrExternalPromotions"
653
+ >
654
+ <label
655
+ class="searchstax-sorting-label"
656
+ for="sort-by"
657
+ >Sort By</label>
658
+ <select
659
+ id="searchstax-search-order-select"
660
+ class="searchstax-search-order-select"
661
+ :value="selectedSorting"
662
+ @change="orderChange($event)"
663
+ >
664
+ <option value=""> Relevance </option>
665
+ <option value="date desc"> Newest Content </option>
666
+ <option value="date asc"> Oldest Content </option>
667
+ </select>
193
668
  </div>
194
- </div>
195
- </template>
196
- </SearchstaxResultWidget>
669
+ </template>
670
+ </SearchstaxSortingWidget>
197
671
  ```
198
672
 
673
+
674
+ ## Template overrides
675
+ Templates use vue slots.
676
+
199
677
  ## STYLING
200
678
 
201
679
  scss styles can be imported from searchstudio-ux-js