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