@zerocost/sdk 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +51 -38
- package/dist/index.js +51 -38
- package/dist/modules/widget.d.ts +2 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -146,6 +146,7 @@ var POSITION_STYLES = {
|
|
|
146
146
|
"sidebar-left": "position:fixed;top:50%;left:24px;transform:translateY(-50%);z-index:9999;",
|
|
147
147
|
"sidebar-right": "position:fixed;top:50%;right:24px;transform:translateY(-50%);z-index:9999;"
|
|
148
148
|
};
|
|
149
|
+
var FORMAT_PRIORITY = ["video-widget", "sponsored-card", "sidebar-display", "tooltip-ad", "inline-text"];
|
|
149
150
|
var WidgetModule = class {
|
|
150
151
|
constructor(client) {
|
|
151
152
|
this.client = client;
|
|
@@ -154,10 +155,14 @@ var WidgetModule = class {
|
|
|
154
155
|
async autoInjectWithConfig(display) {
|
|
155
156
|
try {
|
|
156
157
|
const configs = this.normalizeConfigs(display);
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
const chosen = this.pickOneFormat(configs);
|
|
159
|
+
if (!chosen) {
|
|
160
|
+
this.client.log("No ad formats enabled. Skipping injection.");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
this.client.log(`Auto-inject: rendering "${chosen.format}" only.`);
|
|
164
|
+
await this.mountSingleFormat(chosen.format, chosen.config);
|
|
165
|
+
this.client.log("\u2713 Ad slot injected.");
|
|
161
166
|
} catch (err) {
|
|
162
167
|
this.client.log(`Widget autoInject error: ${err}`);
|
|
163
168
|
}
|
|
@@ -166,15 +171,18 @@ var WidgetModule = class {
|
|
|
166
171
|
try {
|
|
167
172
|
this.client.log("Fetching ad placements from server...");
|
|
168
173
|
const { display } = await this.client.request("/get-placements");
|
|
169
|
-
|
|
170
|
-
const enabledCount = Object.values(configs).filter((c) => c.enabled).length;
|
|
171
|
-
this.client.log(`Auto-inject: ${enabledCount} ad format(s) enabled. No custom component needed \u2014 ads render automatically.`);
|
|
172
|
-
await this.mountFormats(configs);
|
|
173
|
-
this.client.log("\u2713 Ad slots injected successfully. Ads will appear once inventory is available.");
|
|
174
|
+
await this.autoInjectWithConfig(display);
|
|
174
175
|
} catch (err) {
|
|
175
176
|
this.client.log(`Widget autoInject error: ${err}`);
|
|
176
177
|
}
|
|
177
178
|
}
|
|
179
|
+
pickOneFormat(configs) {
|
|
180
|
+
for (const fmt of FORMAT_PRIORITY) {
|
|
181
|
+
const cfg = configs[fmt];
|
|
182
|
+
if (cfg?.enabled) return { format: fmt, config: cfg };
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
178
186
|
normalizeConfigs(display) {
|
|
179
187
|
if (display && "video-widget" in display) {
|
|
180
188
|
return display;
|
|
@@ -182,30 +190,25 @@ var WidgetModule = class {
|
|
|
182
190
|
const pos = display?.position || "bottom-right";
|
|
183
191
|
const theme = display?.theme || "dark";
|
|
184
192
|
return {
|
|
185
|
-
"video-widget": { position: pos, theme, autoplay:
|
|
186
|
-
"tooltip-ad": { position: pos, theme, autoplay: false, enabled:
|
|
187
|
-
"sponsored-card": { position: pos, theme, autoplay: false, enabled:
|
|
188
|
-
"inline-text": { position: "after-paragraph-1", theme, autoplay: false, enabled:
|
|
193
|
+
"video-widget": { position: pos, theme, autoplay: true, enabled: true },
|
|
194
|
+
"tooltip-ad": { position: pos, theme, autoplay: false, enabled: false },
|
|
195
|
+
"sponsored-card": { position: pos, theme, autoplay: false, enabled: false },
|
|
196
|
+
"inline-text": { position: "after-paragraph-1", theme, autoplay: false, enabled: false }
|
|
189
197
|
};
|
|
190
198
|
}
|
|
191
|
-
async
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const maxW = format === "video-widget" ? "max-width:200px;" : format === "sponsored-card" || format === "sidebar-display" ? "max-width:176px;" : "max-width:320px;";
|
|
205
|
-
el.setAttribute("style", posStyle + maxW);
|
|
206
|
-
document.body.appendChild(el);
|
|
207
|
-
await this.mount(elId, { format, refreshInterval: 30, theme: cfg.theme, autoplay: cfg.autoplay });
|
|
208
|
-
}
|
|
199
|
+
async mountSingleFormat(format, cfg) {
|
|
200
|
+
const elId = `zerocost-${format}`;
|
|
201
|
+
if (document.getElementById(elId)) return;
|
|
202
|
+
if (format === "inline-text") return;
|
|
203
|
+
const el = document.createElement("div");
|
|
204
|
+
el.id = elId;
|
|
205
|
+
el.setAttribute("data-zerocost", "");
|
|
206
|
+
el.setAttribute("data-format", format);
|
|
207
|
+
const posStyle = POSITION_STYLES[cfg.position] || POSITION_STYLES["bottom-right"];
|
|
208
|
+
const maxW = format === "video-widget" ? "max-width:200px;" : format === "sponsored-card" || format === "sidebar-display" ? "max-width:176px;" : "max-width:320px;";
|
|
209
|
+
el.setAttribute("style", posStyle + maxW);
|
|
210
|
+
document.body.appendChild(el);
|
|
211
|
+
await this.mount(elId, { format, refreshInterval: 30, theme: cfg.theme, autoplay: cfg.autoplay ?? true });
|
|
209
212
|
}
|
|
210
213
|
async mount(targetElementId, options = {}) {
|
|
211
214
|
const el = document.getElementById(targetElementId);
|
|
@@ -238,6 +241,12 @@ var WidgetModule = class {
|
|
|
238
241
|
}
|
|
239
242
|
el.innerHTML = data.html;
|
|
240
243
|
el.setAttribute("data-zerocost-ad-id", ad.id);
|
|
244
|
+
const video = el.querySelector("video");
|
|
245
|
+
if (video) {
|
|
246
|
+
video.muted = true;
|
|
247
|
+
video.play().catch(() => {
|
|
248
|
+
});
|
|
249
|
+
}
|
|
241
250
|
const ctas = el.querySelectorAll("[data-zc-cta]");
|
|
242
251
|
ctas.forEach((cta) => {
|
|
243
252
|
cta.addEventListener("click", () => {
|
|
@@ -308,7 +317,7 @@ var WidgetModule = class {
|
|
|
308
317
|
return `
|
|
309
318
|
<div style="width:200px;aspect-ratio:9/16;border-radius:12px;border:1px solid ${border};overflow:hidden;position:relative;font-family:system-ui,-apple-system,sans-serif;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.5" : "0.15"});">
|
|
310
319
|
<button data-zc-close style="position:absolute;top:8px;right:8px;z-index:20;width:24px;height:24px;border-radius:50%;background:rgba(0,0,0,0.5);backdrop-filter:blur(4px);border:none;color:rgba(255,255,255,0.7);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;line-height:1;">\u2715</button>
|
|
311
|
-
${hasVideo ? `<video src="${this.esc(videoSrc)}"
|
|
320
|
+
${hasVideo ? `<video src="${this.esc(videoSrc)}" autoplay muted loop playsinline preload="auto" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;"></video>` : `<img src="${this.esc(videoSrc)}" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;" />`}
|
|
312
321
|
<div style="position:absolute;inset-inline:0;bottom:0;padding:12px;background:linear-gradient(to top,rgba(0,0,0,0.9),rgba(0,0,0,0.5),transparent);z-index:10;">
|
|
313
322
|
<div style="font-size:8px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:rgba(255,255,255,0.5);margin-bottom:2px;">Sponsored by ${this.esc(sponsor)}</div>
|
|
314
323
|
<div style="color:#fff;font-weight:600;font-size:12px;line-height:1.3;">${this.esc(ad.description || "")}</div>
|
|
@@ -327,7 +336,8 @@ var WidgetModule = class {
|
|
|
327
336
|
const fgFaint = isDark ? "#888" : "#999";
|
|
328
337
|
const border = isDark ? "#333" : "#e0e0e0";
|
|
329
338
|
return `
|
|
330
|
-
<div style="max-width:320px;border-radius:8px;padding:12px;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;">
|
|
339
|
+
<div style="max-width:320px;border-radius:8px;padding:12px;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;position:relative;">
|
|
340
|
+
<button data-zc-close style="position:absolute;top:6px;right:6px;z-index:20;width:20px;height:20px;border-radius:50%;background:${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)"};border:none;color:${fgFaint};cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;">\u2715</button>
|
|
331
341
|
<div style="font-size:10px;font-family:monospace;margin-bottom:6px;display:flex;align-items:center;color:${fgFaint};">
|
|
332
342
|
<span style="width:6px;height:6px;border-radius:50%;background:#22c55e;margin-right:6px;display:inline-block;"></span>
|
|
333
343
|
Sponsored
|
|
@@ -348,13 +358,11 @@ var WidgetModule = class {
|
|
|
348
358
|
const fg = isDark ? "#fff" : "#111";
|
|
349
359
|
const fgFaint = isDark ? "#888" : "#999";
|
|
350
360
|
const border = isDark ? "#333" : "#e0e0e0";
|
|
351
|
-
const iconBg = isDark ? "#0a0a0a" : "#f5f5f5";
|
|
352
|
-
const initial = (ad.title || "A").charAt(0).toUpperCase();
|
|
353
361
|
return `
|
|
354
|
-
<div style="width:176px;border-radius:12px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;">
|
|
362
|
+
<div style="width:176px;border-radius:12px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;position:relative;">
|
|
363
|
+
<button data-zc-close style="position:absolute;top:6px;right:6px;z-index:20;width:20px;height:20px;border-radius:50%;background:rgba(0,0,0,0.5);backdrop-filter:blur(4px);border:none;color:rgba(255,255,255,0.7);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;">\u2715</button>
|
|
355
364
|
${ad.image_url ? `<img src="${this.esc(ad.image_url)}" style="width:100%;height:80px;object-fit:cover;display:block;" />` : `<div style="height:80px;background:linear-gradient(135deg,rgba(249,115,22,0.2),rgba(236,72,153,0.2));"></div>`}
|
|
356
365
|
<div style="padding:12px;">
|
|
357
|
-
<div style="width:24px;height:24px;border-radius:4px;background:${iconBg};border:1px solid ${border};display:flex;align-items:center;justify-content:center;font-weight:700;font-size:9px;color:${fg};margin-bottom:8px;">${initial}</div>
|
|
358
366
|
<div style="font-weight:700;font-size:12px;color:${fg};margin-bottom:2px;letter-spacing:-0.01em;">${this.esc(ad.title)}</div>
|
|
359
367
|
<div style="font-size:10px;color:${fgFaint};line-height:1.4;margin-bottom:12px;">${this.esc(ad.description || "")}</div>
|
|
360
368
|
<a href="${this.esc(ad.landing_url)}" target="_blank" rel="noopener" data-zc-cta style="display:block;width:100%;padding:6px 0;border:1px solid ${border};border-radius:4px;font-size:10px;font-weight:500;color:${fg};text-align:center;text-decoration:none;cursor:pointer;">${this.esc(ad.cta_text || "Learn More")}</a>
|
|
@@ -379,7 +387,8 @@ var WidgetModule = class {
|
|
|
379
387
|
const initial = "\u25B2";
|
|
380
388
|
const sponsor = ad.title?.split("\u2014")[0]?.trim() || ad.title || "Sponsor";
|
|
381
389
|
return `
|
|
382
|
-
<div style="border-radius:8px;overflow:hidden;border:1px solid ${border};background:${bg};font-family:system-ui,-apple-system,sans-serif;max-width:100%;">
|
|
390
|
+
<div style="border-radius:8px;overflow:hidden;border:1px solid ${border};background:${bg};font-family:system-ui,-apple-system,sans-serif;max-width:100%;position:relative;">
|
|
391
|
+
<button data-zc-close style="position:absolute;top:6px;right:6px;z-index:20;width:20px;height:20px;border-radius:50%;background:${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)"};border:none;color:${fgFaint};cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;">\u2715</button>
|
|
383
392
|
<div style="padding:8px 12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid ${headerBorder};">
|
|
384
393
|
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:${fgFaint};">Sponsored</span>
|
|
385
394
|
<span style="font-size:9px;color:${fgFaint};">Ad \xB7 ${this.esc(sponsor)}</span>
|
|
@@ -768,6 +777,10 @@ var ZerocostSDK = class {
|
|
|
768
777
|
this.core.log("Running in non-browser environment \u2014 skipping DOM injection.");
|
|
769
778
|
return;
|
|
770
779
|
}
|
|
780
|
+
const isIframe = window !== window.top;
|
|
781
|
+
if (isIframe) {
|
|
782
|
+
this.core.log("Running inside an iframe. Ads will still render if permissions allow.");
|
|
783
|
+
}
|
|
771
784
|
this.core.log("Initializing... Ads will be auto-injected into the DOM. No custom component required.");
|
|
772
785
|
try {
|
|
773
786
|
const { display, dataCollection } = await this.core.request("/get-placements");
|
package/dist/index.js
CHANGED
|
@@ -117,6 +117,7 @@ var POSITION_STYLES = {
|
|
|
117
117
|
"sidebar-left": "position:fixed;top:50%;left:24px;transform:translateY(-50%);z-index:9999;",
|
|
118
118
|
"sidebar-right": "position:fixed;top:50%;right:24px;transform:translateY(-50%);z-index:9999;"
|
|
119
119
|
};
|
|
120
|
+
var FORMAT_PRIORITY = ["video-widget", "sponsored-card", "sidebar-display", "tooltip-ad", "inline-text"];
|
|
120
121
|
var WidgetModule = class {
|
|
121
122
|
constructor(client) {
|
|
122
123
|
this.client = client;
|
|
@@ -125,10 +126,14 @@ var WidgetModule = class {
|
|
|
125
126
|
async autoInjectWithConfig(display) {
|
|
126
127
|
try {
|
|
127
128
|
const configs = this.normalizeConfigs(display);
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
const chosen = this.pickOneFormat(configs);
|
|
130
|
+
if (!chosen) {
|
|
131
|
+
this.client.log("No ad formats enabled. Skipping injection.");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.client.log(`Auto-inject: rendering "${chosen.format}" only.`);
|
|
135
|
+
await this.mountSingleFormat(chosen.format, chosen.config);
|
|
136
|
+
this.client.log("\u2713 Ad slot injected.");
|
|
132
137
|
} catch (err) {
|
|
133
138
|
this.client.log(`Widget autoInject error: ${err}`);
|
|
134
139
|
}
|
|
@@ -137,15 +142,18 @@ var WidgetModule = class {
|
|
|
137
142
|
try {
|
|
138
143
|
this.client.log("Fetching ad placements from server...");
|
|
139
144
|
const { display } = await this.client.request("/get-placements");
|
|
140
|
-
|
|
141
|
-
const enabledCount = Object.values(configs).filter((c) => c.enabled).length;
|
|
142
|
-
this.client.log(`Auto-inject: ${enabledCount} ad format(s) enabled. No custom component needed \u2014 ads render automatically.`);
|
|
143
|
-
await this.mountFormats(configs);
|
|
144
|
-
this.client.log("\u2713 Ad slots injected successfully. Ads will appear once inventory is available.");
|
|
145
|
+
await this.autoInjectWithConfig(display);
|
|
145
146
|
} catch (err) {
|
|
146
147
|
this.client.log(`Widget autoInject error: ${err}`);
|
|
147
148
|
}
|
|
148
149
|
}
|
|
150
|
+
pickOneFormat(configs) {
|
|
151
|
+
for (const fmt of FORMAT_PRIORITY) {
|
|
152
|
+
const cfg = configs[fmt];
|
|
153
|
+
if (cfg?.enabled) return { format: fmt, config: cfg };
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
149
157
|
normalizeConfigs(display) {
|
|
150
158
|
if (display && "video-widget" in display) {
|
|
151
159
|
return display;
|
|
@@ -153,30 +161,25 @@ var WidgetModule = class {
|
|
|
153
161
|
const pos = display?.position || "bottom-right";
|
|
154
162
|
const theme = display?.theme || "dark";
|
|
155
163
|
return {
|
|
156
|
-
"video-widget": { position: pos, theme, autoplay:
|
|
157
|
-
"tooltip-ad": { position: pos, theme, autoplay: false, enabled:
|
|
158
|
-
"sponsored-card": { position: pos, theme, autoplay: false, enabled:
|
|
159
|
-
"inline-text": { position: "after-paragraph-1", theme, autoplay: false, enabled:
|
|
164
|
+
"video-widget": { position: pos, theme, autoplay: true, enabled: true },
|
|
165
|
+
"tooltip-ad": { position: pos, theme, autoplay: false, enabled: false },
|
|
166
|
+
"sponsored-card": { position: pos, theme, autoplay: false, enabled: false },
|
|
167
|
+
"inline-text": { position: "after-paragraph-1", theme, autoplay: false, enabled: false }
|
|
160
168
|
};
|
|
161
169
|
}
|
|
162
|
-
async
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const maxW = format === "video-widget" ? "max-width:200px;" : format === "sponsored-card" || format === "sidebar-display" ? "max-width:176px;" : "max-width:320px;";
|
|
176
|
-
el.setAttribute("style", posStyle + maxW);
|
|
177
|
-
document.body.appendChild(el);
|
|
178
|
-
await this.mount(elId, { format, refreshInterval: 30, theme: cfg.theme, autoplay: cfg.autoplay });
|
|
179
|
-
}
|
|
170
|
+
async mountSingleFormat(format, cfg) {
|
|
171
|
+
const elId = `zerocost-${format}`;
|
|
172
|
+
if (document.getElementById(elId)) return;
|
|
173
|
+
if (format === "inline-text") return;
|
|
174
|
+
const el = document.createElement("div");
|
|
175
|
+
el.id = elId;
|
|
176
|
+
el.setAttribute("data-zerocost", "");
|
|
177
|
+
el.setAttribute("data-format", format);
|
|
178
|
+
const posStyle = POSITION_STYLES[cfg.position] || POSITION_STYLES["bottom-right"];
|
|
179
|
+
const maxW = format === "video-widget" ? "max-width:200px;" : format === "sponsored-card" || format === "sidebar-display" ? "max-width:176px;" : "max-width:320px;";
|
|
180
|
+
el.setAttribute("style", posStyle + maxW);
|
|
181
|
+
document.body.appendChild(el);
|
|
182
|
+
await this.mount(elId, { format, refreshInterval: 30, theme: cfg.theme, autoplay: cfg.autoplay ?? true });
|
|
180
183
|
}
|
|
181
184
|
async mount(targetElementId, options = {}) {
|
|
182
185
|
const el = document.getElementById(targetElementId);
|
|
@@ -209,6 +212,12 @@ var WidgetModule = class {
|
|
|
209
212
|
}
|
|
210
213
|
el.innerHTML = data.html;
|
|
211
214
|
el.setAttribute("data-zerocost-ad-id", ad.id);
|
|
215
|
+
const video = el.querySelector("video");
|
|
216
|
+
if (video) {
|
|
217
|
+
video.muted = true;
|
|
218
|
+
video.play().catch(() => {
|
|
219
|
+
});
|
|
220
|
+
}
|
|
212
221
|
const ctas = el.querySelectorAll("[data-zc-cta]");
|
|
213
222
|
ctas.forEach((cta) => {
|
|
214
223
|
cta.addEventListener("click", () => {
|
|
@@ -279,7 +288,7 @@ var WidgetModule = class {
|
|
|
279
288
|
return `
|
|
280
289
|
<div style="width:200px;aspect-ratio:9/16;border-radius:12px;border:1px solid ${border};overflow:hidden;position:relative;font-family:system-ui,-apple-system,sans-serif;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.5" : "0.15"});">
|
|
281
290
|
<button data-zc-close style="position:absolute;top:8px;right:8px;z-index:20;width:24px;height:24px;border-radius:50%;background:rgba(0,0,0,0.5);backdrop-filter:blur(4px);border:none;color:rgba(255,255,255,0.7);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;line-height:1;">\u2715</button>
|
|
282
|
-
${hasVideo ? `<video src="${this.esc(videoSrc)}"
|
|
291
|
+
${hasVideo ? `<video src="${this.esc(videoSrc)}" autoplay muted loop playsinline preload="auto" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;"></video>` : `<img src="${this.esc(videoSrc)}" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;" />`}
|
|
283
292
|
<div style="position:absolute;inset-inline:0;bottom:0;padding:12px;background:linear-gradient(to top,rgba(0,0,0,0.9),rgba(0,0,0,0.5),transparent);z-index:10;">
|
|
284
293
|
<div style="font-size:8px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:rgba(255,255,255,0.5);margin-bottom:2px;">Sponsored by ${this.esc(sponsor)}</div>
|
|
285
294
|
<div style="color:#fff;font-weight:600;font-size:12px;line-height:1.3;">${this.esc(ad.description || "")}</div>
|
|
@@ -298,7 +307,8 @@ var WidgetModule = class {
|
|
|
298
307
|
const fgFaint = isDark ? "#888" : "#999";
|
|
299
308
|
const border = isDark ? "#333" : "#e0e0e0";
|
|
300
309
|
return `
|
|
301
|
-
<div style="max-width:320px;border-radius:8px;padding:12px;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;">
|
|
310
|
+
<div style="max-width:320px;border-radius:8px;padding:12px;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;position:relative;">
|
|
311
|
+
<button data-zc-close style="position:absolute;top:6px;right:6px;z-index:20;width:20px;height:20px;border-radius:50%;background:${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)"};border:none;color:${fgFaint};cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;">\u2715</button>
|
|
302
312
|
<div style="font-size:10px;font-family:monospace;margin-bottom:6px;display:flex;align-items:center;color:${fgFaint};">
|
|
303
313
|
<span style="width:6px;height:6px;border-radius:50%;background:#22c55e;margin-right:6px;display:inline-block;"></span>
|
|
304
314
|
Sponsored
|
|
@@ -319,13 +329,11 @@ var WidgetModule = class {
|
|
|
319
329
|
const fg = isDark ? "#fff" : "#111";
|
|
320
330
|
const fgFaint = isDark ? "#888" : "#999";
|
|
321
331
|
const border = isDark ? "#333" : "#e0e0e0";
|
|
322
|
-
const iconBg = isDark ? "#0a0a0a" : "#f5f5f5";
|
|
323
|
-
const initial = (ad.title || "A").charAt(0).toUpperCase();
|
|
324
332
|
return `
|
|
325
|
-
<div style="width:176px;border-radius:12px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;">
|
|
333
|
+
<div style="width:176px;border-radius:12px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,${isDark ? "0.4" : "0.12"});background:${bg};border:1px solid ${border};font-family:system-ui,-apple-system,sans-serif;position:relative;">
|
|
334
|
+
<button data-zc-close style="position:absolute;top:6px;right:6px;z-index:20;width:20px;height:20px;border-radius:50%;background:rgba(0,0,0,0.5);backdrop-filter:blur(4px);border:none;color:rgba(255,255,255,0.7);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;">\u2715</button>
|
|
326
335
|
${ad.image_url ? `<img src="${this.esc(ad.image_url)}" style="width:100%;height:80px;object-fit:cover;display:block;" />` : `<div style="height:80px;background:linear-gradient(135deg,rgba(249,115,22,0.2),rgba(236,72,153,0.2));"></div>`}
|
|
327
336
|
<div style="padding:12px;">
|
|
328
|
-
<div style="width:24px;height:24px;border-radius:4px;background:${iconBg};border:1px solid ${border};display:flex;align-items:center;justify-content:center;font-weight:700;font-size:9px;color:${fg};margin-bottom:8px;">${initial}</div>
|
|
329
337
|
<div style="font-weight:700;font-size:12px;color:${fg};margin-bottom:2px;letter-spacing:-0.01em;">${this.esc(ad.title)}</div>
|
|
330
338
|
<div style="font-size:10px;color:${fgFaint};line-height:1.4;margin-bottom:12px;">${this.esc(ad.description || "")}</div>
|
|
331
339
|
<a href="${this.esc(ad.landing_url)}" target="_blank" rel="noopener" data-zc-cta style="display:block;width:100%;padding:6px 0;border:1px solid ${border};border-radius:4px;font-size:10px;font-weight:500;color:${fg};text-align:center;text-decoration:none;cursor:pointer;">${this.esc(ad.cta_text || "Learn More")}</a>
|
|
@@ -350,7 +358,8 @@ var WidgetModule = class {
|
|
|
350
358
|
const initial = "\u25B2";
|
|
351
359
|
const sponsor = ad.title?.split("\u2014")[0]?.trim() || ad.title || "Sponsor";
|
|
352
360
|
return `
|
|
353
|
-
<div style="border-radius:8px;overflow:hidden;border:1px solid ${border};background:${bg};font-family:system-ui,-apple-system,sans-serif;max-width:100%;">
|
|
361
|
+
<div style="border-radius:8px;overflow:hidden;border:1px solid ${border};background:${bg};font-family:system-ui,-apple-system,sans-serif;max-width:100%;position:relative;">
|
|
362
|
+
<button data-zc-close style="position:absolute;top:6px;right:6px;z-index:20;width:20px;height:20px;border-radius:50%;background:${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)"};border:none;color:${fgFaint};cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;">\u2715</button>
|
|
354
363
|
<div style="padding:8px 12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid ${headerBorder};">
|
|
355
364
|
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:${fgFaint};">Sponsored</span>
|
|
356
365
|
<span style="font-size:9px;color:${fgFaint};">Ad \xB7 ${this.esc(sponsor)}</span>
|
|
@@ -739,6 +748,10 @@ var ZerocostSDK = class {
|
|
|
739
748
|
this.core.log("Running in non-browser environment \u2014 skipping DOM injection.");
|
|
740
749
|
return;
|
|
741
750
|
}
|
|
751
|
+
const isIframe = window !== window.top;
|
|
752
|
+
if (isIframe) {
|
|
753
|
+
this.core.log("Running inside an iframe. Ads will still render if permissions allow.");
|
|
754
|
+
}
|
|
742
755
|
this.core.log("Initializing... Ads will be auto-injected into the DOM. No custom component required.");
|
|
743
756
|
try {
|
|
744
757
|
const { display, dataCollection } = await this.core.request("/get-placements");
|
package/dist/modules/widget.d.ts
CHANGED
|
@@ -15,8 +15,9 @@ export declare class WidgetModule {
|
|
|
15
15
|
theme: string;
|
|
16
16
|
}): Promise<void>;
|
|
17
17
|
autoInject(): Promise<void>;
|
|
18
|
+
private pickOneFormat;
|
|
18
19
|
private normalizeConfigs;
|
|
19
|
-
private
|
|
20
|
+
private mountSingleFormat;
|
|
20
21
|
mount(targetElementId: string, options?: {
|
|
21
22
|
format?: string;
|
|
22
23
|
refreshInterval?: number;
|