@qld-gov-au/qgds-bootstrap5 2.0.11 → 2.1.0

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 (119) hide show
  1. package/.esbuild/plugins/qgds-plugin-generate-icon-assets.js +31 -24
  2. package/.storybook/preview.js +5 -2
  3. package/dist/assets/components/bs5/button/button.hbs +1 -1
  4. package/dist/assets/components/bs5/dateinput/dateinput.hbs +27 -27
  5. package/dist/assets/components/bs5/footer/customLinks.hbs +1 -1
  6. package/dist/assets/components/bs5/footer/followLinks.hbs +1 -1
  7. package/dist/assets/components/bs5/formcheck/formcheck.hbs +10 -2
  8. package/dist/assets/components/bs5/head/head.hbs +1 -1
  9. package/dist/assets/components/bs5/inpageAlert/inpageAlert.hbs +10 -2
  10. package/dist/assets/components/bs5/searchInput/searchInput.hbs +35 -31
  11. package/dist/assets/components/bs5/select/select.hbs +19 -19
  12. package/dist/assets/components/bs5/textarea/textarea.hbs +17 -17
  13. package/dist/assets/components/bs5/textbox/textbox.hbs +17 -18
  14. package/dist/assets/css/qld.bootstrap.css +2 -2
  15. package/dist/assets/css/qld.bootstrap.css.map +3 -3
  16. package/dist/assets/css/qld.bootstrap.legacy.css +2 -2
  17. package/dist/assets/css/qld.bootstrap.legacy.css.map +3 -3
  18. package/dist/assets/img/icons-sprite.svg +24 -24
  19. package/dist/assets/js/handlebars.helpers.bundle.js +1 -1
  20. package/dist/assets/js/handlebars.init.min.js +159 -140
  21. package/dist/assets/js/handlebars.init.min.js.map +2 -2
  22. package/dist/assets/js/handlebars.partials.js +159 -140
  23. package/dist/assets/js/handlebars.partials.js.map +2 -2
  24. package/dist/assets/js/qld.bootstrap.min.js +9 -10
  25. package/dist/assets/js/qld.bootstrap.min.js.map +4 -4
  26. package/dist/assets/node/handlebars.init.min.js +57 -11
  27. package/dist/assets/node/handlebars.init.min.js.map +2 -2
  28. package/dist/components/bs5/button/button.hbs +1 -1
  29. package/dist/components/bs5/dateinput/dateinput.hbs +27 -27
  30. package/dist/components/bs5/footer/customLinks.hbs +1 -1
  31. package/dist/components/bs5/footer/followLinks.hbs +1 -1
  32. package/dist/components/bs5/formcheck/formcheck.hbs +10 -2
  33. package/dist/components/bs5/head/head.hbs +1 -1
  34. package/dist/components/bs5/inpageAlert/inpageAlert.hbs +10 -2
  35. package/dist/components/bs5/searchInput/searchInput.hbs +35 -31
  36. package/dist/components/bs5/select/select.hbs +19 -19
  37. package/dist/components/bs5/textarea/textarea.hbs +17 -17
  38. package/dist/components/bs5/textbox/textbox.hbs +17 -18
  39. package/dist/package.json +1 -1
  40. package/dist/sample-data/dateinput/dateinput.data.json +14 -12
  41. package/dist/sample-data/footer/footer.data.json +3 -0
  42. package/dist/sample-data/formcheck/stories/checkbox/checkbox.data.json +4 -5
  43. package/dist/sample-data/formcheck/stories/radio/radio.data.json +4 -4
  44. package/dist/sample-data/inpageAlert/inpageAlert.data.json +1 -1
  45. package/dist/sample-data/searchInput/searchInput.data.json +20 -10
  46. package/dist/sample-data/select/select.data.json +12 -10
  47. package/dist/sample-data/textarea/textarea.data.json +14 -11
  48. package/dist/sample-data/textbox/textbox.data.json +13 -10
  49. package/package.json +1 -1
  50. package/src/components/bs5/breadcrumbs/breadcrumbs.scss +3 -4
  51. package/src/components/bs5/button/Button.js +32 -6
  52. package/src/components/bs5/button/button.hbs +1 -1
  53. package/src/components/bs5/button/button.scss +0 -5
  54. package/src/components/bs5/card/card.scss +2 -0
  55. package/src/components/bs5/dateinput/Dateinput.js +26 -11
  56. package/src/components/bs5/dateinput/dateinput.data.json +14 -12
  57. package/src/components/bs5/dateinput/dateinput.hbs +27 -27
  58. package/src/components/bs5/footer/customLinks.hbs +1 -1
  59. package/src/components/bs5/footer/followLinks.hbs +1 -1
  60. package/src/components/bs5/footer/footer.data.json +3 -0
  61. package/src/components/bs5/formcheck/Formcheck.js +57 -6
  62. package/src/components/bs5/formcheck/_form-variables.scss +167 -0
  63. package/src/components/bs5/formcheck/formcheck.hbs +10 -2
  64. package/src/components/bs5/formcheck/formcheck.scss +268 -65
  65. package/src/components/bs5/formcheck/stories/bootstrap-validation/bootstrap-validation.stories.js +304 -0
  66. package/src/components/bs5/formcheck/stories/checkbox/checkbox.data.json +4 -5
  67. package/src/components/bs5/formcheck/stories/checkbox/checkbox.stories.js +19 -111
  68. package/src/components/bs5/formcheck/stories/radio/radio.data.json +4 -4
  69. package/src/components/bs5/formcheck/stories/radio/radio.stories.js +30 -122
  70. package/src/components/bs5/header/header.scss +1 -2
  71. package/src/components/bs5/icons/_icons.list.js +7 -7
  72. package/src/components/bs5/icons/_icons.list.scss +113 -112
  73. package/src/components/bs5/icons/_icons.variables.scss +7 -6
  74. package/src/components/bs5/icons/icons.scss +2 -1
  75. package/src/components/bs5/inpageAlert/inpageAlert.data.json +1 -1
  76. package/src/components/bs5/inpageAlert/inpageAlert.hbs +10 -2
  77. package/src/components/bs5/inpageAlert/inpageAlert.scss +50 -52
  78. package/src/components/bs5/inpageAlert/inpageAlert.stories.js +54 -3
  79. package/src/components/bs5/pageLayout/{ThemeShowcase.stories.js → PaletteShowcase.stories.js} +40 -38
  80. package/src/components/bs5/searchInput/__snapshots__/searchInput.test.js.snap +25 -29
  81. package/src/components/bs5/searchInput/search.functions.js +120 -108
  82. package/src/components/bs5/searchInput/searchInput.data.json +20 -10
  83. package/src/components/bs5/searchInput/searchInput.hbs +35 -31
  84. package/src/components/bs5/searchInput/searchInput.scss +193 -196
  85. package/src/components/bs5/searchInput/searchInput.stories.js +35 -13
  86. package/src/components/bs5/searchInput/searchInput.test.js +96 -120
  87. package/src/components/bs5/select/Select.js +13 -5
  88. package/src/components/bs5/select/Select.stories.js +27 -83
  89. package/src/components/bs5/select/select.data.json +12 -10
  90. package/src/components/bs5/select/select.hbs +19 -19
  91. package/src/components/bs5/skiplinks/skipLinks.scss +12 -4
  92. package/src/components/bs5/textarea/Textarea.js +13 -5
  93. package/src/components/bs5/textarea/Textarea.stories.js +29 -55
  94. package/src/components/bs5/textarea/textarea.data.json +14 -11
  95. package/src/components/bs5/textarea/textarea.hbs +17 -17
  96. package/src/components/bs5/textbox/Textbox.js +16 -5
  97. package/src/components/bs5/textbox/Textbox.stories.js +26 -51
  98. package/src/components/bs5/textbox/textInput.scss +12 -232
  99. package/src/components/bs5/textbox/textbox.data.json +13 -10
  100. package/src/components/bs5/textbox/textbox.hbs +17 -18
  101. package/src/components/common/focus-styles/focusStyles.mdx +20 -0
  102. package/src/components/common/focus-styles/focusStyles.stories.js +58 -0
  103. package/src/css/functions/_index.scss +5 -0
  104. package/src/css/functions/color-icon.scss +31 -0
  105. package/src/css/functions/remify.scss +32 -0
  106. package/src/css/functions/snap-line-height.scss +7 -0
  107. package/src/css/functions/string-replace.scss +49 -0
  108. package/src/css/functions/svg-encode.scss +22 -0
  109. package/src/css/main.scss +1 -1
  110. package/src/css/mixins/focusable.scss +3 -0
  111. package/src/css/mixins/make-icon.scss +1 -1
  112. package/src/css/mixins/make-link.scss +13 -10
  113. package/src/css/{qld-theme.scss → qld-palettes.scss} +50 -35
  114. package/src/css/qld-type.scss +5 -1
  115. package/src/css/qld-utilities.scss +9 -1
  116. package/src/css/qld-variables.scss +1 -1
  117. package/src/img/icons-sprite.svg +24 -24
  118. package/src/js/qld.bootstrap.js +3 -55
  119. package/src/components/bs5/formcheck/_formcheck.stories.bak.js +0 -432
