acinguiux-preact-components 0.0.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.
- package/package.json +56 -0
- package/src/content/themes/theme-acinguiux-amg/theme-acinguiux-amg.css +23 -0
- package/src/content/themes/theme-acinguiux-cafe/theme-acinguiux-cafe.css +47 -0
- package/src/content/themes/theme-acinguiux-energy/theme-acinguiux-energy.css +45 -0
- package/src/content/themes/theme-acinguiux-livewire/theme-acinguiux-livewire.css +22 -0
- package/src/content/themes/theme-acinguiux-livewire-italy/theme-acinguiux-livewire-italy.css +22 -0
- package/src/content/themes/theme-acinguiux-recharge/theme-acinguiux-recharge.css +49 -0
- package/src/content/themes/theme-allon/theme-allon.css +25 -0
- package/src/content/themes/theme-atlas/theme-atlas.css +31 -0
- package/src/content/themes/theme-aurvana/resources/favicon/apple-touch-icon.png +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/favico.ico +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/favicon-96x96.png +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/favicon.ico +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/favicon.png +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/favicon.svg +13 -0
- package/src/content/themes/theme-aurvana/resources/favicon/google-touch-icon.png +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/manifest.json +14 -0
- package/src/content/themes/theme-aurvana/resources/favicon/site.webmanifest +21 -0
- package/src/content/themes/theme-aurvana/resources/favicon/web-app-manifest-192x192.png +0 -0
- package/src/content/themes/theme-aurvana/resources/favicon/web-app-manifest-512x512.png +0 -0
- package/src/content/themes/theme-aurvana/theme-aurvana.css +49 -0
- package/src/content/themes/theme-base/theme-base.css +49 -0
- package/src/content/themes/theme-base2/resources/favicon/android-chrome-192x192.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/android-chrome-512x512.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/apple-touch-icon.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favico.ico +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favicon-16x16.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favicon-32x32.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favicon-96x96.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favicon.ico +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favicon.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/favicon.svg +9 -0
- package/src/content/themes/theme-base2/resources/favicon/google-touch-icon.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/manifest.json +14 -0
- package/src/content/themes/theme-base2/resources/favicon/site.webmanifest +1 -0
- package/src/content/themes/theme-base2/resources/favicon/web-app-manifest-192x192.png +0 -0
- package/src/content/themes/theme-base2/resources/favicon/web-app-manifest-512x512.png +0 -0
- package/src/content/themes/theme-base2/resources/fonts/acinguiux-typeface-la-heavy-221208.woff2 +0 -0
- package/src/content/themes/theme-base2/theme-base2.css +47 -0
- package/src/content/themes/theme-eco-marathon/theme-eco-marathon.css +22 -0
- package/src/content/themes/theme-energy-transition-campus-amsterdam/theme-energy-transition-campus-amsterdam.css +26 -0
- package/src/content/themes/theme-evpass/theme-evpass.css +46 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/apple-touch-icon.png +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/favico.ico +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/favicon-96x96.png +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/favicon.ico +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/favicon.png +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/favicon.svg +9 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/google-touch-icon.png +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/manifest.json +14 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/site.webmanifest +21 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/web-app-manifest-192x192.png +0 -0
- package/src/content/themes/theme-nam-2025/resources/favicon/web-app-manifest-512x512.png +0 -0
- package/src/content/themes/theme-nam-2025/theme-nam-2025.css +47 -0
- package/src/content/themes/theme-pennzoil/theme-pennzoil.css +36 -0
- package/src/content/themes/theme-quaker-state/theme-quaker-state.css +63 -0
- package/src/content/themes/theme-tafawoq/theme-tafawoq.css +26 -0
- package/src/content/themes/theme-vegetable/resources/favicon/apple-touch-icon.png +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/favico.ico +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/favicon-96x96.png +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/favicon.ico +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/favicon.png +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/favicon.svg +13 -0
- package/src/content/themes/theme-vegetable/resources/favicon/google-touch-icon.png +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/manifest.json +14 -0
- package/src/content/themes/theme-vegetable/resources/favicon/site.webmanifest +21 -0
- package/src/content/themes/theme-vegetable/resources/favicon/web-app-manifest-192x192.png +0 -0
- package/src/content/themes/theme-vegetable/resources/favicon/web-app-manifest-512x512.png +0 -0
- package/src/content/themes/theme-vegetable/theme-vegetable.css +49 -0
- package/src/content/themes/theme-zeolyst/resources/fonts/type-ar-medium.woff2 +0 -0
- package/src/content/themes/theme-zeolyst/theme-zeolyst.css +29 -0
- package/src/main/atoms/audio.js +16 -0
- package/src/main/atoms/box.js +5 -0
- package/src/main/atoms/button.js +40 -0
- package/src/main/atoms/card.js +22 -0
- package/src/main/atoms/form.js +30 -0
- package/src/main/atoms/heading.js +17 -0
- package/src/main/atoms/icon.js +24 -0
- package/src/main/atoms/img.js +131 -0
- package/src/main/atoms/input.js +55 -0
- package/src/main/atoms/link-text.js +21 -0
- package/src/main/atoms/link.js +60 -0
- package/src/main/atoms/list.js +12 -0
- package/src/main/atoms/logo.js +9 -0
- package/src/main/atoms/menu.js +10 -0
- package/src/main/atoms/message.js +5 -0
- package/src/main/atoms/nav-link.js +49 -0
- package/src/main/atoms/popup.js +47 -0
- package/src/main/atoms/rich-text.js +128 -0
- package/src/main/atoms/scroller.js +224 -0
- package/src/main/atoms/svg.js +65 -0
- package/src/main/atoms/table.js +32 -0
- package/src/main/atoms/textarea.js +10 -0
- package/src/main/atoms/time.js +12 -0
- package/src/main/atoms/video.js +100 -0
- package/src/main/export-main.js +12 -0
- package/src/main/export-matter.js +86 -0
- package/src/main/export-preact-hooks.js +1 -0
- package/src/main/export-preact.js +1 -0
- package/src/main/index.js +13 -0
- package/src/main/molecules/asset.js +23 -0
- package/src/main/molecules/glossary.js +44 -0
- package/src/main/molecules/links.js +23 -0
- package/src/main/molecules/promo-text.js +27 -0
- package/src/main/molecules/tags.js +15 -0
- package/src/main/molecules/tree.js +51 -0
- package/src/main/organisms/accordion-item.js +106 -0
- package/src/main/organisms/author.js +29 -0
- package/src/main/organisms/breadcrumb.js +69 -0
- package/src/main/organisms/call-to-action.js +24 -0
- package/src/main/organisms/carousel.js +178 -0
- package/src/main/organisms/cart-item.js +156 -0
- package/src/main/organisms/cart.js +162 -0
- package/src/main/organisms/contact-form.js +141 -0
- package/src/main/organisms/container/ab-test.js +47 -0
- package/src/main/organisms/container/default.js +6 -0
- package/src/main/organisms/container/filtered-section.js +293 -0
- package/src/main/organisms/container/footer.js +12 -0
- package/src/main/organisms/container/grid.js +44 -0
- package/src/main/organisms/container/header.js +13 -0
- package/src/main/organisms/container/list.js +7 -0
- package/src/main/organisms/container/main.js +6 -0
- package/src/main/organisms/container/raw.js +7 -0
- package/src/main/organisms/container/section.js +28 -0
- package/src/main/organisms/container.js +29 -0
- package/src/main/organisms/content-owner.js +15 -0
- package/src/main/organisms/date-entry.js +56 -0
- package/src/main/organisms/external-search.js +73 -0
- package/src/main/organisms/filtered-item.js +163 -0
- package/src/main/organisms/footer-item.js +17 -0
- package/src/main/organisms/image-gallery.js +164 -0
- package/src/main/organisms/last-modified.js +20 -0
- package/src/main/organisms/legal-footer.js +16 -0
- package/src/main/organisms/list-item.js +48 -0
- package/src/main/organisms/metadata.js +11 -0
- package/src/main/organisms/navigation.js +232 -0
- package/src/main/organisms/notification.js +87 -0
- package/src/main/organisms/order-tracker.js +203 -0
- package/src/main/organisms/page-header-banner.js +26 -0
- package/src/main/organisms/page-header.js +33 -0
- package/src/main/organisms/page-tags.js +14 -0
- package/src/main/organisms/page.js +260 -0
- package/src/main/organisms/press-release.js +24 -0
- package/src/main/organisms/product-admin.js +204 -0
- package/src/main/organisms/promo-banner.js +28 -0
- package/src/main/organisms/promo-bottom.js +23 -0
- package/src/main/organisms/promo-button.js +8 -0
- package/src/main/organisms/promo-card-cover.js +35 -0
- package/src/main/organisms/promo-card.js +33 -0
- package/src/main/organisms/promo-full.js +20 -0
- package/src/main/organisms/promo-image.js +22 -0
- package/src/main/organisms/promo-lure.js +22 -0
- package/src/main/organisms/promo-product-card.js +187 -0
- package/src/main/organisms/promo-product-full.js +293 -0
- package/src/main/organisms/promo-simple.js +23 -0
- package/src/main/organisms/quote.js +21 -0
- package/src/main/organisms/search-form.js +42 -0
- package/src/main/organisms/search-nav.js +66 -0
- package/src/main/organisms/search-result.js +53 -0
- package/src/main/organisms/slider.js +26 -0
- package/src/main/organisms/standalone-asset.js +22 -0
- package/src/main/organisms/tabs.js +277 -0
- package/src/main/organisms/topbar.js +83 -0
- package/src/main/organisms/web-component.js +53 -0
- package/src/main/routing/annotation.js +9 -0
- package/src/main/routing/component.js +138 -0
- package/src/main/routing/empty.js +5 -0
- package/src/main/routing/error-handler.js +64 -0
- package/src/main/routing/placeholder-image.svg +5 -0
- package/src/main/routing/router.js +219 -0
- package/src/main/shared/analytics.js +677 -0
- package/src/main/shared/bubble-event.js +11 -0
- package/src/main/shared/custom-element.js +21 -0
- package/src/main/shared/deep-selector.js +28 -0
- package/src/main/shared/disable-transparency.js +10 -0
- package/src/main/shared/format-time.js +8 -0
- package/src/main/shared/get-id.js +5 -0
- package/src/main/shared/get-meta.js +3 -0
- package/src/main/shared/get-size-class.js +3 -0
- package/src/main/shared/get-size.js +11 -0
- package/src/main/shared/h.js +88 -0
- package/src/main/shared/hash-jump.js +33 -0
- package/src/main/shared/icons/arrow-back.svg +1 -0
- package/src/main/shared/icons/arrow-down.svg +1 -0
- package/src/main/shared/icons/arrow-next.svg +1 -0
- package/src/main/shared/icons/arrow-tail-right.svg +1 -0
- package/src/main/shared/icons/arrow-tail-up.svg +1 -0
- package/src/main/shared/icons/arrow-up.svg +1 -0
- package/src/main/shared/icons/asset-download.svg +1 -0
- package/src/main/shared/icons/logo.svg +5 -0
- package/src/main/shared/icons/low-carbon-placeholder.svg +9 -0
- package/src/main/shared/icons/media-pause.svg +1 -0
- package/src/main/shared/icons/media-play.svg +1 -0
- package/src/main/shared/icons/navigation-burger.svg +1 -0
- package/src/main/shared/icons/navigation-close.svg +1 -0
- package/src/main/shared/icons/navigation-link.svg +1 -0
- package/src/main/shared/icons/navigation-refresh.svg +1 -0
- package/src/main/shared/icons/navigation-search.svg +1 -0
- package/src/main/shared/icons/navigation-share.svg +1 -0
- package/src/main/shared/icons/toggle-newwindow.svg +1 -0
- package/src/main/shared/icons.js +18 -0
- package/src/main/shared/id-from-string.js +5 -0
- package/src/main/shared/mark-selection.js +19 -0
- package/src/main/shared/register.js +26 -0
- package/src/main/shared/renderer.js +43 -0
- package/src/main/shared/simple-consent-api.js +70 -0
- package/src/main/shared/split-links.js +11 -0
- package/src/main/shared/t.js +60 -0
- package/src/main/shared/twind.js +837 -0
- package/src/main/shared/update-head.js +34 -0
- package/src/main/shared/update-scrollbar-width.js +30 -0
- package/src/main/shared/use-link.js +151 -0
- package/src/main/shared/use-persistent-state.js +42 -0
- package/src/main/shared/wait-for-dom-ready.js +6 -0
- package/src/main/shared/wcm-mode.js +4 -0
- package/src/wcs/components/acinguiux-preact-doc/acinguiux-preact-doc.js +207 -0
- package/src/wcs/components/admin-dashboard/admin-dashboard.js +487 -0
- package/src/wcs/components/admin-login/admin-login.js +91 -0
- package/src/wcs/components/bazaar-voice/bazaar-voice.js +56 -0
- package/src/wcs/components/chatbot-koreai/chatbot-koreai.js +176 -0
- package/src/wcs/components/chatbot-koreai/koreai-transport.js +217 -0
- package/src/wcs/components/chatbot-ms/chatbot-ms.js +210 -0
- package/src/wcs/components/chatbot-test/chatbot-test.js +44 -0
- package/src/wcs/components/comparison-chart/comparison-chart.js +111 -0
- package/src/wcs/components/consent-banner/consent-banner.js +248 -0
- package/src/wcs/components/consent-banner/icons/ccpa.svg +6 -0
- package/src/wcs/components/consent-banner/icons/info.svg +1 -0
- package/src/wcs/components/consent-banner/provider-onetrust.js +131 -0
- package/src/wcs/components/decision-tree/arrow-back.svg +3 -0
- package/src/wcs/components/decision-tree/badges.js +37 -0
- package/src/wcs/components/decision-tree/decision-tree.js +162 -0
- package/src/wcs/components/dynamic-contact-details/dynamic-contact-details.js +111 -0
- package/src/wcs/components/example-accordion/example-accordion.js +10 -0
- package/src/wcs/components/example-asset/example-asset.js +12 -0
- package/src/wcs/components/example-form/example-form.js +59 -0
- package/src/wcs/components/example-nested/example-nested.js +10 -0
- package/src/wcs/components/example-routing/example-routing.js +51 -0
- package/src/wcs/components/example-rtl/example-rtl.js +28 -0
- package/src/wcs/components/example-tabs/example-tabs.js +12 -0
- package/src/wcs/components/example-web-component/example-web-component.js +34 -0
- package/src/wcs/components/floating-button/floating-button.js +17 -0
- package/src/wcs/components/formstack-form/fields/address.js +38 -0
- package/src/wcs/components/formstack-form/fields/checkbox.js +42 -0
- package/src/wcs/components/formstack-form/fields/date.js +22 -0
- package/src/wcs/components/formstack-form/fields/description.js +8 -0
- package/src/wcs/components/formstack-form/fields/input.js +8 -0
- package/src/wcs/components/formstack-form/fields/name.js +39 -0
- package/src/wcs/components/formstack-form/fields/radio.js +24 -0
- package/src/wcs/components/formstack-form/fields/rating.js +53 -0
- package/src/wcs/components/formstack-form/fields/section.js +8 -0
- package/src/wcs/components/formstack-form/fields/select.js +10 -0
- package/src/wcs/components/formstack-form/fields/textarea.js +8 -0
- package/src/wcs/components/formstack-form/fields/wrapper.js +11 -0
- package/src/wcs/components/formstack-form/formstack-form.js +280 -0
- package/src/wcs/components/fuel-prices/fuel-prices.js +45 -0
- package/src/wcs/components/furniture-overview/furniture-overview.js +115 -0
- package/src/wcs/components/gauge-value/gauge-value.js +65 -0
- package/src/wcs/components/help-centre/api.js +150 -0
- package/src/wcs/components/help-centre/help-centre.js +400 -0
- package/src/wcs/components/help-centre/icon-search.svg +1 -0
- package/src/wcs/components/image-gen/admin-panel.js +248 -0
- package/src/wcs/components/image-gen/image-gen.js +385 -0
- package/src/wcs/components/image-gen/labels.js +37 -0
- package/src/wcs/components/image-gen/use-api.js +392 -0
- package/src/wcs/components/inspired-gallery/inspired-gallery.js +118 -0
- package/src/wcs/components/launch-container/launch-container.js +95 -0
- package/src/wcs/components/launch-container/ledger.js +140 -0
- package/src/wcs/components/lng-map/lng-map.js +44 -0
- package/src/wcs/components/mouseflow-analytics/mouseflow-analytics.js +39 -0
- package/src/wcs/components/msds-search/msds-search.js +127 -0
- package/src/wcs/components/msds-search/navigation-search.svg +3 -0
- package/src/wcs/components/product-catalogue/icon-back.svg +3 -0
- package/src/wcs/components/product-catalogue/icon-cart.svg +3 -0
- package/src/wcs/components/product-catalogue/icon-close.svg +3 -0
- package/src/wcs/components/product-catalogue/product-catalogue.js +215 -0
- package/src/wcs/components/product-links/icon-cart.svg +3 -0
- package/src/wcs/components/product-links/product-links.js +43 -0
- package/src/wcs/components/rio-iframe/rio-iframe.js +137 -0
- package/src/wcs/components/salsify-products/filter-tools.js +60 -0
- package/src/wcs/components/salsify-products/icon-cart.svg +3 -0
- package/src/wcs/components/salsify-products/process-products.js +53 -0
- package/src/wcs/components/salsify-products/route-tools.js +54 -0
- package/src/wcs/components/salsify-products/salsify-products.js +281 -0
- package/src/wcs/components/shout-out/shout-out.js +51 -0
- package/src/wcs/components/simple-chart/simple-chart.js +53 -0
- package/src/wcs/components/single-stat/single-stat.js +85 -0
- package/src/wcs/components/site-feedback/site-feedback.js +56 -0
- package/src/wcs/components/skds-search/navigation-search.svg +3 -0
- package/src/wcs/components/skds-search/skds-search.js +103 -0
- package/src/wcs/components/smart-banner/smart-banner.js +104 -0
- package/src/wcs/components/standalone-table/arrow-up-down.svg +3 -0
- package/src/wcs/components/standalone-table/arrow-up.svg +3 -0
- package/src/wcs/components/standalone-table/standalone-table.js +440 -0
- package/src/wcs/components/station-locator/station-locator.js +49 -0
- package/src/wcs/components/store-badges/badges.js +60 -0
- package/src/wcs/components/store-badges/store-badges.js +93 -0
- package/src/wcs/components/topbar-button/person.svg +1 -0
- package/src/wcs/components/topbar-button/topbar-button.js +22 -0
- package/src/wcs/components/universal-gallery/universal-gallery.js +308 -0
- package/src/wcs/components/zendesk-chat/zendesk-chat.js +133 -0
- package/src/wcs/shared/chat-bot/README.md +61 -0
- package/src/wcs/shared/chat-bot/chat-bot.js +216 -0
- package/src/wcs/shared/chat-bot/resources/arrow-next.svg +1 -0
- package/src/wcs/shared/chat-bot/resources/navigation-close.svg +1 -0
- package/src/wcs/shared/chat-bot/resources/person.svg +1 -0
- package/src/wcs/shared/chat-bot/resources/upload.svg +1 -0
- package/src/wcs/shared/filtered-data/README.md +52 -0
- package/src/wcs/shared/filtered-data/fetch-data.js +33 -0
- package/src/wcs/shared/filtered-data/filtered-data.js +337 -0
- package/src/wcs/shared/promo-with-popup/icon-close.svg +3 -0
- package/src/wcs/shared/promo-with-popup/icon-next.svg +3 -0
- package/src/wcs/shared/promo-with-popup/icon-prev.svg +3 -0
- package/src/wcs/shared/promo-with-popup/promo-with-popup.js +93 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/* global customElements */
|
|
2
|
+
const LENGTH = 128
|
|
3
|
+
|
|
4
|
+
const ledger = []
|
|
5
|
+
const listeners = []
|
|
6
|
+
|
|
7
|
+
function getComponentModel (el) {
|
|
8
|
+
return globalThis.ami.componentModels.get(el?.closest('[data-name]')?.dataset?.key)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function addListeners (...args) {
|
|
12
|
+
listeners.push(...args)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getTextContent (el) {
|
|
16
|
+
let contentEl = el
|
|
17
|
+
if (el.querySelector('style')) {
|
|
18
|
+
const clonedEl = el.cloneNode(true)
|
|
19
|
+
for (const s of clonedEl.querySelectorAll('style, [aria-hidden]')) { s.remove() }
|
|
20
|
+
contentEl = clonedEl
|
|
21
|
+
}
|
|
22
|
+
return contentEl.textContent.trim()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function record (entry) {
|
|
26
|
+
ledger.push(entry)
|
|
27
|
+
const offset = ledger.length - LENGTH
|
|
28
|
+
if (offset > 0) {
|
|
29
|
+
ledger.splice(0, offset)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const listener of listeners) {
|
|
33
|
+
listener(entry)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let hasLinkListener = false
|
|
38
|
+
function trackLinks () {
|
|
39
|
+
if (hasLinkListener) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Capture link click to prevent navigation from detaching the element.
|
|
44
|
+
// This ensures tracking happens before the navigation.
|
|
45
|
+
hasLinkListener = true
|
|
46
|
+
document.addEventListener('click', event => {
|
|
47
|
+
// Get all the clickable elements on the path (works inside Shadow DOM).
|
|
48
|
+
const els = event.composedPath().filter(e => e?.classList?.contains?.('clickable'))
|
|
49
|
+
|
|
50
|
+
if (els.length === 0) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const tagName = event.target.tagName.toLowerCase()
|
|
55
|
+
const customElementTagName = customElements.get(tagName) ? tagName : null
|
|
56
|
+
|
|
57
|
+
for (const el of els) {
|
|
58
|
+
trackLink(el, customElementTagName)
|
|
59
|
+
}
|
|
60
|
+
}, { capture: true })
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function trackLink (el, customElementTagName) {
|
|
64
|
+
// For web components, use a dummy model with the organism set to the element name.
|
|
65
|
+
const componentModel = {
|
|
66
|
+
organism: customElementTagName,
|
|
67
|
+
...getComponentModel(el)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const linkModel = { name: el.title ? el.title : getTextContent(el) }
|
|
71
|
+
const entry = { eventName: 'Button click', componentModel, linkModel }
|
|
72
|
+
|
|
73
|
+
// This event fires before the expand/collapse event.
|
|
74
|
+
// The aria-expanded attribute will not yet be updated.
|
|
75
|
+
if (el.getAttribute('aria-expanded') === 'false' || el.parentElement.matches('details:not([open])')) {
|
|
76
|
+
entry.eventName = 'Toggle'
|
|
77
|
+
entry.value = 'Expanded'
|
|
78
|
+
} else if (el.getAttribute('aria-expanded') === 'true' || el.parentElement.matches('details[open]')) {
|
|
79
|
+
entry.eventName = 'Toggle'
|
|
80
|
+
entry.value = 'Collapsed'
|
|
81
|
+
} else if (el.href) {
|
|
82
|
+
entry.linkModel.value = el.href
|
|
83
|
+
entry.eventName = 'Link click'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
record(entry)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let hasPageViewListener = false
|
|
90
|
+
|
|
91
|
+
function pageViewListener () {
|
|
92
|
+
record({
|
|
93
|
+
eventName: 'Page view',
|
|
94
|
+
componentModel: getComponentModel(document.querySelector('[data-name="Page"]'))
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function trackPageView () {
|
|
99
|
+
if (hasPageViewListener) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
hasPageViewListener = true
|
|
104
|
+
pageViewListener() // Current page view.
|
|
105
|
+
globalThis.addEventListener('route', () => {
|
|
106
|
+
pageViewListener()
|
|
107
|
+
}) // All future page views.
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function initLedger () {
|
|
111
|
+
if (globalThis?.ami?.ledger) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Expose ledger listeners.
|
|
116
|
+
globalThis.ledgerListeners = globalThis.ledgerListeners || []
|
|
117
|
+
globalThis.ledgerListeners.push = function (handler, ...args) {
|
|
118
|
+
if (globalThis.ledgerListeners.includes(handler)) {
|
|
119
|
+
throw new Error('Handler already added.')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Call handler for all existing entries.
|
|
123
|
+
for (const entry of ledger) {
|
|
124
|
+
handler(entry)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
addListeners(handler, ...args)
|
|
128
|
+
return Array.prototype.push.apply(this, [handler, ...args])
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Add existing ledger listeners.
|
|
132
|
+
addListeners(...globalThis.ledgerListeners)
|
|
133
|
+
|
|
134
|
+
globalThis.ami ||= {}
|
|
135
|
+
globalThis.ami.ledger = ledger
|
|
136
|
+
globalThis.ami.ledger.record = record
|
|
137
|
+
|
|
138
|
+
trackPageView()
|
|
139
|
+
trackLinks()
|
|
140
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const { h, register, preactHooks, getConsent } = globalThis.ami
|
|
2
|
+
const { useRef, useEffect } = preactHooks
|
|
3
|
+
|
|
4
|
+
const POLL_INTERVAL = 1000
|
|
5
|
+
const GAP = '48px'
|
|
6
|
+
|
|
7
|
+
function LNGMap ({ src }) {
|
|
8
|
+
if (!src || !URL.canParse(src)) {
|
|
9
|
+
console.error('Missing data source or invalid URL.')
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ref = useRef(null)
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
let interval = null
|
|
17
|
+
const iframe = ref.current
|
|
18
|
+
const origin = new URL(src).origin
|
|
19
|
+
|
|
20
|
+
// Post consent to iframe.
|
|
21
|
+
const onLoad = () => {
|
|
22
|
+
interval = setInterval(() => {
|
|
23
|
+
iframe?.contentWindow?.postMessage({ consent: JSON.stringify(getConsent()) }, origin)
|
|
24
|
+
}, POLL_INTERVAL)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
iframe?.addEventListener('load', onLoad)
|
|
28
|
+
|
|
29
|
+
// Clear interval and load event when destroyed.
|
|
30
|
+
return () => {
|
|
31
|
+
clearInterval(interval)
|
|
32
|
+
iframe?.removeEventListener('load', onLoad)
|
|
33
|
+
}
|
|
34
|
+
}, [src])
|
|
35
|
+
|
|
36
|
+
return h('iframe', {
|
|
37
|
+
ref,
|
|
38
|
+
className: 'block w-full rounded-2xl border border-txa/20 sm:h-svh md:h-svh lg:aspect-video',
|
|
39
|
+
style: `max-height: calc(100svh - ${GAP})`,
|
|
40
|
+
src
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
register(LNGMap, 'lng-map')
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { h, preactHooks, register, waitForConsent } = globalThis.ami
|
|
2
|
+
const { useEffect, useState } = preactHooks
|
|
3
|
+
|
|
4
|
+
function MouseflowAnalytics ({ id }) {
|
|
5
|
+
if (!id) {
|
|
6
|
+
return null
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (document.documentElement.dataset.mode !== 'publish') {
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Mouseflow is already loaded.
|
|
14
|
+
if (globalThis._mfq) {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const [consent, setConsent] = useState(false)
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
(async () => {
|
|
22
|
+
// This will stop the execution util the consent is granted.
|
|
23
|
+
await waitForConsent({ statistics: true })
|
|
24
|
+
setConsent(true)
|
|
25
|
+
})()
|
|
26
|
+
}, [])
|
|
27
|
+
|
|
28
|
+
if (!consent) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
globalThis._mfq = []
|
|
33
|
+
return h('script', {
|
|
34
|
+
src: `//cdn.mouseflow.com/projects/${id}.js`,
|
|
35
|
+
defer: true
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
register(MouseflowAnalytics, 'mouseflow-analytics')
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import FilteredData from '#acinguiux-preact/wcs/shared/filtered-data/filtered-data.js'
|
|
2
|
+
|
|
3
|
+
const { h, register, matter } = globalThis.ami
|
|
4
|
+
const { Box, Table, Link } = matter
|
|
5
|
+
|
|
6
|
+
const LABELS = {
|
|
7
|
+
notAvailable: 'N/A',
|
|
8
|
+
text: 'Enter your search term',
|
|
9
|
+
selectCountry: 'Country/Region',
|
|
10
|
+
selectLanguage: 'Language',
|
|
11
|
+
search: 'Search',
|
|
12
|
+
download: 'Download',
|
|
13
|
+
noResults: 'No results found. Please do not use wild card.'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const fields = [
|
|
17
|
+
{ key: 'productName', name: 'Name' },
|
|
18
|
+
{ key: 'country', name: 'Country/Region' },
|
|
19
|
+
{ key: 'language', name: 'Language' },
|
|
20
|
+
{ key: 'specId', name: 'Specification' },
|
|
21
|
+
{ key: 'cas', name: 'CAS' },
|
|
22
|
+
{ key: 'url', name: 'SDS URL', isUrl: true },
|
|
23
|
+
{ key: 'versionNumber', name: 'Version' }
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
// -----------------------------------------------------------------------------
|
|
27
|
+
// Filtered Data hooks & helpers
|
|
28
|
+
// -----------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
async function getData ({ src }) {
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch(src)
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(`Failed to load resource: ${src} (Status: ${res.status})`)
|
|
35
|
+
}
|
|
36
|
+
const json = await res.json()
|
|
37
|
+
if (!json?.Items?.length) {
|
|
38
|
+
throw new Error('Invalid JSON structure: missing or empty Items array')
|
|
39
|
+
}
|
|
40
|
+
return json.Items.map(item => {
|
|
41
|
+
const {
|
|
42
|
+
SequenceNumber: msdsId,
|
|
43
|
+
ProductName: productName,
|
|
44
|
+
/* LanguageCode */
|
|
45
|
+
LanguageName: language,
|
|
46
|
+
/* DocDescription */
|
|
47
|
+
URL: url,
|
|
48
|
+
SICC: siccCode,
|
|
49
|
+
/* CountryCode */
|
|
50
|
+
CAS: cas,
|
|
51
|
+
NormedCAS: casNumberFormatted,
|
|
52
|
+
NamSyn: synonyms,
|
|
53
|
+
LanguageCountryDocType: languageCountry,
|
|
54
|
+
SpecIdFull: specId,
|
|
55
|
+
Version: versionNumber
|
|
56
|
+
} = item
|
|
57
|
+
|
|
58
|
+
const country = languageCountry?.split?.(';')?.[1]
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
msdsId, productName, country, language, siccCode, url, cas, casNumberFormatted, synonyms, specId, versionNumber
|
|
62
|
+
}
|
|
63
|
+
}) || []
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Error in getData:', error)
|
|
66
|
+
throw error
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function naFormat (value) {
|
|
71
|
+
return (value === null || value === undefined) ? LABELS.notAvailable : value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function Items ({ items }) {
|
|
75
|
+
if (!items?.length) {
|
|
76
|
+
return h('div', { className: 'text-center' }, LABELS.noResults)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return h(Box, { className: 'bg-bga text-txa rounded-2xl w-full overflow-x-auto' },
|
|
80
|
+
h(Table,
|
|
81
|
+
h('tr', fields.map(headerItem => h('th', headerItem.name))),
|
|
82
|
+
items.map(
|
|
83
|
+
result => h('tr', fields.map(
|
|
84
|
+
field => {
|
|
85
|
+
const fieldValue = result[field.key]
|
|
86
|
+
return h('td', fieldValue && field.isUrl
|
|
87
|
+
? h(Link, {
|
|
88
|
+
_variant: 'full',
|
|
89
|
+
_model: {
|
|
90
|
+
name: LABELS.download,
|
|
91
|
+
value: fieldValue
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
: naFormat(fieldValue))
|
|
95
|
+
}
|
|
96
|
+
))
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// -----------------------------------------------------------------------------
|
|
103
|
+
// Main component, custom element definition
|
|
104
|
+
// -----------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
function MSDSSearch ({ src }) {
|
|
107
|
+
return h(FilteredData, {
|
|
108
|
+
getData,
|
|
109
|
+
filters: [{
|
|
110
|
+
type: 'text',
|
|
111
|
+
label: LABELS.text,
|
|
112
|
+
keys: ['productName', 'siccCode', 'synonyms', 'cas', 'casNumberFormatted', 'specId']
|
|
113
|
+
}, {
|
|
114
|
+
type: 'select',
|
|
115
|
+
label: LABELS.selectCountry,
|
|
116
|
+
keys: ['', 'country']
|
|
117
|
+
}, {
|
|
118
|
+
type: 'select',
|
|
119
|
+
label: LABELS.selectLanguage,
|
|
120
|
+
keys: ['', 'language']
|
|
121
|
+
}],
|
|
122
|
+
Items,
|
|
123
|
+
src
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
register(MSDSSearch, 'msds-search')
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
|
2
|
+
<path fill="#595959" d="M10.5,2 C15.1944204,2 19,5.80557963 19,10.5 C19,12.4865245 18.3185332,14.3138839 17.1766205,15.7610573 L21.7071068,20.2928932 L20.2928932,21.7071068 L15.7610573,17.1766205 C14.3138839,18.3185332 12.4865245,19 10.5,19 C5.80557963,19 2,15.1944204 2,10.5 C2,5.80557963 5.80557963,2 10.5,2 Z M10.5,4 C6.91014913,4 4,6.91014913 4,10.5 C4,14.0898509 6.91014913,17 10.5,17 C14.0898509,17 17,14.0898509 17,10.5 C17,6.91014913 14.0898509,4 10.5,4 Z"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.20731 4.42397C4.16978 4.18006 3.95991 4 3.71312 4H2.5C2.22386 4 2 3.77614 2 3.5V2.5C2 2.22386 2.22386 2 2.5 2H4.57104C5.3114 2 5.94102 2.54017 6.0536 3.27191L6.2591 4.60767H20.5105C20.8335 4.60767 21.0717 4.90937 20.9968 5.22359L19.2352 12.6149C19.1815 12.8401 18.9803 12.999 18.7488 12.999H7.55007L7.79269 14.576C7.83022 14.8199 8.04009 15 8.28688 15H18.5C18.7761 15 19 15.2239 19 15.5V16.5C19 16.7761 18.7761 17 18.5 17H7.42896C6.6886 17 6.05898 16.4598 5.9464 15.7281L4.20731 4.42397ZM6.58786 6.60767L7.26279 10.999H17.4458C17.5153 10.999 17.5756 10.9513 17.5917 10.8838L18.5669 6.79244C18.5893 6.69818 18.5179 6.60767 18.421 6.60767H6.58786ZM10 20C10 21.1046 9.10457 22 8 22C6.89543 22 6 21.1046 6 20C6 18.8954 6.89543 18 8 18C9.10457 18 10 18.8954 10 20ZM19 20C19 21.1046 18.1046 22 17 22C15.8954 22 15 21.1046 15 20C15 18.8954 15.8954 18 17 18C18.1046 18 19 18.8954 19 20Z" fill="#292929"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { fetchCsv } from '#acinguiux-preact/wcs/shared/filtered-data/fetch-data.js'
|
|
2
|
+
import FilteredData from '#acinguiux-preact/wcs/shared/filtered-data/filtered-data.js'
|
|
3
|
+
import ICON_BACK from './icon-back.svg'
|
|
4
|
+
import ICON_CART from './icon-cart.svg'
|
|
5
|
+
import ICON_CLOSE from './icon-close.svg'
|
|
6
|
+
|
|
7
|
+
const { h, matter, preactHooks, register } = globalThis.ami
|
|
8
|
+
const { Box, Button, Card, Heading, Popup, RichText, Scroller } = matter
|
|
9
|
+
const { useEffect, useRef, useState } = preactHooks
|
|
10
|
+
|
|
11
|
+
const LABELS = {
|
|
12
|
+
CATEGORY: 'Nach Kategorie filtern',
|
|
13
|
+
ORDER_BY: 'Sortieren nach',
|
|
14
|
+
LOAD_MORE: 'Mehr laden',
|
|
15
|
+
RESET_FILTERS: 'Filter zurücksetzen',
|
|
16
|
+
ASCENDING: 'aufsteigend',
|
|
17
|
+
DESCENDING: 'absteigend',
|
|
18
|
+
ALL_CATEGORIES: 'Alle Prämienkategorien',
|
|
19
|
+
POINTS: 'Punkte',
|
|
20
|
+
BACK_TO_OVERVIEW: 'Zurück zur übersicht',
|
|
21
|
+
LEARN_MORE: 'Mehr erfahren'
|
|
22
|
+
}
|
|
23
|
+
const IMG_SIZE = { width: 320, height: 320 }
|
|
24
|
+
const FORWARD_URL = 'https://www.acinguiuxsmart.com/smart/reward?site=de-de&code='
|
|
25
|
+
|
|
26
|
+
// -----------------------------------------------------------------------------
|
|
27
|
+
// Data fetch utilities
|
|
28
|
+
// -----------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
async function getData ({ src, imageRoot }) {
|
|
31
|
+
const products = await fetchCsv(src)
|
|
32
|
+
const sanitizedImageRoot = (imageRoot ?? '').replace(/\/$/, '')
|
|
33
|
+
parseProducts(products, sanitizedImageRoot)
|
|
34
|
+
|
|
35
|
+
return products
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseProducts (products, imageRoot) {
|
|
39
|
+
for (const product of products) {
|
|
40
|
+
product.IMAGE = `${imageRoot}/${product.GIFT_CODE}.jpg`
|
|
41
|
+
product[LABELS.POINTS] = Number.parseInt(product.POINTS, 10) || ''
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// -----------------------------------------------------------------------------
|
|
46
|
+
// Common presentation components (item)
|
|
47
|
+
// -----------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
function Item ({ product, role }) {
|
|
50
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
51
|
+
const cardRef = useRef(null)
|
|
52
|
+
|
|
53
|
+
const closePopup = () => {
|
|
54
|
+
setIsOpen(false)
|
|
55
|
+
cardRef.current?.focus()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return h('div', { className: 'animate-fade h-full', role },
|
|
59
|
+
h(Card, {
|
|
60
|
+
key: product.GIFT_CODE,
|
|
61
|
+
tabindex: 0,
|
|
62
|
+
ref: cardRef,
|
|
63
|
+
onClick: event => {
|
|
64
|
+
cardRef.current = event.currentTarget
|
|
65
|
+
setIsOpen(true)
|
|
66
|
+
},
|
|
67
|
+
onKeyDown: event => event.key === 'Enter' && event.currentTarget.click(),
|
|
68
|
+
children: h('div',
|
|
69
|
+
h(ProductAsset, { product }),
|
|
70
|
+
h('div', { className: 'sm:col-span-1' },
|
|
71
|
+
h(Box,
|
|
72
|
+
h('span', product.BRAND),
|
|
73
|
+
h(Heading, { _level: '3' }, product.GIFT_NAME),
|
|
74
|
+
h('p', product.CATEGORY_NAME)
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
}),
|
|
79
|
+
h(Popup, {
|
|
80
|
+
onKeyDown: event => event.key === 'Escape' && closePopup(),
|
|
81
|
+
_show: isOpen,
|
|
82
|
+
_layout: 'center',
|
|
83
|
+
children: isOpen && [
|
|
84
|
+
h('div', { className: 'flex gap-2' },
|
|
85
|
+
h('div', { className: 'grow' },
|
|
86
|
+
h(Heading, { _level: '3', className: 'pr-10' }, product.GIFT_NAME)
|
|
87
|
+
),
|
|
88
|
+
h('div', { className: 'shrink-0' },
|
|
89
|
+
h(Button, {
|
|
90
|
+
_variant: 'plain',
|
|
91
|
+
_textless: true,
|
|
92
|
+
_size: 'xs',
|
|
93
|
+
_model: {
|
|
94
|
+
name: LABELS.BACK_TO_OVERVIEW,
|
|
95
|
+
value: '#',
|
|
96
|
+
icon: ICON_CLOSE
|
|
97
|
+
},
|
|
98
|
+
onClick: event => {
|
|
99
|
+
event.preventDefault()
|
|
100
|
+
closePopup()
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
)
|
|
104
|
+
),
|
|
105
|
+
h(ProductAsset, { product, className: 'rounded-lg overflow-hidden' }),
|
|
106
|
+
h(Heading, { _level: '5' }, product.BRAND),
|
|
107
|
+
h(RichText, product.DESCRIPTION),
|
|
108
|
+
h('div', { className: 'flex gap-5 sm:flex-wrap' },
|
|
109
|
+
h(Button, {
|
|
110
|
+
_size: 'sm',
|
|
111
|
+
_model: {
|
|
112
|
+
name: LABELS.BACK_TO_OVERVIEW,
|
|
113
|
+
value: '#',
|
|
114
|
+
icon: ICON_BACK
|
|
115
|
+
},
|
|
116
|
+
onClick: event => {
|
|
117
|
+
event.preventDefault()
|
|
118
|
+
closePopup()
|
|
119
|
+
}
|
|
120
|
+
}),
|
|
121
|
+
h(Button, {
|
|
122
|
+
target: '_blank',
|
|
123
|
+
rel: 'noopener',
|
|
124
|
+
_size: 'sm',
|
|
125
|
+
_model: {
|
|
126
|
+
name: LABELS.LEARN_MORE,
|
|
127
|
+
value: `${FORWARD_URL}${product.GIFT_CODE}`,
|
|
128
|
+
icon: ICON_CART
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
)
|
|
132
|
+
]
|
|
133
|
+
})
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function ProductAsset ({ product, className = '' }) {
|
|
138
|
+
return h('div', { className },
|
|
139
|
+
h('img', { src: product.IMAGE, alt: product.GIFT_NAME, className: 'block object-cover w-full h-auto', loading: 'lazy', ...IMG_SIZE }),
|
|
140
|
+
h('div', { className: 'relative' },
|
|
141
|
+
h('div', { className: 'bg-bgb text-txb absolute bottom-3 left-3 pt-2 pb-2 pl-3 pr-3 rounded-lg font-bold' },
|
|
142
|
+
`${product.POINTS} ${LABELS.POINTS}`
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// -----------------------------------------------------------------------------
|
|
149
|
+
// Default variant (via Filtered data): items
|
|
150
|
+
// -----------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
function Items ({ items }) {
|
|
153
|
+
return h('div', { className: 'grid gap-5 grid-cols-4 md:grid-cols-2 sm:grid-cols-1', role: 'list' }, items.map(product =>
|
|
154
|
+
h(Item, { product, role: 'listitem' })
|
|
155
|
+
))
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// -----------------------------------------------------------------------------
|
|
159
|
+
// Slider variant: items
|
|
160
|
+
// -----------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
function Slider ({ src, imageRoot }) {
|
|
163
|
+
const [items, setItems] = useState([])
|
|
164
|
+
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
getData({ src, imageRoot }).then(setItems)
|
|
167
|
+
}, [])
|
|
168
|
+
|
|
169
|
+
return h(Scroller, {
|
|
170
|
+
// Remove gap; shadow compensation is enough.
|
|
171
|
+
_style: id => `${id} [role="list"] { gap: 0 }`,
|
|
172
|
+
// Compensate for shadow.
|
|
173
|
+
children: items.map(product => h('div', { style: 'padding: 10px' },
|
|
174
|
+
h(Item, { product })
|
|
175
|
+
))
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// -----------------------------------------------------------------------------
|
|
180
|
+
// Main component, custom element definition
|
|
181
|
+
// -----------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
function ProductCatalogue ({ src, 'image-root': imageRoot, variant }) {
|
|
184
|
+
if (!src) {
|
|
185
|
+
return null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (variant === 'slider') {
|
|
189
|
+
return h(Slider, { src, imageRoot })
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return h(FilteredData, {
|
|
193
|
+
getData,
|
|
194
|
+
filters: [{
|
|
195
|
+
type: 'select',
|
|
196
|
+
label: LABELS.CATEGORY,
|
|
197
|
+
keys: [LABELS.ALL_CATEGORIES, 'CATEGORY_NAME']
|
|
198
|
+
}, {
|
|
199
|
+
type: 'order',
|
|
200
|
+
label: LABELS.ORDER_BY,
|
|
201
|
+
keys: [LABELS.POINTS, `-${LABELS.POINTS}`]
|
|
202
|
+
}],
|
|
203
|
+
Items,
|
|
204
|
+
i18n: {
|
|
205
|
+
loadMore: LABELS.LOAD_MORE,
|
|
206
|
+
resetFilters: LABELS.RESET_FILTERS,
|
|
207
|
+
ascending: LABELS.ASCENDING,
|
|
208
|
+
descending: LABELS.DESCENDING
|
|
209
|
+
},
|
|
210
|
+
src,
|
|
211
|
+
imageRoot
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
register(ProductCatalogue, 'product-catalogue')
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.20731 4.42397C4.16978 4.18006 3.95991 4 3.71312 4H2.5C2.22386 4 2 3.77614 2 3.5V2.5C2 2.22386 2.22386 2 2.5 2H4.57104C5.3114 2 5.94102 2.54017 6.0536 3.27191L6.2591 4.60767H20.5105C20.8335 4.60767 21.0717 4.90937 20.9968 5.22359L19.2352 12.6149C19.1815 12.8401 18.9803 12.999 18.7488 12.999H7.55007L7.79269 14.576C7.83022 14.8199 8.04009 15 8.28688 15H18.5C18.7761 15 19 15.2239 19 15.5V16.5C19 16.7761 18.7761 17 18.5 17H7.42896C6.6886 17 6.05898 16.4598 5.9464 15.7281L4.20731 4.42397ZM6.58786 6.60767L7.26279 10.999H17.4458C17.5153 10.999 17.5756 10.9513 17.5917 10.8838L18.5669 6.79244C18.5893 6.69818 18.5179 6.60767 18.421 6.60767H6.58786ZM10 20C10 21.1046 9.10457 22 8 22C6.89543 22 6 21.1046 6 20C6 18.8954 6.89543 18 8 18C9.10457 18 10 18.8954 10 20ZM19 20C19 21.1046 18.1046 22 17 22C15.8954 22 15 21.1046 15 20C15 18.8954 15.8954 18 17 18C18.1046 18 19 18.8954 19 20Z" fill="#292929"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import ICON_CART from './icon-cart.svg'
|
|
2
|
+
|
|
3
|
+
const { h, preactHooks, matter, register } = globalThis.ami
|
|
4
|
+
const { useMemo, useState } = preactHooks
|
|
5
|
+
const { Box, Button, Heading, Link } = matter
|
|
6
|
+
|
|
7
|
+
const IS_PUBLISH = document.documentElement.dataset.mode === 'publish'
|
|
8
|
+
const VISIBLE_VENDOR_COUNT = 3
|
|
9
|
+
|
|
10
|
+
const getSpaceSeparatedValues = text => {
|
|
11
|
+
const [, name, value] = text?.match(/^(.*)\s(\S+)$/) || []
|
|
12
|
+
return (name && value) ? { name, value } : null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function ProductLinks ({ heading = 'Buy now', 'view-more': viewMore = 'View more retailers', ...props }) {
|
|
16
|
+
const [isExpanded, setIsExpanded] = useState(false)
|
|
17
|
+
|
|
18
|
+
const vendors = useMemo(() =>
|
|
19
|
+
Object.entries(props)
|
|
20
|
+
.filter(([propName]) => propName.startsWith('vendor-'))
|
|
21
|
+
.map(([, propValue], i) => {
|
|
22
|
+
const parserVals = getSpaceSeparatedValues(propValue)
|
|
23
|
+
return parserVals ? { ...parserVals, order: i === 0 ? -1 : Math.random() } : null // eslint-disable-line sonarjs/pseudo-random
|
|
24
|
+
})
|
|
25
|
+
.filter(Boolean) // Filter out empty/incorrect values.
|
|
26
|
+
.sort((v1, v2) => IS_PUBLISH ? v1.order - v2.order : 0), // Randomize order for publish mode (except for the first link).
|
|
27
|
+
[])
|
|
28
|
+
|
|
29
|
+
if (!vendors.length) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return h(Box, { className: 'rounded-2xl bg-bga text-txa space-y-5' },
|
|
34
|
+
h(Heading, { _level: 2 }, heading),
|
|
35
|
+
...vendors.map((vendor, i) =>
|
|
36
|
+
(isExpanded || i < VISIBLE_VENDOR_COUNT) && h(Button, { _model: { ...vendor, icon: ICON_CART }, _wide: true })
|
|
37
|
+
),
|
|
38
|
+
!isExpanded && (vendors.length > VISIBLE_VENDOR_COUNT) &&
|
|
39
|
+
h(Link, { _variant: 'full', _model: { name: viewMore }, onClick: () => setIsExpanded(true) })
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
register(ProductLinks, 'product-links')
|