@adsterra-ad/svelte 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,329 @@
1
+ // src/index.ts
2
+ import { configureAds } from "@adsterra-ad/core";
3
+
4
+ // src/AdBanner.svelte
5
+ import "svelte/internal/disclose-version";
6
+ import "svelte/internal/flags/legacy";
7
+ import * as $ from "svelte/internal/client";
8
+ import { onMount } from "svelte";
9
+ import { buildSrcDoc, createBannerId, resolveAdConfig } from "@adsterra-ad/core";
10
+ var root_2 = $.from_html(`<span> </span>`);
11
+ var root_3 = $.from_html(`<span> </span>`);
12
+ var root_1 = $.from_html(`<div><!> <div data-testid="ad-banner"><iframe title="Advertisement" frameborder="0" scrolling="no" sandbox="allow-scripts allow-forms allow-same-origin allow-popups allow-modals"></iframe></div> <!></div>`);
13
+ function AdBanner($$anchor, $$props) {
14
+ $.push($$props, false);
15
+ let format = $.prop($$props, "format", 8);
16
+ let provider = $.prop($$props, "provider", 8, "adsterra");
17
+ let adKey = $.prop($$props, "adKey", 8, "");
18
+ let className = $.prop($$props, "className", 8, "");
19
+ let adLabel = $.prop($$props, "adLabel", 8, "Advertisement");
20
+ let showAdLabel = $.prop($$props, "showAdLabel", 8, true);
21
+ let adLabelPosition = $.prop($$props, "adLabelPosition", 8, "top-left");
22
+ let onLoad = $.prop($$props, "onLoad", 24, () => void 0);
23
+ let onError = $.prop($$props, "onError", 24, () => void 0);
24
+ const bannerId = createBannerId();
25
+ let activeProvider = $.mutable_source(provider());
26
+ let adLoaded = $.mutable_source(false);
27
+ let adFailed = $.mutable_source(false);
28
+ let config = $.mutable_source(resolveAdConfig(format(), adKey() || void 0));
29
+ let iframeSrcDoc = $.mutable_source("");
30
+ let wrapperStyle = $.mutable_source("");
31
+ let topLabel = $.mutable_source(false);
32
+ let bottomLabel = $.mutable_source(false);
33
+ let labelSpacing = $.mutable_source("");
34
+ let labelAlign = $.mutable_source("");
35
+ let visibilityStyle = $.mutable_source("");
36
+ const handleMessage = (event) => {
37
+ const data = event.data;
38
+ if (!data || data.bannerId !== bannerId) return;
39
+ if (data.type === "ad-load-success") {
40
+ $.set(adLoaded, true);
41
+ onLoad()?.();
42
+ return;
43
+ }
44
+ if (data.type === "ad-load-error") {
45
+ $.set(adFailed, true);
46
+ onError()?.();
47
+ }
48
+ };
49
+ onMount(() => {
50
+ window.addEventListener("message", handleMessage);
51
+ return () => window.removeEventListener("message", handleMessage);
52
+ });
53
+ $.legacy_pre_effect(() => ($.deep_read_state(provider()), $.get(activeProvider)), () => {
54
+ if (provider() !== $.get(activeProvider)) $.set(activeProvider, provider());
55
+ });
56
+ $.legacy_pre_effect(
57
+ () => (resolveAdConfig, $.deep_read_state(format()), $.deep_read_state(adKey())),
58
+ () => {
59
+ $.set(config, resolveAdConfig(format(), adKey() || void 0));
60
+ }
61
+ );
62
+ $.legacy_pre_effect(
63
+ () => (buildSrcDoc, $.deep_read_state(format()), $.get(activeProvider), $.get(config)),
64
+ () => {
65
+ $.set(iframeSrcDoc, buildSrcDoc({
66
+ format: format(),
67
+ provider: $.get(activeProvider),
68
+ config: $.get(config),
69
+ bannerId
70
+ }));
71
+ }
72
+ );
73
+ $.legacy_pre_effect(() => $.deep_read_state(adLabelPosition()), () => {
74
+ $.set(wrapperStyle, `display:inline-flex;flex-direction:column;align-items:${adLabelPosition().endsWith("left") ? "flex-start" : adLabelPosition().endsWith("right") ? "flex-end" : "center"};`);
75
+ });
76
+ $.legacy_pre_effect(
77
+ () => ($.deep_read_state(showAdLabel()), $.deep_read_state(adLabelPosition())),
78
+ () => {
79
+ $.set(topLabel, showAdLabel() && adLabelPosition().startsWith("top"));
80
+ }
81
+ );
82
+ $.legacy_pre_effect(
83
+ () => ($.deep_read_state(showAdLabel()), $.deep_read_state(adLabelPosition())),
84
+ () => {
85
+ $.set(bottomLabel, showAdLabel() && adLabelPosition().startsWith("bottom"));
86
+ }
87
+ );
88
+ $.legacy_pre_effect(() => ($.get(topLabel), $.get(bottomLabel)), () => {
89
+ $.set(labelSpacing, $.get(topLabel) ? "margin-bottom:4px;" : $.get(bottomLabel) ? "margin-top:4px;" : "");
90
+ });
91
+ $.legacy_pre_effect(() => $.deep_read_state(adLabelPosition()), () => {
92
+ $.set(labelAlign, `text-align:${adLabelPosition().endsWith("left") ? "left" : adLabelPosition().endsWith("right") ? "right" : "center"};width:100%;`);
93
+ });
94
+ $.legacy_pre_effect(() => $.get(adLoaded), () => {
95
+ $.set(visibilityStyle, $.get(adLoaded) ? "opacity:1;transform:scale(1);" : "opacity:0;transform:scale(0.95);pointer-events:none;position:absolute;width:0;height:0;overflow:hidden;");
96
+ });
97
+ $.legacy_pre_effect_reset();
98
+ $.init();
99
+ var fragment = $.comment();
100
+ var node = $.first_child(fragment);
101
+ {
102
+ var consequent_2 = ($$anchor2) => {
103
+ var div = root_1();
104
+ var node_1 = $.child(div);
105
+ {
106
+ var consequent = ($$anchor3) => {
107
+ var span = root_2();
108
+ var text = $.child(span, true);
109
+ $.reset(span);
110
+ $.template_effect(() => {
111
+ $.set_style(span, `font-size:10px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:#9ca3af;${$.get(labelSpacing) ?? ""}${$.get(labelAlign) ?? ""}`);
112
+ $.set_text(text, adLabel());
113
+ });
114
+ $.append($$anchor3, span);
115
+ };
116
+ $.if(node_1, ($$render) => {
117
+ if ($.get(topLabel)) $$render(consequent);
118
+ });
119
+ }
120
+ var div_1 = $.sibling(node_1, 2);
121
+ var iframe = $.child(div_1);
122
+ $.reset(div_1);
123
+ var node_2 = $.sibling(div_1, 2);
124
+ {
125
+ var consequent_1 = ($$anchor3) => {
126
+ var span_1 = root_3();
127
+ var text_1 = $.child(span_1, true);
128
+ $.reset(span_1);
129
+ $.template_effect(() => {
130
+ $.set_style(span_1, `font-size:10px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:#9ca3af;${$.get(labelSpacing) ?? ""}${$.get(labelAlign) ?? ""}`);
131
+ $.set_text(text_1, adLabel());
132
+ });
133
+ $.append($$anchor3, span_1);
134
+ };
135
+ $.if(node_2, ($$render) => {
136
+ if ($.get(bottomLabel)) $$render(consequent_1);
137
+ });
138
+ }
139
+ $.reset(div);
140
+ $.template_effect(() => {
141
+ $.set_class(div, 1, className());
142
+ $.set_style(div, `${$.get(wrapperStyle) ?? ""}${$.get(visibilityStyle) ?? ""}`);
143
+ $.set_style(div_1, `width:${($.get(config), $.untrack(() => typeof $.get(config).width === "number" ? `${$.get(config).width}px` : $.get(config).width)) ?? ""};height:${($.get(config), $.untrack(() => typeof $.get(config).height === "number" ? `${$.get(config).height}px` : $.get(config).height)) ?? ""};overflow:hidden;border-radius:6px;border:1px solid #e5e7eb;background:#f3f4f6;display:flex;align-items:center;justify-content:center;`);
144
+ $.set_attribute(iframe, "srcdoc", $.get(iframeSrcDoc));
145
+ });
146
+ $.append($$anchor2, div);
147
+ };
148
+ $.if(node, ($$render) => {
149
+ if (!$.get(adFailed)) $$render(consequent_2);
150
+ });
151
+ }
152
+ $.append($$anchor, fragment);
153
+ $.pop();
154
+ }
155
+
156
+ // src/AdContainer.svelte
157
+ import "svelte/internal/disclose-version";
158
+ import "svelte/internal/flags/legacy";
159
+ import * as $2 from "svelte/internal/client";
160
+ var root_12 = $2.from_html(`<div><!></div>`);
161
+ function AdContainer($$anchor, $$props) {
162
+ $2.push($$props, false);
163
+ let format = $2.prop($$props, "format", 8);
164
+ let provider = $2.prop($$props, "provider", 8, "adsterra");
165
+ let adKey = $2.prop($$props, "adKey", 8, "");
166
+ let className = $2.prop($$props, "className", 8, "");
167
+ let adLabel = $2.prop($$props, "adLabel", 8, "Advertisement");
168
+ let showAdLabel = $2.prop($$props, "showAdLabel", 8, true);
169
+ let adLabelPosition = $2.prop($$props, "adLabelPosition", 8, "top-left");
170
+ let adLoaded = $2.mutable_source(false);
171
+ let adFailed = $2.mutable_source(false);
172
+ let visibilityStyle = $2.mutable_source("");
173
+ $2.legacy_pre_effect(() => $2.get(adLoaded), () => {
174
+ $2.set(visibilityStyle, $2.get(adLoaded) ? "opacity:1;transform:scale(1);" : "opacity:0;transform:scale(0.95);pointer-events:none;position:absolute;width:0;height:0;overflow:hidden;");
175
+ });
176
+ $2.legacy_pre_effect_reset();
177
+ var fragment = $2.comment();
178
+ var node = $2.first_child(fragment);
179
+ {
180
+ var consequent = ($$anchor2) => {
181
+ var div = root_12();
182
+ var node_1 = $2.child(div);
183
+ AdBanner(node_1, {
184
+ get format() {
185
+ return format();
186
+ },
187
+ get provider() {
188
+ return provider();
189
+ },
190
+ get adKey() {
191
+ return adKey();
192
+ },
193
+ get className() {
194
+ return className();
195
+ },
196
+ get adLabel() {
197
+ return adLabel();
198
+ },
199
+ get showAdLabel() {
200
+ return showAdLabel();
201
+ },
202
+ get adLabelPosition() {
203
+ return adLabelPosition();
204
+ },
205
+ onLoad: () => $2.set(adLoaded, true),
206
+ onError: () => $2.set(adFailed, true)
207
+ });
208
+ $2.reset(div);
209
+ $2.template_effect(() => $2.set_style(div, $2.get(visibilityStyle)));
210
+ $2.append($$anchor2, div);
211
+ };
212
+ $2.if(node, ($$render) => {
213
+ if (!$2.get(adFailed)) $$render(consequent);
214
+ });
215
+ }
216
+ $2.append($$anchor, fragment);
217
+ $2.pop();
218
+ }
219
+
220
+ // src/SocialBar.svelte
221
+ import "svelte/internal/disclose-version";
222
+ import "svelte/internal/flags/legacy";
223
+ import * as $3 from "svelte/internal/client";
224
+ import { onMount as onMount2 } from "svelte";
225
+ var root_13 = $3.from_html(`<div><div style="position:relative;max-width:100%;overflow:hidden;border-radius:12px;border:1px solid #e5e7eb;background:#fff;padding:8px;padding-top:24px;box-shadow:0 20px 30px rgba(0,0,0,0.2);"><button aria-label="Close advertisement" style="position:absolute;top:4px;right:4px;cursor:pointer;">x</button> <div class="hidden sm:block"><!></div> <div class="block space-y-2 sm:hidden"><!> <!></div></div></div>`);
226
+ function SocialBar($$anchor, $$props) {
227
+ $3.push($$props, false);
228
+ const adsLoaded = $3.mutable_source();
229
+ const adsFailed = $3.mutable_source();
230
+ let delayMs = $3.prop($$props, "delayMs", 8, 5e3);
231
+ let storageKey = $3.prop($$props, "storageKey", 8, "social-bar-closed");
232
+ let isVisible = $3.mutable_source(false);
233
+ let isClosed = $3.mutable_source(false);
234
+ let desktopAdLoaded = $3.mutable_source(false);
235
+ let desktopAdFailed = $3.mutable_source(false);
236
+ let mobileAd1Loaded = $3.mutable_source(false);
237
+ let mobileAd1Failed = $3.mutable_source(false);
238
+ let mobileAd2Loaded = $3.mutable_source(false);
239
+ let mobileAd2Failed = $3.mutable_source(false);
240
+ let isMobile = $3.mutable_source(false);
241
+ onMount2(() => {
242
+ const checkMobile = () => {
243
+ $3.set(isMobile, window.innerWidth < 640);
244
+ };
245
+ checkMobile();
246
+ window.addEventListener("resize", checkMobile);
247
+ if (sessionStorage.getItem(storageKey()) === "true") {
248
+ $3.set(isClosed, true);
249
+ return () => window.removeEventListener("resize", checkMobile);
250
+ }
251
+ const timer = setTimeout(
252
+ () => {
253
+ if (!$3.get(isClosed)) $3.set(isVisible, true);
254
+ },
255
+ delayMs()
256
+ );
257
+ return () => {
258
+ clearTimeout(timer);
259
+ window.removeEventListener("resize", checkMobile);
260
+ };
261
+ });
262
+ function close() {
263
+ $3.set(isVisible, false);
264
+ $3.set(isClosed, true);
265
+ sessionStorage.setItem(storageKey(), "true");
266
+ }
267
+ $3.legacy_pre_effect(
268
+ () => ($3.get(isMobile), $3.get(mobileAd1Loaded), $3.get(mobileAd2Loaded), $3.get(desktopAdLoaded)),
269
+ () => {
270
+ $3.set(adsLoaded, $3.get(isMobile) ? $3.get(mobileAd1Loaded) || $3.get(mobileAd2Loaded) : $3.get(desktopAdLoaded));
271
+ }
272
+ );
273
+ $3.legacy_pre_effect(
274
+ () => ($3.get(isMobile), $3.get(mobileAd1Failed), $3.get(mobileAd2Failed), $3.get(desktopAdFailed)),
275
+ () => {
276
+ $3.set(adsFailed, $3.get(isMobile) ? $3.get(mobileAd1Failed) || $3.get(mobileAd2Failed) : $3.get(desktopAdFailed));
277
+ }
278
+ );
279
+ $3.legacy_pre_effect_reset();
280
+ $3.init();
281
+ var fragment = $3.comment();
282
+ var node = $3.first_child(fragment);
283
+ {
284
+ var consequent = ($$anchor2) => {
285
+ var div = root_13();
286
+ var div_1 = $3.child(div);
287
+ var button = $3.child(div_1);
288
+ var div_2 = $3.sibling(button, 2);
289
+ var node_1 = $3.child(div_2);
290
+ AdBanner(node_1, {
291
+ format: "728x90",
292
+ onLoad: () => $3.set(desktopAdLoaded, true),
293
+ onError: () => $3.set(desktopAdFailed, true)
294
+ });
295
+ $3.reset(div_2);
296
+ var div_3 = $3.sibling(div_2, 2);
297
+ var node_2 = $3.child(div_3);
298
+ AdBanner(node_2, {
299
+ format: "320x50",
300
+ onLoad: () => $3.set(mobileAd1Loaded, true),
301
+ onError: () => $3.set(mobileAd1Failed, true)
302
+ });
303
+ var node_3 = $3.sibling(node_2, 2);
304
+ AdBanner(node_3, {
305
+ format: "320x50",
306
+ onLoad: () => $3.set(mobileAd2Loaded, true),
307
+ onError: () => $3.set(mobileAd2Failed, true)
308
+ });
309
+ $3.reset(div_3);
310
+ $3.reset(div_1);
311
+ $3.reset(div);
312
+ $3.template_effect(() => $3.set_class(div, 1, `fixed right-0 bottom-0 left-0 z-[100] flex justify-center p-4 ${!$3.get(adsLoaded) ? "pointer-events-none h-0 overflow-hidden p-0 opacity-0" : ""}`));
313
+ $3.delegated("click", button, close);
314
+ $3.append($$anchor2, div);
315
+ };
316
+ $3.if(node, ($$render) => {
317
+ if ($3.get(isVisible) && !$3.get(isClosed) && !$3.get(adsFailed)) $$render(consequent);
318
+ });
319
+ }
320
+ $3.append($$anchor, fragment);
321
+ $3.pop();
322
+ }
323
+ $3.delegate(["click"]);
324
+ export {
325
+ AdBanner,
326
+ AdContainer,
327
+ SocialBar,
328
+ configureAds
329
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@adsterra-ad/svelte",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "svelte": "src/index.ts",
6
+ "types": "src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "svelte": "./src/index.ts",
10
+ "types": "./src/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "dependencies": {
22
+ "@adsterra-ad/core": "0.1.0"
23
+ },
24
+ "peerDependencies": {
25
+ "svelte": "^4.0.0 || ^5.0.0"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup src/index.ts --format esm",
29
+ "typecheck": "tsc --noEmit",
30
+ "prepublishOnly": "npm run build && npm run typecheck"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.2.4",
34
+ "typescript": "^5.5.4"
35
+ }
36
+ }
@@ -0,0 +1,91 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { buildSrcDoc, createBannerId, resolveAdConfig, type AdFormat, type AdProvider, type BannerMessage } from '@adsterra-ad/core';
4
+
5
+ export let format: AdFormat;
6
+ export let provider: AdProvider = 'adsterra';
7
+ export let adKey = '';
8
+ export let className = '';
9
+ export let adLabel = 'Advertisement';
10
+ export let showAdLabel = true;
11
+ export let adLabelPosition:
12
+ | 'top-left'
13
+ | 'top-center'
14
+ | 'top-right'
15
+ | 'bottom-left'
16
+ | 'bottom-center'
17
+ | 'bottom-right' = 'top-left';
18
+ export let onLoad: (() => void) | undefined = undefined;
19
+ export let onError: (() => void) | undefined = undefined;
20
+
21
+ const bannerId = createBannerId();
22
+ let activeProvider: AdProvider = provider;
23
+ let adLoaded = false;
24
+ let adFailed = false;
25
+
26
+ let config = resolveAdConfig(format, adKey || undefined);
27
+ let iframeSrcDoc = '';
28
+ let wrapperStyle = '';
29
+ let topLabel = false;
30
+ let bottomLabel = false;
31
+ let labelSpacing = '';
32
+ let labelAlign = '';
33
+ let visibilityStyle = '';
34
+
35
+ $: if (provider !== activeProvider) activeProvider = provider;
36
+ $: config = resolveAdConfig(format, adKey || undefined);
37
+ $: iframeSrcDoc = buildSrcDoc({ format, provider: activeProvider, config, bannerId });
38
+
39
+ $: wrapperStyle = `display:inline-flex;flex-direction:column;align-items:${adLabelPosition.endsWith('left') ? 'flex-start' : adLabelPosition.endsWith('right') ? 'flex-end' : 'center'};`;
40
+ $: topLabel = showAdLabel && adLabelPosition.startsWith('top');
41
+ $: bottomLabel = showAdLabel && adLabelPosition.startsWith('bottom');
42
+ $: labelSpacing = topLabel ? 'margin-bottom:4px;' : bottomLabel ? 'margin-top:4px;' : '';
43
+ $: labelAlign = `text-align:${adLabelPosition.endsWith('left') ? 'left' : adLabelPosition.endsWith('right') ? 'right' : 'center'};width:100%;`;
44
+ $: visibilityStyle = adLoaded
45
+ ? 'opacity:1;transform:scale(1);'
46
+ : 'opacity:0;transform:scale(0.95);pointer-events:none;position:absolute;width:0;height:0;overflow:hidden;';
47
+
48
+ const handleMessage = (event: MessageEvent<BannerMessage>) => {
49
+ const data = event.data;
50
+ if (!data || data.bannerId !== bannerId) return;
51
+
52
+ if (data.type === 'ad-load-success') {
53
+ adLoaded = true;
54
+ onLoad?.();
55
+ return;
56
+ }
57
+
58
+ if (data.type === 'ad-load-error') {
59
+ adFailed = true;
60
+ onError?.();
61
+ }
62
+ };
63
+
64
+ onMount(() => {
65
+ window.addEventListener('message', handleMessage);
66
+ return () => window.removeEventListener('message', handleMessage);
67
+ });
68
+ </script>
69
+
70
+ {#if !adFailed}
71
+ <div class="{className}" style="{wrapperStyle}{visibilityStyle}">
72
+ {#if topLabel}
73
+ <span style="font-size:10px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:#9ca3af;{labelSpacing}{labelAlign}">{adLabel}</span>
74
+ {/if}
75
+ <div
76
+ data-testid="ad-banner"
77
+ style="width:{typeof config.width === 'number' ? `${config.width}px` : config.width};height:{typeof config.height === 'number' ? `${config.height}px` : config.height};overflow:hidden;border-radius:6px;border:1px solid #e5e7eb;background:#f3f4f6;display:flex;align-items:center;justify-content:center;"
78
+ >
79
+ <iframe
80
+ title="Advertisement"
81
+ srcdoc={iframeSrcDoc}
82
+ frameborder="0"
83
+ scrolling="no"
84
+ sandbox="allow-scripts allow-forms allow-same-origin allow-popups allow-modals"
85
+ ></iframe>
86
+ </div>
87
+ {#if bottomLabel}
88
+ <span style="font-size:10px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:#9ca3af;{labelSpacing}{labelAlign}">{adLabel}</span>
89
+ {/if}
90
+ </div>
91
+ {/if}
@@ -0,0 +1,42 @@
1
+ <script lang="ts">
2
+ import AdBanner from './AdBanner.svelte';
3
+ import type { AdFormat, AdProvider } from '@adsterra-ad/core';
4
+
5
+ export let format: AdFormat;
6
+ export let provider: AdProvider = 'adsterra';
7
+ export let adKey = '';
8
+ export let className = '';
9
+ export let adLabel = 'Advertisement';
10
+ export let showAdLabel = true;
11
+ export let adLabelPosition:
12
+ | 'top-left'
13
+ | 'top-center'
14
+ | 'top-right'
15
+ | 'bottom-left'
16
+ | 'bottom-center'
17
+ | 'bottom-right' = 'top-left';
18
+
19
+ let adLoaded = false;
20
+ let adFailed = false;
21
+ let visibilityStyle = '';
22
+
23
+ $: visibilityStyle = adLoaded
24
+ ? 'opacity:1;transform:scale(1);'
25
+ : 'opacity:0;transform:scale(0.95);pointer-events:none;position:absolute;width:0;height:0;overflow:hidden;';
26
+ </script>
27
+
28
+ {#if !adFailed}
29
+ <div style={visibilityStyle}>
30
+ <AdBanner
31
+ {format}
32
+ {provider}
33
+ {adKey}
34
+ {className}
35
+ {adLabel}
36
+ {showAdLabel}
37
+ {adLabelPosition}
38
+ onLoad={() => (adLoaded = true)}
39
+ onError={() => (adFailed = true)}
40
+ />
41
+ </div>
42
+ {/if}
@@ -0,0 +1,62 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import AdBanner from './AdBanner.svelte';
4
+
5
+ export let delayMs = 5000;
6
+ export let storageKey = 'social-bar-closed';
7
+
8
+ let isVisible = false;
9
+ let isClosed = false;
10
+
11
+ let desktopAdLoaded = false;
12
+ let desktopAdFailed = false;
13
+ let mobileAd1Loaded = false;
14
+ let mobileAd1Failed = false;
15
+ let mobileAd2Loaded = false;
16
+ let mobileAd2Failed = false;
17
+ let isMobile = false;
18
+
19
+ $: adsLoaded = isMobile ? mobileAd1Loaded || mobileAd2Loaded : desktopAdLoaded;
20
+ $: adsFailed = isMobile ? mobileAd1Failed || mobileAd2Failed : desktopAdFailed;
21
+
22
+ onMount(() => {
23
+ const checkMobile = () => { isMobile = window.innerWidth < 640; };
24
+ checkMobile();
25
+ window.addEventListener('resize', checkMobile);
26
+
27
+ if (sessionStorage.getItem(storageKey) === 'true') {
28
+ isClosed = true;
29
+ return () => window.removeEventListener('resize', checkMobile);
30
+ }
31
+
32
+ const timer = setTimeout(() => {
33
+ if (!isClosed) isVisible = true;
34
+ }, delayMs);
35
+
36
+ return () => {
37
+ clearTimeout(timer);
38
+ window.removeEventListener('resize', checkMobile);
39
+ };
40
+ });
41
+
42
+ function close() {
43
+ isVisible = false;
44
+ isClosed = true;
45
+ sessionStorage.setItem(storageKey, 'true');
46
+ }
47
+ </script>
48
+
49
+ {#if isVisible && !isClosed && !adsFailed}
50
+ <div class="fixed right-0 bottom-0 left-0 z-[100] flex justify-center p-4 {!adsLoaded ? 'pointer-events-none h-0 overflow-hidden p-0 opacity-0' : ''}">
51
+ <div style="position:relative;max-width:100%;overflow:hidden;border-radius:12px;border:1px solid #e5e7eb;background:#fff;padding:8px;padding-top:24px;box-shadow:0 20px 30px rgba(0,0,0,0.2);">
52
+ <button onclick={close} aria-label="Close advertisement" style="position:absolute;top:4px;right:4px;cursor:pointer;">x</button>
53
+ <div class="hidden sm:block">
54
+ <AdBanner format="728x90" onLoad={() => (desktopAdLoaded = true)} onError={() => (desktopAdFailed = true)} />
55
+ </div>
56
+ <div class="block space-y-2 sm:hidden">
57
+ <AdBanner format="320x50" onLoad={() => (mobileAd1Loaded = true)} onError={() => (mobileAd1Failed = true)} />
58
+ <AdBanner format="320x50" onLoad={() => (mobileAd2Loaded = true)} onError={() => (mobileAd2Failed = true)} />
59
+ </div>
60
+ </div>
61
+ </div>
62
+ {/if}
package/src/index.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ import type { Component } from 'svelte';
2
+ import type { AdFormat, AdProvider } from '@adsterra-ad/core';
3
+
4
+ export type AdLabelPosition =
5
+ | 'top-left'
6
+ | 'top-center'
7
+ | 'top-right'
8
+ | 'bottom-left'
9
+ | 'bottom-center'
10
+ | 'bottom-right';
11
+
12
+ export interface AdBannerProps {
13
+ format: AdFormat;
14
+ provider?: AdProvider;
15
+ adKey?: string;
16
+ className?: string;
17
+ adLabel?: string;
18
+ showAdLabel?: boolean;
19
+ adLabelPosition?: AdLabelPosition;
20
+ onLoad?: () => void;
21
+ onError?: () => void;
22
+ }
23
+
24
+ export interface AdContainerProps {
25
+ format: AdFormat;
26
+ provider?: AdProvider;
27
+ adKey?: string;
28
+ className?: string;
29
+ adLabel?: string;
30
+ showAdLabel?: boolean;
31
+ adLabelPosition?: AdLabelPosition;
32
+ }
33
+
34
+ export interface SocialBarProps {
35
+ delayMs?: number;
36
+ storageKey?: string;
37
+ }
38
+
39
+ export const AdBanner: Component<AdBannerProps>;
40
+ export const AdContainer: Component<AdContainerProps>;
41
+ export const SocialBar: Component<SocialBarProps>;
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { configureAds } from '@adsterra-ad/core';
2
+ export { default as AdBanner } from './AdBanner.svelte';
3
+ export { default as AdContainer } from './AdContainer.svelte';
4
+ export { default as SocialBar } from './SocialBar.svelte';
@@ -0,0 +1,5 @@
1
+ declare module '*.svelte' {
2
+ import type { ComponentType } from 'svelte';
3
+ const component: ComponentType;
4
+ export default component;
5
+ }