@liquidcommercedev/rmn-sdk 1.4.6 → 1.5.0-beta.2
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/dist/index.cjs +2463 -720
- package/dist/index.esm.js +2463 -721
- package/dist/types/common/helpers/uuid.helper.d.ts +49 -0
- package/dist/types/enums.d.ts +59 -1
- package/dist/types/index.umd.d.ts +2 -2
- package/dist/types/modules/element/component/carousel/carousel.component.d.ts +3 -0
- package/dist/types/modules/element/component/carousel/carousel.interface.d.ts +35 -0
- package/dist/types/modules/element/component/carousel/carousel.style.d.ts +2 -0
- package/dist/types/modules/element/component/carousel/index.d.ts +3 -0
- package/dist/types/modules/element/component/spot/index.d.ts +2 -0
- package/dist/types/modules/element/component/spot/spot.component.d.ts +3 -0
- package/dist/types/modules/element/component/spot/spot.interface.d.ts +10 -0
- package/dist/types/modules/element/component/utils.d.ts +1 -0
- package/dist/types/modules/{spot/html/constants/html.constant.d.ts → element/element.constant.d.ts} +2 -5
- package/dist/types/modules/element/element.interface.d.ts +52 -0
- package/dist/types/modules/element/element.service.d.ts +40 -0
- package/dist/types/modules/element/index.d.ts +3 -0
- package/dist/types/modules/element/template/helper.d.ts +4 -0
- package/dist/types/modules/element/template/index.d.ts +1 -0
- package/dist/types/modules/element/template/reservebar/collection-banner-without-text-block.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/homepage-hero-full-image.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/homepage-hero-three-tile.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/homepage-hero-two-tile.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/large-category-image-tout.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/navigation-banner.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/small-category-image-tout.template.d.ts +3 -0
- package/dist/types/modules/element/template/reservebar/small-discover-tout.template.d.ts +3 -0
- package/dist/types/modules/element/template/template.service.d.ts +11 -0
- package/dist/types/modules/element/template/template.type.d.ts +11 -0
- package/dist/types/modules/event/event.constant.d.ts +1 -0
- package/dist/types/modules/event/event.interface.d.ts +72 -0
- package/dist/types/modules/event/event.service.d.ts +47 -0
- package/dist/types/modules/event/helpers/index.d.ts +3 -0
- package/dist/types/modules/event/helpers/intersection.service.d.ts +8 -0
- package/dist/types/modules/event/helpers/localstorage.service.d.ts +26 -0
- package/dist/types/modules/event/helpers/resize.service.d.ts +30 -0
- package/dist/types/modules/event/index.d.ts +4 -0
- package/dist/types/modules/event/pubsub.d.ts +69 -0
- package/dist/types/modules/selection/index.d.ts +4 -0
- package/dist/types/modules/selection/selection.constant.d.ts +1 -0
- package/dist/types/modules/{spot/spot.interface.d.ts → selection/selection.interface.d.ts} +10 -13
- package/dist/types/modules/selection/selection.service.d.ts +18 -0
- package/dist/types/modules/{spot/spot.type.d.ts → selection/selection.type.d.ts} +4 -3
- package/dist/types/rmn-client.d.ts +66 -23
- package/dist/types/static.constant.d.ts +4 -0
- package/dist/types/types.d.ts +17 -6
- package/package.json +2 -2
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
- package/dist/types/modules/spot/html/constants/index.d.ts +0 -1
- package/dist/types/modules/spot/html/index.d.ts +0 -1
- package/dist/types/modules/spot/html/spot.element.service.d.ts +0 -7
- package/dist/types/modules/spot/html/templates/index.d.ts +0 -1
- package/dist/types/modules/spot/html/templates/reservebar/collection-banner-without-text-block.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/homepage-hero-full-image.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/homepage-hero-three-tile.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/homepage-hero-two-tile.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/large-category-image-tout.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/navigation-banner.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/small-category-image-tout.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/reservebar/small-discover-tout.template.d.ts +0 -2
- package/dist/types/modules/spot/html/templates/spot.template.d.ts +0 -21
- package/dist/types/modules/spot/index.d.ts +0 -6
- package/dist/types/modules/spot/spot.constant.d.ts +0 -4
- package/dist/types/modules/spot/spot.enum.d.ts +0 -57
- package/dist/types/modules/spot/spot.html.service.d.ts +0 -22
- package/dist/types/modules/spot/spot.selection.service.d.ts +0 -15
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/billboard-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/billboard-v2.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/billboard-v3.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/in-text/in-text-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/in-text/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-leaderboard/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-leaderboard/large-leaderboard-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-leaderboard/large-leaderboard-v2.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-rectangle/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-rectangle/large-rectangle-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/square/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/square/square-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/square/square-v2.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/vertical-rectangle/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/vertical-rectangle/vertical-rectangle-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/wide-skyscraper/index.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/iab/wide-skyscraper/wide-skyscraper-v1.template.d.ts +0 -0
- /package/dist/types/modules/{spot/html/templates → element/template}/reservebar/index.d.ts +0 -0
package/dist/index.esm.js
CHANGED
|
@@ -42,6 +42,7 @@ var RMN_SPOT_TYPE;
|
|
|
42
42
|
var RMN_FILTER_PROPERTIES;
|
|
43
43
|
(function (RMN_FILTER_PROPERTIES) {
|
|
44
44
|
RMN_FILTER_PROPERTIES["KEYWORDS"] = "keywords";
|
|
45
|
+
RMN_FILTER_PROPERTIES["PAGE_LOCATION"] = "pageLocation";
|
|
45
46
|
RMN_FILTER_PROPERTIES["PARENTCO"] = "parentCo";
|
|
46
47
|
RMN_FILTER_PROPERTIES["BRAND"] = "brand";
|
|
47
48
|
RMN_FILTER_PROPERTIES["CATEGORY"] = "category";
|
|
@@ -53,6 +54,7 @@ var RMN_FILTER_PROPERTIES;
|
|
|
53
54
|
})(RMN_FILTER_PROPERTIES || (RMN_FILTER_PROPERTIES = {}));
|
|
54
55
|
var RMN_SPOT_EVENT;
|
|
55
56
|
(function (RMN_SPOT_EVENT) {
|
|
57
|
+
RMN_SPOT_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
|
|
56
58
|
RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
|
|
57
59
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
|
58
60
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
|
@@ -60,7 +62,6 @@ var RMN_SPOT_EVENT;
|
|
|
60
62
|
RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
|
|
61
63
|
RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
|
|
62
64
|
})(RMN_SPOT_EVENT || (RMN_SPOT_EVENT = {}));
|
|
63
|
-
|
|
64
65
|
var RMN_ENV;
|
|
65
66
|
(function (RMN_ENV) {
|
|
66
67
|
RMN_ENV["LOCAL"] = "local";
|
|
@@ -14997,7 +14998,7 @@ class BaseApi extends BaseApiAbstract {
|
|
|
14997
14998
|
*/
|
|
14998
14999
|
async post(path, data, configOverrides) {
|
|
14999
15000
|
let requestData = data;
|
|
15000
|
-
if (this.authInfo.env
|
|
15001
|
+
if (![RMN_ENV.LOCAL, RMN_ENV.DEVELOPMENT].includes(this.authInfo.env)) {
|
|
15001
15002
|
const timestamp = new Date().getTime();
|
|
15002
15003
|
configOverrides = {
|
|
15003
15004
|
...configOverrides,
|
|
@@ -15150,9 +15151,7 @@ class AuthService extends BaseApi {
|
|
|
15150
15151
|
}
|
|
15151
15152
|
|
|
15152
15153
|
const SPOT_ELEMENT_TAG = 'spot-element';
|
|
15153
|
-
const
|
|
15154
|
-
const SPOTS_SELECTION_API_PATH = '/spots/selection';
|
|
15155
|
-
|
|
15154
|
+
const CAROUSEL_ELEMENT_TAG = 'spot-carousel-element';
|
|
15156
15155
|
const GFONT_PRECONNECT = `
|
|
15157
15156
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
15158
15157
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
@@ -15163,141 +15162,1156 @@ const GFONT_SOURCE_SANS_3 = `
|
|
|
15163
15162
|
const GFONT_CORMORANT = `
|
|
15164
15163
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,300..700;1,300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
|
|
15165
15164
|
`;
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15165
|
+
|
|
15166
|
+
class IntersectionObserverService {
|
|
15167
|
+
constructor(defaultOptions = {}) {
|
|
15168
|
+
this.observers = new Map();
|
|
15169
|
+
this.defaultOptions = {
|
|
15170
|
+
root: null,
|
|
15171
|
+
rootMargin: '0px',
|
|
15172
|
+
threshold: 0.5,
|
|
15173
|
+
...defaultOptions,
|
|
15174
|
+
};
|
|
15174
15175
|
}
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15176
|
+
observe(element, callback, options = {}) {
|
|
15177
|
+
const mergedOptions = { ...this.defaultOptions, ...options };
|
|
15178
|
+
const ioCallback = (entries) => {
|
|
15179
|
+
entries.forEach((entry) => {
|
|
15180
|
+
if (entry.isIntersecting) {
|
|
15181
|
+
callback(entry);
|
|
15182
|
+
}
|
|
15183
|
+
});
|
|
15184
|
+
};
|
|
15185
|
+
const observer = new IntersectionObserver(ioCallback, mergedOptions);
|
|
15186
|
+
this.observers.set(element, observer);
|
|
15187
|
+
observer.observe(element);
|
|
15188
|
+
}
|
|
15189
|
+
unobserve(element) {
|
|
15190
|
+
const observer = this.observers.get(element);
|
|
15191
|
+
if (observer) {
|
|
15192
|
+
observer.unobserve(element);
|
|
15193
|
+
observer.disconnect();
|
|
15194
|
+
this.observers.delete(element);
|
|
15195
|
+
}
|
|
15178
15196
|
}
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15197
|
+
unobserveAll() {
|
|
15198
|
+
this.observers.forEach((observer, element) => {
|
|
15199
|
+
observer.unobserve(element);
|
|
15200
|
+
observer.disconnect();
|
|
15201
|
+
});
|
|
15202
|
+
this.observers.clear();
|
|
15182
15203
|
}
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15204
|
+
}
|
|
15205
|
+
|
|
15206
|
+
class LocalStorage {
|
|
15207
|
+
constructor() {
|
|
15208
|
+
this.spots = new Map();
|
|
15209
|
+
// Sync local storage with the current state
|
|
15210
|
+
this.syncLocalStorage();
|
|
15211
|
+
// Remove expired spots
|
|
15212
|
+
this.removeExpiredSpots();
|
|
15213
|
+
}
|
|
15214
|
+
static getInstance() {
|
|
15215
|
+
if (!LocalStorage.instance) {
|
|
15216
|
+
LocalStorage.instance = new LocalStorage();
|
|
15217
|
+
}
|
|
15218
|
+
return LocalStorage.instance;
|
|
15219
|
+
}
|
|
15220
|
+
syncLocalStorage() {
|
|
15221
|
+
const localStorageData = localStorage.getItem(LocalStorage.localStorageKey);
|
|
15222
|
+
// TODO: Encrypt the data before storing it in the local storage
|
|
15223
|
+
if (localStorageData) {
|
|
15224
|
+
try {
|
|
15225
|
+
const parsedData = JSON.parse(localStorageData);
|
|
15226
|
+
if (parsedData && typeof parsedData === 'object') {
|
|
15227
|
+
this.spots = this.objToMap(parsedData);
|
|
15228
|
+
}
|
|
15229
|
+
else {
|
|
15230
|
+
this.clearLocalStorage();
|
|
15231
|
+
}
|
|
15232
|
+
}
|
|
15233
|
+
catch (_a) {
|
|
15234
|
+
// If there is an error parsing the data, clear the local storage to prevent any issues
|
|
15235
|
+
this.clearLocalStorage();
|
|
15236
|
+
}
|
|
15237
|
+
}
|
|
15238
|
+
}
|
|
15239
|
+
setSpot(spotId, data) {
|
|
15240
|
+
data.createdAt = Date.now();
|
|
15241
|
+
this.spots.set(spotId, data);
|
|
15242
|
+
this.updateLocalStorage();
|
|
15243
|
+
}
|
|
15244
|
+
getSpot(spotId) {
|
|
15245
|
+
return this.spots.get(spotId);
|
|
15246
|
+
}
|
|
15247
|
+
removeSpot(spotId) {
|
|
15248
|
+
this.spots.delete(spotId);
|
|
15249
|
+
this.updateLocalStorage();
|
|
15250
|
+
}
|
|
15251
|
+
updateLocalStorage() {
|
|
15252
|
+
const data = this.mapToObj(this.spots);
|
|
15253
|
+
localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(data));
|
|
15254
|
+
}
|
|
15255
|
+
clearLocalStorage() {
|
|
15256
|
+
localStorage.removeItem(LocalStorage.localStorageKey);
|
|
15257
|
+
}
|
|
15258
|
+
removeExpiredSpots() {
|
|
15259
|
+
const currentTime = Date.now();
|
|
15260
|
+
this.spots.forEach((spot, spotId) => {
|
|
15261
|
+
var _a;
|
|
15262
|
+
if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) > LocalStorage.spotExpirationTime) {
|
|
15263
|
+
this.spots.delete(spotId);
|
|
15264
|
+
}
|
|
15265
|
+
});
|
|
15266
|
+
this.updateLocalStorage();
|
|
15267
|
+
}
|
|
15268
|
+
mapToObj(map) {
|
|
15269
|
+
return Object.fromEntries(map);
|
|
15270
|
+
}
|
|
15271
|
+
objToMap(obj) {
|
|
15272
|
+
return new Map(Object.entries(obj));
|
|
15273
|
+
}
|
|
15274
|
+
}
|
|
15275
|
+
LocalStorage.localStorageKey = 'lc_rmn';
|
|
15276
|
+
LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
|
15277
|
+
|
|
15278
|
+
class ResizeObserverService {
|
|
15279
|
+
constructor({ element, maxSize, minScale }) {
|
|
15280
|
+
this.element = element;
|
|
15281
|
+
if (!element.parentElement) {
|
|
15282
|
+
throw new Error('RmnSdk: Spot element must have a parent container.');
|
|
15283
|
+
}
|
|
15284
|
+
this.container = element.parentElement;
|
|
15285
|
+
this.setDimensions(maxSize, minScale);
|
|
15286
|
+
this.resizeObserver = new ResizeObserver(() => this.updateElementSize());
|
|
15287
|
+
this.resizeObserver.observe(this.container);
|
|
15288
|
+
// Initial size update
|
|
15289
|
+
this.updateElementSize();
|
|
15290
|
+
}
|
|
15291
|
+
setDimensions(maxSize, minScale) {
|
|
15292
|
+
if (minScale <= 0 || minScale > 1) {
|
|
15293
|
+
throw new Error('RmnSdk: Invalid minScale value');
|
|
15294
|
+
}
|
|
15295
|
+
const minSize = {
|
|
15296
|
+
width: maxSize.width * minScale,
|
|
15297
|
+
height: maxSize.height * minScale,
|
|
15298
|
+
};
|
|
15299
|
+
if (maxSize.width <= 0 || maxSize.height <= 0 || minSize.width <= 0 || minSize.height <= 0) {
|
|
15300
|
+
throw new Error('RmnSdk: Invalid dimensions');
|
|
15301
|
+
}
|
|
15302
|
+
if (minSize.width > maxSize.width || minSize.height > maxSize.height) {
|
|
15303
|
+
throw new Error('RmnSdk: Minimum size cannot be greater than maximum size');
|
|
15304
|
+
}
|
|
15305
|
+
this.maxSize = maxSize;
|
|
15306
|
+
this.minSize = minSize;
|
|
15307
|
+
this.aspectRatio = this.maxSize.width / this.maxSize.height;
|
|
15308
|
+
}
|
|
15309
|
+
updateElementSize() {
|
|
15310
|
+
const { clientWidth: containerWidth, clientHeight: containerHeight } = this.container;
|
|
15311
|
+
let newWidth;
|
|
15312
|
+
let newHeight;
|
|
15313
|
+
// First, try to fit the maximum width
|
|
15314
|
+
newWidth = Math.min(containerWidth, this.maxSize.width);
|
|
15315
|
+
newHeight = newWidth / this.aspectRatio;
|
|
15316
|
+
// If the height exceeds the container, adjust based on height
|
|
15317
|
+
if (newWidth > containerWidth) {
|
|
15318
|
+
newWidth = containerWidth;
|
|
15319
|
+
newHeight = containerHeight * this.aspectRatio;
|
|
15320
|
+
}
|
|
15321
|
+
// Ensure we're not going below minimum dimensions
|
|
15322
|
+
newWidth = Math.max(newWidth, this.minSize.width);
|
|
15323
|
+
newHeight = Math.max(newHeight, this.minSize.height);
|
|
15324
|
+
this.element.style.width = `${newWidth}px`;
|
|
15325
|
+
this.element.style.height = `${newHeight}px`;
|
|
15326
|
+
// Calculate the scale percentage
|
|
15327
|
+
const scaleWidth = newWidth / this.maxSize.width;
|
|
15328
|
+
const scaleHeight = newHeight / this.maxSize.height;
|
|
15329
|
+
const scale = Math.min(scaleWidth, scaleHeight);
|
|
15330
|
+
// Dispatch a custom event
|
|
15331
|
+
this.element.dispatchEvent(new CustomEvent('spotSizeChanged', {
|
|
15332
|
+
detail: {
|
|
15333
|
+
width: this.maxSize.width,
|
|
15334
|
+
height: this.maxSize.height,
|
|
15335
|
+
newWidth,
|
|
15336
|
+
newHeight,
|
|
15337
|
+
scale,
|
|
15338
|
+
},
|
|
15339
|
+
}));
|
|
15340
|
+
}
|
|
15341
|
+
disconnect() {
|
|
15342
|
+
this.resizeObserver.disconnect();
|
|
15343
|
+
}
|
|
15344
|
+
}
|
|
15345
|
+
|
|
15346
|
+
function calculateScaleFactor(elementScale) {
|
|
15347
|
+
// Step 1: Apply square root for non-linear scaling
|
|
15348
|
+
// This creates a more gradual scaling effect, especially for larger changes
|
|
15349
|
+
// For example:
|
|
15350
|
+
// - elementScale of 0.25 (1/4 size) becomes 0.5
|
|
15351
|
+
// - elementScale of 1 (unchanged) remains 1
|
|
15352
|
+
// - elementScale of 4 (4x size) becomes 2
|
|
15353
|
+
const baseFactor = Math.sqrt(elementScale);
|
|
15354
|
+
// Step 2: Apply additional dampening to further soften the scaling effect
|
|
15355
|
+
// The dampening factor (0.5) can be adjusted:
|
|
15356
|
+
// - Lower values (closer to 0) make scaling more subtle
|
|
15357
|
+
// - Higher values (closer to 1) make scaling more pronounced
|
|
15358
|
+
const dampening = 0.35;
|
|
15359
|
+
// Calculate the scaleFactor:
|
|
15360
|
+
// 1. (baseFactor - 1) represents the change from the original size
|
|
15361
|
+
// 2. Multiply by dampening to reduce the effect
|
|
15362
|
+
// 3. Add 1 to center the scaling around the original size
|
|
15363
|
+
// For example, if baseFactor is 2:
|
|
15364
|
+
// scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
|
|
15365
|
+
const scaleFactor = 1 + (baseFactor - 1) * dampening;
|
|
15366
|
+
// Step 3: Define the allowed range for the scale factor
|
|
15367
|
+
// This ensures that the font size never changes too drastically
|
|
15368
|
+
const minScale = 0.35; // Font will never be smaller than 50% of original
|
|
15369
|
+
const maxScale = 1.5; // Font will never be larger than 150% of original
|
|
15370
|
+
// Step 4: Clamp the scale factor to the defined range
|
|
15371
|
+
// Math.min ensures the value doesn't exceed maxScale
|
|
15372
|
+
// Math.max ensures the value isn't less than minScale
|
|
15373
|
+
return Math.max(minScale, Math.min(maxScale, scaleFactor));
|
|
15374
|
+
}
|
|
15375
|
+
|
|
15376
|
+
const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
|
15377
|
+
:host {
|
|
15378
|
+
position: relative;
|
|
15379
|
+
display: inline-block;
|
|
15380
|
+
margin: 0;
|
|
15381
|
+
overflow: hidden;
|
|
15382
|
+
width: ${fluid ? '100%' : `${width}px`};
|
|
15383
|
+
height: ${fluid ? '100%' : `${height}px`};
|
|
15384
|
+
}
|
|
15385
|
+
|
|
15386
|
+
.slides {
|
|
15387
|
+
position: relative;
|
|
15388
|
+
height: 100%;
|
|
15194
15389
|
width: 100%;
|
|
15390
|
+
}
|
|
15391
|
+
|
|
15392
|
+
.slide {
|
|
15393
|
+
display: none;
|
|
15394
|
+
|
|
15395
|
+
justify-content: center;
|
|
15396
|
+
align-items: center;
|
|
15195
15397
|
height: 100%;
|
|
15196
|
-
|
|
15197
|
-
}
|
|
15198
|
-
`;
|
|
15398
|
+
width: 100%;
|
|
15199
15399
|
}
|
|
15200
|
-
return { style, wrapper, slot };
|
|
15201
|
-
};
|
|
15202
15400
|
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15401
|
+
.slide.active {
|
|
15402
|
+
display: flex;
|
|
15403
|
+
}
|
|
15404
|
+
|
|
15405
|
+
.dots {
|
|
15406
|
+
position: absolute;
|
|
15407
|
+
display: flex;
|
|
15408
|
+
align-items: center;
|
|
15409
|
+
gap: 8px;
|
|
15410
|
+
opacity: var(--opacity, 1);
|
|
15411
|
+
}
|
|
15412
|
+
|
|
15413
|
+
.dots.small .dot {
|
|
15414
|
+
width: 8px;
|
|
15415
|
+
height: 8px;
|
|
15416
|
+
}
|
|
15417
|
+
|
|
15418
|
+
.dots.base .dot {
|
|
15419
|
+
width: 12px;
|
|
15420
|
+
height: 12px;
|
|
15421
|
+
}
|
|
15422
|
+
|
|
15423
|
+
.dots.large .dot {
|
|
15424
|
+
width: 16px;
|
|
15425
|
+
height: 16px;
|
|
15426
|
+
}
|
|
15427
|
+
|
|
15428
|
+
.dots .dot {
|
|
15429
|
+
border-radius: 50%;
|
|
15430
|
+
cursor: pointer;
|
|
15431
|
+
transition: all 0.3s ease;
|
|
15432
|
+
}
|
|
15433
|
+
|
|
15434
|
+
.dots.top-left,
|
|
15435
|
+
.dots.bottom-left {
|
|
15436
|
+
left: 10px;
|
|
15437
|
+
}
|
|
15438
|
+
|
|
15439
|
+
.dots.top-center,
|
|
15440
|
+
.dots.bottom-center {
|
|
15441
|
+
left: 50%;
|
|
15442
|
+
transform: translateX(-50%);
|
|
15443
|
+
}
|
|
15444
|
+
|
|
15445
|
+
.dots.top-right,
|
|
15446
|
+
.dots.bottom-right {
|
|
15447
|
+
right: 10px;
|
|
15448
|
+
}
|
|
15449
|
+
|
|
15450
|
+
.dots.top-left,
|
|
15451
|
+
.dots.top-center,
|
|
15452
|
+
.dots.top-right {
|
|
15453
|
+
top: 10px;
|
|
15454
|
+
}
|
|
15455
|
+
|
|
15456
|
+
.dots.bottom-left,
|
|
15457
|
+
.dots.bottom-center,
|
|
15458
|
+
.dots.bottom-right {
|
|
15459
|
+
bottom: 10px;
|
|
15460
|
+
}
|
|
15461
|
+
|
|
15462
|
+
.dots.middle-left {
|
|
15463
|
+
left: 10px;
|
|
15464
|
+
top: 50%;
|
|
15465
|
+
transform: translateY(-50%);
|
|
15466
|
+
flex-direction: column;
|
|
15467
|
+
}
|
|
15468
|
+
|
|
15469
|
+
.dots.middle-right {
|
|
15470
|
+
right: 10px;
|
|
15471
|
+
top: 50%;
|
|
15472
|
+
transform: translateY(-50%);
|
|
15473
|
+
flex-direction: column;
|
|
15474
|
+
}
|
|
15475
|
+
|
|
15476
|
+
.buttons {
|
|
15477
|
+
opacity: var(--opacity, 1);
|
|
15478
|
+
}
|
|
15479
|
+
|
|
15480
|
+
.buttons button {
|
|
15481
|
+
background-color: #00000080;
|
|
15482
|
+
color: #fff;
|
|
15483
|
+
border: none;
|
|
15484
|
+
padding: 10px;
|
|
15485
|
+
cursor: pointer;
|
|
15486
|
+
transition: background-color 0.3s ease;
|
|
15487
|
+
}
|
|
15488
|
+
|
|
15489
|
+
.buttons.small button {
|
|
15490
|
+
padding: 6px;
|
|
15491
|
+
}
|
|
15492
|
+
|
|
15493
|
+
.buttons.base button {
|
|
15494
|
+
padding: 10px;
|
|
15495
|
+
}
|
|
15496
|
+
|
|
15497
|
+
.buttons.large button {
|
|
15498
|
+
padding: 14px;
|
|
15499
|
+
}
|
|
15500
|
+
|
|
15501
|
+
.buttons button:hover {
|
|
15502
|
+
background-color: #000000b3;
|
|
15503
|
+
}
|
|
15504
|
+
|
|
15505
|
+
.buttons.buttons-separate button {
|
|
15506
|
+
position: absolute;
|
|
15507
|
+
top: 50%;
|
|
15508
|
+
transform: translateY(-50%);
|
|
15509
|
+
}
|
|
15510
|
+
|
|
15511
|
+
.buttons.buttons-separate .prev-button {
|
|
15512
|
+
left: 10px;
|
|
15513
|
+
}
|
|
15514
|
+
|
|
15515
|
+
.buttons.buttons-separate .next-button {
|
|
15516
|
+
right: 10px;
|
|
15517
|
+
}
|
|
15518
|
+
|
|
15519
|
+
.buttons.buttons-together {
|
|
15520
|
+
position: absolute;
|
|
15521
|
+
display: flex;
|
|
15522
|
+
gap: 10px;
|
|
15523
|
+
}
|
|
15524
|
+
|
|
15525
|
+
.buttons.buttons-together.top-left,
|
|
15526
|
+
.buttons.buttons-together.bottom-left {
|
|
15527
|
+
left: 10px;
|
|
15528
|
+
}
|
|
15529
|
+
|
|
15530
|
+
.buttons.buttons-together.top-center,
|
|
15531
|
+
.buttons.buttons-together.bottom-center {
|
|
15532
|
+
left: 50%;
|
|
15533
|
+
transform: translateX(-50%);
|
|
15534
|
+
}
|
|
15535
|
+
|
|
15536
|
+
.buttons.buttons-together.top-right,
|
|
15537
|
+
.buttons.buttons-together.bottom-right {
|
|
15538
|
+
right: 10px;
|
|
15539
|
+
}
|
|
15540
|
+
|
|
15541
|
+
.buttons.buttons-together.top-left,
|
|
15542
|
+
.buttons.buttons-together.top-center,
|
|
15543
|
+
.buttons.buttons-together.top-right {
|
|
15544
|
+
top: 10px;
|
|
15545
|
+
}
|
|
15546
|
+
|
|
15547
|
+
.buttons.buttons-together.bottom-left,
|
|
15548
|
+
.buttons.buttons-together.bottom-center,
|
|
15549
|
+
.buttons.buttons-together.bottom-right {
|
|
15550
|
+
bottom: 10px;
|
|
15551
|
+
}
|
|
15552
|
+
|
|
15553
|
+
.buttons.buttons-together.middle-left,
|
|
15554
|
+
.buttons.buttons-together.middle-right {
|
|
15555
|
+
top: 50%;
|
|
15556
|
+
transform: translateY(-50%);
|
|
15557
|
+
flex-direction: column;
|
|
15558
|
+
}
|
|
15559
|
+
|
|
15560
|
+
.buttons.buttons-together.middle-left {
|
|
15561
|
+
left: 10px;
|
|
15562
|
+
}
|
|
15563
|
+
|
|
15564
|
+
.buttons.buttons-together.middle-right {
|
|
15565
|
+
right: 10px;
|
|
15566
|
+
}
|
|
15567
|
+
|
|
15568
|
+
@media (max-width: 768px) {
|
|
15569
|
+
.buttons button {
|
|
15570
|
+
padding: 8px 12px;
|
|
15571
|
+
font-size: 14px;
|
|
15222
15572
|
}
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15573
|
+
}
|
|
15574
|
+
`;
|
|
15575
|
+
|
|
15576
|
+
let CarouselElement;
|
|
15577
|
+
if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
|
|
15578
|
+
class CustomCarouselElement extends HTMLElement {
|
|
15579
|
+
constructor() {
|
|
15580
|
+
super();
|
|
15581
|
+
this.currentSlide = 0;
|
|
15582
|
+
this.dotElements = [];
|
|
15583
|
+
this.prevButton = null;
|
|
15584
|
+
this.nextButton = null;
|
|
15585
|
+
this.autoplayInterval = null;
|
|
15586
|
+
this.useDots = false;
|
|
15587
|
+
this.useButtons = false;
|
|
15588
|
+
this.originalFontSizes = new Map();
|
|
15589
|
+
this.attachShadow({ mode: 'open' });
|
|
15229
15590
|
}
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
|
|
15234
|
-
|
|
15235
|
-
background-repeat: no-repeat;
|
|
15236
|
-
background-size: cover;
|
|
15591
|
+
connectedCallback() {
|
|
15592
|
+
this.initializeOptions();
|
|
15593
|
+
this.setupResizeObserver();
|
|
15594
|
+
this.render();
|
|
15595
|
+
this.setupCarousel();
|
|
15237
15596
|
}
|
|
15238
|
-
|
|
15239
|
-
|
|
15240
|
-
|
|
15241
|
-
|
|
15242
|
-
flex-direction: column;
|
|
15243
|
-
justify-content: center;
|
|
15244
|
-
align-items: center;
|
|
15245
|
-
height: 50%;
|
|
15246
|
-
width: 100%;
|
|
15247
|
-
padding: 5% 10%;
|
|
15248
|
-
box-sizing: border-box;
|
|
15249
|
-
font-family: "Source Sans 3", sans-serif;
|
|
15597
|
+
disconnectedCallback() {
|
|
15598
|
+
var _a;
|
|
15599
|
+
this.stopAutoplay();
|
|
15600
|
+
(_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
15250
15601
|
}
|
|
15251
|
-
|
|
15252
|
-
|
|
15253
|
-
|
|
15254
|
-
|
|
15255
|
-
|
|
15256
|
-
|
|
15257
|
-
|
|
15602
|
+
initializeOptions() {
|
|
15603
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
15604
|
+
this.useDots = ((_a = this.data) === null || _a === void 0 ? void 0 : _a.useDots) === true || typeof ((_b = this.data) === null || _b === void 0 ? void 0 : _b.useDots) === 'object';
|
|
15605
|
+
this.useButtons = ((_c = this.data) === null || _c === void 0 ? void 0 : _c.useButtons) === true || typeof ((_d = this.data) === null || _d === void 0 ? void 0 : _d.useButtons) === 'object';
|
|
15606
|
+
this.autoplay = (_f = (_e = this.data) === null || _e === void 0 ? void 0 : _e.autoplay) !== null && _f !== void 0 ? _f : true;
|
|
15607
|
+
this.interval = (_h = (_g = this.data) === null || _g === void 0 ? void 0 : _g.interval) !== null && _h !== void 0 ? _h : CustomCarouselElement.defaultInterval;
|
|
15608
|
+
this.dotsOptions = {
|
|
15609
|
+
position: 'bottom-center',
|
|
15610
|
+
color: '#d9d9d9',
|
|
15611
|
+
activeColor: '#b5914a',
|
|
15612
|
+
size: 'base',
|
|
15613
|
+
opacity: 1,
|
|
15614
|
+
...(typeof ((_j = this.data) === null || _j === void 0 ? void 0 : _j.useDots) === 'object' ? this.data.useDots : {}),
|
|
15615
|
+
};
|
|
15616
|
+
this.buttonsOptions = {
|
|
15617
|
+
together: false,
|
|
15618
|
+
position: 'middle-sides',
|
|
15619
|
+
textColor: '#000000',
|
|
15620
|
+
backgroundColor: '#ffffff',
|
|
15621
|
+
borderRadius: '50%',
|
|
15622
|
+
prev: 'Prev',
|
|
15623
|
+
next: 'Next',
|
|
15624
|
+
size: 'base',
|
|
15625
|
+
opacity: 1,
|
|
15626
|
+
...(typeof ((_k = this.data) === null || _k === void 0 ? void 0 : _k.useButtons) === 'object' ? this.data.useButtons : {}),
|
|
15627
|
+
};
|
|
15628
|
+
this.validateOptions();
|
|
15258
15629
|
}
|
|
15259
|
-
|
|
15260
|
-
|
|
15261
|
-
|
|
15262
|
-
|
|
15263
|
-
|
|
15264
|
-
|
|
15630
|
+
setupResizeObserver() {
|
|
15631
|
+
if (this.data && !this.data.fluid) {
|
|
15632
|
+
this.resizeObserver = new ResizeObserverService({
|
|
15633
|
+
element: this,
|
|
15634
|
+
maxSize: {
|
|
15635
|
+
width: this.data.width,
|
|
15636
|
+
height: this.data.height,
|
|
15637
|
+
},
|
|
15638
|
+
minScale: this.data.minScale,
|
|
15639
|
+
});
|
|
15640
|
+
this.addEventListener('spotSizeChanged', this.handleCarouselSizeChanged.bind(this));
|
|
15641
|
+
}
|
|
15265
15642
|
}
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
15271
|
-
|
|
15272
|
-
text-decoration: underline;
|
|
15273
|
-
text-transform: uppercase;
|
|
15274
|
-
border: none;
|
|
15275
|
-
cursor: pointer;
|
|
15276
|
-
padding: 0;
|
|
15277
|
-
transition: opacity 0.3s ease;
|
|
15643
|
+
handleCarouselSizeChanged(event) {
|
|
15644
|
+
const isRBSpot = 'rbHeroadaksda'.startsWith('rb');
|
|
15645
|
+
if (!isRBSpot) {
|
|
15646
|
+
// Adjust text elements font size based on the scale factor
|
|
15647
|
+
this.adjustFontSize(event.detail.scale);
|
|
15648
|
+
}
|
|
15278
15649
|
}
|
|
15279
|
-
|
|
15280
|
-
|
|
15650
|
+
adjustFontSize(elementScale) {
|
|
15651
|
+
var _a;
|
|
15652
|
+
const scaleFactor = calculateScaleFactor(elementScale);
|
|
15653
|
+
// Find all text elements within the shadow root
|
|
15654
|
+
const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('h1, h2, h3, h4, p, span');
|
|
15655
|
+
elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
|
|
15656
|
+
if (element instanceof HTMLElement) {
|
|
15657
|
+
if (!this.originalFontSizes.has(element)) {
|
|
15658
|
+
const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
|
|
15659
|
+
this.originalFontSizes.set(element, originalSize);
|
|
15660
|
+
}
|
|
15661
|
+
const originalSize = this.originalFontSizes.get(element);
|
|
15662
|
+
const newFontSize = originalSize * scaleFactor;
|
|
15663
|
+
element.style.fontSize = `${newFontSize}px`;
|
|
15664
|
+
}
|
|
15665
|
+
});
|
|
15281
15666
|
}
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
|
|
15667
|
+
render() {
|
|
15668
|
+
var _a;
|
|
15669
|
+
if (!this.shadowRoot)
|
|
15670
|
+
return;
|
|
15671
|
+
const style = document.createElement('style');
|
|
15672
|
+
style.textContent = CAROUSEL_COMPONENT_STYLE(this.data);
|
|
15673
|
+
this.shadowRoot.appendChild(style);
|
|
15674
|
+
const slides = this.renderSlides();
|
|
15675
|
+
this.shadowRoot.appendChild(slides);
|
|
15676
|
+
this.slidesContainer = (_a = this.shadowRoot.querySelector('.slides')) !== null && _a !== void 0 ? _a : undefined;
|
|
15677
|
+
if (this.useDots) {
|
|
15678
|
+
const dots = this.renderDots();
|
|
15679
|
+
if (dots)
|
|
15680
|
+
this.shadowRoot.appendChild(dots);
|
|
15285
15681
|
}
|
|
15286
|
-
.
|
|
15287
|
-
|
|
15288
|
-
|
|
15682
|
+
if (this.useButtons) {
|
|
15683
|
+
const buttons = this.renderButtons();
|
|
15684
|
+
if (buttons)
|
|
15685
|
+
this.shadowRoot.appendChild(buttons);
|
|
15289
15686
|
}
|
|
15290
|
-
|
|
15291
|
-
|
|
15687
|
+
}
|
|
15688
|
+
setupCarousel() {
|
|
15689
|
+
this.setupDots();
|
|
15690
|
+
this.setupButtons();
|
|
15691
|
+
if (this.autoplay) {
|
|
15692
|
+
this.startAutoplay();
|
|
15292
15693
|
}
|
|
15694
|
+
this.updateCarousel();
|
|
15293
15695
|
}
|
|
15294
|
-
|
|
15295
|
-
|
|
15296
|
-
|
|
15297
|
-
|
|
15298
|
-
|
|
15299
|
-
|
|
15300
|
-
|
|
15696
|
+
renderSlides() {
|
|
15697
|
+
const slidesContainer = document.createElement('div');
|
|
15698
|
+
slidesContainer.className = 'slides';
|
|
15699
|
+
this.slides.forEach((slide, index) => {
|
|
15700
|
+
const slideElement = document.createElement('div');
|
|
15701
|
+
slideElement.className = `slide ${index === this.currentSlide ? 'active' : ''}`;
|
|
15702
|
+
if (slide instanceof HTMLElement) {
|
|
15703
|
+
slideElement.appendChild(slide);
|
|
15704
|
+
}
|
|
15705
|
+
slidesContainer.appendChild(slideElement);
|
|
15706
|
+
});
|
|
15707
|
+
return slidesContainer;
|
|
15708
|
+
}
|
|
15709
|
+
renderDots() {
|
|
15710
|
+
const dotsContainer = document.createElement('div');
|
|
15711
|
+
dotsContainer.className = `dots ${this.dotsOptions.position} ${this.dotsOptions.size}`;
|
|
15712
|
+
dotsContainer.style.cssText = `--opacity: ${this.dotsOptions.opacity}`;
|
|
15713
|
+
this.slides.forEach((_, index) => {
|
|
15714
|
+
const dot = document.createElement('span');
|
|
15715
|
+
dot.className = `dot ${index === this.currentSlide ? 'active' : ''}`;
|
|
15716
|
+
dot.style.backgroundColor = this.dotsOptions.color;
|
|
15717
|
+
dotsContainer.appendChild(dot);
|
|
15718
|
+
});
|
|
15719
|
+
return dotsContainer;
|
|
15720
|
+
}
|
|
15721
|
+
renderButtons() {
|
|
15722
|
+
const buttonsContainer = document.createElement('div');
|
|
15723
|
+
const buttonsClass = this.buttonsOptions.together
|
|
15724
|
+
? `buttons-together ${this.buttonsOptions.position}`
|
|
15725
|
+
: 'buttons-separate';
|
|
15726
|
+
buttonsContainer.className = `buttons ${buttonsClass} ${this.buttonsOptions.size}`;
|
|
15727
|
+
buttonsContainer.style.cssText = `--opacity: ${this.buttonsOptions.opacity}`;
|
|
15728
|
+
this.prevButton = this.createButton('prev-button', this.buttonsOptions.prev);
|
|
15729
|
+
this.nextButton = this.createButton('next-button', this.buttonsOptions.next);
|
|
15730
|
+
buttonsContainer.appendChild(this.prevButton);
|
|
15731
|
+
buttonsContainer.appendChild(this.nextButton);
|
|
15732
|
+
return buttonsContainer;
|
|
15733
|
+
}
|
|
15734
|
+
createButton(className, text) {
|
|
15735
|
+
const button = document.createElement('button');
|
|
15736
|
+
button.className = className;
|
|
15737
|
+
button.textContent = text;
|
|
15738
|
+
button.style.color = this.buttonsOptions.textColor;
|
|
15739
|
+
button.style.backgroundColor = this.buttonsOptions.backgroundColor;
|
|
15740
|
+
button.style.borderRadius = this.buttonsOptions.borderRadius;
|
|
15741
|
+
return button;
|
|
15742
|
+
}
|
|
15743
|
+
setupDots() {
|
|
15744
|
+
if (!this.shadowRoot || !this.useDots)
|
|
15745
|
+
return;
|
|
15746
|
+
this.dotElements = Array.from(this.shadowRoot.querySelectorAll('.dot'));
|
|
15747
|
+
this.dotElements.forEach((dot, index) => {
|
|
15748
|
+
dot.addEventListener('click', () => {
|
|
15749
|
+
this.goToSlide(index);
|
|
15750
|
+
this.resetAutoplay();
|
|
15751
|
+
});
|
|
15752
|
+
});
|
|
15753
|
+
}
|
|
15754
|
+
setupButtons() {
|
|
15755
|
+
var _a, _b;
|
|
15756
|
+
if (!this.useButtons)
|
|
15757
|
+
return;
|
|
15758
|
+
(_a = this.prevButton) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => {
|
|
15759
|
+
this.prevSlide();
|
|
15760
|
+
this.resetAutoplay();
|
|
15761
|
+
});
|
|
15762
|
+
(_b = this.nextButton) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {
|
|
15763
|
+
this.nextSlide();
|
|
15764
|
+
this.resetAutoplay();
|
|
15765
|
+
});
|
|
15766
|
+
}
|
|
15767
|
+
nextSlide() {
|
|
15768
|
+
this.goToSlide((this.currentSlide + 1) % this.slides.length);
|
|
15769
|
+
}
|
|
15770
|
+
prevSlide() {
|
|
15771
|
+
this.goToSlide((this.currentSlide - 1 + this.slides.length) % this.slides.length);
|
|
15772
|
+
}
|
|
15773
|
+
goToSlide(index) {
|
|
15774
|
+
this.currentSlide = index;
|
|
15775
|
+
this.updateCarousel();
|
|
15776
|
+
}
|
|
15777
|
+
updateCarousel() {
|
|
15778
|
+
if (!this.slidesContainer)
|
|
15779
|
+
return;
|
|
15780
|
+
const slides = Array.from(this.slidesContainer.children);
|
|
15781
|
+
slides.forEach((slide, index) => {
|
|
15782
|
+
slide.classList.toggle('active', index === this.currentSlide);
|
|
15783
|
+
});
|
|
15784
|
+
this.updateDots();
|
|
15785
|
+
}
|
|
15786
|
+
updateDots() {
|
|
15787
|
+
if (!this.useDots)
|
|
15788
|
+
return;
|
|
15789
|
+
this.dotElements.forEach((dot, index) => {
|
|
15790
|
+
const isActive = index === this.currentSlide;
|
|
15791
|
+
dot.classList.toggle('active', isActive);
|
|
15792
|
+
dot.style.backgroundColor = isActive
|
|
15793
|
+
? this.dotsOptions.activeColor
|
|
15794
|
+
: this.dotsOptions.color;
|
|
15795
|
+
});
|
|
15796
|
+
}
|
|
15797
|
+
startAutoplay() {
|
|
15798
|
+
this.autoplayInterval = window.setInterval(() => this.nextSlide(), this.interval);
|
|
15799
|
+
}
|
|
15800
|
+
stopAutoplay() {
|
|
15801
|
+
if (this.autoplayInterval !== null) {
|
|
15802
|
+
window.clearInterval(this.autoplayInterval);
|
|
15803
|
+
this.autoplayInterval = null;
|
|
15804
|
+
}
|
|
15805
|
+
}
|
|
15806
|
+
resetAutoplay() {
|
|
15807
|
+
if (this.autoplay) {
|
|
15808
|
+
this.stopAutoplay();
|
|
15809
|
+
this.startAutoplay();
|
|
15810
|
+
}
|
|
15811
|
+
}
|
|
15812
|
+
validateOptions() {
|
|
15813
|
+
this.validatePosition(this.dotsOptions.position, 'dotsPosition', 'bottom-center');
|
|
15814
|
+
this.validateButtonsPosition();
|
|
15815
|
+
}
|
|
15816
|
+
validatePosition(position, optionName, defaultValue) {
|
|
15817
|
+
if (!CustomCarouselElement.validPositions.includes(position)) {
|
|
15818
|
+
console.warn(`Invalid ${optionName}: ${position}. Defaulting to '${defaultValue}'.`);
|
|
15819
|
+
if (optionName === 'dotsPosition') {
|
|
15820
|
+
this.dotsOptions.position = defaultValue;
|
|
15821
|
+
}
|
|
15822
|
+
else if (optionName === 'buttonsPosition') {
|
|
15823
|
+
this.buttonsOptions.position = defaultValue;
|
|
15824
|
+
}
|
|
15825
|
+
}
|
|
15826
|
+
}
|
|
15827
|
+
validateButtonsPosition() {
|
|
15828
|
+
if (this.useButtons) {
|
|
15829
|
+
if (this.buttonsOptions.together) {
|
|
15830
|
+
this.validatePosition(this.buttonsOptions.position, 'buttonsPosition', 'bottom-center');
|
|
15831
|
+
}
|
|
15832
|
+
else if (this.buttonsOptions.position !== 'middle-sides') {
|
|
15833
|
+
console.warn(`Invalid buttonsPosition: ${this.buttonsOptions.position}. When buttons are not together, only 'middle-sides' is allowed. Defaulting to 'middle-sides'.`);
|
|
15834
|
+
this.buttonsOptions.position = 'middle-sides';
|
|
15835
|
+
}
|
|
15836
|
+
}
|
|
15837
|
+
}
|
|
15838
|
+
}
|
|
15839
|
+
CustomCarouselElement.defaultInterval = 5000;
|
|
15840
|
+
CustomCarouselElement.validPositions = [
|
|
15841
|
+
'top-left',
|
|
15842
|
+
'top-center',
|
|
15843
|
+
'top-right',
|
|
15844
|
+
'bottom-left',
|
|
15845
|
+
'bottom-center',
|
|
15846
|
+
'bottom-right',
|
|
15847
|
+
'middle-left',
|
|
15848
|
+
'middle-right',
|
|
15849
|
+
'middle-sides',
|
|
15850
|
+
];
|
|
15851
|
+
CarouselElement = CustomCarouselElement;
|
|
15852
|
+
}
|
|
15853
|
+
|
|
15854
|
+
let SpotElement;
|
|
15855
|
+
if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
|
|
15856
|
+
class CustomSpotElement extends HTMLElement {
|
|
15857
|
+
constructor() {
|
|
15858
|
+
super();
|
|
15859
|
+
this.originalFontSizes = new Map();
|
|
15860
|
+
this.attachShadow({ mode: 'open' });
|
|
15861
|
+
}
|
|
15862
|
+
connectedCallback() {
|
|
15863
|
+
this.setupResizeObserver();
|
|
15864
|
+
this.render();
|
|
15865
|
+
}
|
|
15866
|
+
disconnectedCallback() {
|
|
15867
|
+
var _a;
|
|
15868
|
+
this.removeEventListener('spotSizeChanged', this.handleSpotSizeChanged);
|
|
15869
|
+
(_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
15870
|
+
}
|
|
15871
|
+
/**
|
|
15872
|
+
* Setup observers for the spot element
|
|
15873
|
+
* #########################################################
|
|
15874
|
+
*/
|
|
15875
|
+
setupResizeObserver() {
|
|
15876
|
+
if (this.data && !this.data.fluid) {
|
|
15877
|
+
this.resizeObserver = new ResizeObserverService({
|
|
15878
|
+
element: this,
|
|
15879
|
+
maxSize: {
|
|
15880
|
+
width: this.data.width,
|
|
15881
|
+
height: this.data.height,
|
|
15882
|
+
},
|
|
15883
|
+
minScale: this.data.minScale,
|
|
15884
|
+
});
|
|
15885
|
+
this.addEventListener('spotSizeChanged', this.handleSpotSizeChanged.bind(this));
|
|
15886
|
+
}
|
|
15887
|
+
}
|
|
15888
|
+
/**
|
|
15889
|
+
* Observer additional event handlers
|
|
15890
|
+
* #########################################################
|
|
15891
|
+
*/
|
|
15892
|
+
handleSpotSizeChanged(event) {
|
|
15893
|
+
var _a, _b, _c;
|
|
15894
|
+
const isRBSpot = (_c = (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.spot) === null || _b === void 0 ? void 0 : _b.startsWith('rb')) !== null && _c !== void 0 ? _c : false;
|
|
15895
|
+
if (!isRBSpot) {
|
|
15896
|
+
// Adjust text elements font size based on the scale factor
|
|
15897
|
+
this.adjustFontSize(event.detail.scale);
|
|
15898
|
+
}
|
|
15899
|
+
}
|
|
15900
|
+
adjustFontSize(elementScale) {
|
|
15901
|
+
var _a;
|
|
15902
|
+
const scaleFactor = calculateScaleFactor(elementScale);
|
|
15903
|
+
// Find all text elements within the shadow root
|
|
15904
|
+
const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('h1, h2, h3, h4, p, span');
|
|
15905
|
+
elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
|
|
15906
|
+
if (element instanceof HTMLElement) {
|
|
15907
|
+
if (!this.originalFontSizes.has(element)) {
|
|
15908
|
+
const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
|
|
15909
|
+
this.originalFontSizes.set(element, originalSize);
|
|
15910
|
+
}
|
|
15911
|
+
const originalSize = this.originalFontSizes.get(element);
|
|
15912
|
+
const newFontSize = originalSize * scaleFactor;
|
|
15913
|
+
element.style.fontSize = `${newFontSize}px`;
|
|
15914
|
+
}
|
|
15915
|
+
});
|
|
15916
|
+
}
|
|
15917
|
+
/**
|
|
15918
|
+
* Spot element rendering
|
|
15919
|
+
* #########################################################
|
|
15920
|
+
*/
|
|
15921
|
+
render() {
|
|
15922
|
+
if (!this.shadowRoot || !this.data || !this.content)
|
|
15923
|
+
return;
|
|
15924
|
+
const style = this.getTemplateStyle(this.data.width, this.data.height);
|
|
15925
|
+
if (this.content instanceof HTMLElement) {
|
|
15926
|
+
this.shadowRoot.replaceChildren(style, this.content);
|
|
15927
|
+
}
|
|
15928
|
+
}
|
|
15929
|
+
getTemplateStyle(width, height) {
|
|
15930
|
+
const style = document.createElement('style');
|
|
15931
|
+
style.textContent = `
|
|
15932
|
+
:host {
|
|
15933
|
+
display: block;
|
|
15934
|
+
position: relative;
|
|
15935
|
+
box-sizing: border-box;
|
|
15936
|
+
overflow: hidden;
|
|
15937
|
+
width: ${this.data.fluid ? '100%' : `${width}px`};
|
|
15938
|
+
height: ${this.data.fluid ? '100%' : `${height}px`};
|
|
15939
|
+
}
|
|
15940
|
+
`;
|
|
15941
|
+
return style;
|
|
15942
|
+
}
|
|
15943
|
+
}
|
|
15944
|
+
SpotElement = CustomSpotElement;
|
|
15945
|
+
}
|
|
15946
|
+
|
|
15947
|
+
class ElementService {
|
|
15948
|
+
static getInstance() {
|
|
15949
|
+
return SingletonManager.getInstance('ElementService', () => new ElementService());
|
|
15950
|
+
}
|
|
15951
|
+
/**
|
|
15952
|
+
* Creates the html element based on the provided data, content and configs using shadow dom.
|
|
15953
|
+
*
|
|
15954
|
+
* This method is only available in browser environments.
|
|
15955
|
+
*
|
|
15956
|
+
* @param {ICreateSpotElementParams} params - The parameters to create the final element.
|
|
15957
|
+
*
|
|
15958
|
+
* @return {HTMLElement | null} - The html element or null if the browser environment is not available.
|
|
15959
|
+
*/
|
|
15960
|
+
createSpotElement({ content, config }) {
|
|
15961
|
+
var _a, _b;
|
|
15962
|
+
if (!this.ensureBrowserEnvironmentAndDefineElement()) {
|
|
15963
|
+
return null;
|
|
15964
|
+
}
|
|
15965
|
+
const spot = document.createElement(SPOT_ELEMENT_TAG);
|
|
15966
|
+
spot.setAttribute('type', (_a = config === null || config === void 0 ? void 0 : config.spot) !== null && _a !== void 0 ? _a : '');
|
|
15967
|
+
spot.data = {
|
|
15968
|
+
spot: config === null || config === void 0 ? void 0 : config.spot,
|
|
15969
|
+
fluid: (_b = config === null || config === void 0 ? void 0 : config.fluid) !== null && _b !== void 0 ? _b : false,
|
|
15970
|
+
...config,
|
|
15971
|
+
};
|
|
15972
|
+
spot.content = content;
|
|
15973
|
+
return spot;
|
|
15974
|
+
}
|
|
15975
|
+
/**
|
|
15976
|
+
* Creates the carousel html element based on the provided slides and configs using shadow dom.
|
|
15977
|
+
*
|
|
15978
|
+
* This method is only available in browser environments.
|
|
15979
|
+
*
|
|
15980
|
+
* @param {ICreateCarouselElementParams} params - The parameters to create the final element.
|
|
15981
|
+
*
|
|
15982
|
+
* @return {HTMLElement | null} - The html element or null if the browser environment is not available.
|
|
15983
|
+
*/
|
|
15984
|
+
createCarouselElement({ slides, config, }) {
|
|
15985
|
+
if (!this.ensureBrowserEnvironmentAndDefineElement()) {
|
|
15986
|
+
return null;
|
|
15987
|
+
}
|
|
15988
|
+
const carousel = document.createElement(CAROUSEL_ELEMENT_TAG);
|
|
15989
|
+
carousel.data = {
|
|
15990
|
+
spot: config === null || config === void 0 ? void 0 : config.spot,
|
|
15991
|
+
fluid: false,
|
|
15992
|
+
...config,
|
|
15993
|
+
};
|
|
15994
|
+
carousel.slides = slides;
|
|
15995
|
+
return carousel;
|
|
15996
|
+
}
|
|
15997
|
+
/**
|
|
15998
|
+
* Overrides the spot colors with the provided colors.
|
|
15999
|
+
*
|
|
16000
|
+
* @param {ISpot} spot - The spot data.
|
|
16001
|
+
* @param {ISpotColors} colors - The colors to override.
|
|
16002
|
+
*
|
|
16003
|
+
* @return {ISpot} - The spot data with the colors overridden.
|
|
16004
|
+
*/
|
|
16005
|
+
overrideSpotColors(spot, colors) {
|
|
16006
|
+
if (!colors)
|
|
16007
|
+
return spot;
|
|
16008
|
+
const { textColor, backgroundColor, ctaTextColor, ctaBorderColor } = colors;
|
|
16009
|
+
return {
|
|
16010
|
+
...spot,
|
|
16011
|
+
textColor: textColor !== null && textColor !== void 0 ? textColor : spot.textColor,
|
|
16012
|
+
backgroundColor: backgroundColor !== null && backgroundColor !== void 0 ? backgroundColor : spot.backgroundColor,
|
|
16013
|
+
ctaTextColor: ctaTextColor !== null && ctaTextColor !== void 0 ? ctaTextColor : spot.ctaTextColor,
|
|
16014
|
+
ctaBorderColor: ctaBorderColor !== null && ctaBorderColor !== void 0 ? ctaBorderColor : spot.ctaBorderColor,
|
|
16015
|
+
};
|
|
16016
|
+
}
|
|
16017
|
+
/**
|
|
16018
|
+
* @returns {boolean} - True if the browser environment is available and the element is defined.
|
|
16019
|
+
*/
|
|
16020
|
+
ensureBrowserEnvironmentAndDefineElement() {
|
|
16021
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
16022
|
+
console.warn('LiquidCommerce Rmn Sdk: Methods which create elements are only available in browser environments.');
|
|
16023
|
+
return false;
|
|
16024
|
+
}
|
|
16025
|
+
if (!window.customElements.get(SPOT_ELEMENT_TAG)) {
|
|
16026
|
+
window.customElements.define(SPOT_ELEMENT_TAG, SpotElement);
|
|
16027
|
+
}
|
|
16028
|
+
if (!window.customElements.get(CAROUSEL_ELEMENT_TAG)) {
|
|
16029
|
+
window.customElements.define(CAROUSEL_ELEMENT_TAG, CarouselElement);
|
|
16030
|
+
}
|
|
16031
|
+
return true;
|
|
16032
|
+
}
|
|
16033
|
+
}
|
|
16034
|
+
|
|
16035
|
+
class UniqueIdGenerator {
|
|
16036
|
+
/**
|
|
16037
|
+
* Initialize the generator with a node ID
|
|
16038
|
+
* @param nodeId Number between 0-1023 to identify this instance
|
|
16039
|
+
*/
|
|
16040
|
+
static initialize(nodeId = Math.floor(Math.random() * 1024)) {
|
|
16041
|
+
if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
|
|
16042
|
+
throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
|
|
16043
|
+
}
|
|
16044
|
+
this.nodeId = nodeId;
|
|
16045
|
+
}
|
|
16046
|
+
/**
|
|
16047
|
+
* Convert a number to base32 string with specified length
|
|
16048
|
+
*/
|
|
16049
|
+
static toBase32(num, length) {
|
|
16050
|
+
let result = '';
|
|
16051
|
+
while (num > 0) {
|
|
16052
|
+
result = this.base32Chars[Number(num % BigInt(32))] + result;
|
|
16053
|
+
// @ts-expect-error - TS doesn't support bigint division
|
|
16054
|
+
num = num / 32n;
|
|
16055
|
+
}
|
|
16056
|
+
return result.padStart(length, '0');
|
|
16057
|
+
}
|
|
16058
|
+
/**
|
|
16059
|
+
* Generate a cryptographically secure random number
|
|
16060
|
+
*/
|
|
16061
|
+
static getSecureRandom() {
|
|
16062
|
+
if (typeof crypto !== 'undefined') {
|
|
16063
|
+
const buffer = new Uint32Array(1);
|
|
16064
|
+
crypto.getRandomValues(buffer);
|
|
16065
|
+
return buffer[0];
|
|
16066
|
+
}
|
|
16067
|
+
return Math.floor(Math.random() * 0xffffffff);
|
|
16068
|
+
}
|
|
16069
|
+
/**
|
|
16070
|
+
* Wait until next millisecond
|
|
16071
|
+
*/
|
|
16072
|
+
static waitNextMillis(lastTimestamp) {
|
|
16073
|
+
let timestamp = Date.now();
|
|
16074
|
+
while (timestamp <= lastTimestamp) {
|
|
16075
|
+
timestamp = Date.now();
|
|
16076
|
+
}
|
|
16077
|
+
return timestamp;
|
|
16078
|
+
}
|
|
16079
|
+
/**
|
|
16080
|
+
* Generates a highly unique ID with the following format:
|
|
16081
|
+
* TTTTTTTTTTCCCCNNNNNRRRR
|
|
16082
|
+
* T: Timestamp (10 chars)
|
|
16083
|
+
* C: Counter (4 chars)
|
|
16084
|
+
* N: Node ID (5 chars)
|
|
16085
|
+
* R: Random (4 chars)
|
|
16086
|
+
*
|
|
16087
|
+
* Total length: 23 characters, always uppercase alphanumeric
|
|
16088
|
+
*/
|
|
16089
|
+
static generate() {
|
|
16090
|
+
if (this.nodeId === undefined) {
|
|
16091
|
+
this.initialize();
|
|
16092
|
+
}
|
|
16093
|
+
let timestamp = Date.now() - this.epoch;
|
|
16094
|
+
// Handle clock moving backwards or same millisecond
|
|
16095
|
+
if (timestamp < this.lastTimestamp) {
|
|
16096
|
+
throw new Error('Clock moved backwards. Refusing to generate ID.');
|
|
16097
|
+
}
|
|
16098
|
+
if (timestamp === this.lastTimestamp) {
|
|
16099
|
+
this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
|
|
16100
|
+
if (this.sequence === 0) {
|
|
16101
|
+
timestamp = this.waitNextMillis(this.lastTimestamp);
|
|
16102
|
+
}
|
|
16103
|
+
}
|
|
16104
|
+
else {
|
|
16105
|
+
this.sequence = 0;
|
|
16106
|
+
}
|
|
16107
|
+
this.lastTimestamp = timestamp;
|
|
16108
|
+
// Generate random component
|
|
16109
|
+
const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
|
|
16110
|
+
// Combine all components into a BigInt
|
|
16111
|
+
// const id =
|
|
16112
|
+
// (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
|
|
16113
|
+
// (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
|
|
16114
|
+
// (BigInt(this.sequence) << BigInt(16)) |
|
|
16115
|
+
// BigInt(random);
|
|
16116
|
+
// Convert to base32 representation
|
|
16117
|
+
const timeComponent = this.toBase32(BigInt(timestamp), 10);
|
|
16118
|
+
const counterComponent = this.toBase32(BigInt(this.sequence), 4);
|
|
16119
|
+
const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
|
|
16120
|
+
const randomComponent = this.toBase32(BigInt(random), 4);
|
|
16121
|
+
return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
|
|
16122
|
+
}
|
|
16123
|
+
/**
|
|
16124
|
+
* Validates if a string matches the expected ID format
|
|
16125
|
+
*/
|
|
16126
|
+
static isValid(id) {
|
|
16127
|
+
if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
|
|
16128
|
+
return false;
|
|
16129
|
+
try {
|
|
16130
|
+
const timeComponent = id.slice(0, 10);
|
|
16131
|
+
const timestamp = this.decodeBase32(timeComponent);
|
|
16132
|
+
const now = Date.now() - this.epoch;
|
|
16133
|
+
return timestamp >= 0 && timestamp <= now;
|
|
16134
|
+
}
|
|
16135
|
+
catch (_a) {
|
|
16136
|
+
return false;
|
|
16137
|
+
}
|
|
16138
|
+
}
|
|
16139
|
+
/**
|
|
16140
|
+
* Decode base32 string to number
|
|
16141
|
+
*/
|
|
16142
|
+
static decodeBase32(str) {
|
|
16143
|
+
let result = 0;
|
|
16144
|
+
for (const char of str) {
|
|
16145
|
+
result = result * 32 + this.base32Chars.indexOf(char);
|
|
16146
|
+
}
|
|
16147
|
+
return result;
|
|
16148
|
+
}
|
|
16149
|
+
/**
|
|
16150
|
+
* Extract timestamp from ID
|
|
16151
|
+
*/
|
|
16152
|
+
static getTimestamp(id) {
|
|
16153
|
+
if (!this.isValid(id))
|
|
16154
|
+
throw new Error('Invalid ID format');
|
|
16155
|
+
const timeComponent = id.slice(0, 10);
|
|
16156
|
+
const timestamp = this.decodeBase32(timeComponent);
|
|
16157
|
+
return new Date(timestamp + this.epoch);
|
|
16158
|
+
}
|
|
16159
|
+
}
|
|
16160
|
+
// Constants for bit manipulation
|
|
16161
|
+
UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
|
|
16162
|
+
UniqueIdGenerator.nodeBits = 10;
|
|
16163
|
+
UniqueIdGenerator.sequenceBits = 12;
|
|
16164
|
+
// Instance variables
|
|
16165
|
+
UniqueIdGenerator.lastTimestamp = -1;
|
|
16166
|
+
UniqueIdGenerator.sequence = 0;
|
|
16167
|
+
// Character set for base32 encoding (excluding similar looking characters)
|
|
16168
|
+
UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
16169
|
+
|
|
16170
|
+
function convertHexToRgba(hex, opacity = 1) {
|
|
16171
|
+
// Remove # if present
|
|
16172
|
+
const cleanHex = hex.replace('#', '');
|
|
16173
|
+
// Convert hex to RGB
|
|
16174
|
+
const r = parseInt(cleanHex.substring(0, 2), 16);
|
|
16175
|
+
const g = parseInt(cleanHex.substring(2, 4), 16);
|
|
16176
|
+
const b = parseInt(cleanHex.substring(4, 6), 16);
|
|
16177
|
+
// Return rgba string
|
|
16178
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
16179
|
+
}
|
|
16180
|
+
function generateGradientColor(overlay, fallback = '') {
|
|
16181
|
+
if (!overlay) {
|
|
16182
|
+
return fallback;
|
|
16183
|
+
}
|
|
16184
|
+
const OVERLAY_SIZE = {
|
|
16185
|
+
small: 10,
|
|
16186
|
+
base: 30,
|
|
16187
|
+
large: 50,
|
|
16188
|
+
};
|
|
16189
|
+
const OVERLAY_OPACITY = {
|
|
16190
|
+
light: 0.1,
|
|
16191
|
+
medium: 0.4,
|
|
16192
|
+
dark: 0.6,
|
|
16193
|
+
};
|
|
16194
|
+
const { size, opacity, color } = overlay;
|
|
16195
|
+
const goTo = OVERLAY_SIZE[size];
|
|
16196
|
+
const overlayOpacity = OVERLAY_OPACITY[opacity];
|
|
16197
|
+
const fullColor = convertHexToRgba(color, 1);
|
|
16198
|
+
const transparentColor = convertHexToRgba(color, 0);
|
|
16199
|
+
const gradientColor = convertHexToRgba(color, overlayOpacity);
|
|
16200
|
+
return `${fullColor} 0%, ${gradientColor} ${goTo}%, ${transparentColor} 100%`;
|
|
16201
|
+
}
|
|
16202
|
+
function spotHtmlStringToElement(htmlString) {
|
|
16203
|
+
const spot = document.createElement('div');
|
|
16204
|
+
spot.className = 'spot';
|
|
16205
|
+
spot.innerHTML = htmlString;
|
|
16206
|
+
Object.assign(spot.style, {
|
|
16207
|
+
position: 'relative',
|
|
16208
|
+
display: 'block',
|
|
16209
|
+
width: '100%',
|
|
16210
|
+
height: '100%',
|
|
16211
|
+
margin: '0',
|
|
16212
|
+
padding: '0',
|
|
16213
|
+
});
|
|
16214
|
+
return spot;
|
|
16215
|
+
}
|
|
16216
|
+
|
|
16217
|
+
const STYLES$i = ({ primaryImage, secondaryImage }) => `
|
|
16218
|
+
<style>
|
|
16219
|
+
.content {
|
|
16220
|
+
width: 100%;
|
|
16221
|
+
height: 100%;
|
|
16222
|
+
display: flex;
|
|
16223
|
+
flex-direction: row;
|
|
16224
|
+
background-color: #FFFFFF;
|
|
16225
|
+
gap: 0.5cqw;
|
|
16226
|
+
cursor: pointer;
|
|
16227
|
+
color: inherit;
|
|
16228
|
+
}
|
|
16229
|
+
.big-image {
|
|
16230
|
+
width: 65%;
|
|
16231
|
+
height: 100%;
|
|
16232
|
+
background-image: url("${primaryImage}");
|
|
16233
|
+
background-position: center;
|
|
16234
|
+
background-repeat: no-repeat;
|
|
16235
|
+
background-size: cover;
|
|
16236
|
+
}
|
|
16237
|
+
.main {
|
|
16238
|
+
width: 35%;
|
|
16239
|
+
height: 100%;
|
|
16240
|
+
display: flex;
|
|
16241
|
+
flex-direction: column;
|
|
16242
|
+
gap: 0.5cqw;
|
|
16243
|
+
}
|
|
16244
|
+
.small-image {
|
|
16245
|
+
width: 100%;
|
|
16246
|
+
height: 50%;
|
|
16247
|
+
background-image: url("${secondaryImage}");
|
|
16248
|
+
background-position: center;
|
|
16249
|
+
background-repeat: no-repeat;
|
|
16250
|
+
background-size: cover;
|
|
16251
|
+
}
|
|
16252
|
+
.text {
|
|
16253
|
+
background: #E8E6DE;
|
|
16254
|
+
text-align: center;
|
|
16255
|
+
display: flex;
|
|
16256
|
+
flex-direction: column;
|
|
16257
|
+
justify-content: center;
|
|
16258
|
+
align-items: center;
|
|
16259
|
+
height: 50%;
|
|
16260
|
+
width: 100%;
|
|
16261
|
+
padding: 5% 10%;
|
|
16262
|
+
box-sizing: border-box;
|
|
16263
|
+
font-family: "Source Sans 3", sans-serif;
|
|
16264
|
+
}
|
|
16265
|
+
.header {
|
|
16266
|
+
font-size: 2.2cqw;
|
|
16267
|
+
color: #000000;
|
|
16268
|
+
font-style: normal;
|
|
16269
|
+
font-weight: 400;
|
|
16270
|
+
font-family: "Cormorant", serif;
|
|
16271
|
+
margin: 0;
|
|
16272
|
+
}
|
|
16273
|
+
.description {
|
|
16274
|
+
font-size: 1.2cqw;
|
|
16275
|
+
color: #000000;
|
|
16276
|
+
font-style: normal;
|
|
16277
|
+
font-weight: 400;
|
|
16278
|
+
margin: 1cqh 0;
|
|
16279
|
+
}
|
|
16280
|
+
.button {
|
|
16281
|
+
font-size: 1cqw;
|
|
16282
|
+
color: #000000;
|
|
16283
|
+
background-color: transparent;
|
|
16284
|
+
font-style: normal;
|
|
16285
|
+
font-weight: 700;
|
|
16286
|
+
text-decoration: underline;
|
|
16287
|
+
text-transform: uppercase;
|
|
16288
|
+
border: none;
|
|
16289
|
+
cursor: pointer;
|
|
16290
|
+
padding: 0;
|
|
16291
|
+
transition: opacity 0.3s ease;
|
|
16292
|
+
}
|
|
16293
|
+
.content:hover .button {
|
|
16294
|
+
opacity: 0.7;
|
|
16295
|
+
}
|
|
16296
|
+
@container (max-width: 600px) {
|
|
16297
|
+
.header {
|
|
16298
|
+
font-size: 3cqw;
|
|
16299
|
+
}
|
|
16300
|
+
.description {
|
|
16301
|
+
font-size: 1.6cqw;
|
|
16302
|
+
margin: 0;
|
|
16303
|
+
}
|
|
16304
|
+
.button {
|
|
16305
|
+
font-size: 1.4cqw;
|
|
16306
|
+
}
|
|
16307
|
+
}
|
|
16308
|
+
</style>
|
|
16309
|
+
`;
|
|
16310
|
+
function billboardV1Template(spot) {
|
|
16311
|
+
return `
|
|
16312
|
+
${GFONT_PRECONNECT}
|
|
16313
|
+
${GFONT_SOURCE_SANS_3}
|
|
16314
|
+
${GFONT_CORMORANT}
|
|
15301
16315
|
${STYLES$i(spot)}
|
|
15302
16316
|
<div class="content">
|
|
15303
16317
|
<div class="big-image"></div>
|
|
@@ -16017,185 +17031,204 @@ function wideSkyscraperV1Template(spot) {
|
|
|
16017
17031
|
`;
|
|
16018
17032
|
}
|
|
16019
17033
|
|
|
16020
|
-
const STYLES$7 = ({ primaryImage, mobilePrimaryImage = primaryImage }) => `
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
|
|
16035
|
-
}
|
|
16036
|
-
|
|
16037
|
-
.content {
|
|
16038
|
-
background-image: url("${primaryImage}");
|
|
16039
|
-
}
|
|
17034
|
+
const STYLES$7 = ({ primaryImage, mobilePrimaryImage = primaryImage }, { prefix }) => `
|
|
17035
|
+
<style>
|
|
17036
|
+
.${prefix} {
|
|
17037
|
+
display: block;
|
|
17038
|
+
width: 100%;
|
|
17039
|
+
height: 100%;
|
|
17040
|
+
background-image: url("${mobilePrimaryImage}");
|
|
17041
|
+
background-size: cover;
|
|
17042
|
+
background-repeat: no-repeat;
|
|
17043
|
+
background-position: center;
|
|
17044
|
+
cursor: pointer;
|
|
17045
|
+
container-type: inline-size;
|
|
17046
|
+
}
|
|
17047
|
+
|
|
17048
|
+
@container (min-width: 640px) {
|
|
17049
|
+
.${prefix} {
|
|
17050
|
+
background-image: url("${primaryImage}");
|
|
16040
17051
|
}
|
|
16041
|
-
|
|
17052
|
+
}
|
|
17053
|
+
</style>
|
|
16042
17054
|
`;
|
|
16043
|
-
function rbCollectionBannerWithoutTextBlockTemplate(spot) {
|
|
17055
|
+
function rbCollectionBannerWithoutTextBlockTemplate(spot, config) {
|
|
17056
|
+
const { prefix = '' } = config;
|
|
16044
17057
|
return `
|
|
16045
|
-
${STYLES$7(spot)}
|
|
16046
|
-
<div class="
|
|
17058
|
+
${STYLES$7(spot, config)}
|
|
17059
|
+
<div class="${prefix}"></div>
|
|
16047
17060
|
`;
|
|
16048
17061
|
}
|
|
16049
17062
|
|
|
16050
|
-
const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }) =>
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
.content {
|
|
16057
|
-
display: flex;
|
|
16058
|
-
flex-direction: column;
|
|
16059
|
-
justify-content: flex-end;
|
|
16060
|
-
align-items: flex-start;
|
|
16061
|
-
width: 100%;
|
|
16062
|
-
height: 100%;
|
|
16063
|
-
background-image: url("${mobilePrimaryImage}");
|
|
16064
|
-
background-size: cover;
|
|
16065
|
-
background-repeat: no-repeat;
|
|
16066
|
-
background-position: center;
|
|
16067
|
-
padding: 3%;
|
|
16068
|
-
box-sizing: border-box;
|
|
16069
|
-
color: ${textColor};
|
|
16070
|
-
cursor: pointer;
|
|
16071
|
-
}
|
|
16072
|
-
.text {
|
|
16073
|
-
display: flex;
|
|
16074
|
-
flex-direction: column;
|
|
16075
|
-
justify-content: flex-start;
|
|
16076
|
-
align-items: flex-start;
|
|
16077
|
-
width: 100%;
|
|
16078
|
-
height: fit-content;
|
|
16079
|
-
gap: 5px;
|
|
16080
|
-
}
|
|
16081
|
-
.header {
|
|
16082
|
-
font-size: 18px;
|
|
16083
|
-
margin: 0;
|
|
16084
|
-
font-family: "Cormorant";
|
|
16085
|
-
font-style: normal;
|
|
16086
|
-
font-weight: 300;
|
|
16087
|
-
line-height: normal;
|
|
16088
|
-
}
|
|
16089
|
-
.description {
|
|
16090
|
-
font-size: 10px;
|
|
16091
|
-
font-family: "Source Sans 3", system-ui;
|
|
16092
|
-
font-style: normal;
|
|
16093
|
-
font-weight: 400;
|
|
16094
|
-
line-height: 20px;
|
|
16095
|
-
margin: 0;
|
|
16096
|
-
}
|
|
16097
|
-
.cta-button {
|
|
16098
|
-
font-size: 8px;
|
|
16099
|
-
font-family: "Source Sans 3", system-ui;
|
|
16100
|
-
font-style: normal;
|
|
16101
|
-
font-weight: 400;
|
|
16102
|
-
line-height: 18px;
|
|
16103
|
-
border-radius: 5px;
|
|
16104
|
-
border: 0.5px solid ${ctaBorderColor};
|
|
16105
|
-
display: inline-block;
|
|
16106
|
-
padding: 7px 20px;
|
|
16107
|
-
color: ${ctaTextColor};
|
|
16108
|
-
transition: background-color 0.3s ease;
|
|
16109
|
-
}
|
|
16110
|
-
.content:hover .cta-button {
|
|
16111
|
-
background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
|
|
16112
|
-
}
|
|
16113
|
-
@media (min-width: 640px) {
|
|
16114
|
-
.content {
|
|
16115
|
-
background-image: url("${primaryImage}");
|
|
16116
|
-
}
|
|
16117
|
-
}
|
|
16118
|
-
@media (min-width: 768px) {
|
|
16119
|
-
.primary-image {
|
|
16120
|
-
width: 66.66666%;
|
|
16121
|
-
height: 100%;
|
|
16122
|
-
}
|
|
16123
|
-
.main {
|
|
17063
|
+
const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
|
|
17064
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 40%');
|
|
17065
|
+
return `
|
|
17066
|
+
<style>
|
|
17067
|
+
.${prefix} {
|
|
17068
|
+
display: flex;
|
|
16124
17069
|
flex-direction: column;
|
|
17070
|
+
justify-content: flex-end;
|
|
17071
|
+
align-items: flex-start;
|
|
17072
|
+
width: 100%;
|
|
16125
17073
|
height: 100%;
|
|
16126
|
-
|
|
17074
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
|
|
17075
|
+
background-size: cover;
|
|
17076
|
+
background-repeat: no-repeat;
|
|
17077
|
+
background-position: center;
|
|
17078
|
+
padding: 3%;
|
|
17079
|
+
box-sizing: border-box;
|
|
17080
|
+
color: ${textColor};
|
|
17081
|
+
cursor: pointer;
|
|
17082
|
+
container-type: inline-size;
|
|
16127
17083
|
}
|
|
16128
|
-
|
|
17084
|
+
|
|
17085
|
+
.${prefix}__text {
|
|
17086
|
+
display: flex;
|
|
17087
|
+
flex-direction: column;
|
|
17088
|
+
justify-content: flex-start;
|
|
17089
|
+
align-items: flex-start;
|
|
16129
17090
|
width: 100%;
|
|
16130
|
-
height:
|
|
17091
|
+
height: fit-content;
|
|
17092
|
+
gap: 8px;
|
|
16131
17093
|
}
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
}
|
|
16135
|
-
.description {
|
|
16136
|
-
font-size: 12px;
|
|
16137
|
-
}
|
|
16138
|
-
.cta-button {
|
|
16139
|
-
font-size: 12px;
|
|
16140
|
-
}
|
|
16141
|
-
}
|
|
16142
|
-
@media (min-width: 1024px) {
|
|
16143
|
-
.header {
|
|
17094
|
+
|
|
17095
|
+
.${prefix}__header {
|
|
16144
17096
|
font-size: 24px;
|
|
17097
|
+
margin: 0;
|
|
17098
|
+
font-family: "Cormorant";
|
|
17099
|
+
font-style: normal;
|
|
17100
|
+
font-weight: 300;
|
|
17101
|
+
line-height: normal;
|
|
16145
17102
|
}
|
|
16146
|
-
|
|
16147
|
-
|
|
17103
|
+
|
|
17104
|
+
.${prefix}__description {
|
|
17105
|
+
font-size: 10px;
|
|
17106
|
+
font-family: "Source Sans 3", system-ui;
|
|
17107
|
+
font-style: normal;
|
|
17108
|
+
font-weight: 400;
|
|
17109
|
+
line-height: 20px;
|
|
17110
|
+
margin: 0;
|
|
16148
17111
|
}
|
|
16149
|
-
|
|
16150
|
-
|
|
17112
|
+
|
|
17113
|
+
.${prefix}__cta-button {
|
|
17114
|
+
font-size: 8px;
|
|
17115
|
+
font-family: "Source Sans 3", system-ui;
|
|
17116
|
+
font-style: normal;
|
|
17117
|
+
font-weight: 400;
|
|
17118
|
+
line-height: 18px;
|
|
17119
|
+
border-radius: 5px;
|
|
17120
|
+
border: 0.5px solid ${ctaBorderColor};
|
|
17121
|
+
display: inline-block;
|
|
17122
|
+
padding: 7px 20px;
|
|
17123
|
+
color: ${ctaTextColor};
|
|
17124
|
+
transition: background-color 0.3s ease;
|
|
16151
17125
|
}
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
font-size: 28px;
|
|
17126
|
+
|
|
17127
|
+
.${prefix}:hover .cta-button {
|
|
17128
|
+
background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
|
|
16156
17129
|
}
|
|
16157
|
-
|
|
16158
|
-
|
|
17130
|
+
|
|
17131
|
+
@container (min-width: 640px) {
|
|
17132
|
+
.${prefix} {
|
|
17133
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
|
17134
|
+
}
|
|
16159
17135
|
}
|
|
16160
|
-
|
|
16161
|
-
|
|
17136
|
+
|
|
17137
|
+
@container (min-width: 768px) {
|
|
17138
|
+
.${prefix}__primary-image {
|
|
17139
|
+
width: 66.66666%;
|
|
17140
|
+
height: 100%;
|
|
17141
|
+
}
|
|
17142
|
+
|
|
17143
|
+
.${prefix}__main {
|
|
17144
|
+
flex-direction: column;
|
|
17145
|
+
height: 100%;
|
|
17146
|
+
width: 33.33333%;
|
|
17147
|
+
}
|
|
17148
|
+
|
|
17149
|
+
.${prefix}__secondary-image {
|
|
17150
|
+
width: 100%;
|
|
17151
|
+
height: 50%;
|
|
17152
|
+
}
|
|
17153
|
+
|
|
17154
|
+
.${prefix}__description {
|
|
17155
|
+
font-size: 12px;
|
|
17156
|
+
}
|
|
17157
|
+
|
|
17158
|
+
.${prefix}__cta-button {
|
|
17159
|
+
font-size: 12px;
|
|
17160
|
+
}
|
|
16162
17161
|
}
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
|
|
16166
|
-
|
|
17162
|
+
|
|
17163
|
+
@container (min-width: 1024px) {
|
|
17164
|
+
.${prefix}__header {
|
|
17165
|
+
font-size: 26px;
|
|
17166
|
+
}
|
|
17167
|
+
|
|
17168
|
+
.${prefix}__description {
|
|
17169
|
+
font-size: 13px;
|
|
17170
|
+
}
|
|
17171
|
+
|
|
17172
|
+
.${prefix}__cta-button {
|
|
17173
|
+
font-size: 13px;
|
|
17174
|
+
}
|
|
17175
|
+
}
|
|
17176
|
+
|
|
17177
|
+
@container (min-width: 1280px) {
|
|
17178
|
+
.${prefix}__header {
|
|
17179
|
+
font-size: 28px;
|
|
17180
|
+
}
|
|
17181
|
+
|
|
17182
|
+
.${prefix}__description {
|
|
17183
|
+
font-size: 14px;
|
|
17184
|
+
}
|
|
17185
|
+
|
|
17186
|
+
.${prefix}__cta-button {
|
|
17187
|
+
font-size: 14px;
|
|
17188
|
+
}
|
|
17189
|
+
}
|
|
17190
|
+
</style>
|
|
17191
|
+
`;
|
|
17192
|
+
};
|
|
17193
|
+
function rbHomepageHeroFullImageTemplate(spot, config) {
|
|
17194
|
+
const { prefix = '' } = config;
|
|
16167
17195
|
return `
|
|
16168
17196
|
${GFONT_PRECONNECT}
|
|
16169
17197
|
${GFONT_SOURCE_SANS_3}
|
|
16170
17198
|
${GFONT_CORMORANT}
|
|
16171
|
-
${STYLES$6(spot)}
|
|
16172
|
-
<div class="
|
|
16173
|
-
|
|
16174
|
-
|
|
16175
|
-
|
|
16176
|
-
|
|
16177
|
-
|
|
17199
|
+
${STYLES$6(spot, config)}
|
|
17200
|
+
<div class="${prefix}">
|
|
17201
|
+
<div class="${prefix}__text">
|
|
17202
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
17203
|
+
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
|
17204
|
+
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
|
17205
|
+
</div>
|
|
16178
17206
|
</div>
|
|
16179
17207
|
`;
|
|
16180
17208
|
}
|
|
16181
17209
|
|
|
16182
|
-
const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, secondaryImage, mobileSecondaryImage = secondaryImage, }) => `
|
|
16183
|
-
|
|
16184
|
-
|
|
16185
|
-
|
|
16186
|
-
|
|
17210
|
+
const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, secondaryImage, mobileSecondaryImage = secondaryImage, }, { prefix }) => `
|
|
17211
|
+
<style>
|
|
17212
|
+
.${prefix} {
|
|
17213
|
+
width: 100%;
|
|
17214
|
+
height: 100%;
|
|
17215
|
+
display: block;
|
|
17216
|
+
position: relative;
|
|
17217
|
+
container-type: inline-size;
|
|
16187
17218
|
}
|
|
16188
|
-
|
|
17219
|
+
|
|
17220
|
+
.${prefix}__content {
|
|
16189
17221
|
width: 100%;
|
|
16190
17222
|
height: 100%;
|
|
16191
17223
|
display: flex;
|
|
16192
|
-
flex-direction: column;
|
|
17224
|
+
flex-direction: column;
|
|
16193
17225
|
background-color: transparent;
|
|
16194
|
-
gap:
|
|
17226
|
+
gap: 6px;
|
|
16195
17227
|
color: inherit;
|
|
16196
17228
|
cursor: pointer;
|
|
16197
17229
|
}
|
|
16198
|
-
|
|
17230
|
+
|
|
17231
|
+
.${prefix}__primary-image {
|
|
16199
17232
|
width: 100%;
|
|
16200
17233
|
height: 60%;
|
|
16201
17234
|
background-image: url("${mobilePrimaryImage}");
|
|
@@ -16203,14 +17236,16 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16203
17236
|
background-repeat: no-repeat;
|
|
16204
17237
|
background-size: cover;
|
|
16205
17238
|
}
|
|
16206
|
-
|
|
17239
|
+
|
|
17240
|
+
.${prefix}__main {
|
|
16207
17241
|
width: 100%;
|
|
16208
17242
|
height: 40%;
|
|
16209
17243
|
display: flex;
|
|
16210
17244
|
flex-direction: row;
|
|
16211
|
-
|
|
17245
|
+
gap: 6px;
|
|
16212
17246
|
}
|
|
16213
|
-
|
|
17247
|
+
|
|
17248
|
+
.${prefix}__secondary-image {
|
|
16214
17249
|
width: 50%;
|
|
16215
17250
|
height: 100%;
|
|
16216
17251
|
background-image: url("${mobileSecondaryImage}");
|
|
@@ -16218,7 +17253,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16218
17253
|
background-repeat: no-repeat;
|
|
16219
17254
|
background-size: cover;
|
|
16220
17255
|
}
|
|
16221
|
-
|
|
17256
|
+
|
|
17257
|
+
.${prefix}__text {
|
|
16222
17258
|
color: ${textColor};
|
|
16223
17259
|
background-color: ${backgroundColor};
|
|
16224
17260
|
text-align: center;
|
|
@@ -16228,11 +17264,12 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16228
17264
|
align-items: center;
|
|
16229
17265
|
width: 50%;
|
|
16230
17266
|
height: 100%;
|
|
16231
|
-
gap:
|
|
17267
|
+
gap: 10px;
|
|
16232
17268
|
padding: 0 10px;
|
|
16233
17269
|
box-sizing: border-box;
|
|
16234
17270
|
}
|
|
16235
|
-
|
|
17271
|
+
|
|
17272
|
+
.${prefix}__header {
|
|
16236
17273
|
color: inherit;
|
|
16237
17274
|
margin: 0;
|
|
16238
17275
|
font-size: 18px;
|
|
@@ -16241,7 +17278,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16241
17278
|
font-weight: 700;
|
|
16242
17279
|
line-height: normal;
|
|
16243
17280
|
}
|
|
16244
|
-
|
|
17281
|
+
|
|
17282
|
+
.${prefix}__description {
|
|
16245
17283
|
color: inherit;
|
|
16246
17284
|
margin: 0;
|
|
16247
17285
|
font-size: 10px;
|
|
@@ -16249,7 +17287,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16249
17287
|
font-style: normal;
|
|
16250
17288
|
font-weight: 400;
|
|
16251
17289
|
}
|
|
16252
|
-
|
|
17290
|
+
|
|
17291
|
+
.${prefix}__cta-button {
|
|
16253
17292
|
color: ${ctaTextColor};
|
|
16254
17293
|
background-color: transparent;
|
|
16255
17294
|
font-size: 8px;
|
|
@@ -16264,108 +17303,120 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16264
17303
|
padding: 0;
|
|
16265
17304
|
transition: opacity 0.3s ease;
|
|
16266
17305
|
}
|
|
16267
|
-
|
|
17306
|
+
|
|
17307
|
+
.${prefix}__content:hover .${prefix}__cta-button {
|
|
16268
17308
|
opacity: 0.8;
|
|
16269
17309
|
}
|
|
16270
|
-
|
|
16271
|
-
|
|
17310
|
+
|
|
17311
|
+
@container (min-width: 640px) {
|
|
17312
|
+
.${prefix}__primary-image {
|
|
16272
17313
|
background-image: url("${primaryImage}");
|
|
16273
17314
|
}
|
|
16274
|
-
|
|
17315
|
+
|
|
17316
|
+
.${prefix}__secondary-image {
|
|
16275
17317
|
background-image: url("${secondaryImage}");
|
|
16276
17318
|
}
|
|
16277
17319
|
}
|
|
16278
|
-
|
|
16279
|
-
|
|
17320
|
+
|
|
17321
|
+
@container (min-width: 768px) {
|
|
17322
|
+
.${prefix}__content {
|
|
16280
17323
|
flex-direction: row;
|
|
16281
17324
|
}
|
|
16282
|
-
|
|
17325
|
+
|
|
17326
|
+
.${prefix}__primary-image {
|
|
16283
17327
|
width: 66.66666%;
|
|
16284
17328
|
height: 100%;
|
|
16285
17329
|
}
|
|
16286
|
-
|
|
17330
|
+
|
|
17331
|
+
.${prefix}__main {
|
|
16287
17332
|
flex-direction: column;
|
|
16288
17333
|
height: 100%;
|
|
16289
17334
|
width: 33.33333%;
|
|
16290
17335
|
}
|
|
16291
|
-
|
|
17336
|
+
|
|
17337
|
+
.${prefix}__secondary-image {
|
|
16292
17338
|
width: 100%;
|
|
16293
17339
|
height: 50%;
|
|
16294
17340
|
}
|
|
16295
|
-
|
|
17341
|
+
|
|
17342
|
+
.${prefix}__text {
|
|
16296
17343
|
width: 100%;
|
|
16297
17344
|
height: 50%;
|
|
16298
17345
|
}
|
|
16299
|
-
|
|
17346
|
+
.${prefix}__header {
|
|
16300
17347
|
font-size: 22px;
|
|
16301
17348
|
}
|
|
16302
|
-
|
|
17349
|
+
.${prefix}__description {
|
|
16303
17350
|
font-size: 12px;
|
|
16304
17351
|
}
|
|
16305
|
-
|
|
17352
|
+
.${prefix}__cta-button {
|
|
16306
17353
|
font-size: 12px;
|
|
16307
17354
|
}
|
|
16308
17355
|
}
|
|
16309
|
-
|
|
16310
|
-
|
|
17356
|
+
|
|
17357
|
+
@container (min-width: 1024px) {
|
|
17358
|
+
.${prefix}__header {
|
|
16311
17359
|
font-size: 24px;
|
|
16312
17360
|
}
|
|
16313
|
-
|
|
17361
|
+
.${prefix}__description {
|
|
16314
17362
|
font-size: 13px;
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
17363
|
+
}
|
|
17364
|
+
.${prefix}__cta-button {
|
|
17365
|
+
font-size: 13px;
|
|
17366
|
+
}
|
|
16319
17367
|
}
|
|
16320
|
-
|
|
16321
|
-
|
|
17368
|
+
|
|
17369
|
+
@container (min-width: 1280px) {
|
|
17370
|
+
.${prefix}__header {
|
|
16322
17371
|
font-size: 28px;
|
|
16323
17372
|
}
|
|
16324
|
-
|
|
17373
|
+
.${prefix}__description {
|
|
16325
17374
|
font-size: 14px;
|
|
16326
17375
|
}
|
|
16327
|
-
|
|
17376
|
+
.${prefix}__cta-button {
|
|
16328
17377
|
font-size: 14px;
|
|
16329
17378
|
}
|
|
16330
17379
|
}
|
|
16331
|
-
|
|
17380
|
+
</style>
|
|
16332
17381
|
`;
|
|
16333
|
-
function rbHomepageHeroThreeTileTemplate(spot) {
|
|
17382
|
+
function rbHomepageHeroThreeTileTemplate(spot, config) {
|
|
17383
|
+
const { prefix = '' } = config;
|
|
16334
17384
|
return `
|
|
16335
17385
|
${GFONT_PRECONNECT}
|
|
16336
17386
|
${GFONT_SOURCE_SANS_3}
|
|
16337
17387
|
${GFONT_CORMORANT}
|
|
16338
|
-
${STYLES$5(spot)}
|
|
16339
|
-
<div class="
|
|
16340
|
-
<div class="
|
|
16341
|
-
|
|
16342
|
-
<div class="
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
17388
|
+
${STYLES$5(spot, config)}
|
|
17389
|
+
<div class="${prefix}">
|
|
17390
|
+
<div class="${prefix}__content">
|
|
17391
|
+
<div class="${prefix}__primary-image"></div>
|
|
17392
|
+
<div class="${prefix}__main">
|
|
17393
|
+
<div class="${prefix}__secondary-image"></div>
|
|
17394
|
+
<div class="${prefix}__text">
|
|
17395
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
17396
|
+
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
|
17397
|
+
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
|
17398
|
+
</div>
|
|
16347
17399
|
</div>
|
|
16348
17400
|
</div>
|
|
16349
17401
|
</div>
|
|
16350
17402
|
`;
|
|
16351
17403
|
}
|
|
16352
17404
|
|
|
16353
|
-
const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, }) => `
|
|
17405
|
+
const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
|
|
16354
17406
|
<style>
|
|
16355
|
-
|
|
16356
|
-
min-width: 320px;
|
|
16357
|
-
min-height: 388px;
|
|
16358
|
-
}
|
|
16359
|
-
.content {
|
|
17407
|
+
.${prefix} {
|
|
16360
17408
|
width: 100%;
|
|
16361
17409
|
height: 100%;
|
|
16362
17410
|
display: flex;
|
|
16363
|
-
flex-direction: column-reverse;
|
|
17411
|
+
flex-direction: column-reverse;
|
|
16364
17412
|
background-color: transparent;
|
|
16365
|
-
gap:
|
|
17413
|
+
gap: 6px;
|
|
16366
17414
|
cursor: pointer;
|
|
17415
|
+
container-type: inline-size;
|
|
17416
|
+
position: relative;
|
|
16367
17417
|
}
|
|
16368
|
-
|
|
17418
|
+
|
|
17419
|
+
.${prefix}__image {
|
|
16369
17420
|
width: 100%;
|
|
16370
17421
|
height: 100%;
|
|
16371
17422
|
background-image: url("${mobilePrimaryImage}");
|
|
@@ -16373,7 +17424,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16373
17424
|
background-repeat: no-repeat;
|
|
16374
17425
|
background-size: cover;
|
|
16375
17426
|
}
|
|
16376
|
-
|
|
17427
|
+
|
|
17428
|
+
.${prefix}__text {
|
|
16377
17429
|
color: ${textColor};
|
|
16378
17430
|
background-color: ${backgroundColor};
|
|
16379
17431
|
text-align: center;
|
|
@@ -16383,11 +17435,12 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16383
17435
|
align-items: center;
|
|
16384
17436
|
width: 100%;
|
|
16385
17437
|
height: 100%;
|
|
16386
|
-
gap:
|
|
17438
|
+
gap: 10px;
|
|
16387
17439
|
padding: 0 10px;
|
|
16388
17440
|
box-sizing: border-box;
|
|
16389
17441
|
}
|
|
16390
|
-
|
|
17442
|
+
|
|
17443
|
+
.${prefix}__header {
|
|
16391
17444
|
font-size: 18px;
|
|
16392
17445
|
margin: 0;
|
|
16393
17446
|
color: inherit;
|
|
@@ -16396,7 +17449,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16396
17449
|
font-weight: 700;
|
|
16397
17450
|
line-height: normal;
|
|
16398
17451
|
}
|
|
16399
|
-
|
|
17452
|
+
|
|
17453
|
+
.${prefix}__description {
|
|
16400
17454
|
color: inherit;
|
|
16401
17455
|
margin: 0;
|
|
16402
17456
|
font-size: 10px;
|
|
@@ -16404,7 +17458,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16404
17458
|
font-style: normal;
|
|
16405
17459
|
font-weight: 400;
|
|
16406
17460
|
}
|
|
16407
|
-
|
|
17461
|
+
|
|
17462
|
+
.${prefix}__cta-button {
|
|
16408
17463
|
color: ${ctaTextColor};
|
|
16409
17464
|
background-color: transparent;
|
|
16410
17465
|
font-size: 8px;
|
|
@@ -16419,205 +17474,225 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
|
16419
17474
|
padding: 0;
|
|
16420
17475
|
transition: opacity 0.3s ease;
|
|
16421
17476
|
}
|
|
16422
|
-
|
|
17477
|
+
|
|
17478
|
+
.${prefix}__content:hover .${prefix}__cta-button {
|
|
16423
17479
|
opacity: 0.8;
|
|
16424
17480
|
}
|
|
16425
|
-
|
|
16426
|
-
|
|
17481
|
+
|
|
17482
|
+
@container (min-width: 640px) {
|
|
17483
|
+
.${prefix}__image {
|
|
16427
17484
|
background-image: url("${primaryImage}");
|
|
16428
17485
|
}
|
|
16429
17486
|
}
|
|
16430
|
-
|
|
16431
|
-
|
|
17487
|
+
|
|
17488
|
+
@container (min-width: 768px) {
|
|
17489
|
+
.${prefix} {
|
|
16432
17490
|
flex-direction: row;
|
|
16433
17491
|
}
|
|
16434
|
-
|
|
17492
|
+
.${prefix}__image {
|
|
16435
17493
|
width: 66.66666%;
|
|
16436
17494
|
height: 100%;
|
|
16437
17495
|
}
|
|
16438
|
-
|
|
16439
|
-
width: 33.
|
|
17496
|
+
.${prefix}__text {
|
|
17497
|
+
width: 33.33333%;
|
|
16440
17498
|
height: 100%;
|
|
16441
17499
|
}
|
|
16442
|
-
|
|
17500
|
+
.${prefix}__header {
|
|
16443
17501
|
font-size: 22px;
|
|
16444
17502
|
}
|
|
16445
|
-
|
|
17503
|
+
.${prefix}__description {
|
|
16446
17504
|
font-size: 12px;
|
|
16447
17505
|
}
|
|
16448
|
-
|
|
17506
|
+
.${prefix}__cta-button {
|
|
16449
17507
|
font-size: 12px;
|
|
16450
17508
|
}
|
|
16451
17509
|
}
|
|
16452
|
-
|
|
16453
|
-
|
|
17510
|
+
|
|
17511
|
+
@container (min-width: 1024px) {
|
|
17512
|
+
.${prefix}__header {
|
|
16454
17513
|
font-size: 24px;
|
|
16455
17514
|
}
|
|
16456
|
-
|
|
17515
|
+
.${prefix}__description {
|
|
16457
17516
|
font-size: 13px;
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
17517
|
+
}
|
|
17518
|
+
.${prefix}__cta-button {
|
|
17519
|
+
font-size: 13px;
|
|
17520
|
+
}
|
|
16462
17521
|
}
|
|
16463
|
-
|
|
16464
|
-
|
|
17522
|
+
|
|
17523
|
+
@container (min-width: 1280px) {
|
|
17524
|
+
.${prefix}__header {
|
|
16465
17525
|
font-size: 28px;
|
|
16466
17526
|
}
|
|
16467
|
-
|
|
17527
|
+
.${prefix}__description {
|
|
16468
17528
|
font-size: 14px;
|
|
16469
17529
|
}
|
|
16470
|
-
|
|
17530
|
+
.${prefix}__cta-button {
|
|
16471
17531
|
font-size: 14px;
|
|
16472
17532
|
}
|
|
16473
17533
|
}
|
|
16474
17534
|
</style>
|
|
16475
17535
|
`;
|
|
16476
|
-
function rbHomepageHeroTwoTileTemplate(spot) {
|
|
17536
|
+
function rbHomepageHeroTwoTileTemplate(spot, config) {
|
|
17537
|
+
const { prefix = '' } = config;
|
|
16477
17538
|
return `
|
|
16478
17539
|
${GFONT_PRECONNECT}
|
|
16479
17540
|
${GFONT_SOURCE_SANS_3}
|
|
16480
17541
|
${GFONT_CORMORANT}
|
|
16481
|
-
${STYLES$4(spot)}
|
|
16482
|
-
<div class="
|
|
16483
|
-
<div class="
|
|
16484
|
-
${spot.header ? `<h2 class="
|
|
16485
|
-
${spot.description ? `<p class="
|
|
16486
|
-
${spot.ctaText ? `<span class="
|
|
17542
|
+
${STYLES$4(spot, config)}
|
|
17543
|
+
<div class="${prefix}">
|
|
17544
|
+
<div class="${prefix}__text">
|
|
17545
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
17546
|
+
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
|
17547
|
+
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
|
16487
17548
|
</div>
|
|
16488
|
-
<div class="
|
|
17549
|
+
<div class="${prefix}__image"></div>
|
|
16489
17550
|
</div>
|
|
16490
17551
|
`;
|
|
16491
17552
|
}
|
|
16492
17553
|
|
|
16493
|
-
const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }) =>
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
16507
|
-
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
|
|
16512
|
-
color: ${textColor};
|
|
16513
|
-
}
|
|
16514
|
-
.text {
|
|
16515
|
-
padding: 20px;
|
|
16516
|
-
width: 70%;
|
|
16517
|
-
display: flex;
|
|
16518
|
-
flex-direction: column;
|
|
16519
|
-
justify-content: center;
|
|
16520
|
-
align-items: flex-start;
|
|
16521
|
-
gap: 10px;
|
|
16522
|
-
}
|
|
16523
|
-
.header {
|
|
16524
|
-
color: inherit;
|
|
16525
|
-
margin: 0;
|
|
16526
|
-
font-size: 20px;
|
|
16527
|
-
font-family: "Cormorant";
|
|
16528
|
-
font-style: normal;
|
|
16529
|
-
font-weight: 300;
|
|
16530
|
-
line-height: normal;
|
|
16531
|
-
}
|
|
16532
|
-
.description {
|
|
16533
|
-
color: inherit;
|
|
16534
|
-
font-size: 12px;
|
|
16535
|
-
line-height: 16px;
|
|
16536
|
-
font-family: "Source Sans 3", system-ui;
|
|
16537
|
-
font-style: normal;
|
|
16538
|
-
font-weight: 400;
|
|
16539
|
-
margin: 0;
|
|
16540
|
-
}
|
|
16541
|
-
.cta-button {
|
|
16542
|
-
width: fit-content;
|
|
16543
|
-
display: inline-block;
|
|
16544
|
-
padding: 7px 20px;
|
|
16545
|
-
border: 0.5px solid ${ctaBorderColor};
|
|
16546
|
-
border-radius: 5px;
|
|
16547
|
-
color: ${ctaTextColor};
|
|
16548
|
-
font-size: 8px;
|
|
16549
|
-
transition: background-color 0.3s ease;
|
|
16550
|
-
font-family: "Source Sans 3", system-ui;
|
|
16551
|
-
font-style: normal;
|
|
16552
|
-
font-weight: 400;
|
|
16553
|
-
}
|
|
16554
|
-
.content:hover .cta-button {
|
|
16555
|
-
background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
|
|
16556
|
-
}
|
|
16557
|
-
@media (min-width: 640px) {
|
|
16558
|
-
.content {
|
|
16559
|
-
background-image: url("${primaryImage}");
|
|
16560
|
-
}
|
|
16561
|
-
}
|
|
16562
|
-
@media (min-width: 768px) {
|
|
16563
|
-
.text {
|
|
16564
|
-
padding: 25px;
|
|
17554
|
+
const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
|
|
17555
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
|
17556
|
+
return `
|
|
17557
|
+
<style>
|
|
17558
|
+
.${prefix} {
|
|
17559
|
+
width: 100%;
|
|
17560
|
+
height: 100%;
|
|
17561
|
+
display: flex;
|
|
17562
|
+
flex-direction: column;
|
|
17563
|
+
justify-content: flex-end;
|
|
17564
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
|
|
17565
|
+
background-size: cover;
|
|
17566
|
+
background-repeat: no-repeat;
|
|
17567
|
+
background-position: center;
|
|
17568
|
+
border-radius: 5px;
|
|
17569
|
+
overflow: hidden;
|
|
17570
|
+
cursor: pointer;
|
|
17571
|
+
color: ${textColor};
|
|
17572
|
+
container-type: inline-size;
|
|
16565
17573
|
}
|
|
16566
|
-
|
|
16567
|
-
|
|
17574
|
+
|
|
17575
|
+
.${prefix}__text {
|
|
17576
|
+
padding: 20px;
|
|
17577
|
+
width: 70%;
|
|
17578
|
+
display: flex;
|
|
17579
|
+
flex-direction: column;
|
|
17580
|
+
justify-content: center;
|
|
17581
|
+
align-items: flex-start;
|
|
17582
|
+
gap: 10px;
|
|
16568
17583
|
}
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
17584
|
+
|
|
17585
|
+
.${prefix}__header {
|
|
17586
|
+
color: inherit;
|
|
17587
|
+
margin: 0;
|
|
17588
|
+
font-size: 20px;
|
|
17589
|
+
font-family: "Cormorant";
|
|
17590
|
+
font-style: normal;
|
|
17591
|
+
font-weight: 300;
|
|
17592
|
+
line-height: normal;
|
|
16572
17593
|
}
|
|
16573
|
-
|
|
17594
|
+
|
|
17595
|
+
.${prefix}__description {
|
|
17596
|
+
color: inherit;
|
|
16574
17597
|
font-size: 12px;
|
|
17598
|
+
line-height: 16px;
|
|
17599
|
+
font-family: "Source Sans 3", system-ui;
|
|
17600
|
+
font-style: normal;
|
|
17601
|
+
font-weight: 400;
|
|
17602
|
+
margin: 0;
|
|
16575
17603
|
}
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
17604
|
+
|
|
17605
|
+
.${prefix}__cta-button {
|
|
17606
|
+
width: fit-content;
|
|
17607
|
+
display: inline-block;
|
|
17608
|
+
padding: 7px 20px;
|
|
17609
|
+
border: 0.5px solid ${ctaBorderColor};
|
|
17610
|
+
border-radius: 5px;
|
|
17611
|
+
color: ${ctaTextColor};
|
|
17612
|
+
font-size: 8px;
|
|
17613
|
+
transition: background-color 0.3s ease;
|
|
17614
|
+
font-family: "Source Sans 3", system-ui;
|
|
17615
|
+
font-style: normal;
|
|
17616
|
+
font-weight: 400;
|
|
16580
17617
|
}
|
|
16581
|
-
|
|
16582
|
-
|
|
17618
|
+
|
|
17619
|
+
.${prefix}:hover .${prefix}__cta-button {
|
|
17620
|
+
background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
|
|
17621
|
+
}
|
|
17622
|
+
|
|
17623
|
+
@container (min-width: 640px) {
|
|
17624
|
+
.${prefix} {
|
|
17625
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
|
17626
|
+
}
|
|
16583
17627
|
}
|
|
16584
|
-
|
|
16585
|
-
|
|
17628
|
+
|
|
17629
|
+
@container (min-width: 768px) {
|
|
17630
|
+
.${prefix}__text {
|
|
17631
|
+
padding: 25px;
|
|
17632
|
+
}
|
|
17633
|
+
|
|
17634
|
+
.${prefix}__header {
|
|
17635
|
+
font-size: 24px;
|
|
17636
|
+
}
|
|
17637
|
+
|
|
17638
|
+
.${prefix}__description {
|
|
17639
|
+
font-size: 13px;
|
|
17640
|
+
line-height: 18px;
|
|
17641
|
+
}
|
|
17642
|
+
|
|
17643
|
+
.${prefix}__cta-button {
|
|
17644
|
+
font-size: 12px;
|
|
17645
|
+
}
|
|
16586
17646
|
}
|
|
16587
|
-
|
|
16588
|
-
|
|
17647
|
+
|
|
17648
|
+
@container (min-width: 1024px) {
|
|
17649
|
+
.${prefix}__text {
|
|
17650
|
+
padding: 30px;
|
|
17651
|
+
}
|
|
17652
|
+
|
|
17653
|
+
.${prefix}__header {
|
|
17654
|
+
font-size: 28px;
|
|
17655
|
+
}
|
|
17656
|
+
|
|
17657
|
+
.${prefix}__description {
|
|
17658
|
+
font-size: 14px;
|
|
17659
|
+
}
|
|
17660
|
+
|
|
17661
|
+
.${prefix}__cta-button {
|
|
17662
|
+
font-size: 13px;
|
|
17663
|
+
}
|
|
16589
17664
|
}
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
17665
|
+
|
|
17666
|
+
@container (min-width: 1280px) {
|
|
17667
|
+
.${prefix}__cta-button {
|
|
17668
|
+
font-size: 14px;
|
|
17669
|
+
}
|
|
16594
17670
|
}
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
function rbLargeCategoryImageToutTemplate(spot) {
|
|
17671
|
+
</style>
|
|
17672
|
+
`;
|
|
17673
|
+
};
|
|
17674
|
+
function rbLargeCategoryImageToutTemplate(spot, config) {
|
|
17675
|
+
const { prefix = '' } = config;
|
|
16599
17676
|
return `
|
|
16600
17677
|
${GFONT_PRECONNECT}
|
|
16601
17678
|
${GFONT_SOURCE_SANS_3}
|
|
16602
17679
|
${GFONT_CORMORANT}
|
|
16603
|
-
${STYLES$3(spot)}
|
|
16604
|
-
<div class="
|
|
16605
|
-
<div class="
|
|
16606
|
-
${spot.header ? `<h2 class="
|
|
16607
|
-
${spot.description ? `<p class="
|
|
16608
|
-
${spot.ctaText ? `<span class="
|
|
17680
|
+
${STYLES$3(spot, config)}
|
|
17681
|
+
<div class="${prefix}">
|
|
17682
|
+
<div class="${prefix}__text">
|
|
17683
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
17684
|
+
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
|
17685
|
+
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
|
16609
17686
|
</div>
|
|
16610
17687
|
</div>
|
|
16611
17688
|
`;
|
|
16612
17689
|
}
|
|
16613
17690
|
|
|
16614
|
-
const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage, }) =>
|
|
17691
|
+
const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
|
|
17692
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
|
17693
|
+
return `
|
|
16615
17694
|
<style>
|
|
16616
|
-
|
|
16617
|
-
min-width: 320px;
|
|
16618
|
-
min-height: 150px;
|
|
16619
|
-
}
|
|
16620
|
-
.content {
|
|
17695
|
+
.${prefix} {
|
|
16621
17696
|
width: 100%;
|
|
16622
17697
|
height: 100%;
|
|
16623
17698
|
display: flex;
|
|
@@ -16626,17 +17701,15 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
|
16626
17701
|
border-radius: 5px;
|
|
16627
17702
|
overflow: hidden;
|
|
16628
17703
|
cursor: pointer;
|
|
16629
|
-
background-image: url("${mobilePrimaryImage}");
|
|
17704
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
|
|
16630
17705
|
background-size: cover;
|
|
16631
17706
|
background-position: center;
|
|
16632
|
-
background-blend-mode: overlay;
|
|
16633
17707
|
background-repeat: no-repeat;
|
|
17708
|
+
container-type: inline-size;
|
|
17709
|
+
position: relative;
|
|
16634
17710
|
}
|
|
16635
|
-
|
|
16636
|
-
|
|
16637
|
-
width: fit-content;
|
|
16638
|
-
}
|
|
16639
|
-
.header {
|
|
17711
|
+
|
|
17712
|
+
.${prefix}__header {
|
|
16640
17713
|
font-size: 16px;
|
|
16641
17714
|
color: ${textColor};
|
|
16642
17715
|
line-height: 20px;
|
|
@@ -16644,103 +17717,107 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
|
16644
17717
|
font-family: "Source Sans 3", system-ui;
|
|
16645
17718
|
font-style: normal;
|
|
16646
17719
|
margin: 0;
|
|
17720
|
+
padding: 15px 10%;
|
|
16647
17721
|
}
|
|
16648
|
-
|
|
16649
|
-
|
|
16650
|
-
|
|
17722
|
+
|
|
17723
|
+
@container (min-width: 640px) {
|
|
17724
|
+
.${prefix} {
|
|
17725
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
|
16651
17726
|
}
|
|
16652
17727
|
}
|
|
16653
|
-
|
|
16654
|
-
|
|
17728
|
+
|
|
17729
|
+
@container (min-width: 768px) {
|
|
17730
|
+
.${prefix}__header {
|
|
16655
17731
|
font-size: 22px;
|
|
16656
17732
|
}
|
|
16657
17733
|
}
|
|
16658
|
-
|
|
16659
|
-
|
|
17734
|
+
|
|
17735
|
+
@container (min-width: 1024px) {
|
|
17736
|
+
.${prefix}__header {
|
|
16660
17737
|
font-size: 24px;
|
|
16661
17738
|
}
|
|
16662
17739
|
}
|
|
16663
|
-
|
|
16664
|
-
|
|
17740
|
+
|
|
17741
|
+
@container (min-width: 1280px) {
|
|
17742
|
+
.${prefix}__header {
|
|
16665
17743
|
font-size: 28px;
|
|
16666
17744
|
}
|
|
16667
17745
|
}
|
|
16668
17746
|
</style>
|
|
16669
17747
|
`;
|
|
16670
|
-
|
|
17748
|
+
};
|
|
17749
|
+
function rbNavigationBannerTemplate(spot, config) {
|
|
17750
|
+
const { prefix = '' } = config;
|
|
16671
17751
|
return `
|
|
16672
17752
|
${GFONT_PRECONNECT}
|
|
16673
17753
|
${GFONT_SOURCE_SANS_3}
|
|
16674
|
-
${STYLES$2(spot)}
|
|
16675
|
-
<div class="
|
|
16676
|
-
|
|
16677
|
-
${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
|
|
16678
|
-
</div>
|
|
17754
|
+
${STYLES$2(spot, config)}
|
|
17755
|
+
<div class="${prefix}">
|
|
17756
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
16679
17757
|
</div>
|
|
16680
17758
|
`;
|
|
16681
17759
|
}
|
|
16682
17760
|
|
|
16683
|
-
const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage, }) =>
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
16690
|
-
|
|
16691
|
-
|
|
16692
|
-
|
|
16693
|
-
|
|
16694
|
-
|
|
16695
|
-
|
|
16696
|
-
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16700
|
-
|
|
16701
|
-
cursor: pointer;
|
|
16702
|
-
}
|
|
16703
|
-
.text {
|
|
16704
|
-
padding: 10px;
|
|
16705
|
-
width: 70%;
|
|
16706
|
-
}
|
|
16707
|
-
.header {
|
|
16708
|
-
font-size: 12px;
|
|
16709
|
-
color: ${textColor};
|
|
16710
|
-
line-height: 16px;
|
|
16711
|
-
font-family: "Source Sans 3", system-ui;
|
|
16712
|
-
font-style: normal;
|
|
16713
|
-
font-weight: 400;
|
|
16714
|
-
line-height: normal;
|
|
16715
|
-
margin: 0;
|
|
16716
|
-
}
|
|
16717
|
-
@media (min-width: 640px) {
|
|
16718
|
-
.content {
|
|
16719
|
-
background-image: url("${primaryImage}");
|
|
17761
|
+
const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
|
|
17762
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
|
17763
|
+
return `
|
|
17764
|
+
<style>
|
|
17765
|
+
.${prefix} {
|
|
17766
|
+
width: 100%;
|
|
17767
|
+
height: 100%;
|
|
17768
|
+
display: flex;
|
|
17769
|
+
flex-direction: column;
|
|
17770
|
+
justify-content: flex-end;
|
|
17771
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
|
|
17772
|
+
background-size: cover;
|
|
17773
|
+
background-repeat: no-repeat;
|
|
17774
|
+
background-position: center;
|
|
17775
|
+
border-radius: 5px;
|
|
17776
|
+
overflow: hidden;
|
|
17777
|
+
cursor: pointer;
|
|
17778
|
+
container-type: inline-size;
|
|
16720
17779
|
}
|
|
16721
|
-
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
17780
|
+
|
|
17781
|
+
.${prefix}__text {
|
|
17782
|
+
padding: 10px;
|
|
17783
|
+
width: 70%;
|
|
17784
|
+
}
|
|
17785
|
+
|
|
17786
|
+
.${prefix}__header {
|
|
17787
|
+
font-size: 12px;
|
|
17788
|
+
color: ${textColor};
|
|
17789
|
+
line-height: 16px;
|
|
17790
|
+
font-family: "Source Sans 3", system-ui;
|
|
17791
|
+
font-style: normal;
|
|
17792
|
+
font-weight: 400;
|
|
17793
|
+
margin: 0;
|
|
17794
|
+
}
|
|
17795
|
+
|
|
17796
|
+
@container (min-width: 640px) {
|
|
17797
|
+
.${prefix} {
|
|
17798
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
|
17799
|
+
}
|
|
17800
|
+
}
|
|
17801
|
+
</style>
|
|
17802
|
+
`;
|
|
17803
|
+
};
|
|
17804
|
+
function rbSmallCategoryImageToutTemplate(spot, config) {
|
|
17805
|
+
const { prefix = '' } = config;
|
|
16725
17806
|
return `
|
|
16726
17807
|
${GFONT_PRECONNECT}
|
|
16727
17808
|
${GFONT_CORMORANT}
|
|
16728
|
-
${STYLES$1(spot)}
|
|
16729
|
-
<div class="
|
|
16730
|
-
<div class="
|
|
16731
|
-
${spot.header ? `<h2 class="
|
|
17809
|
+
${STYLES$1(spot, config)}
|
|
17810
|
+
<div class="${prefix}">
|
|
17811
|
+
<div class="${prefix}__text">
|
|
17812
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
16732
17813
|
</div>
|
|
16733
17814
|
</div>
|
|
16734
17815
|
`;
|
|
16735
17816
|
}
|
|
16736
17817
|
|
|
16737
|
-
const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primaryImage, mobilePrimaryImage = primaryImage, }) => `
|
|
17818
|
+
const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
|
|
16738
17819
|
<style>
|
|
16739
|
-
|
|
16740
|
-
min-width: 165px;
|
|
16741
|
-
min-height: 250px;
|
|
16742
|
-
}
|
|
16743
|
-
.content {
|
|
17820
|
+
.${prefix} {
|
|
16744
17821
|
width: 100%;
|
|
16745
17822
|
height: 100%;
|
|
16746
17823
|
background-color: ${backgroundColor};
|
|
@@ -16748,8 +17825,10 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
|
|
|
16748
17825
|
display: flex;
|
|
16749
17826
|
flex-direction: column;
|
|
16750
17827
|
border-radius: 5px;
|
|
17828
|
+
container-type: inline-size;
|
|
16751
17829
|
}
|
|
16752
|
-
|
|
17830
|
+
|
|
17831
|
+
.${prefix}__image {
|
|
16753
17832
|
width: 100%;
|
|
16754
17833
|
height: 100%;
|
|
16755
17834
|
background-image: url("${mobilePrimaryImage}");
|
|
@@ -16758,7 +17837,8 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
|
|
|
16758
17837
|
background-position: center;
|
|
16759
17838
|
border-radius: 5px;
|
|
16760
17839
|
}
|
|
16761
|
-
|
|
17840
|
+
|
|
17841
|
+
.${prefix}__text {
|
|
16762
17842
|
text-align: left;
|
|
16763
17843
|
display: flex;
|
|
16764
17844
|
flex-direction: row;
|
|
@@ -16768,7 +17848,8 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
|
|
|
16768
17848
|
height: fit-content;
|
|
16769
17849
|
position: relative;
|
|
16770
17850
|
}
|
|
16771
|
-
|
|
17851
|
+
|
|
17852
|
+
.${prefix}__header {
|
|
16772
17853
|
font-size: 12px;
|
|
16773
17854
|
color: ${textColor};
|
|
16774
17855
|
padding-top: 5px;
|
|
@@ -16776,46 +17857,42 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
|
|
|
16776
17857
|
font-family: "Source Sans 3", system-ui;
|
|
16777
17858
|
font-style: normal;
|
|
16778
17859
|
font-weight: 400;
|
|
16779
|
-
line-height: normal;
|
|
16780
17860
|
margin: 0;
|
|
16781
17861
|
}
|
|
16782
|
-
|
|
16783
|
-
|
|
17862
|
+
|
|
17863
|
+
@container (min-width: 640px) {
|
|
17864
|
+
.${prefix}__image {
|
|
16784
17865
|
background-image: url("${primaryImage}");
|
|
16785
17866
|
}
|
|
16786
17867
|
}
|
|
16787
17868
|
</style>
|
|
16788
17869
|
`;
|
|
16789
|
-
function rbSmallDiscoverToutTemplate(spot) {
|
|
17870
|
+
function rbSmallDiscoverToutTemplate(spot, config) {
|
|
17871
|
+
const { prefix = '' } = config;
|
|
16790
17872
|
return `
|
|
16791
17873
|
${GFONT_PRECONNECT}
|
|
16792
17874
|
${GFONT_CORMORANT}
|
|
16793
|
-
${STYLES(spot)}
|
|
16794
|
-
<div class="
|
|
16795
|
-
<div class="
|
|
16796
|
-
<div class="
|
|
16797
|
-
${spot.header ? `<h2 class="
|
|
17875
|
+
${STYLES(spot, config)}
|
|
17876
|
+
<div class="${prefix}">
|
|
17877
|
+
<div class="${prefix}__image"></div>
|
|
17878
|
+
<div class="${prefix}__text">
|
|
17879
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
|
16798
17880
|
</div>
|
|
16799
17881
|
</div>
|
|
16800
17882
|
`;
|
|
16801
17883
|
}
|
|
16802
17884
|
|
|
16803
|
-
var ENUM_SPOT_ELEMENT_ATTRIBUTE;
|
|
16804
|
-
(function (ENUM_SPOT_ELEMENT_ATTRIBUTE) {
|
|
16805
|
-
ENUM_SPOT_ELEMENT_ATTRIBUTE["WIDTH"] = "width";
|
|
16806
|
-
ENUM_SPOT_ELEMENT_ATTRIBUTE["HEIGHT"] = "height";
|
|
16807
|
-
ENUM_SPOT_ELEMENT_ATTRIBUTE["FLUID"] = "fluid";
|
|
16808
|
-
ENUM_SPOT_ELEMENT_ATTRIBUTE["REDIRECT_ON_CLICK"] = "redirect-on-click";
|
|
16809
|
-
})(ENUM_SPOT_ELEMENT_ATTRIBUTE || (ENUM_SPOT_ELEMENT_ATTRIBUTE = {}));
|
|
16810
17885
|
/**
|
|
16811
|
-
*
|
|
17886
|
+
* Returns the HTML element for the given spot.
|
|
16812
17887
|
*
|
|
16813
|
-
* @param {ISpot}
|
|
17888
|
+
* @param {ISpot} spot - The spot object.
|
|
17889
|
+
* @param {ISpotTemplateConfig} config - The spot template configuration.
|
|
16814
17890
|
*
|
|
16815
|
-
* @return {
|
|
17891
|
+
* @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
|
|
16816
17892
|
*/
|
|
16817
|
-
const
|
|
17893
|
+
const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
16818
17894
|
const templates = {
|
|
17895
|
+
// Reserve Bar Spot Templates
|
|
16819
17896
|
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE]: {
|
|
16820
17897
|
rbHomepageHeroThreeTile: rbHomepageHeroThreeTileTemplate,
|
|
16821
17898
|
},
|
|
@@ -16843,6 +17920,7 @@ const GET_SPOT_TEMPLATE_HTML_STRING = (data) => {
|
|
|
16843
17920
|
[RMN_SPOT_TYPE.RB_PRODUCT_UPCS]: {
|
|
16844
17921
|
rbProductUpcs: () => '', // No template for this spot type, it will be handled by ReserveBar App.
|
|
16845
17922
|
},
|
|
17923
|
+
// IAB Standard Spot Templates
|
|
16846
17924
|
[RMN_SPOT_TYPE.BILLBOARD]: {
|
|
16847
17925
|
billboardV1: billboardV1Template,
|
|
16848
17926
|
billboardV2: billboardV2Template,
|
|
@@ -16869,232 +17947,854 @@ const GET_SPOT_TEMPLATE_HTML_STRING = (data) => {
|
|
|
16869
17947
|
inTextV1: inTextV1Template,
|
|
16870
17948
|
},
|
|
16871
17949
|
};
|
|
16872
|
-
const spotVariants = templates[
|
|
17950
|
+
const spotVariants = templates[spot.spot];
|
|
16873
17951
|
if (!spotVariants) {
|
|
16874
|
-
return
|
|
17952
|
+
return null;
|
|
16875
17953
|
}
|
|
16876
|
-
const variantTemplate = spotVariants[
|
|
17954
|
+
const variantTemplate = spotVariants[spot.variant];
|
|
16877
17955
|
if (!variantTemplate) {
|
|
16878
|
-
return
|
|
17956
|
+
return null;
|
|
16879
17957
|
}
|
|
16880
|
-
|
|
17958
|
+
// Generate a highly unique prefix to avoid conflicts with other elements.
|
|
17959
|
+
const prefix = 's' + UniqueIdGenerator.generate().toLowerCase();
|
|
17960
|
+
const spotHtmlString = variantTemplate(spot, { ...config, prefix });
|
|
17961
|
+
return spotHtmlStringToElement(spotHtmlString);
|
|
16881
17962
|
};
|
|
16882
17963
|
|
|
16883
|
-
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
17964
|
+
/**
|
|
17965
|
+
* PubSub class
|
|
17966
|
+
* Manages event subscriptions and publications
|
|
17967
|
+
* @template IEventMap A record type defining the structure of events and their data
|
|
17968
|
+
*/
|
|
17969
|
+
class PubSub {
|
|
17970
|
+
constructor() {
|
|
17971
|
+
/**
|
|
17972
|
+
* Object to store subscribers for each event type
|
|
17973
|
+
*/
|
|
17974
|
+
this.subscribers = {};
|
|
17975
|
+
}
|
|
17976
|
+
static getInstance() {
|
|
17977
|
+
if (!PubSub.instance) {
|
|
17978
|
+
PubSub.instance = new PubSub();
|
|
16891
17979
|
}
|
|
16892
|
-
|
|
16893
|
-
|
|
16894
|
-
|
|
16895
|
-
|
|
16896
|
-
|
|
17980
|
+
return PubSub.instance;
|
|
17981
|
+
}
|
|
17982
|
+
/**
|
|
17983
|
+
* Subscribe to an event
|
|
17984
|
+
* @param eventType - The type of event to subscribe to
|
|
17985
|
+
* @param callback - The function to be called when the event is published
|
|
17986
|
+
* @returns A function to unsubscribe from the event
|
|
17987
|
+
*
|
|
17988
|
+
* @Example:
|
|
17989
|
+
* const unsubscribe = pubSub.subscribe('userLogin', (data) => {
|
|
17990
|
+
* console.log(`User ${data.username} logged in`);
|
|
17991
|
+
* });
|
|
17992
|
+
*/
|
|
17993
|
+
subscribe(eventType, callback) {
|
|
17994
|
+
if (!this.subscribers[eventType]) {
|
|
17995
|
+
this.subscribers[eventType] = [];
|
|
16897
17996
|
}
|
|
16898
|
-
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
this.
|
|
17997
|
+
this.subscribers[eventType].push(callback);
|
|
17998
|
+
// Return an unsubscribe function
|
|
17999
|
+
return () => {
|
|
18000
|
+
this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
|
|
18001
|
+
};
|
|
18002
|
+
}
|
|
18003
|
+
/**
|
|
18004
|
+
* Publish an event
|
|
18005
|
+
* @param eventType - The type of event to publish
|
|
18006
|
+
* @param data - The data to be passed to the event subscribers
|
|
18007
|
+
*
|
|
18008
|
+
* @Example:
|
|
18009
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
|
18010
|
+
*/
|
|
18011
|
+
publish(eventType, data) {
|
|
18012
|
+
if (!this.subscribers[eventType]) {
|
|
18013
|
+
return;
|
|
16902
18014
|
}
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
18015
|
+
this.subscribers[eventType].forEach((callback) => callback(data));
|
|
18016
|
+
}
|
|
18017
|
+
}
|
|
18018
|
+
/**
|
|
18019
|
+
* Usage Example:
|
|
18020
|
+
*
|
|
18021
|
+
* interface IEventMap {
|
|
18022
|
+
* userLogin: { username: string; timestamp: number };
|
|
18023
|
+
* pageView: { url: string; timestamp: number };
|
|
18024
|
+
* }
|
|
18025
|
+
*
|
|
18026
|
+
* const pubSub = new PubSub<IEventMap>();
|
|
18027
|
+
*
|
|
18028
|
+
* // Subscribe to events
|
|
18029
|
+
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
|
18030
|
+
* console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
|
|
18031
|
+
* });
|
|
18032
|
+
*
|
|
18033
|
+
* pubSub.subscribe('pageView', (data) => {
|
|
18034
|
+
* console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
|
|
18035
|
+
* });
|
|
18036
|
+
*
|
|
18037
|
+
* // Publish events
|
|
18038
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
|
18039
|
+
* pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
|
|
18040
|
+
*
|
|
18041
|
+
* // Unsubscribe from an event
|
|
18042
|
+
* unsubscribeLogin();
|
|
18043
|
+
*/
|
|
18044
|
+
|
|
18045
|
+
class EventService {
|
|
18046
|
+
constructor() {
|
|
18047
|
+
this.pubSub = PubSub.getInstance();
|
|
18048
|
+
this.localStorage = LocalStorage.getInstance();
|
|
18049
|
+
this.activeSpots = new Map();
|
|
18050
|
+
this.spotStates = new Map();
|
|
18051
|
+
this.intersectionObserver = new IntersectionObserverService();
|
|
18052
|
+
}
|
|
18053
|
+
static getInstance() {
|
|
18054
|
+
if (!EventService.instance) {
|
|
18055
|
+
EventService.instance = new EventService();
|
|
16907
18056
|
}
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
18057
|
+
return EventService.instance;
|
|
18058
|
+
}
|
|
18059
|
+
subscribe(eventType, callback) {
|
|
18060
|
+
return this.pubSub.subscribe(eventType, callback);
|
|
18061
|
+
}
|
|
18062
|
+
publish(eventType, data) {
|
|
18063
|
+
this.pubSub.publish(eventType, data);
|
|
18064
|
+
}
|
|
18065
|
+
registerSpot(params) {
|
|
18066
|
+
const { placementId, spot, spotElement } = params;
|
|
18067
|
+
this.activeSpots.set(placementId, { spotElement });
|
|
18068
|
+
// Fire impression event
|
|
18069
|
+
this.fireImpressionEvent(placementId, spot, spotElement);
|
|
18070
|
+
// Handle intersection observer
|
|
18071
|
+
this.handleIntersectionObserver(placementId, spot, spotElement);
|
|
18072
|
+
// Attach click event listener
|
|
18073
|
+
spotElement.addEventListener('click', async () => await this.handleClick(params));
|
|
18074
|
+
}
|
|
18075
|
+
unregisterSpot(placementId) {
|
|
18076
|
+
const placementIdClean = placementId.replace('#', '');
|
|
18077
|
+
const spotData = this.activeSpots.get(placementIdClean);
|
|
18078
|
+
if (!spotData) {
|
|
18079
|
+
this.handleSpotState(placementIdClean, {
|
|
18080
|
+
state: {
|
|
18081
|
+
error: `Active spot with placementId ${placementIdClean} not found.`,
|
|
18082
|
+
},
|
|
18083
|
+
});
|
|
18084
|
+
return;
|
|
16920
18085
|
}
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
}
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
18086
|
+
this.intersectionObserver.unobserve(spotData.spotElement);
|
|
18087
|
+
this.handleSpotState(placementIdClean, {
|
|
18088
|
+
dom: {
|
|
18089
|
+
spotElement: undefined,
|
|
18090
|
+
visibleOnViewport: false,
|
|
18091
|
+
},
|
|
18092
|
+
state: {
|
|
18093
|
+
unmounted: true,
|
|
18094
|
+
mounted: false,
|
|
18095
|
+
},
|
|
18096
|
+
});
|
|
18097
|
+
this.activeSpots.delete(placementIdClean);
|
|
18098
|
+
const placementElement = document.getElementById(placementIdClean);
|
|
18099
|
+
if (!placementElement) {
|
|
18100
|
+
this.handleSpotState(placementIdClean, {
|
|
18101
|
+
state: {
|
|
18102
|
+
error: `Placement element with id ${placementIdClean} not found.`,
|
|
18103
|
+
},
|
|
18104
|
+
});
|
|
18105
|
+
return;
|
|
16931
18106
|
}
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
18107
|
+
placementElement.innerHTML = '';
|
|
18108
|
+
}
|
|
18109
|
+
/**
|
|
18110
|
+
* Updates the state of a spot.
|
|
18111
|
+
*
|
|
18112
|
+
* @param {string} placementId - The placement ID of the spot.
|
|
18113
|
+
* @param {Partial<ILifecycleState>} updates - The updates to apply to the spot state.
|
|
18114
|
+
* @param {boolean} publish - Whether to publish the updated state.
|
|
18115
|
+
*
|
|
18116
|
+
* @returns {void}
|
|
18117
|
+
*/
|
|
18118
|
+
handleSpotState(placementId, updates, publish = true) {
|
|
18119
|
+
let currentState = this.spotStates.get(placementId);
|
|
18120
|
+
if (!currentState) {
|
|
18121
|
+
currentState = {
|
|
18122
|
+
identifier: {
|
|
18123
|
+
placementId,
|
|
18124
|
+
spotId: '',
|
|
18125
|
+
spotType: '',
|
|
18126
|
+
},
|
|
18127
|
+
dom: {
|
|
18128
|
+
spotElement: undefined,
|
|
18129
|
+
visibleOnViewport: false,
|
|
18130
|
+
},
|
|
18131
|
+
state: {
|
|
18132
|
+
mounted: false,
|
|
18133
|
+
unmounted: false,
|
|
18134
|
+
loading: false,
|
|
18135
|
+
error: undefined,
|
|
18136
|
+
},
|
|
18137
|
+
displayConfig: {
|
|
18138
|
+
isCarousel: false,
|
|
18139
|
+
isCarouselItem: false,
|
|
18140
|
+
isSingleItem: false,
|
|
18141
|
+
},
|
|
16937
18142
|
};
|
|
16938
|
-
this.observer = new IntersectionObserver((entries) => {
|
|
16939
|
-
var _a;
|
|
16940
|
-
if (entries[0].isIntersecting) {
|
|
16941
|
-
this.registerEvent(RMN_SPOT_EVENT.IMPRESSION);
|
|
16942
|
-
(_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
16943
|
-
}
|
|
16944
|
-
}, options);
|
|
16945
|
-
this.observer.observe(this);
|
|
16946
18143
|
}
|
|
16947
|
-
|
|
16948
|
-
|
|
18144
|
+
this.spotStates.set(placementId, { ...currentState, ...updates });
|
|
18145
|
+
if (publish) {
|
|
18146
|
+
this.pubSub.publish(RMN_SPOT_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
|
|
16949
18147
|
}
|
|
16950
|
-
|
|
18148
|
+
}
|
|
18149
|
+
async handleClick({ placementId, spot, spotElement, }) {
|
|
18150
|
+
var _a, _b, _c;
|
|
18151
|
+
// Publish click event
|
|
18152
|
+
this.pubSub.publish(RMN_SPOT_EVENT.CLICK, {
|
|
18153
|
+
placementId,
|
|
18154
|
+
spotId: spot.id,
|
|
18155
|
+
spotElement,
|
|
18156
|
+
});
|
|
18157
|
+
// Fire click event
|
|
18158
|
+
await this.fireEvent({
|
|
18159
|
+
event: RMN_SPOT_EVENT.CLICK,
|
|
18160
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
|
18161
|
+
});
|
|
18162
|
+
// Save spot to local storage for event tracking
|
|
18163
|
+
this.localStorage.setSpot(spot.id, {
|
|
18164
|
+
spotId: spot.id,
|
|
18165
|
+
spotType: spot.spot,
|
|
18166
|
+
events: spot.events,
|
|
18167
|
+
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 'GROUPING-12345', 'DAN-12345', 131398103],
|
|
18168
|
+
});
|
|
18169
|
+
}
|
|
18170
|
+
handleIntersectionObserver(placementId, _spot, spotElement) {
|
|
18171
|
+
const spotIsVisibleCallback = async () => {
|
|
18172
|
+
this.intersectionObserver.unobserve(spotElement);
|
|
18173
|
+
this.handleSpotState(placementId, {
|
|
18174
|
+
dom: {
|
|
18175
|
+
spotElement,
|
|
18176
|
+
visibleOnViewport: true,
|
|
18177
|
+
},
|
|
18178
|
+
});
|
|
18179
|
+
};
|
|
18180
|
+
this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
|
|
18181
|
+
}
|
|
18182
|
+
fireImpressionEvent(placementId, spot, spotElement) {
|
|
18183
|
+
this.pubSub.publish(RMN_SPOT_EVENT.IMPRESSION, {
|
|
18184
|
+
placementId,
|
|
18185
|
+
spotId: spot.id,
|
|
18186
|
+
spotElement,
|
|
18187
|
+
});
|
|
18188
|
+
(async () => {
|
|
16951
18189
|
var _a, _b;
|
|
16952
|
-
|
|
18190
|
+
await this.fireEvent({
|
|
18191
|
+
event: RMN_SPOT_EVENT.IMPRESSION,
|
|
18192
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
|
18193
|
+
});
|
|
18194
|
+
})();
|
|
18195
|
+
}
|
|
18196
|
+
/**
|
|
18197
|
+
* Fires an event using the navigator.sendBeacon method or a fallback method if sendBeacon is not available.
|
|
18198
|
+
* If the event is a click event and a redirect URL is found, it redirects the user to that URL.
|
|
18199
|
+
*
|
|
18200
|
+
* @param {IFireEventParams} params - The parameters for firing the event.
|
|
18201
|
+
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
|
18202
|
+
* @param {string} params.eventUrl - The URL to which the event is sent.
|
|
18203
|
+
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
|
18204
|
+
*/
|
|
18205
|
+
async fireEvent({ event, eventUrl }) {
|
|
18206
|
+
var _a;
|
|
18207
|
+
try {
|
|
18208
|
+
const didFireEvent = ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === null || _a === void 0 ? void 0 : _a.call(navigator, eventUrl)) || (await this.fallbackEventFire(eventUrl));
|
|
18209
|
+
if (!didFireEvent) {
|
|
16953
18210
|
return;
|
|
16954
|
-
const shouldRedirectOnClick = this.getAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.REDIRECT_ON_CLICK) === 'true';
|
|
16955
|
-
const eventUrl = (_b = (_a = this.data.events.find((e) => e.event === event)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '';
|
|
16956
|
-
try {
|
|
16957
|
-
const options = {
|
|
16958
|
-
method: 'POST',
|
|
16959
|
-
redirect: event === RMN_SPOT_EVENT.CLICK && shouldRedirectOnClick ? 'follow' : 'manual',
|
|
16960
|
-
};
|
|
16961
|
-
const response = await fetch(eventUrl, options);
|
|
16962
|
-
if (response.ok && event === RMN_SPOT_EVENT.CLICK && shouldRedirectOnClick) {
|
|
16963
|
-
window.location.href = this.getRedirectUrlFromPayload(eventUrl);
|
|
16964
|
-
}
|
|
16965
18211
|
}
|
|
16966
|
-
|
|
16967
|
-
|
|
18212
|
+
if (event === RMN_SPOT_EVENT.CLICK) {
|
|
18213
|
+
const redirectUrl = this.getRedirectUrlFromPayload(eventUrl);
|
|
18214
|
+
if (redirectUrl) {
|
|
18215
|
+
window.location.href = redirectUrl;
|
|
18216
|
+
}
|
|
16968
18217
|
}
|
|
16969
18218
|
}
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
const base64String = (_a = new URL(url).searchParams.get('e')) !== null && _a !== void 0 ? _a : '';
|
|
16973
|
-
try {
|
|
16974
|
-
const data = JSON.parse(atob(base64String));
|
|
16975
|
-
return (_b = data.ur) !== null && _b !== void 0 ? _b : '';
|
|
16976
|
-
}
|
|
16977
|
-
catch (_c) {
|
|
16978
|
-
return '';
|
|
16979
|
-
}
|
|
18219
|
+
catch (_b) {
|
|
18220
|
+
// Handle errors silently
|
|
16980
18221
|
}
|
|
16981
18222
|
}
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
if (!this.ensureBrowserEnvironmentAndDefineElement()) {
|
|
17006
|
-
return null;
|
|
18223
|
+
// Fallback method using fetch if sendBeacon isn't available
|
|
18224
|
+
async fallbackEventFire(url) {
|
|
18225
|
+
try {
|
|
18226
|
+
const racePromise = Promise.race([
|
|
18227
|
+
// Promise #1: The fetch request
|
|
18228
|
+
fetch(url, {
|
|
18229
|
+
method: 'POST',
|
|
18230
|
+
keepalive: true,
|
|
18231
|
+
}),
|
|
18232
|
+
// Promise #2: The timeout
|
|
18233
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 2000)),
|
|
18234
|
+
]);
|
|
18235
|
+
/**
|
|
18236
|
+
* Prevent requests from hanging indefinitely
|
|
18237
|
+
* Improve user experience by failing fast
|
|
18238
|
+
* Handle slow network conditions gracefully
|
|
18239
|
+
* Ensure resources are freed up in a timely manner
|
|
18240
|
+
*/
|
|
18241
|
+
const response = await racePromise;
|
|
18242
|
+
return response.ok;
|
|
18243
|
+
}
|
|
18244
|
+
catch (_a) {
|
|
18245
|
+
return false;
|
|
17007
18246
|
}
|
|
17008
|
-
const isFluid = (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false;
|
|
17009
|
-
const shouldRedirectOnClick = (_b = config === null || config === void 0 ? void 0 : config.redirectOnClick) !== null && _b !== void 0 ? _b : true;
|
|
17010
|
-
const element = document.createElement(SPOT_ELEMENT_TAG);
|
|
17011
|
-
element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.WIDTH, spot.width.toString());
|
|
17012
|
-
element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.HEIGHT, spot.height.toString());
|
|
17013
|
-
element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.FLUID, isFluid.toString());
|
|
17014
|
-
element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.REDIRECT_ON_CLICK, shouldRedirectOnClick.toString());
|
|
17015
|
-
// Share the spot data with the element
|
|
17016
|
-
element.data = spot;
|
|
17017
|
-
// Set custom content
|
|
17018
|
-
if (config === null || config === void 0 ? void 0 : config.customContent) {
|
|
17019
|
-
element.customContent = config.customContent;
|
|
17020
|
-
}
|
|
17021
|
-
return element;
|
|
17022
18247
|
}
|
|
17023
18248
|
/**
|
|
17024
|
-
*
|
|
18249
|
+
* Extracts and decodes a URL from a base64-encoded query parameter.
|
|
18250
|
+
*
|
|
18251
|
+
* @param {string} url - The URL containing the base64-encoded query parameter.
|
|
18252
|
+
* @returns {string | null} - The decoded URL or null if not found or invalid.
|
|
17025
18253
|
*/
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
18254
|
+
getRedirectUrlFromPayload(url) {
|
|
18255
|
+
try {
|
|
18256
|
+
const base64String = new URL(url).searchParams.get('e');
|
|
18257
|
+
if (!base64String) {
|
|
18258
|
+
return null;
|
|
18259
|
+
}
|
|
18260
|
+
const data = JSON.parse(atob(base64String));
|
|
18261
|
+
return data.ur || null;
|
|
17030
18262
|
}
|
|
17031
|
-
|
|
17032
|
-
|
|
18263
|
+
catch (_a) {
|
|
18264
|
+
return null;
|
|
17033
18265
|
}
|
|
17034
|
-
return true;
|
|
17035
18266
|
}
|
|
17036
18267
|
}
|
|
17037
18268
|
|
|
17038
|
-
|
|
18269
|
+
const SELECTION_API_PATH = '/spots/selection';
|
|
18270
|
+
|
|
18271
|
+
class SelectionService extends BaseApi {
|
|
17039
18272
|
constructor(auth) {
|
|
17040
18273
|
super(auth);
|
|
17041
18274
|
}
|
|
17042
18275
|
static getInstance(auth) {
|
|
17043
|
-
return SingletonManager.getInstance('
|
|
18276
|
+
return SingletonManager.getInstance('SelectionService', () => new SelectionService(auth));
|
|
17044
18277
|
}
|
|
17045
18278
|
/**
|
|
17046
18279
|
* Makes a selection request on our server based on the provided data.
|
|
17047
18280
|
*
|
|
17048
18281
|
* @param {ISpotSelectionParams} data - Spots selection parameters.
|
|
17049
18282
|
*
|
|
17050
|
-
* @return {Promise<ISpots>} - The spots response object.
|
|
18283
|
+
* @return {Promise<ISpots | { error: string }>} - The spots response object.
|
|
17051
18284
|
*/
|
|
17052
18285
|
async spotSelection(data) {
|
|
17053
|
-
const { isOk, val, isErr } = await this.post(
|
|
18286
|
+
const { isOk, val, isErr } = await this.post(SELECTION_API_PATH, data, {});
|
|
17054
18287
|
if (isErr) {
|
|
17055
|
-
|
|
18288
|
+
return { error: `There was an error during spot selection: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})` };
|
|
17056
18289
|
}
|
|
17057
18290
|
if (isOk && val && val.data && (val === null || val === void 0 ? void 0 : val.refresh.token)) {
|
|
17058
18291
|
this.authInfo.authenticated = true;
|
|
17059
18292
|
this.authInfo.token = val.refresh.token;
|
|
17060
18293
|
return val.data.spots;
|
|
17061
18294
|
}
|
|
17062
|
-
|
|
18295
|
+
return { error: 'Spot selection response was not successful' };
|
|
17063
18296
|
}
|
|
17064
18297
|
}
|
|
17065
18298
|
|
|
18299
|
+
const SPOT_EVENTS_EXAMPLE = [
|
|
18300
|
+
{
|
|
18301
|
+
event: RMN_SPOT_EVENT.CLICK,
|
|
18302
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
|
|
18303
|
+
},
|
|
18304
|
+
{
|
|
18305
|
+
event: RMN_SPOT_EVENT.IMPRESSION,
|
|
18306
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
|
|
18307
|
+
},
|
|
18308
|
+
{
|
|
18309
|
+
event: RMN_SPOT_EVENT.PURCHASE,
|
|
18310
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
|
|
18311
|
+
},
|
|
18312
|
+
{
|
|
18313
|
+
event: RMN_SPOT_EVENT.ADD_TO_CART,
|
|
18314
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
|
|
18315
|
+
},
|
|
18316
|
+
{
|
|
18317
|
+
event: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
|
|
18318
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
|
|
18319
|
+
},
|
|
18320
|
+
{
|
|
18321
|
+
event: RMN_SPOT_EVENT.BUY_NOW,
|
|
18322
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
|
|
18323
|
+
},
|
|
18324
|
+
];
|
|
18325
|
+
const RB_SPOTS_SELECTION_EXAMPLE = {
|
|
18326
|
+
rbHomepageHeroFullImage: [
|
|
18327
|
+
{
|
|
18328
|
+
id: '111111_111111',
|
|
18329
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
|
18330
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
|
18331
|
+
width: 1140,
|
|
18332
|
+
height: 640,
|
|
18333
|
+
header: 'Artisanal Craft Beer Collection',
|
|
18334
|
+
description: 'Discover our curated selection of small-batch, flavor-packed craft beers.',
|
|
18335
|
+
ctaText: 'Explore the Collection',
|
|
18336
|
+
textColor: '#ffffff',
|
|
18337
|
+
ctaTextColor: '#ffffff',
|
|
18338
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Craft+Beer+Collection',
|
|
18339
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Craft+Beer',
|
|
18340
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18341
|
+
},
|
|
18342
|
+
{
|
|
18343
|
+
id: '222222_222222',
|
|
18344
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
|
18345
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
|
18346
|
+
width: 1140,
|
|
18347
|
+
height: 640,
|
|
18348
|
+
header: 'Summer Wine Spectacular',
|
|
18349
|
+
description: 'Refresh your palate with our handpicked selection of crisp, summer wines.',
|
|
18350
|
+
ctaText: 'Shop Summer Wines',
|
|
18351
|
+
textColor: '#000000',
|
|
18352
|
+
ctaTextColor: '#ffffff',
|
|
18353
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Summer+Wines',
|
|
18354
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Summer+Wines',
|
|
18355
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18356
|
+
},
|
|
18357
|
+
],
|
|
18358
|
+
rbHomepageHeroTwoTile: [
|
|
18359
|
+
{
|
|
18360
|
+
id: '333333_333333',
|
|
18361
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
|
18362
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
|
18363
|
+
width: 1140,
|
|
18364
|
+
height: 640,
|
|
18365
|
+
header: 'Whiskey Wonderland',
|
|
18366
|
+
description: 'Embark on a journey through our premium whiskey selection.',
|
|
18367
|
+
ctaText: 'Discover Whiskeys',
|
|
18368
|
+
textColor: '#ffffff',
|
|
18369
|
+
backgroundColor: '#2c1a05',
|
|
18370
|
+
ctaTextColor: '#2c1a05',
|
|
18371
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey+Collection',
|
|
18372
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
|
|
18373
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18374
|
+
},
|
|
18375
|
+
],
|
|
18376
|
+
rbHomepageHeroThreeTile: [
|
|
18377
|
+
{
|
|
18378
|
+
id: '444444_444444',
|
|
18379
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
|
18380
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
|
18381
|
+
width: 1140,
|
|
18382
|
+
height: 640,
|
|
18383
|
+
header: 'Cocktail Essentials',
|
|
18384
|
+
description: 'Stock your bar with premium spirits and mixers for the perfect cocktail.',
|
|
18385
|
+
ctaText: 'Build Your Bar',
|
|
18386
|
+
textColor: '#ffffff',
|
|
18387
|
+
backgroundColor: '#1a3c4d',
|
|
18388
|
+
ctaTextColor: '#1a3c4d',
|
|
18389
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Spirits',
|
|
18390
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Mixers',
|
|
18391
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktail+Kit',
|
|
18392
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Cocktail+Mixers',
|
|
18393
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18394
|
+
},
|
|
18395
|
+
],
|
|
18396
|
+
rbLargeCategoryImageTout: [
|
|
18397
|
+
{
|
|
18398
|
+
id: '555555_555555',
|
|
18399
|
+
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
|
18400
|
+
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
|
18401
|
+
width: 468,
|
|
18402
|
+
height: 410,
|
|
18403
|
+
header: 'Rare & Limited Edition',
|
|
18404
|
+
description: 'Discover our collection of hard-to-find and limited release spirits.',
|
|
18405
|
+
textColor: '#ffffff',
|
|
18406
|
+
ctaTextColor: '#ffffff',
|
|
18407
|
+
primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
|
|
18408
|
+
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
|
|
18409
|
+
ctaText: 'Shop Rare Spirits',
|
|
18410
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18411
|
+
},
|
|
18412
|
+
],
|
|
18413
|
+
rbSmallDiscoverTout: [
|
|
18414
|
+
{
|
|
18415
|
+
id: '666666_666666',
|
|
18416
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
|
18417
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
|
18418
|
+
width: 224,
|
|
18419
|
+
height: 378,
|
|
18420
|
+
header: 'Château Margaux 2015 Bordeaux',
|
|
18421
|
+
textColor: '#ffffff',
|
|
18422
|
+
primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
|
|
18423
|
+
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
|
|
18424
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18425
|
+
},
|
|
18426
|
+
],
|
|
18427
|
+
rbSmallCategoryImageTout: [
|
|
18428
|
+
{
|
|
18429
|
+
id: '777777_777777',
|
|
18430
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
|
18431
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
|
18432
|
+
width: 224,
|
|
18433
|
+
height: 410,
|
|
18434
|
+
header: 'Japanese Sake',
|
|
18435
|
+
textColor: '#ffffff',
|
|
18436
|
+
primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
|
|
18437
|
+
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
|
|
18438
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18439
|
+
},
|
|
18440
|
+
],
|
|
18441
|
+
rbCollectionBannerWithoutTextBlock: [
|
|
18442
|
+
{
|
|
18443
|
+
id: '888888_888888',
|
|
18444
|
+
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
|
18445
|
+
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
|
18446
|
+
width: 887,
|
|
18447
|
+
height: 344,
|
|
18448
|
+
primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
|
|
18449
|
+
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
|
|
18450
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18451
|
+
},
|
|
18452
|
+
],
|
|
18453
|
+
rbNavigationBanner: [
|
|
18454
|
+
{
|
|
18455
|
+
id: '999999_999999',
|
|
18456
|
+
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
|
18457
|
+
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
|
18458
|
+
width: 440,
|
|
18459
|
+
height: 220,
|
|
18460
|
+
header: 'Explore Tequilas',
|
|
18461
|
+
textColor: '#ffffff',
|
|
18462
|
+
primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
|
|
18463
|
+
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
|
|
18464
|
+
events: SPOT_EVENTS_EXAMPLE,
|
|
18465
|
+
},
|
|
18466
|
+
],
|
|
18467
|
+
};
|
|
18468
|
+
|
|
17066
18469
|
class LiquidCommerceRmnClient {
|
|
17067
18470
|
constructor(auth) {
|
|
17068
|
-
this.
|
|
17069
|
-
this.
|
|
18471
|
+
this.selectionService = SelectionService.getInstance(auth);
|
|
18472
|
+
this.elementService = ElementService.getInstance();
|
|
18473
|
+
this.eventService = EventService.getInstance();
|
|
17070
18474
|
}
|
|
17071
18475
|
/**
|
|
17072
18476
|
* Makes a selection request on our server based on the provided data.
|
|
17073
18477
|
*
|
|
17074
18478
|
* To create a spot html element, use the RmnCreateSpotElement function.
|
|
17075
18479
|
*
|
|
17076
|
-
* @param {ISpotSelectionParams}
|
|
18480
|
+
* @param {ISpotSelectionParams} params - Spots selection parameters.
|
|
17077
18481
|
*
|
|
17078
|
-
* @return {Promise<ISpots>} - The spots response object.
|
|
18482
|
+
* @return {Promise<ISpots | {error : string}>} - The spots response object.
|
|
17079
18483
|
*/
|
|
17080
|
-
async spotSelection(
|
|
17081
|
-
return this.
|
|
18484
|
+
async spotSelection(params) {
|
|
18485
|
+
return this.selectionService.spotSelection(params);
|
|
18486
|
+
}
|
|
18487
|
+
/**
|
|
18488
|
+
* Injects the spot elements into their provided placement.
|
|
18489
|
+
*
|
|
18490
|
+
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
|
18491
|
+
*
|
|
18492
|
+
* @return {Promise<void>} - A promise that resolves when the spot elements are injected.
|
|
18493
|
+
*/
|
|
18494
|
+
async injectSpotElement(params) {
|
|
18495
|
+
var _a;
|
|
18496
|
+
const config = params.config;
|
|
18497
|
+
let inject = params.inject;
|
|
18498
|
+
if (!inject.length) {
|
|
18499
|
+
this.eventService.handleSpotState('all', {
|
|
18500
|
+
state: {
|
|
18501
|
+
error: 'No spot elements provided for injection.',
|
|
18502
|
+
loading: false,
|
|
18503
|
+
},
|
|
18504
|
+
});
|
|
18505
|
+
return;
|
|
18506
|
+
}
|
|
18507
|
+
// Update the state of the spots to loading
|
|
18508
|
+
this.updateSpotsState(inject);
|
|
18509
|
+
// Prevent duplicate placement ids
|
|
18510
|
+
const hasDuplicatePlacementIds = this.preventDuplicateSpotPlacementIds(inject);
|
|
18511
|
+
if (!hasDuplicatePlacementIds) {
|
|
18512
|
+
return;
|
|
18513
|
+
}
|
|
18514
|
+
// Prevent non-existent spot types
|
|
18515
|
+
inject = this.preventNonExistentSpotTypes(inject);
|
|
18516
|
+
// Make the spot selection request
|
|
18517
|
+
const response = await this.spotSelectionRequest({ ...params, inject });
|
|
18518
|
+
// const response = await this.useSpotSelectionExample(inject);
|
|
18519
|
+
// Handle the response
|
|
18520
|
+
if (typeof response === 'object' && 'error' in response) {
|
|
18521
|
+
this.eventService.handleSpotState('all', {
|
|
18522
|
+
state: {
|
|
18523
|
+
error: response.error,
|
|
18524
|
+
},
|
|
18525
|
+
});
|
|
18526
|
+
return;
|
|
18527
|
+
}
|
|
18528
|
+
for (const item of inject) {
|
|
18529
|
+
const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
|
|
18530
|
+
const spots = response[item.placementId];
|
|
18531
|
+
if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
|
|
18532
|
+
this.eventService.handleSpotState(item.placementId, {
|
|
18533
|
+
state: {
|
|
18534
|
+
error: `No spots found for type "${item.spotType}".`,
|
|
18535
|
+
loading: false,
|
|
18536
|
+
},
|
|
18537
|
+
});
|
|
18538
|
+
continue;
|
|
18539
|
+
}
|
|
18540
|
+
const placementId = item.placementId.replace('#', '');
|
|
18541
|
+
const placement = document.getElementById(placementId);
|
|
18542
|
+
if (!placement) {
|
|
18543
|
+
this.eventService.handleSpotState(item.placementId, {
|
|
18544
|
+
state: {
|
|
18545
|
+
error: `Placement not found for id "${placementId}".`,
|
|
18546
|
+
loading: false,
|
|
18547
|
+
},
|
|
18548
|
+
});
|
|
18549
|
+
continue;
|
|
18550
|
+
}
|
|
18551
|
+
// Take over placement styles
|
|
18552
|
+
placement.removeAttribute('style');
|
|
18553
|
+
placement.removeAttribute('class');
|
|
18554
|
+
Object.assign(placement.style, {
|
|
18555
|
+
width: '100%',
|
|
18556
|
+
height: 'auto',
|
|
18557
|
+
display: 'flex',
|
|
18558
|
+
justifyContent: 'center',
|
|
18559
|
+
});
|
|
18560
|
+
if (spots.length === 1) {
|
|
18561
|
+
const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
|
|
18562
|
+
if (!isInjected) {
|
|
18563
|
+
continue;
|
|
18564
|
+
}
|
|
18565
|
+
}
|
|
18566
|
+
if (spots.length > 1) {
|
|
18567
|
+
const isInjected = this.injectCarouselSpotElement(placement, spots, itemConfig);
|
|
18568
|
+
if (!isInjected) {
|
|
18569
|
+
continue;
|
|
18570
|
+
}
|
|
18571
|
+
}
|
|
18572
|
+
}
|
|
18573
|
+
}
|
|
18574
|
+
/**
|
|
18575
|
+
* Makes a selection request on our server based on the provided data.
|
|
18576
|
+
*
|
|
18577
|
+
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
|
18578
|
+
*
|
|
18579
|
+
* @return {Promise<ISpots | {error: string}>} - The spots response object.
|
|
18580
|
+
*/
|
|
18581
|
+
async spotSelectionRequest(params) {
|
|
18582
|
+
const { inject, filter, config } = params;
|
|
18583
|
+
const request = {
|
|
18584
|
+
url: config === null || config === void 0 ? void 0 : config.url,
|
|
18585
|
+
filter,
|
|
18586
|
+
spots: inject.map((item) => ({
|
|
18587
|
+
placementId: item.placementId,
|
|
18588
|
+
spot: item.spotType,
|
|
18589
|
+
count: item === null || item === void 0 ? void 0 : item.count,
|
|
18590
|
+
...item === null || item === void 0 ? void 0 : item.filter,
|
|
18591
|
+
})),
|
|
18592
|
+
};
|
|
18593
|
+
return this.spotSelection(request);
|
|
17082
18594
|
}
|
|
17083
18595
|
/**
|
|
17084
|
-
*
|
|
18596
|
+
* Injects a carousel element with the provided spots into the placement.
|
|
18597
|
+
*
|
|
18598
|
+
* @param {HTMLElement} placement - The placement element.
|
|
18599
|
+
* @param {ISpot[]} spots - The spot data.
|
|
18600
|
+
* @param {IInjectSpotElementConfig} config - The configuration object.
|
|
17085
18601
|
*
|
|
17086
|
-
*
|
|
18602
|
+
* @return {void}
|
|
18603
|
+
*/
|
|
18604
|
+
injectCarouselSpotElement(placement, spots, config) {
|
|
18605
|
+
var _a;
|
|
18606
|
+
const carouselSlides = [];
|
|
18607
|
+
for (const spotItem of spots) {
|
|
18608
|
+
this.eventService.handleSpotState(placement.id, {
|
|
18609
|
+
displayConfig: {
|
|
18610
|
+
isCarousel: true,
|
|
18611
|
+
isCarouselItem: true,
|
|
18612
|
+
isSingleItem: false,
|
|
18613
|
+
},
|
|
18614
|
+
}, false);
|
|
18615
|
+
const spot = this.elementService.overrideSpotColors(spotItem, config === null || config === void 0 ? void 0 : config.colors);
|
|
18616
|
+
const content = SPOT_TEMPLATE_HTML_ELEMENT(spot, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
|
18617
|
+
if (!content) {
|
|
18618
|
+
this.eventService.handleSpotState(placement.id, {
|
|
18619
|
+
state: {
|
|
18620
|
+
error: `Failed to inject carousel spot item element. Could not create element for type "${spot.spot}".`,
|
|
18621
|
+
loading: false,
|
|
18622
|
+
},
|
|
18623
|
+
});
|
|
18624
|
+
continue;
|
|
18625
|
+
}
|
|
18626
|
+
this.eventService.registerSpot({
|
|
18627
|
+
spot,
|
|
18628
|
+
placementId: placement.id,
|
|
18629
|
+
spotElement: content,
|
|
18630
|
+
});
|
|
18631
|
+
carouselSlides.push(content);
|
|
18632
|
+
}
|
|
18633
|
+
// Get the max width and height of the spots
|
|
18634
|
+
const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
|
|
18635
|
+
maxWidth: Math.max(max.maxWidth, spot.width),
|
|
18636
|
+
maxHeight: Math.max(max.maxHeight, spot.height),
|
|
18637
|
+
}), { maxWidth: 0, maxHeight: 0 });
|
|
18638
|
+
// Create the carousel element
|
|
18639
|
+
const carouselElement = this.elementService.createCarouselElement({
|
|
18640
|
+
slides: carouselSlides,
|
|
18641
|
+
config: {
|
|
18642
|
+
fluid: config === null || config === void 0 ? void 0 : config.fluid,
|
|
18643
|
+
width: maxWidth,
|
|
18644
|
+
height: maxHeight,
|
|
18645
|
+
minScale: (_a = config === null || config === void 0 ? void 0 : config.minScale) !== null && _a !== void 0 ? _a : 0.25, // Scale down to 25% of the original size
|
|
18646
|
+
...config === null || config === void 0 ? void 0 : config.carousel,
|
|
18647
|
+
},
|
|
18648
|
+
});
|
|
18649
|
+
if (!carouselElement) {
|
|
18650
|
+
this.eventService.handleSpotState(placement.id, {
|
|
18651
|
+
state: {
|
|
18652
|
+
error: `Failed to inject spot carousel element. Could not create spot carousel element.`,
|
|
18653
|
+
loading: false,
|
|
18654
|
+
},
|
|
18655
|
+
});
|
|
18656
|
+
return false;
|
|
18657
|
+
}
|
|
18658
|
+
placement.replaceChildren(carouselElement);
|
|
18659
|
+
this.eventService.handleSpotState(placement.id, {
|
|
18660
|
+
dom: {
|
|
18661
|
+
spotElement: carouselElement,
|
|
18662
|
+
},
|
|
18663
|
+
state: {
|
|
18664
|
+
mounted: true,
|
|
18665
|
+
loading: false,
|
|
18666
|
+
},
|
|
18667
|
+
});
|
|
18668
|
+
return true;
|
|
18669
|
+
}
|
|
18670
|
+
/**
|
|
18671
|
+
* Injects a single spot element into the provided placement.
|
|
17087
18672
|
*
|
|
18673
|
+
* @param {IInjectSpotElement} injectItem - The inject item data.
|
|
18674
|
+
* @param {HTMLElement} placement - The placement element.
|
|
17088
18675
|
* @param {ISpot} spot - The spot data.
|
|
17089
|
-
* @param {
|
|
17090
|
-
*
|
|
17091
|
-
* @
|
|
17092
|
-
|
|
18676
|
+
* @param {IInjectSpotElementConfig} config - The configuration object.
|
|
18677
|
+
*
|
|
18678
|
+
* @return {void}
|
|
18679
|
+
*/
|
|
18680
|
+
injectOneSpotElement(injectItem, placement, spot, config) {
|
|
18681
|
+
var _a;
|
|
18682
|
+
const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
|
|
18683
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
|
18684
|
+
displayConfig: {
|
|
18685
|
+
isSingleItem: true,
|
|
18686
|
+
},
|
|
18687
|
+
}, false);
|
|
18688
|
+
// Create the spot template element
|
|
18689
|
+
const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
|
18690
|
+
if (!content) {
|
|
18691
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
|
18692
|
+
state: {
|
|
18693
|
+
error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
|
|
18694
|
+
loading: false,
|
|
18695
|
+
},
|
|
18696
|
+
});
|
|
18697
|
+
return false;
|
|
18698
|
+
}
|
|
18699
|
+
// Create the spot element
|
|
18700
|
+
const spotElement = this.elementService.createSpotElement({
|
|
18701
|
+
content,
|
|
18702
|
+
config: {
|
|
18703
|
+
fluid: config === null || config === void 0 ? void 0 : config.fluid,
|
|
18704
|
+
spot: spot.spot,
|
|
18705
|
+
width: spot.width,
|
|
18706
|
+
height: spot.height,
|
|
18707
|
+
minScale: (_a = config === null || config === void 0 ? void 0 : config.minScale) !== null && _a !== void 0 ? _a : 0.25, // Scale down to 25% of the original size
|
|
18708
|
+
},
|
|
18709
|
+
});
|
|
18710
|
+
if (!spotElement) {
|
|
18711
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
|
18712
|
+
state: {
|
|
18713
|
+
error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
|
|
18714
|
+
loading: false,
|
|
18715
|
+
},
|
|
18716
|
+
});
|
|
18717
|
+
return false;
|
|
18718
|
+
}
|
|
18719
|
+
this.eventService.registerSpot({
|
|
18720
|
+
spot: spotData,
|
|
18721
|
+
placementId: injectItem.placementId,
|
|
18722
|
+
spotElement,
|
|
18723
|
+
});
|
|
18724
|
+
placement.replaceChildren(spotElement);
|
|
18725
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
|
18726
|
+
dom: {
|
|
18727
|
+
spotElement,
|
|
18728
|
+
},
|
|
18729
|
+
state: {
|
|
18730
|
+
mounted: true,
|
|
18731
|
+
loading: false,
|
|
18732
|
+
},
|
|
18733
|
+
});
|
|
18734
|
+
return true;
|
|
18735
|
+
}
|
|
18736
|
+
/**
|
|
18737
|
+
* Prevents duplicate placement ids in the inject data.
|
|
18738
|
+
*
|
|
18739
|
+
* @param {IInjectSpotElement[]} inject - The inject data.
|
|
17093
18740
|
*
|
|
17094
|
-
* @
|
|
18741
|
+
* @throws {Error} - If a duplicate placement id is found.
|
|
18742
|
+
*
|
|
18743
|
+
* @return {void}
|
|
17095
18744
|
*/
|
|
17096
|
-
|
|
17097
|
-
|
|
18745
|
+
preventDuplicateSpotPlacementIds(inject) {
|
|
18746
|
+
const placementIds = new Set();
|
|
18747
|
+
for (const item of inject) {
|
|
18748
|
+
if (placementIds.has(item.placementId)) {
|
|
18749
|
+
this.eventService.handleSpotState(item.placementId, {
|
|
18750
|
+
state: {
|
|
18751
|
+
error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
|
|
18752
|
+
},
|
|
18753
|
+
});
|
|
18754
|
+
return false;
|
|
18755
|
+
}
|
|
18756
|
+
placementIds.add(item.placementId);
|
|
18757
|
+
}
|
|
18758
|
+
return true;
|
|
18759
|
+
}
|
|
18760
|
+
preventNonExistentSpotTypes(inject) {
|
|
18761
|
+
const newInject = [];
|
|
18762
|
+
for (const item of inject) {
|
|
18763
|
+
if (!Object.values(RMN_SPOT_TYPE).includes(item.spotType)) {
|
|
18764
|
+
this.eventService.handleSpotState(item.placementId, {
|
|
18765
|
+
state: {
|
|
18766
|
+
error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
|
|
18767
|
+
},
|
|
18768
|
+
});
|
|
18769
|
+
continue;
|
|
18770
|
+
}
|
|
18771
|
+
newInject.push(item);
|
|
18772
|
+
}
|
|
18773
|
+
return newInject;
|
|
18774
|
+
}
|
|
18775
|
+
updateSpotsState(inject) {
|
|
18776
|
+
for (const item of inject) {
|
|
18777
|
+
this.eventService.handleSpotState(item.placementId, {
|
|
18778
|
+
identifier: {
|
|
18779
|
+
placementId: item.placementId,
|
|
18780
|
+
spotType: item.spotType,
|
|
18781
|
+
},
|
|
18782
|
+
state: {
|
|
18783
|
+
loading: true,
|
|
18784
|
+
},
|
|
18785
|
+
});
|
|
18786
|
+
}
|
|
18787
|
+
}
|
|
18788
|
+
useSpotSelectionExample(inject) {
|
|
18789
|
+
const examples = RB_SPOTS_SELECTION_EXAMPLE;
|
|
18790
|
+
const data = {};
|
|
18791
|
+
inject.map((item) => {
|
|
18792
|
+
var _a, _b, _c;
|
|
18793
|
+
data[item.placementId] = (_c = (_a = examples[item.spotType]) === null || _a === void 0 ? void 0 : _a.slice(0, (_b = item.count) !== null && _b !== void 0 ? _b : 1)) !== null && _c !== void 0 ? _c : [];
|
|
18794
|
+
});
|
|
18795
|
+
return new Promise((resolve) => {
|
|
18796
|
+
resolve(data);
|
|
18797
|
+
});
|
|
17098
18798
|
}
|
|
17099
18799
|
}
|
|
17100
18800
|
/**
|
|
@@ -17110,24 +18810,66 @@ async function RmnClient(apiKey, config) {
|
|
|
17110
18810
|
const credentials = await authService.initialize();
|
|
17111
18811
|
return new LiquidCommerceRmnClient(credentials);
|
|
17112
18812
|
}
|
|
18813
|
+
/**
|
|
18814
|
+
* Creates a new instance of the RmnEventManager.
|
|
18815
|
+
*
|
|
18816
|
+
* @return {IRmnEventManager} - The RmnEventManager instance.
|
|
18817
|
+
*/
|
|
18818
|
+
function RmnEventManager() {
|
|
18819
|
+
const eventService = EventService.getInstance();
|
|
18820
|
+
return {
|
|
18821
|
+
/**
|
|
18822
|
+
* Subscribes to an event type.
|
|
18823
|
+
*/
|
|
18824
|
+
subscribe: (eventType, callback
|
|
18825
|
+
/* eslint-disable arrow-body-style */
|
|
18826
|
+
) => {
|
|
18827
|
+
return eventService.subscribe(eventType, callback);
|
|
18828
|
+
},
|
|
18829
|
+
/**
|
|
18830
|
+
* Publishes an event type.
|
|
18831
|
+
*/
|
|
18832
|
+
publish: (eventType, data) => {
|
|
18833
|
+
eventService.publish(eventType, data);
|
|
18834
|
+
},
|
|
18835
|
+
/**
|
|
18836
|
+
* Destroys a spot element
|
|
18837
|
+
*/
|
|
18838
|
+
destroySpot: (placementId) => {
|
|
18839
|
+
eventService.unregisterSpot(placementId);
|
|
18840
|
+
},
|
|
18841
|
+
};
|
|
18842
|
+
}
|
|
17113
18843
|
/**
|
|
17114
18844
|
* Creates the spot html element based on the provided data using shadow dom.
|
|
17115
18845
|
*
|
|
17116
18846
|
* This method is useful when you are initializing the client in a non-browser environment.
|
|
17117
|
-
* When you request a spot selection, you will receive the spot data in server-side and return them
|
|
18847
|
+
* When you request a spot selection, you will receive the spot data in server-side and return them to the client.
|
|
17118
18848
|
* Then you can use this function to create the spot html element based on the provided data without the need of the RmnClient instance.
|
|
17119
18849
|
*
|
|
17120
18850
|
* @param {ISpot} spot - The spot data.
|
|
17121
|
-
* @param {
|
|
17122
|
-
* @param {ICreateSpotElementConfig.fluid} config.fluid - If the spot should be fluid or not.
|
|
17123
|
-
* @param {ICreateSpotElementConfig.customContent} config.customContent - Use a custom html element/string.
|
|
17124
|
-
* @param {ICreateSpotElementConfig.redirectOnClick} config.redirectOnClick - If the spot should redirect on click.
|
|
18851
|
+
* @param {IRmnCreateSpotElementConfig} config - The configuration object.
|
|
17125
18852
|
*
|
|
17126
18853
|
* @return {HTMLElement | null} - The spot html element or null if the browser environment is not available.
|
|
17127
18854
|
*/
|
|
17128
18855
|
function RmnCreateSpotElement(spot, config) {
|
|
17129
|
-
|
|
17130
|
-
|
|
18856
|
+
var _a;
|
|
18857
|
+
const elementService = ElementService.getInstance();
|
|
18858
|
+
const spotData = elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
|
|
18859
|
+
const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
|
18860
|
+
if (!content) {
|
|
18861
|
+
console.warn(`RmnSdk: Failed to create spot element for type "${spotData.spot}".`);
|
|
18862
|
+
return null;
|
|
18863
|
+
}
|
|
18864
|
+
return elementService.createSpotElement({
|
|
18865
|
+
content,
|
|
18866
|
+
config: {
|
|
18867
|
+
fluid: true,
|
|
18868
|
+
width: spot.width,
|
|
18869
|
+
height: spot.height,
|
|
18870
|
+
minScale: (_a = config === null || config === void 0 ? void 0 : config.minScale) !== null && _a !== void 0 ? _a : 0.25, // Scale down to 25% of the original size
|
|
18871
|
+
},
|
|
18872
|
+
});
|
|
17131
18873
|
}
|
|
17132
18874
|
|
|
17133
|
-
export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement };
|
|
18875
|
+
export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement, RmnEventManager };
|