@salesforcedevs/dx-components 1.3.210-lnb2-alpha → 1.3.210-lnb3-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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.3.210-lnb2-alpha",
3
+ "version": "1.3.210-lnb3-alpha",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -272,6 +272,20 @@
272
272
  </g>
273
273
  </g>
274
274
  </symbol>
275
+ <symbol id="data-cloud" viewBox="0 0 56 56" xmlns="http://www.w3.org/2000/svg" style="fill:#fff">
276
+ <defs>
277
+ <style>.acls-2,.acls-4{stroke-width:0}.acls-2{fill:#8a8ed1}.acls-4{fill:#fff}</style>
278
+ </defs>
279
+ <path class="acls-2" d="M28 4C14.77 4 4 14.77 4 28c0 7.9 3.84 14.93 9.76 19.3.7-4.58 3.55-8.46 7.5-10.56-2.61-2.02-4.29-5.17-4.29-8.71C16.97 21.95 21.92 17 28 17s11.03 4.95 11.03 11.03c0 3.54-1.69 6.69-4.29 8.71 3.95 2.1 6.8 5.98 7.5 10.56 5.92-4.37 9.77-11.4 9.77-19.31 0-13.23-10.77-24-24-24Z"/>
280
+ <path class="acls-2" d="M11.07 18.3c.69-1.2 2.21-1.61 3.41-.92a2.5 2.5 0 0 1 .93 3.41c-.46.81-1.3 1.26-2.17 1.26-.42 0-.85-.11-1.24-.34a2.489 2.489 0 0 1-.92-3.41ZM8.49 28.06c0-1.38 1.11-2.5 2.49-2.51 1.38 0 2.51 1.11 2.51 2.5s-1.11 2.5-2.49 2.5h-.01c-1.38 0-2.5-1.11-2.5-2.49ZM14.55 38.71a2.504 2.504 0 0 1-3.42-.9c-.7-1.2-.29-2.73.9-3.42 1.19-.7 2.73-.29 3.42.9a2.51 2.51 0 0 1-.9 3.42ZM20.7 15.46c-.4.23-.83.34-1.26.34-.86 0-1.7-.44-2.16-1.24-.7-1.19-.3-2.73.9-3.42 1.19-.7 2.72-.29 3.42.9a2.51 2.51 0 0 1-.9 3.42ZM28 13.49h-.07c-1.38 0-2.5-1.11-2.5-2.49 0-1.38 1.11-2.5 2.49-2.51h.11c1.37.02 2.47 1.13 2.47 2.5s-1.12 2.5-2.5 2.5ZM38.67 14.52a2.51 2.51 0 0 1-2.17 1.24c-.43 0-.86-.1-1.25-.33a2.5 2.5 0 0 1 2.5-4.33c1.2.69 1.6 2.22.92 3.42ZM41.48 17.32a2.5 2.5 0 0 1 2.5 4.33c-.39.23-.82.33-1.25.33-.86 0-1.7-.44-2.17-1.24-.69-1.2-.28-2.73.92-3.42ZM44.91 37.73c-.46.81-1.3 1.26-2.17 1.26-.42 0-.85-.11-1.24-.34a2.493 2.493 0 0 1-.92-3.41c.69-1.2 2.22-1.61 3.42-.92a2.5 2.5 0 0 1 .91 3.41ZM45.01 30.48c-1.38 0-2.5-1.12-2.5-2.49s1.12-2.51 2.5-2.51a2.5 2.5 0 0 1 0 5Z"/>
281
+ <circle class="acls-4" cx="27.99" cy="28.03" r="7.03"/>
282
+ <path class="acls-4" d="M27.99 39.06c-5.75 0-10.42 4.67-10.42 10.42v.13C20.72 51.14 24.26 52 28 52s7.26-.86 10.41-2.38v-.14c0-5.75-4.67-10.42-10.42-10.42Z"/>
283
+ <circle cx="28" cy="28" r="28" style="stroke-width:0;fill:#200647"/>
284
+ <path class="acls-4" d="M38.41 49.62C35.26 51.14 31.73 52 28 52s-7.27-.86-10.43-2.39v-.13c0-5.75 4.67-10.42 10.42-10.42s10.42 4.67 10.42 10.42v.14Z"/>
285
+ <circle class="acls-4" cx="27.99" cy="28.03" r="7.03"/>
286
+ <path d="M42.23 47.31c-.7-4.58-3.55-8.47-7.5-10.56 2.61-2.02 4.29-5.17 4.29-8.71 0-6.08-4.95-11.03-11.03-11.03s-11.03 4.95-11.03 11.03c0 3.54 1.69 6.69 4.29 8.71-3.95 2.1-6.8 5.98-7.5 10.56-5.91-4.38-9.76-11.4-9.76-19.3C4 14.77 14.77 4 28 4s24 10.77 24 24c0 7.91-3.85 14.94-9.77 19.31Z" style="fill:#7f8ced;stroke-width:0"/>
287
+ <path class="acls-4" d="M37.75 11.1a2.5 2.5 0 0 0-2.5 4.33c.39.23.82.33 1.25.33.86 0 1.7-.44 2.17-1.24.68-1.2.28-2.73-.92-3.42ZM11 30.55c1.38 0 2.49-1.12 2.49-2.5s-1.13-2.5-2.51-2.5a2.5 2.5 0 0 0-2.49 2.51c0 1.38 1.12 2.49 2.5 2.49H11ZM42.73 21.98c.43 0 .86-.1 1.25-.33a2.5 2.5 0 0 0-2.5-4.33c-1.2.69-1.61 2.22-.92 3.42.47.8 1.31 1.24 2.17 1.24ZM11.99 21.71c.39.23.82.34 1.24.34a2.5 2.5 0 0 0 1.24-4.67c-1.2-.69-2.72-.28-3.41.92s-.28 2.73.92 3.41ZM44 34.32c-1.2-.69-2.73-.28-3.42.92-.69 1.19-.28 2.72.92 3.41.39.23.82.34 1.24.34.87 0 1.71-.45 2.17-1.26a2.5 2.5 0 0 0-.91-3.41ZM45.01 25.48c-1.38 0-2.5 1.12-2.5 2.51s1.12 2.49 2.5 2.49a2.5 2.5 0 0 0 0-5ZM28.03 8.49h-.11A2.5 2.5 0 0 0 25.43 11c0 1.38 1.12 2.49 2.5 2.49H28a2.5 2.5 0 0 0 .03-5ZM18.18 11.14a2.49 2.49 0 0 0-.9 3.42c.46.8 1.3 1.24 2.16 1.24.43 0 .86-.11 1.26-.34a2.51 2.51 0 0 0 .9-3.42c-.7-1.19-2.23-1.6-3.42-.9ZM12.03 34.39c-1.19.69-1.6 2.22-.9 3.42a2.504 2.504 0 0 0 3.42.9 2.51 2.51 0 0 0 .9-3.42 2.499 2.499 0 0 0-3.42-.9Z"/>
288
+ </symbol>
275
289
  <symbol viewBox="0 0 56 56" version="1.1" xmlns="http://www.w3.org/2000/svg" id="integration">
276
290
  <g id="Atoms" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
277
291
  <g id="ICONS-symbols" transform="translate(-1005.000000, 0.000000)" fill-rule="nonzero">
@@ -913,4 +927,31 @@
913
927
  </clipPath>
914
928
  </defs>
915
929
  </symbol>
930
+ <symbol fill="none" id="data-cloud" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 56">
931
+ <path fill="#8a8ed1" d="m28,4C14.77,4,4,14.77,4,28c0,7.9,3.84,14.93,9.76,19.3.7-4.58,3.55-8.46,7.5-10.56-2.61-2.02-4.29-5.17-4.29-8.71,0-6.08,4.95-11.03,11.03-11.03s11.03,4.95,11.03,11.03c0,3.54-1.69,6.69-4.29,8.71,3.95,2.1,6.8,5.98,7.5,10.56,5.92-4.37,9.77-11.4,9.77-19.31,0-13.23-10.77-24-24-24Z"/>
932
+ <path fill="#8a8ed1" d="m11.07,18.3c.69-1.2,2.21-1.61,3.41-.92,1.2.68,1.61,2.21.93,3.41h0c-.46.81-1.3,1.26-2.17,1.26-.42,0-.85-.11-1.24-.34-1.2-.68-1.61-2.21-.92-3.41Z"/>
933
+ <path fill="#8a8ed1" d="m8.49,28.06c0-1.38,1.11-2.5,2.49-2.51,1.38,0,2.51,1.11,2.51,2.5s-1.11,2.5-2.49,2.5h-.01c-1.38,0-2.5-1.11-2.5-2.49Z"/>
934
+ <path fill="#8a8ed1" d="m14.55,38.71c-.4.23-.83.34-1.26.34-.86,0-1.7-.45-2.16-1.24-.7-1.2-.29-2.73.9-3.42,1.19-.7,2.73-.29,3.42.9.69,1.19.29,2.72-.9,3.42Z"/>
935
+ <path fill="#8a8ed1" d="m20.7,15.46c-.4.23-.83.34-1.26.34-.86,0-1.7-.44-2.16-1.24-.7-1.19-.3-2.73.9-3.42,1.19-.7,2.72-.29,3.42.9.69,1.19.29,2.72-.9,3.42Z"/>
936
+ <path fill="#8a8ed1" d="m28,13.49h-.07c-1.38,0-2.5-1.11-2.5-2.49,0-1.38,1.11-2.5,2.49-2.51h.11c1.37.02,2.47,1.13,2.47,2.5s-1.12,2.5-2.5,2.5Z"/>
937
+ <path fill="#8a8ed1" d="m38.67,14.52c-.47.8-1.31,1.24-2.17,1.24-.43,0-.86-.1-1.25-.33-1.2-.69-1.6-2.22-.91-3.42.69-1.19,2.22-1.6,3.41-.91,1.2.69,1.6,2.22.92,3.42Z"/>
938
+ <path fill="#8a8ed1" d="m41.48,17.32c1.19-.69,2.72-.28,3.41.91.69,1.2.29,2.73-.91,3.42-.39.23-.82.33-1.25.33-.86,0-1.7-.44-2.17-1.24-.69-1.2-.28-2.73.92-3.42Z"/>
939
+ <path fill="#8a8ed1" d="m44.91,37.73c-.46.81-1.3,1.26-2.17,1.26-.42,0-.85-.11-1.24-.34-1.2-.69-1.61-2.22-.92-3.41.69-1.2,2.22-1.61,3.42-.92,1.19.69,1.6,2.22.91,3.41Z"/>
940
+ <path fill="#8a8ed1" d="m45.01,30.48c-1.38,0-2.5-1.12-2.5-2.49s1.12-2.51,2.5-2.51,2.5,1.12,2.5,2.5-1.12,2.5-2.5,2.5Z"/>
941
+ <circle fill="#fff" cx="27.99" cy="28.03" r="7.03"/>
942
+ <path fill="#fff" d="m27.99,39.06c-5.75,0-10.42,4.67-10.42,10.42v.13c3.15,1.53,6.69,2.39,10.43,2.39s7.26-.86,10.41-2.38v-.14c0-5.75-4.67-10.42-10.42-10.42Z"/>
943
+ <circle fill="#200647" class="cls-1" cx="28" cy="28" r="28"/>
944
+ <path fill="#fff" d="m38.41,49.62c-3.15,1.52-6.68,2.38-10.41,2.38s-7.27-.86-10.43-2.39v-.13c0-5.75,4.67-10.42,10.42-10.42s10.42,4.67,10.42,10.42v.14Z"/>
945
+ <circle fill="#fff" cx="27.99" cy="28.03" r="7.03"/>
946
+ <path fill="#7f8ced" d="m42.23,47.31c-.7-4.58-3.55-8.47-7.5-10.56,2.61-2.02,4.29-5.17,4.29-8.71,0-6.08-4.95-11.03-11.03-11.03s-11.03,4.95-11.03,11.03c0,3.54,1.69,6.69,4.29,8.71-3.95,2.1-6.8,5.98-7.5,10.56-5.91-4.38-9.76-11.4-9.76-19.3C4,14.77,14.77,4,28,4s24,10.77,24,24c0,7.91-3.85,14.94-9.77,19.31Z"/>
947
+ <path fill="#fff" d="m37.75,11.1c-1.19-.69-2.72-.28-3.41.91-.69,1.2-.29,2.73.91,3.42.39.23.82.33,1.25.33.86,0,1.7-.44,2.17-1.24.68-1.2.28-2.73-.92-3.42Z"/>
948
+ <path fill="#fff" d="m11,30.55c1.38,0,2.49-1.12,2.49-2.5s-1.13-2.5-2.51-2.5c-1.38.01-2.5,1.13-2.49,2.51,0,1.38,1.12,2.49,2.5,2.49h.01Z"/>
949
+ <path fill="#fff" d="m42.73,21.98c.43,0,.86-.1,1.25-.33,1.2-.69,1.6-2.22.91-3.42-.69-1.19-2.22-1.6-3.41-.91-1.2.69-1.61,2.22-.92,3.42.47.8,1.31,1.24,2.17,1.24Z"/>
950
+ <path fill="#fff" d="m11.99,21.71c.39.23.82.34,1.24.34.87,0,1.71-.45,2.17-1.26h0c.68-1.2.27-2.73-.93-3.41-1.2-.69-2.72-.28-3.41.92s-.28,2.73.92,3.41Z"/>
951
+ <path fill="#fff" d="m44,34.32c-1.2-.69-2.73-.28-3.42.92-.69,1.19-.28,2.72.92,3.41.39.23.82.34,1.24.34.87,0,1.71-.45,2.17-1.26.69-1.19.28-2.72-.91-3.41Z"/>
952
+ <path fill="#fff" d="m45.01,25.48c-1.38,0-2.5,1.12-2.5,2.51s1.12,2.49,2.5,2.49,2.5-1.12,2.5-2.5-1.12-2.5-2.5-2.5Z"/>
953
+ <path fill="#fff" d="m28.03,8.49h-.11c-1.38.01-2.5,1.13-2.49,2.51,0,1.38,1.12,2.49,2.5,2.49h.07c1.38,0,2.5-1.12,2.5-2.5s-1.1-2.48-2.47-2.5Z"/>
954
+ <path fill="#fff" d="m18.18,11.14c-1.2.69-1.6,2.23-.9,3.42.46.8,1.3,1.24,2.16,1.24.43,0,.86-.11,1.26-.34,1.19-.7,1.59-2.23.9-3.42-.7-1.19-2.23-1.6-3.42-.9Z"/>
955
+ <path fill="#fff" d="m12.03,34.39c-1.19.69-1.6,2.22-.9,3.42.46.79,1.3,1.24,2.16,1.24.43,0,.86-.11,1.26-.34,1.19-.7,1.59-2.23.9-3.42-.69-1.19-2.23-1.6-3.42-.9Z"/>
956
+ </symbol>
916
957
  </svg>
@@ -94,7 +94,9 @@ export const generalLinksRaw: OptionWithRequiredNested[] = [
94
94
  id: "Events and Calendar"
95
95
  },
96
96
  {
97
- link: { href: "https://go.appexchange.com/partnerprogram" },
97
+ link: {
98
+ href: "https://www.salesforce.com/partners/become-a-partner/"
99
+ },
98
100
  label: "Partner Community",
99
101
  id: "Partner Community"
100
102
  },
@@ -14,19 +14,25 @@ export default class MainContentHeader extends LightningElement {
14
14
  @api imgSrcMobile!: string;
15
15
  @api ctaTarget?: string | null = null;
16
16
  @api ctaTargetSecondary?: string | null = null;
17
- @api backgroundColor?: string;
18
- @api backgroundColorDark: boolean = false;
17
+ @api backgroundGradientColor?: string;
18
+ @api backgroundGradientDark: boolean = false;
19
19
  @api hasSwoop: boolean = false;
20
20
 
21
21
  private get style() {
22
22
  return cx(
23
- this.backgroundColor &&
24
- `background-color: var(--dx-g-${this.backgroundColor});`
23
+ this.backgroundGradientColor &&
24
+ !this.backgroundGradientDark &&
25
+ `background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #ffff 100%), var(--dx-g-${this.backgroundGradientColor});`,
26
+ this.backgroundGradientDark &&
27
+ `background: linear-gradient(90deg, var(--dx-g-indigo-vibrant-20) 0%, var(--dx-g-indigo-vibrant-30) 100%);`
25
28
  );
26
29
  }
27
30
 
28
31
  private get textStyle() {
29
- return cx("text-container", this.backgroundColorDark && "light-text");
32
+ return cx(
33
+ "text-container",
34
+ this.backgroundGradientDark && "light-text"
35
+ );
30
36
  }
31
37
 
32
38
  private onCtaClick(e: Event) {
@@ -164,12 +164,13 @@ export default class ScrollManager extends LightningElement {
164
164
  }
165
165
 
166
166
  saveScroll = throttle(100, () => {
167
+ const scrollingElement = document.scrollingElement || document.body;
167
168
  window.history.replaceState(
168
169
  {
169
170
  ...window.history.state,
170
171
  scroll: {
171
- value: document.body.scrollTop,
172
- docSize: document.body.scrollHeight
172
+ value: scrollingElement.scrollTop,
173
+ docSize: scrollingElement.scrollHeight
173
174
  }
174
175
  },
175
176
  "",
@@ -274,18 +274,15 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
274
274
  }
275
275
 
276
276
  .dx-result-title {
277
+ /* override the default Coveo style */
278
+ color: var(--dx-g-blue-vibrant-20) !important;
279
+ display: block;
277
280
  font-family: var(--dx-g-font-display);
278
281
  font-size: var(--dx-g-text-lg);
279
282
  margin: 0;
280
283
  margin-bottom: var(--dx-g-spacing-sm);
281
284
  }
282
285
 
283
- .CoveoResultLink,
284
- a.CoveoResultLink,
285
- .CoveoResult a.CoveoResultLink {
286
- color: var(--dx-g-blue-vibrant-20);
287
- }
288
-
289
286
  .dx-result-excerpt {
290
287
  color: var(--dx-g-gray-10);
291
288
  font-size: 14px;
@@ -422,11 +419,17 @@ a.CoveoResultLink,
422
419
  width: fit-content;
423
420
  }
424
421
 
425
- .dx-badge {
426
- display: block;
422
+ .dx-result-info {
423
+ display: flex;
424
+ gap: 12px;
427
425
  margin-bottom: var(--dx-g-spacing-smd);
428
426
  }
429
427
 
428
+ .breadcrumb {
429
+ color: #555;
430
+ font-size: var(--dx-g-text-xs);
431
+ }
432
+
430
433
  .no-results {
431
434
  display: flex;
432
435
  justify-content: center;
@@ -6,6 +6,7 @@ import {
6
6
  CONTENT_TYPE_ICONS
7
7
  } from "dxConstants/contentTypes";
8
8
  import { getContentTypeColorVariables } from "dxUtils/contentTypes";
9
+ import { pollUntil } from "dxUtils/async";
9
10
 
10
11
  interface CoveoSearch {
11
12
  state: typeof CoveoSDK.state;
@@ -40,35 +41,78 @@ const resultsTemplatesInnerHtml = `
40
41
  <script
41
42
  id="myDocumentResultTemplate"
42
43
  class="result-template"
43
- type="text/html"
44
+ type="text/underscore"
44
45
  data-field-publicurl=""
45
46
  >
46
47
  <div class="dx-result">
47
- <span class="CoveoFieldValue" data-field="@content_type" data-helper="badge" data-html-value="true"></span>
48
- <p class="dx-result-title">
49
- <a
50
- class="CoveoResultLink"
51
- data-field="@publicurl"
52
- ></a>
53
- </p>
48
+ <div class="dx-result-info">
49
+ <span class="CoveoFieldValue" data-field="@content_type" data-helper="badge" data-html-value="true"></span>
50
+ <% if (!raw.breadcrumbs && !raw.metabreadcrumbs) { %>
51
+ <span class="CoveoFieldValue" data-field="@uri" data-helper="uriBreadcrumbs" data-html-value="true"></span>
52
+ <% } else { %>
53
+ <% if (raw.uri.includes('/references/')) { %>
54
+ <span class="CoveoFieldValue" data-field="@metabreadcrumbs" data-helper="metabreadcrumbs" data-html-value="true"></span>
55
+ <% } else { %>
56
+ <span class="CoveoFieldValue" data-field="@breadcrumbs" data-helper="breadcrumbs" data-html-value="true"></span>
57
+ <% } %>
58
+ <% } %>
59
+ </div>
60
+ <a
61
+ href="<%= raw.uri %>"
62
+ class="dx-result-title"
63
+ >
64
+ <%= title %>
65
+ <% if (!raw.uri.includes('developer.salesforce.com') && !raw.uri.includes('developer-website-s.herokuapp.com')) { %>
66
+ <svg xmlns="http://www.w3.org/2000/svg" style="display: inline; vertical-align: baseline;" fill="var(--dx-g-blue-vibrant-20)" width="20" height="20" part="svg" aria-hidden="true"><use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#new_window"></use></svg>
67
+ <% } %>
68
+ </a>
54
69
  <p class="dx-result-excerpt CoveoExcerpt"></p>
55
70
  </div>
56
71
  </script>
57
72
  <script
58
73
  id="myDefaultResultTemplate"
59
74
  class="result-template"
60
- type="text/html"
75
+ type="text/underscore"
61
76
  >
62
77
  <div class="dx-result">
63
- <span class="CoveoFieldValue" data-field="@content_type" data-helper="badge" data-html-value="true"></span>
64
- <p class="dx-result-title">
65
- <a class="CoveoResultLink"></a>
66
- </p>
78
+ <div class="dx-result-info">
79
+ <span class="CoveoFieldValue" data-field="@content_type" data-helper="badge" data-html-value="true"></span>
80
+ <% if (!raw.breadcrumbs && !raw.metabreadcrumbs) { %>
81
+ <span class="CoveoFieldValue" data-field="@uri" data-helper="uriBreadcrumbs" data-html-value="true"></span>
82
+ <% } else { %>
83
+ <% if (raw.uri.includes('/references/')) { %>
84
+ <span class="CoveoFieldValue" data-field="@metabreadcrumbs" data-helper="metabreadcrumbs" data-html-value="true"></span>
85
+ <% } else { %>
86
+ <span class="CoveoFieldValue" data-field="@breadcrumbs" data-helper="breadcrumbs" data-html-value="true"></span>
87
+ <% } %>
88
+ <% } %>
89
+ </div>
90
+ <a
91
+ href="<%= raw.uri %>"
92
+ class="dx-result-title"
93
+ >
94
+ <% if (title) { %>
95
+ <%= title %>
96
+ <% } else { %>
97
+ <%= uri %>
98
+ <% } %>
99
+ <% if (!raw.uri.includes('developer.salesforce.com') && !raw.uri.includes('developer-website-s.herokuapp.com')) { %>
100
+ <svg xmlns="http://www.w3.org/2000/svg" style="display: inline; vertical-align: baseline;" fill="var(--dx-g-blue-vibrant-20)" width="20" height="20" part="svg" aria-hidden="true"><use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#new_window"></use></svg>
101
+ <% } %>
102
+ </a>
67
103
  <p class="dx-result-excerpt CoveoExcerpt"></p>
68
104
  </div>
69
105
  </script>
70
106
  `;
71
107
 
108
+ const isInternalDomain = (domain: string) =>
109
+ domain === "developer.salesforce.com" ||
110
+ domain === "developer-website-s.herokuapp.com";
111
+
112
+ const isTrailheadDomain = (domain: string) =>
113
+ domain === "trailhead.salesforce.com" ||
114
+ domain === "dev.trailhead.salesforce.com";
115
+
72
116
  const buildTemplateHelperBadge = (value: keyof typeof CONTENT_TYPE_LABELS) => {
73
117
  const style = getContentTypeColorVariables(value);
74
118
  const label = CONTENT_TYPE_LABELS[value];
@@ -88,6 +132,107 @@ const buildTemplateHelperBadge = (value: keyof typeof CONTENT_TYPE_LABELS) => {
88
132
  `;
89
133
  };
90
134
 
135
+ const processParts = (parts: string[], internalFlag = false) => {
136
+ // filter /docs/ breadcrumb item from internal domains
137
+ const filterFn = internalFlag
138
+ ? (part: string) => part !== "docs"
139
+ : (part: string) => part;
140
+
141
+ return parts.filter(filterFn).map((part) => {
142
+ // Remove special characters & .htm/.xml extension
143
+ part = part
144
+ .replace(/_/g, " ")
145
+ .replace(/-/g, " ")
146
+ .replace(/.html*/g, " ")
147
+ .replace(/.xml/g, " ")
148
+ .replace(/b2c/g, "B2C");
149
+
150
+ // Capitalize first letter of each word
151
+ part = part.replace(/\w\S*/g, (w) => {
152
+ return w.replace(/^\w/, (c) => c.toUpperCase());
153
+ });
154
+
155
+ return `<span class="breadcrumb-item">${decodeURI(part)}</span>`;
156
+ });
157
+ };
158
+
159
+ const buildTemplateHelperUriBreadcrumbs = (value: string) => {
160
+ const url = new URL(value);
161
+
162
+ // exclude youtube links from breadcrumbs
163
+ const hostnamePattern = /^((www\.)?(youtube\.com|youtu\.be))$/;
164
+
165
+ // we don't want to show atlas docs because the url structure is mad ugly
166
+ if (hostnamePattern.test(url.hostname) || url.pathname.includes("atlas.")) {
167
+ return "";
168
+ }
169
+
170
+ let parts = url.pathname.split("/").filter((part) => part !== "");
171
+
172
+ // Remove language prefix from trailhead URLs
173
+ if (isTrailheadDomain(url.hostname)) {
174
+ parts = parts
175
+ .slice(1)
176
+ .filter((part) => part !== "content" && part !== "learn");
177
+ }
178
+
179
+ const breadcrumbs = processParts(parts, isInternalDomain(url.hostname));
180
+
181
+ if (!isInternalDomain(url.hostname)) {
182
+ // Remove the first breadcrumb item if it's an internal domain (i.e drop developer.salesforce.com from developer.salesforce.com / B2C Commerce / Open Commerce API / Filtering)
183
+ breadcrumbs.unshift(
184
+ `<span class="breadcrumb-item">${url.hostname}</span>`
185
+ );
186
+
187
+ return `
188
+ <span class="breadcrumb">
189
+ ${breadcrumbs.join(" / ")}
190
+ </span>
191
+ `;
192
+ } else if (breadcrumbs.length === 1) {
193
+ // Hide breadcrumbs if there is only one breadcrumb item
194
+ return "";
195
+ }
196
+
197
+ // remove the last breadcrumb item (the search result title makes it redundant)
198
+ breadcrumbs.pop();
199
+
200
+ return `<span class="breadcrumb">/ ${breadcrumbs.join(" / ")} /</span>`;
201
+ };
202
+
203
+ const buildTemplateHelperBreadcrumbs = (value: string) => {
204
+ const parts = value.split("/").filter((part) => part !== "");
205
+
206
+ // Don't show breadcrumbs if there's only one part
207
+ if (parts.length === 1) {
208
+ return "";
209
+ }
210
+
211
+ const breadcrumbs = processParts(parts);
212
+
213
+ // remove last breadcrumb item
214
+ breadcrumbs.pop();
215
+
216
+ return `
217
+ <span class="breadcrumb">/ ${breadcrumbs.join(" / ")} /</span>
218
+ `;
219
+ };
220
+
221
+ const buildTemplateHelperMetaBreadcrumbs = (value: string) => {
222
+ const parts = value.split("/").filter((part) => part !== "");
223
+
224
+ // Don't show breadcrumbs if there's only one part
225
+ if (parts.length === 1) {
226
+ return "";
227
+ }
228
+
229
+ const breadcrumbs = processParts(parts);
230
+
231
+ return `
232
+ <span class="breadcrumb">/ ${breadcrumbs.join(" / ")}</span>
233
+ `;
234
+ };
235
+
91
236
  // @ts-ignore Dark Magic (TM) we are overriding the 'title' field with a custom getter. We should really stop doing this.
92
237
  export default class SearchResults extends LightningElement {
93
238
  @api coveoOrganizationId!: string;
@@ -139,9 +284,12 @@ export default class SearchResults extends LightningElement {
139
284
  BreadcrumbManager.clearBreadcrumbs();
140
285
  }
141
286
 
142
- private currentPage: number = 1;
287
+ private currentPage: number = 25;
143
288
  private totalPages: number = 1;
144
289
 
290
+ private originalBreadcrumbs: string[] = [];
291
+ private initialWindowWidth = window.innerWidth;
292
+
145
293
  private goToPage(e: CustomEvent) {
146
294
  const page = e.detail;
147
295
  const Pager = Coveo.get(
@@ -179,6 +327,7 @@ export default class SearchResults extends LightningElement {
179
327
  if (Coveo.state(this.root!, "q") === "") {
180
328
  Coveo.state(this.root!, "sort", "date descending");
181
329
  }
330
+
182
331
  this.isInitialized = true;
183
332
  }
184
333
  );
@@ -204,6 +353,110 @@ export default class SearchResults extends LightningElement {
204
353
 
205
354
  this.trackSearchResults(event, this.query, this.totalResults);
206
355
  });
356
+
357
+ Coveo.$$(root).on(Coveo.QueryEvents.deferredQuerySuccess, async () => {
358
+ // wait specified time to ensure breadcrumbs are rendered before processing them
359
+ await pollUntil(
360
+ () => {
361
+ const coveoResults =
362
+ this.root!.querySelector(".CoveoResult");
363
+
364
+ return Boolean(coveoResults);
365
+ },
366
+ 20,
367
+ 1000
368
+ );
369
+
370
+ this.processBreadcrumbs(this.root!);
371
+
372
+ window.onresize = () => this.processBreadcrumbs(root);
373
+ });
374
+ }
375
+
376
+ // Checks if text is wrapping by comparing it with an element's text that doesn't wrap
377
+ private isTextWrapping = (
378
+ elementOne: HTMLElement,
379
+ elementTwo: HTMLElement
380
+ ) => elementOne.offsetHeight > elementTwo.offsetHeight;
381
+
382
+ private truncateBreadcrumbText = (breadcrumbItems: HTMLElement[]) => {
383
+ breadcrumbItems.forEach((breadcrumbItem: HTMLElement) => {
384
+ const breadcrumbItemText = breadcrumbItem.textContent!;
385
+ if (breadcrumbItemText.length > 30) {
386
+ breadcrumbItem.textContent = `${breadcrumbItemText.substring(
387
+ 0,
388
+ 30
389
+ )}...`;
390
+ }
391
+ });
392
+ };
393
+
394
+ private addBreadcrumbEllipsis = (
395
+ breadcrumbItems: HTMLElement[],
396
+ breadcrumb: HTMLElement
397
+ ) => {
398
+ for (let i = 1; i < breadcrumbItems.length; i++) {
399
+ if (this.isTextWrapping(breadcrumb, breadcrumbItems[0])) {
400
+ breadcrumbItems[i].textContent = "...";
401
+ } else {
402
+ break; // Exit the loop if the breadcrumb is no longer overflowing
403
+ }
404
+ }
405
+ };
406
+
407
+ private formatBreadcrumbs = (breadcrumbs: HTMLElement[]) => {
408
+ breadcrumbs?.forEach((breadcrumb: HTMLElement) => {
409
+ // Get all breadcrumb items that are separated by '/'
410
+ const breadcrumbItems: any =
411
+ breadcrumb.querySelectorAll(".breadcrumb-item");
412
+
413
+ // Check if the breadcrumb is overflowing by comparing it's height to the height of the first breadcrumb item
414
+ if (this.isTextWrapping(breadcrumb, breadcrumbItems[0])) {
415
+ // it is overflowing, so we need to truncate long titles to 30 characters
416
+ this.truncateBreadcrumbText(breadcrumbItems);
417
+
418
+ // Iteratively check if the breadcrumb is still overflowing and replace text with '...' starting from the second breadcrumb item
419
+ this.addBreadcrumbEllipsis(breadcrumbItems, breadcrumb);
420
+
421
+ // After processing all breadcrumb items, if it's still overflowing, hide the breadcrumb element
422
+ if (this.isTextWrapping(breadcrumb, breadcrumbItems[0])) {
423
+ breadcrumb.style.display = "none";
424
+ }
425
+ }
426
+ });
427
+ };
428
+
429
+ private restoreBreadcrumbs = (breadcrumbs: HTMLElement[]) => {
430
+ breadcrumbs.forEach((breadcrumb: HTMLElement, index: number) => {
431
+ // eslint-disable-next-line @lwc/lwc/no-inner-html
432
+ breadcrumb.innerHTML = this.originalBreadcrumbs[index];
433
+ });
434
+ };
435
+
436
+ private windowSizeIncreased = () =>
437
+ window.innerWidth > this.initialWindowWidth;
438
+
439
+ private processBreadcrumbs(root: HTMLElement) {
440
+ // Get all breadcrumbs from search results
441
+ const breadcrumbs = Array.from(
442
+ root.querySelectorAll(".breadcrumb")
443
+ ) as HTMLElement[];
444
+
445
+ if (this.originalBreadcrumbs.length === 0) {
446
+ this.originalBreadcrumbs = breadcrumbs.map(
447
+ (breadcrumb) => breadcrumb.innerHTML
448
+ );
449
+ }
450
+
451
+ if (this.windowSizeIncreased()) {
452
+ /*
453
+ Reset the breadcrumbs to their original state and process them again.
454
+ The additional space means we can replace ellipsis with full text.
455
+ */
456
+ this.restoreBreadcrumbs(breadcrumbs);
457
+ }
458
+
459
+ this.formatBreadcrumbs(breadcrumbs);
207
460
  }
208
461
 
209
462
  private initializeCoveo() {
@@ -212,6 +465,7 @@ export default class SearchResults extends LightningElement {
212
465
  const resultsList = this.template.querySelector(".CoveoResultList");
213
466
 
214
467
  if (resultsList) {
468
+ // eslint-disable-next-line @lwc/lwc/no-inner-html
215
469
  resultsList.innerHTML = resultsTemplatesInnerHtml;
216
470
  }
217
471
 
@@ -227,6 +481,21 @@ export default class SearchResults extends LightningElement {
227
481
  buildTemplateHelperBadge
228
482
  );
229
483
 
484
+ Coveo.TemplateHelpers.registerTemplateHelper(
485
+ "breadcrumbs",
486
+ buildTemplateHelperBreadcrumbs
487
+ );
488
+
489
+ Coveo.TemplateHelpers.registerTemplateHelper(
490
+ "metabreadcrumbs",
491
+ buildTemplateHelperMetaBreadcrumbs
492
+ );
493
+
494
+ Coveo.TemplateHelpers.registerTemplateHelper(
495
+ "uriBreadcrumbs",
496
+ buildTemplateHelperUriBreadcrumbs
497
+ );
498
+
230
499
  Coveo.init(this.root);
231
500
  }
232
501
 
@@ -235,6 +504,7 @@ export default class SearchResults extends LightningElement {
235
504
  if (Object.prototype.hasOwnProperty.call(window, "Coveo")) {
236
505
  this.initializeCoveo();
237
506
  } else {
507
+ // eslint-disable-next-line @lwc/lwc/no-document-query
238
508
  const script = document.querySelector("script.coveo-script");
239
509
  script?.addEventListener("load", () => {
240
510
  this.initializeCoveo();
@@ -17,6 +17,8 @@ dx-empty-state {
17
17
  overflow-y: auto;
18
18
  border-top: 1px solid var(--dx-g-gray-90);
19
19
  padding-bottom: var(--dx-g-spacing-md);
20
+ margin-bottom: var(--dx-g-spacing-2xl);
21
+ padding-top: var(--dx-g-spacing-sm);
20
22
  }
21
23
 
22
24
  .loading-skeleton {
@@ -3,6 +3,8 @@
3
3
  .sidebar-content {
4
4
  overflow-y: auto;
5
5
  border-top: 1px solid var(--dx-g-gray-90);
6
+ margin-bottom: var(--dx-g-spacing-2xl);
7
+ padding-top: var(--dx-g-spacing-sm);
6
8
  }
7
9
 
8
10
  dx-empty-state {
@@ -9,6 +9,7 @@ import cx from "classnames";
9
9
  export default class StepSequence extends LightningElement {
10
10
  @api animateTransitions = false;
11
11
  @api communicateStepChanges = false;
12
+ @api containerScrollToId = "";
12
13
  @api forceInitiallyVisible = false;
13
14
  @api initialStepIndex: string | undefined;
14
15
  @api optimizePositionAfterAnimation = false;
@@ -39,15 +40,9 @@ export default class StepSequence extends LightningElement {
39
40
 
40
41
  if (this.useHistory) {
41
42
  this.defaultScrollRestorationValue = history.scrollRestoration;
42
- history.scrollRestoration = "manual";
43
- history.replaceState(
44
- {
45
- ...window.history.state,
46
- currentStepIndex: this.currentStepIndex
47
- },
48
- ""
49
- );
43
+ history.scrollRestoration = "manual"; // Step component must override scroll behavior to work properly with history and maintain scrollTo behavior of component
50
44
  window.addEventListener("popstate", this.handleHistoryPopstate);
45
+ window.addEventListener("hashchange", this.handleHashChange);
51
46
  }
52
47
 
53
48
  if (this.sessionStorageId) {
@@ -87,6 +82,7 @@ export default class StepSequence extends LightningElement {
87
82
 
88
83
  disconnectedCallback() {
89
84
  window.removeEventListener("popstate", this.handleHistoryPopstate);
85
+ window.removeEventListener("hashchange", this.handleHashChange);
90
86
  this.removeEventListener("transitionend", this.handleTransitionEnd);
91
87
  history.scrollRestoration = this.defaultScrollRestorationValue;
92
88
  }
@@ -166,6 +162,17 @@ export default class StepSequence extends LightningElement {
166
162
  }
167
163
 
168
164
  if (this.useHistory && updateHistory) {
165
+ if (typeof history.state?.currentStepIndex !== "number") {
166
+ // This is a "new" interaction with the step component, so we store the current
167
+ // component state in history so that going back from the next step works right
168
+ history.pushState(
169
+ {
170
+ currentStepIndex: this.currentStepIndex
171
+ },
172
+ "",
173
+ this.containerScrollToId // update browser hash for correct "feel" to in-page navigation
174
+ );
175
+ }
169
176
  history.pushState(
170
177
  {
171
178
  currentStepIndex: nextStepIndex
@@ -247,9 +254,34 @@ export default class StepSequence extends LightningElement {
247
254
  }
248
255
 
249
256
  handleHistoryPopstate = ({ state }: PopStateEvent) => {
250
- if (typeof state?.currentStepIndex === "number") {
251
- this.remeasureSteps();
252
- this.changeActiveStep(state.currentStepIndex, false);
257
+ if (
258
+ typeof state?.currentStepIndex !== "number" ||
259
+ state.currentStepIndex === this.currentStepIndex
260
+ ) {
261
+ // This history item is not a step change, so bail early.
262
+ return;
263
+ }
264
+
265
+ this.remeasureSteps();
266
+ this.changeActiveStep(state.currentStepIndex, false);
267
+ this.scrollToStepTop();
268
+ };
269
+
270
+ handleHashChange = ({ newURL }: HashChangeEvent) => {
271
+ const newHash = new URL(newURL).hash;
272
+ const oldScrollValue = history.state?.scroll?.value;
273
+
274
+ if (typeof oldScrollValue === "number") {
275
+ window.scrollTo({
276
+ top: oldScrollValue
277
+ });
278
+ } else if (newHash) {
279
+ document.querySelector(newHash)?.scrollIntoView();
280
+ } else {
281
+ // No hash and no old scroll value means this was the initial history item
282
+ window.scrollTo({
283
+ top: 0
284
+ });
253
285
  }
254
286
  };
255
287
 
@@ -8,6 +8,7 @@ const VALID_BRANDS = [
8
8
  "analytics",
9
9
  "commerce",
10
10
  "employees",
11
+ "data-cloud",
11
12
  "industries",
12
13
  "integration",
13
14
  "learning",