@salesforcedevs/dx-components 1.3.210-lang4-alpha → 1.3.210-lang6-alpha

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.
@@ -11,94 +11,129 @@
11
11
  <div class="dx-search-header-container">
12
12
  <p class="dx-search-header-title">
13
13
  <span class="dx-search-header-title-results">{title}</span>
14
+ &nbsp;
15
+ <strong lwc:if={hasNoResults}>0</strong>
14
16
  &nbsp;results for
15
17
  </p>
16
18
  <p class="dx-search-header-query">&ldquo;{query}&rdquo;</p>
17
19
  </div>
18
20
  </div>
19
21
  <div class="coveo-main-section">
20
- <div class="coveo-facet-column">
21
- <div class="dx-facet-column-header">
22
- <span class="dx-facet-column-header-title">Filters</span>
23
- <template if:true={hasFilters}>
24
- <dx-button onclick={clearFilters} variant="inline">
25
- Clear
26
- </dx-button>
27
- </template>
28
- </div>
29
- <div
30
- class="CoveoDynamicFacetManager"
31
- data-enable-reorder="false"
32
- >
33
- <div
34
- class="CoveoDynamicFacet"
35
- data-title="Content Type"
36
- data-field="@commonsource"
37
- data-tab="All"
38
- data-enable-facet-search="false"
39
- ></div>
40
- <div
41
- class="CoveoDynamicFacet"
42
- data-title="Language"
43
- data-field="@language"
44
- data-tab="All"
45
- data-enable-facet-search="false"
46
- ></div>
47
- </div>
48
- <div class="dx-facet-column-footer">
49
- <dx-button onclick={dismissFiltersOverlay}>
50
- View {title} results
51
- </dx-button>
22
+ <div class="no-results" lwc:if={hasNoResults}>
23
+ <img
24
+ src="https://a.sfdcstatic.com/developer-website/images/binary-cloud-circle-small.svg"
25
+ alt="purple cloud with floating binary numbers above"
26
+ />
27
+ <div class="no-results-info">
28
+ <p class="dx-text-display-8">
29
+ Sorry, no results were found for your search
30
+ &ldquo;{query}&rdquo;
31
+ </p>
32
+ <p class="dx-text-display-8 tip">Search Tips:</p>
33
+ <ul>
34
+ <li>Please consider misspellings</li>
35
+ <li>Try different search keywords</li>
36
+ </ul>
37
+ <dx-hr no-padding="true"></dx-hr>
38
+ <p class="dx-text-display-8 tip">
39
+ Still not finding what you're looking for? Consider
40
+ asking in the&nbsp;
41
+ <a
42
+ class="link"
43
+ href="https://trailhead.salesforce.com/trailblazer-community/feed"
44
+ >
45
+ Trailblazer Community
46
+ </a>
47
+ !
48
+ </p>
52
49
  </div>
53
50
  </div>
54
- <div class="coveo-results-column">
55
- <div class="CoveoShareQuery"></div>
56
- <div class="CoveoExportToExcel"></div>
57
- <div class="CoveoPreferencesPanel">
58
- <div class="CoveoResultsPreferences"></div>
59
- <div class="CoveoResultsFiltersPreferences"></div>
60
- </div>
61
- <div class="CoveoDidYouMean"></div>
62
- <div class="coveo-results-header">
63
- <div class="coveo-summary-section"></div>
64
- <div class="coveo-sort-section" role="radiogroup">
65
- <span
66
- class="CoveoSort"
67
- data-sort-criteria="relevancy"
68
- data-caption="Sorted by Relevance"
69
- ></span>
51
+ <template lwc:if={hasResults}>
52
+ <div class="coveo-facet-column">
53
+ <div class="dx-facet-column-header">
54
+ <span class="dx-facet-column-header-title">
55
+ Filters
56
+ </span>
57
+ <template if:true={hasFilters}>
58
+ <dx-button onclick={clearFilters} variant="inline">
59
+ Clear
60
+ </dx-button>
61
+ </template>
70
62
  </div>