@@ -1,5 +1,3 @@
1
- import { createPopper } from "@popperjs/core";
2
-
3
1
  /**
4
2
  * Fetches data from the provided URL.
5
3
  *
@@ -28,31 +26,26 @@ async function fetchData(url, type) {
28
26
  * @param {HTMLFormElement} form - The form element.
29
27
  * @returns {void}
30
28
  */
31
- export function selectSuggestion(value, form) {
29
+ export function selectDynamicSuggestion(value, form) {
32
30
  const searchInput = form.querySelector(".qld-search-input input");
33
31
  const suggestions = form.querySelector(".suggestions");
34
32
 
35
33
  if (searchInput && suggestions) {
36
34
  searchInput.value = value.trim();
37
- suggestions.classList.add("d-none");
38
-
39
- // Retrieve additional params
40
- const collection =
41
- searchInput.getAttribute("data-collection") || "qgov~sp-search";
42
- const profile = searchInput.getAttribute("data-profile") || "qld";
43
- const numRanks = searchInput.getAttribute("data-numranks") || "10";
44
- const tiers = searchInput.getAttribute("data-tiers") || "off";
45
35
 
46
36
  // Form action
47
37
  const actionUrl = form.getAttribute("action");
48
38
 
39
+ //data-* attributes on search input field
40
+ const atts = searchInput ? searchInput.dataset : null;
41
+
49
42
  // Construct the URL with proper parameters
50
43
  const params = new URLSearchParams({
51
44
  query: value.trim(),
52
- collection: collection,
53
- profile: profile,
54
- num_ranks: numRanks,
55
- tiers: tiers,
45
+ collection: atts.collection || "qgov~sp-search",
46
+ profile: atts.profile || "qld",
47
+ num_ranks: atts.numRanks || "10",
48
+ tiers: atts.tiers || "off",
56
49
  });
57
50
 
58
51
  const searchUrl = `${actionUrl}?${params.toString()}`;
@@ -81,111 +74,134 @@ export async function showSuggestions(value = "", isDefault = false, form) {
81
74
  );
82
75
 
83
76
  if (!suggestions || !searchInput) {
84
- console.warn("Required suggestions elements not found.");
85
77
  return;
86
78
  }
87
79
 
88
- // Hide/show default suggestions
80
+ // Hide/show default suggestions, and return early
89
81
  if (isDefault) {
90
- defaultSuggestionsContainer.classList.remove("d-none");
91
- dynamicSuggestionsContainer.innerHTML = "";
92
- dynamicSuggestionsContainer.classList.add("d-none");
93
- createPopper(searchInput, suggestions, {
94
- placement: "bottom-start",
95
- });
96
- suggestions.classList.remove("d-none");
82
+ if (defaultSuggestionsContainer) {
83
+ defaultSuggestionsContainer.classList.remove("d-none");
84
+ }
85
+ if (dynamicSuggestionsContainer) {
86
+ dynamicSuggestionsContainer.innerHTML = "";
87
+ dynamicSuggestionsContainer.classList.add("d-none");
88
+ }
97
89
  return;
98
90
  }
99
91
 
100
- if (value.length === 0) {
101
- dynamicSuggestionsContainer.innerHTML = "";
102
- dynamicSuggestionsContainer.classList.add("d-none");
103
- return;
92
+ // If input is empty, hide dynamic suggestions and return early
93
+ if (dynamicSuggestionsContainer) {
94
+ if (value.length === 0) {
95
+ dynamicSuggestionsContainer.innerHTML = "";
96
+ dynamicSuggestionsContainer.classList.add("d-none");
97
+ return;
98
+ }
104
99
  }
105
100
 
106
- defaultSuggestionsContainer.classList.add("d-none");
101
+ // Script continues...dynamic suggestions is true and value.length > 0
102
+ defaultSuggestionsContainer?.classList.add("d-none");
103
+
104
+ //data-* attributes on search input field
105
+ const atts = searchInput ? searchInput.dataset : null;
107
106
 
108
107
  // Fetch dynamic suggestions if available
109
- const suggestUrl = searchInput.getAttribute("data-suggestions");
110
- if (suggestUrl) {
111
- const collection =
112
- searchInput.getAttribute("data-collection") || "qgov~sp-search";
113
- const profile = searchInput.getAttribute("data-profile") || "qld";
114
- const fetchedSuggestions = await fetchData(
115
- `${suggestUrl}?collection=${collection}&profile=${profile}&fmt=json&alpha=0.5&partial_query=${encodeURIComponent(value)}`,
116
- "suggestions",
117
- );
118
-
119
- if (fetchedSuggestions.length > 0) {
120
- dynamicSuggestionsContainer.innerHTML = `
121
- <div class="suggestions-category mt-16">
122
- <strong class="suggestions-category-label d-block">Suggestions</strong>
123
- <ul class="mt-2">${fetchedSuggestions
108
+ if (dynamicSuggestionsContainer) {
109
+ const suggestUrl = atts.suggestions;
110
+
111
+ if (suggestUrl) {
112
+ const collection = atts.collection || "qgov~sp-search";
113
+ const profile = atts.profile || "qld";
114
+
115
+ //Fetch data from suggestions API
116
+ const fetchedSuggestions = await fetchData(
117
+ `${suggestUrl}?collection=${collection}&profile=${profile}&fmt=json&alpha=0.5&partial_query=${encodeURIComponent(value)}`,
118
+ "suggestions",
119
+ );
120
+
121
+ //Rended a suggestions list
122
+ if (fetchedSuggestions.length > 0) {
123
+ dynamicSuggestionsContainer.innerHTML = `
124
+ <div class="suggestions-category">
125
+ <ul>${fetchedSuggestions
124
126
  .slice(0, 4)
125
127
  .map((item) => {
126
128
  const highlightedText = item.replace(
127
129
  new RegExp(`(${value})`, "gi"),
128
130
  "<strong>$1</strong>",
129
131
  );
130
- return `<li><a href="#">${highlightedText}</a></li>`;
132
+ return `<li><a tabindex="0" href="#">${highlightedText}</a></li>`;
131
133
  })
132
134
  .join("")}</ul>
133
135
  </div>`;
134
- dynamicSuggestionsContainer.classList.remove("d-none");
135
- createPopper(searchInput, suggestions, {
136
- placement: "bottom-start",
137
- });
138
- suggestions.classList.remove("d-none");
139
-
140
- // Attach click event listeners to each suggestion item
141
- form.querySelectorAll(".suggestions li").forEach((item) => {
142
- item.addEventListener("click", () =>
143
- selectSuggestion(item.innerText, form),
144
- );
145
- });
146
- } else {
147
- dynamicSuggestionsContainer.innerHTML = "";
148
- dynamicSuggestionsContainer.classList.add("d-none");
149
- suggestions.classList.add("d-none");
136
+
137
+ dynamicSuggestionsContainer.classList.remove("d-none");
138
+
139
+ // Bind an event listener to suggestions container
140
+ form
141
+ .querySelector(".suggestions .dynamic-suggestions")
142
+ .addEventListener("click", (event) => {
143
+ let linkItem = event.target.closest("a");
144
+ if (linkItem) {
145
+ event.preventDefault();
146
+ selectDynamicSuggestion(linkItem.innerText, form);
147
+ }
148
+ });
149
+ } else {
150
+ dynamicSuggestionsContainer.innerHTML = "";
151
+ dynamicSuggestionsContainer.classList.add("d-none");
152
+ }
150
153
  }
151
- }
152
154
 
153
- const resultsUrl = searchInput.getAttribute("data-results-url");
154
- if (resultsUrl) {
155
- const collection =
156
- searchInput.getAttribute("data-collection") || "qgov~sp-search";
157
- const profile = searchInput.getAttribute("data-profile") || "qld";
158
- const fetchedServices = await fetchData(
159
- `${resultsUrl}?collection=${collection}&profile=${profile}&smeta_sfinder_sand=yes&query=${encodeURIComponent(value)}`,
160
- "services",
161
- );
162
-
163
- if (
164
- fetchedServices.response.resultPacket &&
165
- fetchedServices.response.resultPacket.results.length > 0
166
- ) {
167
- dynamicSuggestionsContainer.innerHTML += `
168
- <div class="suggestions-category feature pt-16">
169
- <strong class="suggestions-category-label d-block">Services</strong>
170
- <ul class="mt-2">${fetchedServices.response.resultPacket.results
171
- .slice(0, 4)
172
- .map(
173
- (item) => `<li><a href="${item.liveUrl}">${item.title}</a></li>`,
174
- )
175
- .join("")}</ul>
155
+ const resultsUrl = atts.resultsUrl; //data-results-url;
156
+ if (resultsUrl) {
157
+ const collection = atts.collection || "qgov~sp-search";
158
+ const profile = atts.profile || "qld";
159
+
160
+ // Fetch related services from services API
161
+ const fetchedServices = await fetchData(
162
+ `${resultsUrl}?collection=${collection}&profile=${profile}&smeta_sfinder_sand=yes&query=${encodeURIComponent(value)}`,
163
+ "services",
164
+ );
165
+
166
+ if (
167
+ fetchedServices.response.resultPacket &&
168
+ fetchedServices.response.resultPacket.results.length > 0
169
+ ) {
170
+ const viewMoreUrl =
171
+ dynamicSuggestionsContainer.getAttribute("data-view-more");
172
+
173
+ // Build the services HTML safely
174
+ const servicesItems = fetchedServices.response.resultPacket.results
175
+ .slice(0, 4)
176
+ .map(
177
+ (item) =>
178
+ `<li><a tabindex="0" href="${item.liveUrl}">${item.title}</a></li>`,
179
+ )
180
+ .join("");
181
+
182
+ const viewMoreItem = viewMoreUrl
183
+ ? `<li><a tabindex="0" href="${viewMoreUrl}" class="view-more">View more</a></li>`
184
+ : "";
185
+
186
+ dynamicSuggestionsContainer.innerHTML += `
187
+ <div class="suggestions-category feature">
188
+ <strong class="suggestions-category-label d-block">Related services</strong>
189
+ <ul>${servicesItems}${viewMoreItem}</ul>
176
190
  </div>`;
177
- dynamicSuggestionsContainer.classList.remove("d-none");
178
- createPopper(searchInput, suggestions, {
179
- placement: "bottom-start",
180
- });
181
- suggestions.classList.remove("d-none");
182
-
183
- // Attach click event listeners to each suggestion item
184
- form.querySelectorAll(".suggestions li").forEach((item) => {
185
- item.addEventListener("click", () =>
186
- selectSuggestion(item.innerText, form),
187
- );
188
- });
191
+
192
+ dynamicSuggestionsContainer.classList.remove("d-none");
193
+
194
+ // Attach click event listeners to each SERVICE item in list
195
+ form
196
+ .querySelector(".suggestions .dynamic-suggestions")
197
+ .addEventListener("click", (event) => {
198
+ let linkItem = event.target.closest("a");
199
+ if (linkItem) {
200
+ event.preventDefault();
201
+ selectDynamicSuggestion(linkItem.innerText, form);
202
+ }
203
+ });
204
+ }
189
205
  }
190
206
  }
191
207
  }
@@ -199,19 +215,14 @@ export async function showSuggestions(value = "", isDefault = false, form) {
199
215
  */
200
216
  export function submitSearchForm(query = "", form) {
201
217
  const searchInput = form.querySelector(".qld-search-input input");
202
-
203
- const collection =
204
- searchInput.getAttribute("data-collection") || "qgov~sp-search";
205
- const profile = searchInput.getAttribute("data-profile") || "qld";
206
- const numRanks = searchInput.getAttribute("data-numranks") || "10";
207
- const tiers = searchInput.getAttribute("data-tiers") || "off";
218
+ const atts = searchInput ? searchInput.dataset : null;
208
219
 
209
220
  const params = new URLSearchParams({
210
221
  query: query.trim(),
211
- collection: collection,
212
- profile: profile,
213
- num_ranks: numRanks,
214
- tiers: tiers,
222
+ collection: atts.collection || "qgov~sp-search",
223
+ profile: atts.profile || "qld",
224
+ num_ranks: atts.numRanks || "10",
225
+ tiers: atts.tiers || "off",
215
226
  });
216
227
 
217
228
  const searchUrl = `${form.getAttribute("action")}?${params.toString()}`;
@@ -219,4 +230,5 @@ export function submitSearchForm(query = "", form) {
219
230
  }
220
231
 
221
232
  // Attach the function to the window object to make it globally accessible
222
- window.selectSuggestion = (value, form) => selectSuggestion(value, form);
233
+ window.selectDynamicSuggestion = (value, form) =>
234
+ selectDynamicSuggestion(value, form);
@@ -6,7 +6,7 @@
6
6
  "buttonType": "submit",
7
7
  "buttonLabel": "Search",
8
8
  "ariaLabel": "Search website",
9
- "suggestions": true,
9
+ "placeholder": "",
10
10
  "tags": {
11
11
  "collection": "qgov~sp-search",
12
12
  "profile": "qld",
@@ -15,10 +15,20 @@
15
15
  "suggestions": "https://discover.search.qld.gov.au/s/suggest.json",
16
16
  "results-url": "https://discover.search.qld.gov.au/s/search.json"
17
17
  },
18
- "default_suggestions": {
19
- "popular_services": [
18
+ "hasDynamicSuggestions": true,
19
+ "hasDefaultSuggestions": true,
20
+ "dynamicSuggestionsServiceLink": {
21
+ "href": "/queenslanders"
22
+ },
23
+ "defaultSuggestions": {
24
+ "popularServicesTitle": "Popular",
25
+ "popularServicesLink": {
26
+ "label": "View more",
27
+ "href": "/queenslanders"
28
+ },
29
+ "popularServices": [
20
30
  {
21
- "title": "Apply for leave",
31
+ "title": "Apply for leave now",
22
32
  "link": "https://www.forgov.qld.gov.au/pay-benefits-and-policy/leave/submit-a-leave-application"
23
33
  },
24
34
  {
@@ -34,6 +44,11 @@
34
44
  "link": "https://www.forgov.qld.gov.au/recruitment-performance-and-career/recruitment"
35
45
  }
36
46
  ],
47
+ "categoriesTitle": "Collection",
48
+ "categoriesLink": {
49
+ "label": "View all",
50
+ "href": "/queenslanders"
51
+ },
37
52
  "categories": [
38
53
  {
39
54
  "title": "Search for directives, policies, circulars, and guidelines",
@@ -51,11 +66,6 @@
51
66
  "title": "Career development",
52
67
  "link": "https://www.forgov.qld.gov.au/recruitment-performance-and-career/career-development"
53
68
  }
54
- ],
55
- "options": {
56
- "label": "Browse all categories",
57
- "view_more": true,
58
- "href": "/queenslanders"
59
- }
69
+ ]
60
70
  }
61
71
  }
@@ -3,41 +3,45 @@
3
3
  -->
4
4
  <div class="qld-search-input {{customClass}}">
5
5
  <input id="{{ inputID }}" name="{{ inputName }}" class="form-control" type="text" autocomplete="off"
6
- aria-label="{{ ariaLabel }}" {{#each tags}} data-{{@key}}="{{this}}" {{/each}} />
6
+ aria-label="{{ ariaLabel }}" {{#each tags}} data-{{@key}}="{{this}}" {{/each}} placeholder="{{placeholder}}" />
7
7
  <button class="btn btn-primary" type="{{ buttonType }}" id="{{ buttonID }}">
8
8
  <span class="btn-icon"></span>
9
9
  <span class="btn-label">{{ buttonLabel }}</span>
10
10
  </button>
11
- {{#if suggestions}}
12
- <div class="suggestions suggestions__group d-none">
13
- <div class="default-suggestions">
14
- <div class="suggestions-category mt-16">
15
- <strong class="suggestions-category-label d-block">Popular services</strong>
16
- <ul class="mt-2">
17
- {{#each default_suggestions.popular_services}}
18
- <li><a href="{{link}}">{{title}}</a></li>
19
- {{/each}}
20
- </ul>
21
- </div>
22
-
23
- <div class="suggestions-category mt-16">
24
- <strong class="suggestions-category-label d-block">Browse by category</strong>
25
- <ul class="mt-12 mb-0">
26
- {{#each default_suggestions.categories}}
27
- <li><a href="{{link}}">{{title}}</a></li>
28
- {{/each}}
29
- </ul>
30
- </div>
31
-
32
- {{#if default_suggestions.options.view_more}}
33
- <div class="suggestions-category">
34
- <a class="px-16 pt-12 pb-16 d-block suggestions-category-view-more"
35
- href="{{default_suggestions.options.href}}">{{default_suggestions.options.label}}</a>
11
+ {{#ifCond hasDynamicSuggestions '||' hasDefaultSuggestions}}
12
+
13
+ <div class="suggestions suggestions__group default">
14
+ {{#if hasDefaultSuggestions}}
15
+ <div class="default-suggestions">
16
+ <div class="suggestions-category">
17
+ <strong class="suggestions-category-label d-block">{{defaultSuggestions.popularServicesTitle}}</strong>
18
+ <ul>
19
+ {{#each defaultSuggestions.popularServices}}
20
+ <li><a tabindex="0" href="{{link}}">{{title}}</a></li>
21
+ {{/each}}
22
+ {{#if defaultSuggestions.popularServicesLink}}
23
+ <li><a tabindex="0" href="{{defaultSuggestions.popularServicesLink.href}}" class="view-more">{{#if defaultSuggestions.popularServicesLink.label}}{{defaultSuggestions.popularServicesLink.label}}{{else}}View More{{/if}}</a></li>
24
+ {{/if}}
25
+ </ul>
26
+ </div>
27
+ {{#if defaultSuggestions.categories}}
28
+ <div class="suggestions-category">
29
+ <strong class="suggestions-category-label d-block">{{defaultSuggestions.categoriesTitle}}</strong>
30
+ <ul>
31
+ {{#each defaultSuggestions.categories}}
32
+ <li><a tabindex="0"href="{{link}}">{{title}}</a></li>
33
+ {{/each}}
34
+ {{#if defaultSuggestions.categoriesLink}}
35
+ <li><a tabindex="0" href="{{defaultSuggestions.categoriesLink.href}}" class="view-more">{{#if defaultSuggestions.categoriesLink.label}}{{defaultSuggestions.categoriesLink.label}}{{else}}View More{{/if}}</a></li>
36
+ {{/if}}
37
+ </ul>
38
+ </div>
39
+ {{/if}}
36
40
  </div>
37
- {{/if}}
38
- </div>
39
- <div class="dynamic-suggestions"></div>
41
+ {{/if}}
42
+ {{#if hasDynamicSuggestions}}
43
+ <div class="dynamic-suggestions" {{#if dynamicSuggestionsServiceLink.href}}data-view-more="{{dynamicSuggestionsServiceLink.href}}"{{/if}}></div>
44
+ {{/if}}
40
45
  </div>
41
- {{/if}}
42
-
46
+ {{/ifCond}}
43
47
  </div>