71
- <div>
63
+ <div
64
+ class="CoveoDynamicFacetManager"
65
+ data-enable-reorder="false"
66
+ >
67
+ <div
68
+ class="CoveoDynamicFacet"
69
+ data-title="Content Type"
70
+ data-field="@commonsource"
71
+ data-tab="All"
72
+ data-enable-facet-search="false"
73
+ ></div>
72
74
  <div
73
- class="CoveoSearchbox"
74
- data-enable-omnibox="false"
75
- data-add-search-button="false"
76
- aria-hidden="true"
75
+ class="CoveoDynamicFacet"
76
+ data-title="Language"
77
+ data-field="@language"
78
+ data-tab="All"
79
+ data-enable-facet-search="false"
77
80
  ></div>
78
81
  </div>
82
+ <div class="dx-facet-column-footer">
83
+ <dx-button onclick={dismissFiltersOverlay}>
84
+ View {title} results
85
+ </dx-button>
86
+ </div>
79
87
  </div>
80
- <div class="CoveoBreadcrumb"></div>
81
- <div class="CoveoHiddenQuery"></div>
82
- <div class="CoveoErrorReport"></div>
83
- <div
84
- class="CoveoResultList"
85
- data-layout="list"
86
- data-wait-animation="fade"
87
- data-auto-select-fields-to-include="true"
88
- lwc:dom="manual"
89
- ></div>
90
- <div class="coveo-results-footer" aria-hidden="true">
91
- <div class="CoveoPager"></div>
92
- </div>
93
- <div class="pagination-container">
94
- <dx-pagination
95
- current-page={currentPage}
96
- total-pages={totalPages}
97
- onpagechange={goToPage}
98
- pages-to-show="5"
99
- ></dx-pagination>
88
+ <div class="coveo-results-column">
89
+ <div class="CoveoShareQuery"></div>
90
+ <div class="CoveoExportToExcel"></div>
91
+ <div class="CoveoPreferencesPanel">
92
+ <div class="CoveoResultsPreferences"></div>
93
+ <div class="CoveoResultsFiltersPreferences"></div>
94
+ </div>
95
+ <div class="CoveoDidYouMean"></div>
96
+ <div class="coveo-results-header">
97
+ <div class="coveo-summary-section"></div>
98
+ <div class="coveo-sort-section" role="radiogroup">
99
+ <span
100
+ class="CoveoSort"
101
+ data-sort-criteria="relevancy"
102
+ data-caption="Sorted by Relevance"
103
+ ></span>
104
+ </div>
105
+ <div>
106
+ <div
107
+ class="CoveoSearchbox"
108
+ data-enable-omnibox="false"
109
+ data-add-search-button="false"
110
+ aria-hidden="true"
111
+ ></div>
112
+ </div>
113
+ </div>
114
+ <div class="CoveoBreadcrumb"></div>
115
+ <div class="CoveoHiddenQuery"></div>
116
+ <div class="CoveoErrorReport"></div>
117
+ <div
118
+ class="CoveoResultList"
119
+ data-layout="list"
120
+ data-wait-animation="fade"
121
+ data-auto-select-fields-to-include="true"
122
+ lwc:dom="manual"
123
+ ></div>
124
+ <div class="coveo-results-footer" aria-hidden="true">
125
+ <div class="CoveoPager"></div>
126
+ </div>
127
+ <div class="pagination-container">
128
+ <dx-pagination
129
+ current-page={currentPage}
130
+ total-pages={totalPages}
131
+ onpagechange={goToPage}
132
+ pages-to-show="5"
133
+ ></dx-pagination>
134
+ </div>
100
135
  </div>
101
- </div>
136
+ </template>
102
137
  </div>
103
138
  </div>
104
139
  </template>
@@ -118,11 +118,16 @@ export default class SearchResults extends LightningElement {
118
118
 
119
119
  private query: string = "";
120
120
  private hasFilters: boolean = false;
121
+ private hasResults: boolean = true;
121
122
 
122
123
  private get hasQuery(): boolean {
123
124
  return this.query !== "";
124
125
  }
125
126
 
127
+ private get hasNoResults(): boolean {
128
+ return this.hasQuery && !this.hasResults;
129
+ }
130
+
126
131
  private updateSearchQuery() {
127
132
  Coveo.state(this.root!, "q", this._query);
128
133
  }
@@ -185,12 +190,18 @@ export default class SearchResults extends LightningElement {
185
190
  this.currentPage = currentPage;
186
191
  this.totalPages = numberOfPages;
187
192
  this.totalResults = event.detail.results.totalCount;
193
+
194
+ if (!this.totalResults) {
195
+ this.hasResults = false;
196
+ }
197
+
188
198
  this.query = event.detail.query.q ?? "";
189
199
  this.hasFilters = event.detail.query.facets.some((f: any) => {
190
200
  return f.currentValues.some((cv: any) => {
191
201
  return cv.state === "selected";
192
202
  });
193
203
  });
204
+
194
205
  this.trackSearchResults(event, this.query, this.totalResults);
195
206
  });
196
207
  }
@@ -199,6 +210,7 @@ export default class SearchResults extends LightningElement {
199
210
  this.root = this.template.querySelector(".CoveoSearchInterface")!;
200
211
 
201
212
  const resultsList = this.template.querySelector(".CoveoResultList");
213
+
202
214
  if (resultsList) {
203
215
  resultsList.innerHTML = resultsTemplatesInnerHtml;
204
216
  }
@@ -1,8 +1,14 @@
1
1
  @import "dxHelpers/commonSidebar";
2
2
 
3
3
  dx-empty-state {
4
- --dx-c-empty-state-background: var(--sds-g-gray-2);
4
+ --dx-c-empty-state-background-alt: var(--sds-g-gray-1);
5
5
  --dx-c-empty-state-image-width: 400px;
6
+ --dx-c-font-title-alt-size: 18px;
7
+ --dx-c-font-title-alt-margin-top: var(--dx-g-spacing-md);
8
+ --dx-c-font-body-alt-size: var(--dx-g-text-xs);
9
+ --dx-c-font-body-alt-margin-top: 0;
10
+ --dx-c-container-alt-padding: var(--dx-g-spacing-2xl) 37px;
11
+ --dx-c-font-suggestion-alt-size: 10px;
6
12
 
7
13
  display: none;
8
14
  }
@@ -75,8 +75,11 @@
75
75
  ></dx-sidebar-search-result>
76
76
  </template>
77
77
  <dx-empty-state
78
+ variant="alt"
78
79
  class="padding-horizontal"
79
80
  title="No Results"
81
+ body={emptyStateBody}
82
+ suggestions={emptyStateSuggestions}
80
83
  size="small"
81
84
  ></dx-empty-state>
82
85
  </div>
@@ -95,23 +98,23 @@
95
98
 
96
99
  <template if:false={mobile}>
97
100
  <div if:true={hasSidebarFooter} class="footer-nav">
98
- <doc-sidebar-footer-nav
101
+ <dx-sidebar-footer-nav
99
102
  lang-value-path={langValuePath}
100
103
  language={language}
101
104
  languages={languages}
102
105
  bail-href={bailHref}
103
106
  bail-label={bailLabel}
104
- ></doc-sidebar-footer-nav>
107
+ ></dx-sidebar-footer-nav>
105
108
  </div>
106
109
  </template>
107
110
 
108
111
  <template if:true={mobile}>
109
112
  <div if:true={hasMobileSidebarFooter} class="footer-nav">
110
- <doc-sidebar-footer-nav
113
+ <dx-sidebar-footer-nav
111
114
  lang-value-path={langValuePath}
112
115
  language={language}
113
116
  languages={languages}
114
- ></doc-sidebar-footer-nav>
117
+ ></dx-sidebar-footer-nav>
115
118
  </div>
116
119
  </template>
117
120
  </div>
@@ -5,7 +5,6 @@ import { getSidebarSearchParams } from "dxUtils/coveo";
5
5
  import { toJson } from "dxUtils/normalizers";
6
6
  import SidebarSearch from "dx/sidebarSearch";
7
7
  import { SidebarBase } from "dxBaseElements/sidebarBase";
8
- import type { OptionWithLink } from "typings/custom";
9
8
 
10
9
  const MOBILE_SIZE_MATCH = "768px";
11
10
 
@@ -15,20 +14,6 @@ export default class Sidebar extends SidebarBase {
15
14
  @api coveoSearchHub!: string;
16
15
  @api coveoAdvancedQueryConfig!: string;
17
16
  @api header: string = "";
18
- @api langValuePath: string = "id";
19
- @api languages!: OptionWithLink[];
20
- @api language!: string;
21
- @api bailHref!: string;
22
- @api bailLabel!: string;
23
-
24
- @api
25
- get value() {
26
- return this._value;
27
- }
28
-
29
- set value(value) {
30
- this._value = value;
31
- }
32
17
 
33
18
  @api
34
19
  get trees() {
@@ -58,16 +43,10 @@ export default class Sidebar extends SidebarBase {
58
43
  )?.setInputValue(searchTerm);
59
44
  }
60
45
 
61
- private expanded: boolean = true;
62
- private _value?: string = undefined;
63
-
64
46
  @track
65
47
  private _trees!: Array<TreeNode>;
66
-
67
- private mobile: boolean = true;
68
48
  private matchMedia!: MediaQueryList;
69
49
  private valueToLabel: { [key: string]: string } = {};
70
-
71
50
  private isSearchLoading: boolean = false;
72
51
  private searchValue: string | null = null;
73
52
  private searchResults: SidebarSearchResult[] = [];
@@ -101,6 +80,17 @@ export default class Sidebar extends SidebarBase {
101
80
  );
102
81
  }
103
82
 
83
+ private get emptyStateBody(): string {
84
+ return "Search Tips:";
85
+ }
86
+
87
+ private get emptyStateSuggestions(): string {
88
+ return JSON.stringify([
89
+ "Please consider misspellings",
90
+ "Try different search keywords"
91
+ ]);
92
+ }
93
+
104
94
  private get isNearBottomOfSearchResults(): boolean {
105
95
  const scrollArea = this.template.querySelector(
106
96
  ".sidebar-content-search"
@@ -166,32 +156,6 @@ export default class Sidebar extends SidebarBase {
166
156
  this.matchMedia.removeEventListener("change", this.onMediaChange);
167
157
  }
168
158
 
169
- private onMediaChange = (event: MediaQueryListEvent | MediaQueryList) => {
170
- this.mobile = event.matches;
171
- this.expanded = !this.mobile;
172
- };
173
-
174
- private onSelect(event: CustomEvent) {
175
- this._value = event.detail.name;
176
-
177
- if (this.mobile) {
178
- this.onToggleClick();
179
- }
180
- }
181
-
182
- private onToggleClick() {
183
- this.expanded = !this.expanded;
184
- this.dispatchEvent(
185
- new CustomEvent("togglesidebar", {
186
- detail: {
187
- open: this.expanded,
188
- bubbles: true,
189
- composed: true
190
- }
191
- })
192
- );
193
- }
194
-
195
159
  private makeKey(): string {
196
160
  return Math.random().toString(36).substring(7);
197
161
  }
@@ -262,20 +226,4 @@ export default class Sidebar extends SidebarBase {
262
226
  this.template.querySelector("dx-sidebar-search") as any
263
227
  )?.requestOpenDropdown(false);
264
228
  }
265
-
266
- private get hasMobileSidebarFooter(): boolean {
267
- return !!(
268
- this.mobile &&
269
- this.languages &&
270
- toJson(this.languages).length > 1 &&
271
- this.expanded
272
- );
273
- }
274
-
275
- private get hasSidebarFooter(): boolean {
276
- return !!(
277
- (this.languages && toJson(this.languages).length > 1) ||
278
- Boolean(this.bailHref)
279
- );
280
- }
281
229
  }
@@ -0,0 +1,52 @@
1
+ @import "dxHelpers/reset";
2
+
3
+ :host {
4
+ --button-primary-color: var(--dx-g-blue-vibrant-50);
5
+ --button-primary-color-hover: var(--dx-g-cloud-blue-vibrant-95);
6
+ --popover-container-open-transform: translateX(-4px) translateY(-8px);
7
+ --popover-transition: none;
8
+ --dx-c-dropdown-option-font-weight: normal;
9
+ --dx-c-dropdown-option-label-color: var(--dx-g-gray-10);
10
+ }
11
+
12
+ .footer-display {
13
+ display: flex;
14
+ }
15
+
16
+ .footer_lang-dropdown {
17
+ --dx-c-button-primary-color: var(--button-primary-color);
18
+ --border-color: var(--button-primary-color);
19
+
20
+ display: flex;
21
+ padding: 0 var(--dx-g-spacing-md);
22
+ margin-left: var(--dx-g-spacing-sm);
23
+ height: var(--dx-g-spacing-xl);
24
+ border-radius: var(--dx-g-spacing-xs);
25
+ align-items: center;
26
+ }
27
+
28
+ .footer_lang-dropdown[aria-expanded="true"] {
29
+ background-color: var(--dx-g-cloud-blue-vibrant-95);
30
+
31
+ --border-color: var(--dx-g-cloud-blue-vibrant-95);
32
+ }
33
+
34
+ .footer_lang-dropdown:hover,
35
+ .footer_lang-dropdown:active,
36
+ .footer_lang-dropdown:focus,
37
+ .pdf_bail-link:hover {
38
+ background-color: var(--button-primary-color-hover);
39
+
40
+ --border-color: var(--button-primary-color-hover);
41
+ }
42
+
43
+ .pdf_bail-link {
44
+ --dx-c-button-horizontal-spacing: var(--dx-g-spacing-sm);
45
+ --dx-c-button-priamry-color-hover: var(--dx-g-cloud-blue-vibrant-95);
46
+
47
+ padding: 0 var(--dx-g-spacing-md);
48
+ border-radius: var(--dx-g-spacing-xs);
49
+ display: flex;
50
+ height: var(--dx-g-spacing-xl);
51
+ align-items: center;
52
+ }
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div if:false={mobile} class="footer-display">
3
+ <dx-button
4
+ if:true={hasBailLink}
5
+ aria-label={bailLabel}
6
+ class="pdf_bail-link"
7
+ href={bailHref}
8
+ onclick={handleBailClick}
9
+ variant="inline"
10
+ icon-size="medium"
11
+ icon-symbol="new_window"
12
+ target="_blank"
13
+ >
14
+ {bailLabel}
15
+ </dx-button>
16
+ <dx-dropdown
17
+ if:true={hasLanguages}
18
+ options={languages}
19
+ small
20
+ value-path={langValuePath}
21
+ value={language}
22
+ onchange={onLangChange}
23
+ >
24
+ <dx-button
25
+ class="footer_lang-dropdown"
26
+ aria-label="Select Language"
27
+ variant="inline"
28
+ icon-size="medium"
29
+ icon-symbol="world"
30
+ >
31
+ {languageLabel}
32
+ </dx-button>
33
+ </dx-dropdown>
34
+ </div>
35
+ <div if:true={mobile} class="footer-display">
36
+ <dx-dropdown
37
+ if:true={hasLanguages}
38
+ options={languages}
39
+ small
40
+ value-path={langValuePath}
41
+ value={language}
42
+ onchange={onLangChange}
43
+ >
44
+ <dx-button
45
+ class="footer_lang-dropdown"
46
+ aria-label="Select Language"
47
+ variant="inline"
48
+ icon-size="small"
49
+ icon-symbol="world"
50
+ >
51
+ {languageLabel}
52
+ </dx-button>
53
+ </dx-dropdown>
54
+ </div>
55
+ </template>
@@ -0,0 +1,106 @@
1
+ /* eslint-disable @lwc/lwc/no-document-query */
2
+ import { LightningElement, api } from "lwc";
3
+ import type { OptionWithLink } from "typings/custom";
4
+ import { toJson } from "dxUtils/normalizers";
5
+ import get from "lodash.get";
6
+ import { track } from "dxUtils/analytics";
7
+
8
+ const MOBILE_SIZE_MATCH = "768px";
9
+
10
+ export default class SidebarFooterNav extends LightningElement {
11
+ @api langValuePath: string = "id";
12
+ @api bailHref?: string | null = null;
13
+ @api bailLabel?: string | null = null;
14
+
15
+ @api
16
+ get languages() {
17
+ return this._languages;
18
+ }
19
+
20
+ set languages(value) {
21
+ this._languages = toJson(value);
22
+ }
23
+
24
+ @api
25
+ get language() {
26
+ return this._language;
27
+ }
28
+
29
+ set language(value) {
30
+ this._language = value;
31
+ }
32
+
33
+ private _languages!: OptionWithLink[];
34
+ private _language: string | null = null;
35
+ private mobile: boolean = false;
36
+ private matchMedia!: MediaQueryList;
37
+
38
+ private get hasLanguages(): boolean {
39
+ return this.languages?.length > 1;
40
+ }
41
+
42
+ private get languageLabel(): string {
43
+ const matchingLanguageData = this.language
44
+ ? this.languages.find(
45
+ (lang) => get(lang, this.langValuePath) === this.language
46
+ )
47
+ : null;
48
+ return matchingLanguageData?.label || this.languages[0].label;
49
+ }
50
+
51
+ get hasBailLink(): boolean {
52
+ return !!(this.bailHref && this.bailLabel);
53
+ }
54
+
55
+ private onLangChange(event: CustomEvent<string>): void {
56
+ const { detail } = event;
57
+ this._language = detail;
58
+
59
+ this.dispatchEvent(
60
+ new CustomEvent("langchange", {
61
+ detail,
62
+ bubbles: true,
63
+ composed: true
64
+ })
65
+ );
66
+ }
67
+
68
+ private getFilename = function (path: string) {
69
+ return path.substring(path.lastIndexOf("/") + 1);
70
+ };
71
+
72
+ private handleBailClick(event: Event) {
73
+ const payload = {
74
+ click_text: "pdf",
75
+ click_url: this.bailHref,
76
+ element_title: "pdf",
77
+ element_type: "link",
78
+ content_category: "download"
79
+ };
80
+ track(event.target!, "custEv_pdfDownload", {
81
+ ...payload,
82
+ file_name: this.getFilename(this.bailHref!),
83
+ file_extension: "pdf"
84
+ });
85
+
86
+ track(event.target!, "custEv_linkClick", {
87
+ ...payload
88
+ });
89
+ }
90
+
91
+ connectedCallback() {
92
+ this.matchMedia = window.matchMedia(
93
+ `(max-width: ${MOBILE_SIZE_MATCH})`
94
+ );
95
+ this.onMediaChange(this.matchMedia);
96
+ this.matchMedia.addEventListener("change", this.onMediaChange);
97
+ }
98
+
99
+ disconnectedCallback() {
100
+ this.matchMedia.removeEventListener("change", this.onMediaChange);
101
+ }
102
+
103
+ private onMediaChange = (event: MediaQueryListEvent | MediaQueryList) => {
104
+ this.mobile = event.matches;
105
+ };
106
+ }
@@ -5,8 +5,14 @@
5
5
  }
6
6
 
7
7
  dx-empty-state {
8
- --dx-c-empty-state-background: var(--sds-g-gray-2);
8
+ --dx-c-empty-state-background-alt: var(--sds-g-gray-1);
9
9
  --dx-c-empty-state-image-width: 400px;
10
+ --dx-c-font-title-alt-size: 18px;
11
+ --dx-c-font-title-alt-margin-top: var(--dx-g-spacing-md);
12
+ --dx-c-font-body-alt-size: var(--dx-g-text-xs);
13
+ --dx-c-font-body-alt-margin-top: 0;
14
+ --dx-c-container-alt-padding: var(--dx-g-spacing-2xl) 37px;
15
+ --dx-c-font-suggestion-alt-size: 10px;
10
16
 
11
17
  padding-bottom: var(--dx-g-spacing-md);
12
18
  }