@nektarlabs/adsterix-widget 1.3.2 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -18
- package/dist/index.d.mts +47 -2
- package/dist/index.mjs +84 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,24 +53,27 @@ To display an ad, you need a cast hash of the corresponding Farcaster cast. Foll
|
|
|
53
53
|
|
|
54
54
|
## Props
|
|
55
55
|
|
|
56
|
-
| Prop | Type | Default | Description
|
|
57
|
-
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------- |
|
|
58
|
-
| `castHash` | `string` | — | The Farcaster cast hash of the ad to display
|
|
59
|
-
| `onClose` | `() => void` | — | Callback fired when the user closes the ad
|
|
60
|
-
| `width` | `string \| number` | `"100%"` | Width of the widget (px or string)
|
|
61
|
-
| `height` | `string \| number` | — | Height of the widget (px or string). If not provided, maintains 3:2 aspect ratio
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
56
|
+
| Prop | Type | Default | Description |
|
|
57
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | -------------------------------------------------------------------------------------------- |
|
|
58
|
+
| `castHash` | `string` | — | The Farcaster cast hash of the ad to display |
|
|
59
|
+
| `onClose` | `() => void` | — | Callback fired when the user closes the ad |
|
|
60
|
+
| `width` | `string \| number` | `"100%"` | Width of the widget (px or string) |
|
|
61
|
+
| `height` | `string \| number` | — | Height of the widget (px or string). If not provided, maintains 3:2 aspect ratio |
|
|
62
|
+
| `defaultImage` | `string` | — | Default image URL to display when no buyer has purchased the ad slot |
|
|
63
|
+
| `showAdSparkleLabel` | `boolean` | `false` | Whether to show the "Ad ✨" label overlay |
|
|
64
|
+
| `showCloseButton` | `boolean` | `false` | Whether to show the close button |
|
|
65
|
+
| `showBuySlotButton` | `boolean` | `false` | Whether to show the "Buy Slot" button |
|
|
66
|
+
| `showCtaButton` | `boolean` | `false` | Whether to show the CTA (call-to-action) button |
|
|
67
|
+
| `showCtaButtonIcon` | `boolean` | `false` | Whether to show the external link icon on the CTA button |
|
|
68
|
+
| `ctaButtonText` | `string` | `"Learn More"` | Custom text for the CTA button |
|
|
69
|
+
| `ctaNodes` | `React.ReactNode[]` | — | Custom nodes to render instead of the default CTA / Buy Slot buttons |
|
|
70
|
+
| `onCtaNodeClick` | `(index: number, e: React.MouseEvent, ctaDetails: CtaDetails \| null) => void` | — | Callback fired when a custom CTA node is clicked, receives the node index, event and details |
|
|
71
|
+
| `onBuySlotClick` | `(buySlotUrl: string) => void` | — | Callback fired when the "Buy Slot" button is clicked, receives the buy slot URL |
|
|
72
|
+
| `onAdClick` | `(url: string) => void` | — | Callback fired when the CTA button is clicked, receives the ad's target URL |
|
|
73
|
+
| `position` | `"bottom-left" \| "bottom-right" \| "top-left" \| "top-right" \| "bottom-center" \| "top-center" \| "center-left" \| "center-right"` | `"bottom-right"` | Position of the CTA buttons container |
|
|
74
|
+
| `containerStyle` | `React.CSSProperties` | — | Custom styles for the widget container |
|
|
75
|
+
| `buySlotButtonStyle` | `React.CSSProperties` | — | Custom styles for the "Buy Slot" button |
|
|
76
|
+
| `ctaButtonStyle` | `React.CSSProperties` | — | Custom styles for the CTA button |
|
|
74
77
|
|
|
75
78
|
## Example
|
|
76
79
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,24 +1,69 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
interface CtaDetails {
|
|
4
|
+
image: string;
|
|
5
|
+
url: string;
|
|
6
|
+
buySlotUrl: string;
|
|
7
|
+
buyer?: {
|
|
8
|
+
fid: number;
|
|
9
|
+
username: string;
|
|
10
|
+
avatar: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
address: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
interface UseCtaDetailsReturn {
|
|
16
|
+
ctaDetails: CtaDetails | null;
|
|
17
|
+
loading: boolean;
|
|
18
|
+
error: string | null;
|
|
19
|
+
refetch: () => void;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
}
|
|
22
|
+
declare const useCtaDetails: (params: {
|
|
23
|
+
castHash: string;
|
|
24
|
+
}) => UseCtaDetailsReturn;
|
|
25
|
+
|
|
3
26
|
type CtaPosition = "bottom-left" | "bottom-right" | "top-left" | "top-right" | "bottom-center" | "top-center" | "center-left" | "center-right";
|
|
4
27
|
interface AdsterixWidgetProps {
|
|
5
|
-
|
|
28
|
+
/** The Farcaster cast hash to fetch ad details for (required) */
|
|
29
|
+
castHash: string;
|
|
30
|
+
/** Callback fired when the widget is closed via the close button */
|
|
6
31
|
onClose?: () => void;
|
|
32
|
+
/** Width of the widget container (number = px, string = any CSS value). Default: "100%" */
|
|
7
33
|
width?: string | number;
|
|
34
|
+
/** Height of the widget container (number = px, string = any CSS value). If omitted, uses 3:2 aspect ratio */
|
|
8
35
|
height?: string | number;
|
|
36
|
+
/** Default image URL to display when no buyer has purchased the ad slot */
|
|
37
|
+
defaultImage?: string;
|
|
38
|
+
/** Show a small "Ad" label with sparkle icon in the top-left corner */
|
|
9
39
|
showAdSparkleLabel?: boolean;
|
|
40
|
+
/** Show a close button in the top-right corner */
|
|
10
41
|
showCloseButton?: boolean;
|
|
42
|
+
/** Show the "Buy Slot" button (allows users to purchase the ad slot) */
|
|
11
43
|
showBuySlotButton?: boolean;
|
|
44
|
+
/** Show the default CTA button */
|
|
12
45
|
showCtaButton?: boolean;
|
|
46
|
+
/** Show an external link icon inside the CTA button */
|
|
13
47
|
showCtaButtonIcon?: boolean;
|
|
48
|
+
/** Text label for the CTA button. Default: "Learn More" */
|
|
14
49
|
ctaButtonText?: string;
|
|
50
|
+
/** If provided, these nodes will be rendered instead of the default CTA / Buy Slot buttons */
|
|
51
|
+
ctaNodes?: React.ReactNode[];
|
|
52
|
+
/** Called when a custom CTA node is clicked: (index, event, ctaDetails) */
|
|
53
|
+
onCtaNodeClick?: (index: number, e: React.MouseEvent, ctaDetails: CtaDetails | null) => void;
|
|
54
|
+
/** Callback fired when the "Buy Slot" button is clicked, receives the buySlotUrl */
|
|
15
55
|
onBuySlotClick?: (buySlotUrl: string) => void;
|
|
56
|
+
/** Callback fired when the ad (or CTA button) is clicked, receives the destination url */
|
|
16
57
|
onAdClick?: (url: string) => void;
|
|
58
|
+
/** Position of the CTA buttons within the widget. Default: "bottom-right" */
|
|
17
59
|
position?: CtaPosition;
|
|
60
|
+
/** Custom styles to merge into the widget container */
|
|
18
61
|
containerStyle?: React.CSSProperties;
|
|
62
|
+
/** Custom styles to merge into the "Buy Slot" button */
|
|
19
63
|
buySlotButtonStyle?: React.CSSProperties;
|
|
64
|
+
/** Custom styles to merge into the CTA button */
|
|
20
65
|
ctaButtonStyle?: React.CSSProperties;
|
|
21
66
|
}
|
|
22
67
|
declare const AdsterixWidget: React.FC<AdsterixWidgetProps>;
|
|
23
68
|
|
|
24
|
-
export { AdsterixWidget, type AdsterixWidgetProps };
|
|
69
|
+
export { AdsterixWidget, type AdsterixWidgetProps, type CtaDetails, type UseCtaDetailsReturn, useCtaDetails };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,58 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
3
3
|
import { X, ShoppingBag, ExternalLink, Sparkles } from 'lucide-react';
|
|
4
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
// src/AdsterixWidget.tsx
|
|
7
|
+
var useCtaDetails = (params) => {
|
|
8
|
+
const { castHash } = params;
|
|
9
|
+
const [ctaDetails, setCtaDetails] = React.useState(null);
|
|
10
|
+
const [loading, setLoading] = React.useState(Boolean(castHash.trim()));
|
|
11
|
+
const [error, setError] = React.useState(null);
|
|
12
|
+
const fetchCta = React.useCallback(
|
|
13
|
+
async (signal) => {
|
|
14
|
+
const trimmedHash = castHash == null ? void 0 : castHash.trim();
|
|
15
|
+
if (!trimmedHash) {
|
|
16
|
+
setCtaDetails(null);
|
|
17
|
+
setLoading(false);
|
|
18
|
+
setError(null);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setLoading(true);
|
|
22
|
+
setError(null);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(`https://www.adsterix.xyz/api/ads/cta-details/${trimmedHash}`, { signal });
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch: ${response.status}`);
|
|
27
|
+
}
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
setCtaDetails(data);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if ((err == null ? void 0 : err.name) === "AbortError") return;
|
|
32
|
+
setError(err instanceof Error ? err.message : "Unknown error");
|
|
33
|
+
setCtaDetails(null);
|
|
34
|
+
} finally {
|
|
35
|
+
setLoading(false);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
[castHash]
|
|
39
|
+
);
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
fetchCta(controller.signal);
|
|
43
|
+
return () => controller.abort();
|
|
44
|
+
}, [fetchCta]);
|
|
45
|
+
const refetch = React.useCallback(() => {
|
|
46
|
+
fetchCta();
|
|
47
|
+
}, [fetchCta]);
|
|
48
|
+
const reset = React.useCallback(() => {
|
|
49
|
+
setCtaDetails(null);
|
|
50
|
+
setLoading(false);
|
|
51
|
+
setError(null);
|
|
52
|
+
}, []);
|
|
53
|
+
return { ctaDetails, loading, error, refetch, reset };
|
|
54
|
+
};
|
|
55
|
+
var useCtaDetails_default = useCtaDetails;
|
|
7
56
|
var getPositionStyles = (position) => {
|
|
8
57
|
const baseStyles = {
|
|
9
58
|
position: "absolute",
|
|
@@ -50,6 +99,7 @@ var AdsterixWidget = ({
|
|
|
50
99
|
width = "100%",
|
|
51
100
|
position = "bottom-right",
|
|
52
101
|
height,
|
|
102
|
+
defaultImage,
|
|
53
103
|
showAdSparkleLabel = false,
|
|
54
104
|
showCloseButton = false,
|
|
55
105
|
showBuySlotButton = false,
|
|
@@ -60,35 +110,20 @@ var AdsterixWidget = ({
|
|
|
60
110
|
buySlotButtonStyle,
|
|
61
111
|
onBuySlotClick,
|
|
62
112
|
onAdClick,
|
|
63
|
-
|
|
113
|
+
onCtaNodeClick,
|
|
114
|
+
containerStyle: _containerStyle,
|
|
115
|
+
ctaNodes
|
|
64
116
|
}) => {
|
|
65
|
-
const
|
|
66
|
-
const [error, setError] = React.useState(null);
|
|
67
|
-
const [loading, setLoading] = React.useState(false);
|
|
117
|
+
const { ctaDetails, loading, error } = useCtaDetails_default({ castHash });
|
|
68
118
|
const [imageLoaded, setImageLoaded] = React.useState(false);
|
|
69
119
|
const [visible, setVisible] = React.useState(true);
|
|
70
120
|
const [isSmall, setIsSmall] = React.useState(true);
|
|
71
121
|
const containerRef = React.useRef(null);
|
|
122
|
+
const hasBuyer = Boolean(ctaDetails == null ? void 0 : ctaDetails.buyer);
|
|
123
|
+
const displayImage = hasBuyer ? ctaDetails == null ? void 0 : ctaDetails.image : defaultImage ? defaultImage : ctaDetails == null ? void 0 : ctaDetails.image;
|
|
72
124
|
React.useEffect(() => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
setLoading(true);
|
|
76
|
-
setError(null);
|
|
77
|
-
try {
|
|
78
|
-
const response = await fetch(`https://www.adsterix.xyz/api/ads/cta-details/${castHash}`);
|
|
79
|
-
if (!response.ok) {
|
|
80
|
-
throw new Error(`Failed to fetch: ${response.status}`);
|
|
81
|
-
}
|
|
82
|
-
const data = await response.json();
|
|
83
|
-
setCtaDetails(data);
|
|
84
|
-
} catch (err) {
|
|
85
|
-
setError(err instanceof Error ? err.message : "Unknown error");
|
|
86
|
-
} finally {
|
|
87
|
-
setLoading(false);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
fetchCtaDetails();
|
|
91
|
-
}, [castHash]);
|
|
125
|
+
setImageLoaded(false);
|
|
126
|
+
}, [displayImage]);
|
|
92
127
|
React.useEffect(() => {
|
|
93
128
|
if (!containerRef.current) return;
|
|
94
129
|
const checkSize = (entries) => {
|
|
@@ -179,14 +214,15 @@ var AdsterixWidget = ({
|
|
|
179
214
|
{
|
|
180
215
|
style: {
|
|
181
216
|
...containerStyle,
|
|
182
|
-
boxShadow: "0 10px 30px rgba(0,0,0,0.2)"
|
|
217
|
+
boxShadow: "0 10px 30px rgba(0,0,0,0.2)",
|
|
218
|
+
cursor: "pointer"
|
|
183
219
|
},
|
|
184
220
|
children: [
|
|
185
|
-
/* @__PURE__ */ jsx(AnimatePresence, { children: imageLoaded && /* @__PURE__ */ jsx(
|
|
221
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: imageLoaded && displayImage && /* @__PURE__ */ jsx(
|
|
186
222
|
motion.img,
|
|
187
223
|
{
|
|
188
|
-
src:
|
|
189
|
-
alt: "Advertisement",
|
|
224
|
+
src: displayImage,
|
|
225
|
+
alt: hasBuyer ? "Advertisement" : "Default placeholder",
|
|
190
226
|
initial: { opacity: 0 },
|
|
191
227
|
animate: { opacity: 1 },
|
|
192
228
|
transition: { duration: 0.4 },
|
|
@@ -199,7 +235,7 @@ var AdsterixWidget = ({
|
|
|
199
235
|
}
|
|
200
236
|
}
|
|
201
237
|
) }),
|
|
202
|
-
/* @__PURE__ */ jsx("img", { src:
|
|
238
|
+
displayImage && /* @__PURE__ */ jsx("img", { src: displayImage, alt: "", onLoad: () => setImageLoaded(true), style: { display: "none" } }),
|
|
203
239
|
showCloseButton && /* @__PURE__ */ jsx(
|
|
204
240
|
motion.div,
|
|
205
241
|
{
|
|
@@ -229,7 +265,23 @@ var AdsterixWidget = ({
|
|
|
229
265
|
children: /* @__PURE__ */ jsx(X, { size: 14, strokeWidth: 2.5 })
|
|
230
266
|
}
|
|
231
267
|
),
|
|
232
|
-
/* @__PURE__ */
|
|
268
|
+
/* @__PURE__ */ jsx("div", { style: getPositionStyles(position), children: ctaNodes && ctaNodes.length > 0 ? (
|
|
269
|
+
// Render custom nodes provided by the consumer. Each node is wrapped to
|
|
270
|
+
// keep spacing consistent with the default layout and to avoid
|
|
271
|
+
// accidental propagation of clicks to the ad container.
|
|
272
|
+
ctaNodes.map((node, idx) => /* @__PURE__ */ jsx(
|
|
273
|
+
"div",
|
|
274
|
+
{
|
|
275
|
+
style: { display: "flex", alignItems: "center" },
|
|
276
|
+
onClick: (e) => {
|
|
277
|
+
e.stopPropagation();
|
|
278
|
+
onCtaNodeClick == null ? void 0 : onCtaNodeClick(idx, e, ctaDetails);
|
|
279
|
+
},
|
|
280
|
+
children: node
|
|
281
|
+
},
|
|
282
|
+
idx
|
|
283
|
+
))
|
|
284
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
233
285
|
showBuySlotButton && /* @__PURE__ */ jsx(
|
|
234
286
|
CtaButton,
|
|
235
287
|
{
|
|
@@ -253,7 +305,7 @@ var AdsterixWidget = ({
|
|
|
253
305
|
style: ctaButtonStyle
|
|
254
306
|
}
|
|
255
307
|
)
|
|
256
|
-
] }),
|
|
308
|
+
] }) }),
|
|
257
309
|
showAdSparkleLabel && /* @__PURE__ */ jsxs(
|
|
258
310
|
"div",
|
|
259
311
|
{
|
|
@@ -286,6 +338,6 @@ var AdsterixWidget = ({
|
|
|
286
338
|
);
|
|
287
339
|
};
|
|
288
340
|
|
|
289
|
-
export { AdsterixWidget };
|
|
341
|
+
export { AdsterixWidget, useCtaDetails };
|
|
290
342
|
//# sourceMappingURL=index.mjs.map
|
|
291
343
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AdsterixWidget.tsx"],"names":["width"],"mappings":"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","file":"index.mjs","sourcesContent":["import * as React from \"react\"\nimport { motion, AnimatePresence } from \"framer-motion\"\nimport { ExternalLink, Sparkles, ShoppingBag, X } from \"lucide-react\"\n\ntype CtaPosition =\n | \"bottom-left\"\n | \"bottom-right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-center\"\n | \"top-center\"\n | \"center-left\"\n | \"center-right\"\n\nexport interface AdsterixWidgetProps {\n castHash?: string\n onClose?: () => void\n width?: string | number\n height?: string | number\n showAdSparkleLabel?: boolean\n showCloseButton?: boolean\n showBuySlotButton?: boolean\n showCtaButton?: boolean\n showCtaButtonIcon?: boolean\n ctaButtonText?: string\n onBuySlotClick?: (buySlotUrl: string) => void\n onAdClick?: (url: string) => void\n position?: CtaPosition\n containerStyle?: React.CSSProperties\n buySlotButtonStyle?: React.CSSProperties\n ctaButtonStyle?: React.CSSProperties\n}\n\ninterface CtaButtonProps {\n label: string\n icon: React.ReactNode\n onClick: (e: React.MouseEvent) => void\n showLabel: boolean\n style?: React.CSSProperties\n}\n\ninterface CtaDetails {\n image: string\n url: string\n buySlotUrl: string\n}\n\nconst getPositionStyles = (position: CtaPosition): React.CSSProperties => {\n const baseStyles: React.CSSProperties = {\n position: \"absolute\",\n display: \"flex\",\n gap: 8,\n }\n\n const positionMap: Record<CtaPosition, React.CSSProperties> = {\n \"bottom-right\": { bottom: 12, right: 12 },\n \"bottom-left\": { bottom: 12, left: 12 },\n \"top-right\": { top: 12, right: 12 },\n \"top-left\": { top: 12, left: 12 },\n \"bottom-center\": { bottom: 12, left: \"50%\", transform: \"translateX(-50%)\" },\n \"top-center\": { top: 12, left: \"50%\", transform: \"translateX(-50%)\" },\n \"center-left\": { top: \"50%\", left: 12, transform: \"translateY(-50%)\" },\n \"center-right\": { top: \"50%\", right: 12, transform: \"translateY(-50%)\" },\n }\n\n return { ...baseStyles, ...positionMap[position] }\n}\n\nconst CtaButton: React.FC<CtaButtonProps> = ({ label, icon, onClick, showLabel, style = {} }) => {\n const defaultStyle: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: showLabel ? 6 : 0,\n padding: showLabel ? \"8px 14px\" : \"8px\",\n borderRadius: 20,\n background: \"rgba(255,255,255,0.9)\",\n backdropFilter: \"blur(8px)\",\n color: \"#0f172a\",\n fontSize: 13,\n fontWeight: 600,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\",\n cursor: \"pointer\",\n }\n\n const mergedStyle = { ...defaultStyle, ...style }\n\n return (\n <div onClick={onClick} style={mergedStyle}>\n {showLabel && label}\n <span style={{ display: \"flex\", alignItems: \"center\" }}>{icon}</span>\n </div>\n )\n}\n\nexport const AdsterixWidget: React.FC<AdsterixWidgetProps> = ({\n castHash,\n onClose,\n width = \"100%\",\n position = \"bottom-right\",\n height,\n showAdSparkleLabel = false,\n showCloseButton = false,\n showBuySlotButton = false,\n showCtaButton = false,\n showCtaButtonIcon = false,\n ctaButtonText = \"Learn More\",\n ctaButtonStyle,\n buySlotButtonStyle,\n onBuySlotClick,\n onAdClick,\n containerStyle: _containerStyle,\n}) => {\n const [ctaDetails, setCtaDetails] = React.useState<CtaDetails | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(false)\n const [imageLoaded, setImageLoaded] = React.useState(false)\n const [visible, setVisible] = React.useState(true)\n const [isSmall, setIsSmall] = React.useState(true) // Start with true to avoid flash\n const containerRef = React.useRef<HTMLDivElement>(null)\n\n React.useEffect(() => {\n if (!castHash) return\n\n const fetchCtaDetails = async () => {\n setLoading(true)\n setError(null)\n\n try {\n const response = await fetch(`https://www.adsterix.xyz/api/ads/cta-details/${castHash}`)\n\n if (!response.ok) {\n throw new Error(`Failed to fetch: ${response.status}`)\n }\n\n const data = await response.json()\n setCtaDetails(data)\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Unknown error\")\n } finally {\n setLoading(false)\n }\n }\n\n fetchCtaDetails()\n }, [castHash])\n\n React.useEffect(() => {\n if (!containerRef.current) return\n\n const checkSize = (entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const width = entry.contentRect.width\n setIsSmall(width < 270)\n }\n }\n\n const resizeObserver = new ResizeObserver(checkSize)\n resizeObserver.observe(containerRef.current)\n\n // Initial check\n if (containerRef.current) {\n const width = containerRef.current.offsetWidth\n setIsSmall(width < 400)\n }\n\n return () => resizeObserver.disconnect()\n }, [loading, ctaDetails]) // Re-run when content changes\n\n const handleAdClick = () => {\n if (ctaDetails?.url) {\n window.open(ctaDetails.url, \"_blank\", \"noopener,noreferrer\")\n onAdClick?.(ctaDetails.url)\n }\n }\n\n const handleBuySlotClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n if (ctaDetails?.buySlotUrl) {\n window.open(ctaDetails.buySlotUrl, \"_blank\", \"noopener,noreferrer\")\n onBuySlotClick?.(ctaDetails?.buySlotUrl)\n }\n }\n\n const handleClose = (e: React.MouseEvent) => {\n e.stopPropagation()\n setVisible(false)\n onClose?.()\n }\n\n const containerStyle: React.CSSProperties = {\n position: \"relative\",\n width: typeof width === \"number\" ? `${width}px` : width,\n ...(height ? { height: typeof height === \"number\" ? `${height}px` : height } : { aspectRatio: \"3 / 2\" }),\n borderRadius: 12,\n overflow: \"hidden\",\n ..._containerStyle,\n }\n\n if (!visible) return null\n\n if (error) {\n return (\n <div\n style={{\n ...containerStyle,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n background: \"linear-gradient(135deg, #0f172a 0%, #1e293b 100%)\",\n color: \"#f87171\",\n fontSize: 14,\n fontWeight: 500,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n }}\n >\n Unable to load ad\n </div>\n )\n }\n\n if (loading || !ctaDetails) {\n return (\n <div\n ref={containerRef}\n style={{\n ...containerStyle,\n background: \"linear-gradient(135deg, #0f172a 0%, #1e293b 100%)\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%)\",\n }}\n />\n </div>\n )\n }\n\n return (\n <div\n style={{\n ...containerStyle,\n boxShadow: \"0 10px 30px rgba(0,0,0,0.2)\",\n }}\n >\n <AnimatePresence>\n {imageLoaded && (\n <motion.img\n src={ctaDetails.image}\n alt=\"Advertisement\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.4 }}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n }}\n />\n )}\n </AnimatePresence>\n\n <img src={ctaDetails.image} alt=\"\" onLoad={() => setImageLoaded(true)} style={{ display: \"none\" }} />\n\n {/* Close button */}\n {showCloseButton && (\n <motion.div\n onClick={handleClose}\n style={{\n position: \"absolute\",\n top: 10,\n right: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 28,\n height: 28,\n borderRadius: \"50%\",\n background: \"rgba(0,0,0,0.5)\",\n backdropFilter: \"blur(8px)\",\n color: \"rgba(255,255,255,0.8)\",\n cursor: \"pointer\",\n }}\n whileHover={{\n background: \"rgba(0,0,0,0.7)\",\n color: \"rgba(255,255,255,1)\",\n scale: 1.1,\n }}\n whileTap={{ scale: 0.95 }}\n transition={{ type: \"spring\", stiffness: 400, damping: 15 }}\n >\n <X size={14} strokeWidth={2.5} />\n </motion.div>\n )}\n\n <div style={getPositionStyles(position)}>\n {showBuySlotButton && (\n <CtaButton\n label=\"Buy Slot\"\n icon={<ShoppingBag size={14} strokeWidth={2.5} />}\n onClick={handleBuySlotClick}\n showLabel={!isSmall}\n style={buySlotButtonStyle}\n />\n )}\n {showCtaButton && (\n <CtaButton\n label={ctaButtonText}\n icon={showCtaButtonIcon && <ExternalLink size={14} strokeWidth={2.5} />}\n onClick={(e) => {\n e.stopPropagation()\n handleAdClick()\n }}\n showLabel={!isSmall}\n style={ctaButtonStyle}\n />\n )}\n </div>\n\n {showAdSparkleLabel && (\n <div\n style={{\n position: \"absolute\",\n top: 10,\n left: 10,\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"4px 8px\",\n borderRadius: 6,\n background: \"rgba(0,0,0,0.5)\",\n backdropFilter: \"blur(8px)\",\n color: \"rgba(255,255,255,0.8)\",\n fontSize: 10,\n fontWeight: 500,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n letterSpacing: \"0.5px\",\n textTransform: \"uppercase\",\n }}\n >\n <Sparkles size={10} />\n Ad\n </div>\n )}\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useCtaDetails.ts","../src/AdsterixWidget.tsx"],"names":["React2","width"],"mappings":";;;;;;AAuBO,IAAM,aAAA,GAAgB,CAAC,MAAA,KAAsD;AAClF,EAAA,MAAM,EAAE,UAAS,GAAI,MAAA;AACrB,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAU,eAA4B,IAAI,CAAA;AAE1E,EAAA,MAAM,CAAC,SAAS,UAAU,CAAA,GAAU,eAAS,OAAA,CAAQ,QAAA,CAAS,IAAA,EAAM,CAAC,CAAA;AACrE,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAU,eAAwB,IAAI,CAAA;AAE5D,EAAA,MAAM,QAAA,GAAiB,KAAA,CAAA,WAAA;AAAA,IACrB,OAAO,MAAA,KAAyB;AAC9B,MAAA,MAAM,cAAc,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,IAAA,EAAA;AAC9B,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,aAAA,CAAc,IAAI,CAAA;AAClB,QAAA,UAAA,CAAW,KAAK,CAAA;AAChB,QAAA,QAAA,CAAS,IAAI,CAAA;AACb,QAAA;AAAA,MACF;AAEA,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,QAAA,CAAS,IAAI,CAAA;AAEb,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,6CAAA,EAAgD,WAAW,CAAA,CAAA,EAAI,EAAE,QAAQ,CAAA;AAEtG,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,QACvD;AAEA,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,aAAA,CAAc,IAAI,CAAA;AAAA,MACpB,SAAS,GAAA,EAAK;AACZ,QAAA,IAAA,CAAK,GAAA,IAAA,IAAA,GAAA,MAAA,GAAA,GAAA,CAAa,UAAS,YAAA,EAAc;AACzC,QAAA,QAAA,CAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,eAAe,CAAA;AAC7D,QAAA,aAAA,CAAc,IAAI,CAAA;AAAA,MACpB,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AAEA,EAAM,gBAAU,MAAM;AACpB,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,QAAA,CAAS,WAAW,MAAM,CAAA;AAC1B,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAChC,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,MAAM,OAAA,GAAgB,kBAAY,MAAM;AACtC,IAAA,QAAA,EAAS;AAAA,EACX,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,MAAM,KAAA,GAAc,kBAAY,MAAM;AACpC,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,UAAA,CAAW,KAAK,CAAA;AAChB,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,UAAA,EAAY,OAAA,EAAS,KAAA,EAAO,SAAS,KAAA,EAAM;AACtD;AAEA,IAAO,qBAAA,GAAQ,aAAA;AClBf,IAAM,iBAAA,GAAoB,CAAC,QAAA,KAA+C;AACxE,EAAA,MAAM,UAAA,GAAkC;AAAA,IACtC,QAAA,EAAU,UAAA;AAAA,IACV,OAAA,EAAS,MAAA;AAAA,IACT,GAAA,EAAK;AAAA,GACP;AAEA,EAAA,MAAM,WAAA,GAAwD;AAAA,IAC5D,cAAA,EAAgB,EAAE,MAAA,EAAQ,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,IACxC,aAAA,EAAe,EAAE,MAAA,EAAQ,EAAA,EAAI,MAAM,EAAA,EAAG;AAAA,IACtC,WAAA,EAAa,EAAE,GAAA,EAAK,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,IAClC,UAAA,EAAY,EAAE,GAAA,EAAK,EAAA,EAAI,MAAM,EAAA,EAAG;AAAA,IAChC,iBAAiB,EAAE,MAAA,EAAQ,IAAI,IAAA,EAAM,KAAA,EAAO,WAAW,kBAAA,EAAmB;AAAA,IAC1E,cAAc,EAAE,GAAA,EAAK,IAAI,IAAA,EAAM,KAAA,EAAO,WAAW,kBAAA,EAAmB;AAAA,IACpE,eAAe,EAAE,GAAA,EAAK,OAAO,IAAA,EAAM,EAAA,EAAI,WAAW,kBAAA,EAAmB;AAAA,IACrE,gBAAgB,EAAE,GAAA,EAAK,OAAO,KAAA,EAAO,EAAA,EAAI,WAAW,kBAAA;AAAmB,GACzE;AAEA,EAAA,OAAO,EAAE,GAAG,UAAA,EAAY,GAAG,WAAA,CAAY,QAAQ,CAAA,EAAE;AACnD,CAAA;AAEA,IAAM,SAAA,GAAsC,CAAC,EAAE,KAAA,EAAO,IAAA,EAAM,SAAS,SAAA,EAAW,KAAA,GAAQ,EAAC,EAAE,KAAM;AAC/F,EAAA,MAAM,YAAA,GAAoC;AAAA,IACxC,OAAA,EAAS,MAAA;AAAA,IACT,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK,YAAY,CAAA,GAAI,CAAA;AAAA,IACrB,OAAA,EAAS,YAAY,UAAA,GAAa,KAAA;AAAA,IAClC,YAAA,EAAc,EAAA;AAAA,IACd,UAAA,EAAY,uBAAA;AAAA,IACZ,cAAA,EAAgB,WAAA;AAAA,IAChB,KAAA,EAAO,SAAA;AAAA,IACP,QAAA,EAAU,EAAA;AAAA,IACV,UAAA,EAAY,GAAA;AAAA,IACZ,UAAA,EAAY,sCAAA;AAAA,IACZ,SAAA,EAAW,6BAAA;AAAA,IACX,MAAA,EAAQ;AAAA,GACV;AAEA,EAAA,MAAM,WAAA,GAAc,EAAE,GAAG,YAAA,EAAc,GAAG,KAAA,EAAM;AAEhD,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,OAAA,EAAkB,KAAA,EAAO,WAAA,EAC3B,QAAA,EAAA;AAAA,IAAA,SAAA,IAAa,KAAA;AAAA,oBACd,GAAA,CAAC,UAAK,KAAA,EAAO,EAAE,SAAS,MAAA,EAAQ,UAAA,EAAY,QAAA,EAAS,EAAI,QAAA,EAAA,IAAA,EAAK;AAAA,GAAA,EAChE,CAAA;AAEJ,CAAA;AAEO,IAAM,iBAAgD,CAAC;AAAA,EAC5D,QAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA,GAAQ,MAAA;AAAA,EACR,QAAA,GAAW,cAAA;AAAA,EACX,MAAA;AAAA,EACA,YAAA;AAAA,EACA,kBAAA,GAAqB,KAAA;AAAA,EACrB,eAAA,GAAkB,KAAA;AAAA,EAClB,iBAAA,GAAoB,KAAA;AAAA,EACpB,aAAA,GAAgB,KAAA;AAAA,EAChB,iBAAA,GAAoB,KAAA;AAAA,EACpB,aAAA,GAAgB,YAAA;AAAA,EAChB,cAAA;AAAA,EACA,kBAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA,EAAgB,eAAA;AAAA,EAChB;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,EAAE,YAAY,OAAA,EAAS,KAAA,KAAU,qBAAA,CAAc,EAAE,UAAU,CAAA;AACjE,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAUA,eAAS,KAAK,CAAA;AAC1D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAUA,eAAS,IAAI,CAAA;AACjD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAUA,eAAS,IAAI,CAAA;AACjD,EAAA,MAAM,YAAA,GAAqBA,aAAuB,IAAI,CAAA;AAGtD,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,UAAA,IAAA,IAAA,GAAA,MAAA,GAAA,UAAA,CAAY,KAAK,CAAA;AAE1C,EAAA,MAAM,eAAe,QAAA,GAAW,UAAA,IAAA,IAAA,GAAA,MAAA,GAAA,UAAA,CAAY,KAAA,GAAQ,YAAA,GAAe,eAAe,UAAA,IAAA,IAAA,GAAA,MAAA,GAAA,UAAA,CAAY,KAAA;AAG9F,EAAMA,gBAAU,MAAM;AACpB,IAAA,cAAA,CAAe,KAAK,CAAA;AAAA,EACtB,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,EAAMA,gBAAU,MAAM;AACpB,IAAA,IAAI,CAAC,aAAa,OAAA,EAAS;AAE3B,IAAA,MAAM,SAAA,GAAY,CAAC,OAAA,KAAmC;AACpD,MAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,QAAA,MAAMC,MAAAA,GAAQ,MAAM,WAAA,CAAY,KAAA;AAChC,QAAA,UAAA,CAAWA,SAAQ,GAAG,CAAA;AAAA,MACxB;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAI,cAAA,CAAe,SAAS,CAAA;AACnD,IAAA,cAAA,CAAe,OAAA,CAAQ,aAAa,OAAO,CAAA;AAG3C,IAAA,IAAI,aAAa,OAAA,EAAS;AACxB,MAAA,MAAMA,MAAAA,GAAQ,aAAa,OAAA,CAAQ,WAAA;AACnC,MAAA,UAAA,CAAWA,SAAQ,GAAG,CAAA;AAAA,IACxB;AAEA,IAAA,OAAO,MAAM,eAAe,UAAA,EAAW;AAAA,EACzC,CAAA,EAAG,CAAC,OAAA,EAAS,UAAU,CAAC,CAAA;AAExB,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,IAAI,yCAAY,GAAA,EAAK;AACnB,MAAA,MAAA,CAAO,IAAA,CAAK,UAAA,CAAW,GAAA,EAAK,QAAA,EAAU,qBAAqB,CAAA;AAC3D,MAAA,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAY,UAAA,CAAW,GAAA,CAAA;AAAA,IACzB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,kBAAA,GAAqB,CAAC,CAAA,KAAwB;AAClD,IAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,IAAA,IAAI,yCAAY,UAAA,EAAY;AAC1B,MAAA,MAAA,CAAO,IAAA,CAAK,UAAA,CAAW,UAAA,EAAY,QAAA,EAAU,qBAAqB,CAAA;AAClE,MAAA,cAAA,IAAA,IAAA,GAAA,MAAA,GAAA,cAAA,CAAiB,UAAA,IAAA,IAAA,GAAA,MAAA,GAAA,UAAA,CAAY,UAAA,CAAA;AAAA,IAC/B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,CAAA,KAAwB;AAC3C,IAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,IAAA,UAAA,CAAW,KAAK,CAAA;AAChB,IAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,EAAA;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,cAAA,GAAsC;AAAA,IAC1C,QAAA,EAAU,UAAA;AAAA,IACV,OAAO,OAAO,KAAA,KAAU,QAAA,GAAW,CAAA,EAAG,KAAK,CAAA,EAAA,CAAA,GAAO,KAAA;AAAA,IAClD,GAAI,MAAA,GAAS,EAAE,MAAA,EAAQ,OAAO,MAAA,KAAW,QAAA,GAAW,CAAA,EAAG,MAAM,CAAA,EAAA,CAAA,GAAO,MAAA,EAAO,GAAI,EAAE,aAAa,OAAA,EAAQ;AAAA,IACtG,YAAA,EAAc,EAAA;AAAA,IACd,QAAA,EAAU,QAAA;AAAA,IACV,GAAG;AAAA,GACL;AAEA,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,GAAG,cAAA;AAAA,UACH,OAAA,EAAS,MAAA;AAAA,UACT,UAAA,EAAY,QAAA;AAAA,UACZ,cAAA,EAAgB,QAAA;AAAA,UAChB,OAAA,EAAS,EAAA;AAAA,UACT,UAAA,EAAY,mDAAA;AAAA,UACZ,KAAA,EAAO,SAAA;AAAA,UACP,QAAA,EAAU,EAAA;AAAA,UACV,UAAA,EAAY,GAAA;AAAA,UACZ,UAAA,EAAY;AAAA,SACd;AAAA,QACD,QAAA,EAAA;AAAA;AAAA,KAED;AAAA,EAEJ;AAEA,EAAA,IAAI,OAAA,IAAW,CAAC,UAAA,EAAY;AAC1B,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,YAAA;AAAA,QACL,KAAA,EAAO;AAAA,UACL,GAAG,cAAA;AAAA,UACH,UAAA,EAAY;AAAA,SACd;AAAA,QAEA,QAAA,kBAAA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,QAAA,EAAU,UAAA;AAAA,cACV,KAAA,EAAO,CAAA;AAAA,cACP,UAAA,EAAY;AAAA;AACd;AAAA;AACF;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO;AAAA,QACL,GAAG,cAAA;AAAA,QACH,SAAA,EAAW,6BAAA;AAAA,QACX,MAAA,EAAQ;AAAA,OACV;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,eAAA,EAAA,EACE,yBAAe,YAAA,oBACd,GAAA;AAAA,UAAC,MAAA,CAAO,GAAA;AAAA,UAAP;AAAA,YACC,GAAA,EAAK,YAAA;AAAA,YACL,GAAA,EAAK,WAAW,eAAA,GAAkB,qBAAA;AAAA,YAClC,OAAA,EAAS,EAAE,OAAA,EAAS,CAAA,EAAE;AAAA,YACtB,OAAA,EAAS,EAAE,OAAA,EAAS,CAAA,EAAE;AAAA,YACtB,UAAA,EAAY,EAAE,QAAA,EAAU,GAAA,EAAI;AAAA,YAC5B,KAAA,EAAO;AAAA,cACL,QAAA,EAAU,UAAA;AAAA,cACV,KAAA,EAAO,CAAA;AAAA,cACP,KAAA,EAAO,MAAA;AAAA,cACP,MAAA,EAAQ,MAAA;AAAA,cACR,SAAA,EAAW;AAAA;AACb;AAAA,SACF,EAEJ,CAAA;AAAA,QAEC,gCACC,GAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,YAAA,EAAc,KAAI,EAAA,EAAG,MAAA,EAAQ,MAAM,cAAA,CAAe,IAAI,CAAA,EAAG,KAAA,EAAO,EAAE,OAAA,EAAS,QAAO,EAAG,CAAA;AAAA,QAIhG,eAAA,oBACC,GAAA;AAAA,UAAC,MAAA,CAAO,GAAA;AAAA,UAAP;AAAA,YACC,OAAA,EAAS,WAAA;AAAA,YACT,KAAA,EAAO;AAAA,cACL,QAAA,EAAU,UAAA;AAAA,cACV,GAAA,EAAK,EAAA;AAAA,cACL,KAAA,EAAO,EAAA;AAAA,cACP,OAAA,EAAS,MAAA;AAAA,cACT,UAAA,EAAY,QAAA;AAAA,cACZ,cAAA,EAAgB,QAAA;AAAA,cAChB,KAAA,EAAO,EAAA;AAAA,cACP,MAAA,EAAQ,EAAA;AAAA,cACR,YAAA,EAAc,KAAA;AAAA,cACd,UAAA,EAAY,iBAAA;AAAA,cACZ,cAAA,EAAgB,WAAA;AAAA,cAChB,KAAA,EAAO,uBAAA;AAAA,cACP,MAAA,EAAQ;AAAA,aACV;AAAA,YACA,UAAA,EAAY;AAAA,cACV,UAAA,EAAY,iBAAA;AAAA,cACZ,KAAA,EAAO,qBAAA;AAAA,cACP,KAAA,EAAO;AAAA,aACT;AAAA,YACA,QAAA,EAAU,EAAE,KAAA,EAAO,IAAA,EAAK;AAAA,YACxB,YAAY,EAAE,IAAA,EAAM,UAAU,SAAA,EAAW,GAAA,EAAK,SAAS,EAAA,EAAG;AAAA,YAE1D,QAAA,kBAAA,GAAA,CAAC,CAAA,EAAA,EAAE,IAAA,EAAM,EAAA,EAAI,aAAa,GAAA,EAAK;AAAA;AAAA,SACjC;AAAA,wBAGF,GAAA,CAAC,SAAI,KAAA,EAAO,iBAAA,CAAkB,QAAQ,CAAA,EACnC,QAAA,EAAA,QAAA,IAAY,SAAS,MAAA,GAAS,CAAA;AAAA;AAAA;AAAA;AAAA,UAI7B,QAAA,CAAS,GAAA,CAAI,CAAC,IAAA,EAAM,GAAA,qBAClB,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cAEC,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,YAAY,QAAA,EAAS;AAAA,cAC/C,OAAA,EAAS,CAAC,CAAA,KAAM;AACd,gBAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,gBAAA,cAAA,IAAA,IAAA,GAAA,MAAA,GAAA,cAAA,CAAiB,KAAK,CAAA,EAAG,UAAA,CAAA;AAAA,cAC3B,CAAA;AAAA,cAEC,QAAA,EAAA;AAAA,aAAA;AAAA,YAPI;AAAA,WASR;AAAA,4BAED,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,UAAA,iBAAA,oBACC,GAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,UAAA;AAAA,cACN,sBAAM,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAM,EAAA,EAAI,aAAa,GAAA,EAAK,CAAA;AAAA,cAC/C,OAAA,EAAS,kBAAA;AAAA,cACT,WAAW,CAAC,OAAA;AAAA,cACZ,KAAA,EAAO;AAAA;AAAA,WACT;AAAA,UAED,aAAA,oBACC,GAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO,aAAA;AAAA,cACP,MAAM,iBAAA,oBAAqB,GAAA,CAAC,gBAAa,IAAA,EAAM,EAAA,EAAI,aAAa,GAAA,EAAK,CAAA;AAAA,cACrE,OAAA,EAAS,CAAC,CAAA,KAAM;AACd,gBAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,gBAAA,aAAA,EAAc;AAAA,cAChB,CAAA;AAAA,cACA,WAAW,CAAC,OAAA;AAAA,cACZ,KAAA,EAAO;AAAA;AAAA;AACT,SAAA,EAEJ,CAAA,EAEJ,CAAA;AAAA,QAEC,kBAAA,oBACC,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,QAAA,EAAU,UAAA;AAAA,cACV,GAAA,EAAK,EAAA;AAAA,cACL,IAAA,EAAM,EAAA;AAAA,cACN,OAAA,EAAS,MAAA;AAAA,cACT,UAAA,EAAY,QAAA;AAAA,cACZ,GAAA,EAAK,CAAA;AAAA,cACL,OAAA,EAAS,SAAA;AAAA,cACT,YAAA,EAAc,CAAA;AAAA,cACd,UAAA,EAAY,iBAAA;AAAA,cACZ,cAAA,EAAgB,WAAA;AAAA,cAChB,KAAA,EAAO,uBAAA;AAAA,cACP,QAAA,EAAU,EAAA;AAAA,cACV,UAAA,EAAY,GAAA;AAAA,cACZ,UAAA,EAAY,sCAAA;AAAA,cACZ,aAAA,EAAe,OAAA;AAAA,cACf,aAAA,EAAe;AAAA,aACjB;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,QAAA,EAAA,EAAS,MAAM,EAAA,EAAI,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA;AAExB;AAAA;AAAA,GAEJ;AAEJ","file":"index.mjs","sourcesContent":["import * as React from \"react\"\n\nexport interface CtaDetails {\n image: string\n url: string\n buySlotUrl: string\n buyer?: {\n fid: number\n username: string\n avatar: string\n displayName: string\n address: string\n }\n}\n\nexport interface UseCtaDetailsReturn {\n ctaDetails: CtaDetails | null\n loading: boolean\n error: string | null\n refetch: () => void\n reset: () => void\n}\n\nexport const useCtaDetails = (params: { castHash: string }): UseCtaDetailsReturn => {\n const { castHash } = params\n const [ctaDetails, setCtaDetails] = React.useState<CtaDetails | null>(null)\n // Start loading if we have a valid castHash to avoid flash of empty state\n const [loading, setLoading] = React.useState(Boolean(castHash.trim()))\n const [error, setError] = React.useState<string | null>(null)\n\n const fetchCta = React.useCallback(\n async (signal?: AbortSignal) => {\n const trimmedHash = castHash?.trim()\n if (!trimmedHash) {\n setCtaDetails(null)\n setLoading(false)\n setError(null)\n return\n }\n\n setLoading(true)\n setError(null)\n\n try {\n const response = await fetch(`https://www.adsterix.xyz/api/ads/cta-details/${trimmedHash}`, { signal })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch: ${response.status}`)\n }\n\n const data = await response.json()\n setCtaDetails(data)\n } catch (err) {\n if ((err as any)?.name === \"AbortError\") return\n setError(err instanceof Error ? err.message : \"Unknown error\")\n setCtaDetails(null)\n } finally {\n setLoading(false)\n }\n },\n [castHash],\n )\n\n React.useEffect(() => {\n const controller = new AbortController()\n fetchCta(controller.signal)\n return () => controller.abort()\n }, [fetchCta])\n\n const refetch = React.useCallback(() => {\n fetchCta()\n }, [fetchCta])\n\n const reset = React.useCallback(() => {\n setCtaDetails(null)\n setLoading(false)\n setError(null)\n }, [])\n\n return { ctaDetails, loading, error, refetch, reset }\n}\n\nexport default useCtaDetails\n","import * as React from \"react\"\nimport { motion, AnimatePresence } from \"framer-motion\"\nimport { ExternalLink, Sparkles, ShoppingBag, X } from \"lucide-react\"\nimport useCtaDetails, { CtaDetails } from \"./hooks/useCtaDetails\"\n\ntype CtaPosition =\n | \"bottom-left\"\n | \"bottom-right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-center\"\n | \"top-center\"\n | \"center-left\"\n | \"center-right\"\n\nexport interface AdsterixWidgetProps {\n /** The Farcaster cast hash to fetch ad details for (required) */\n castHash: string\n /** Callback fired when the widget is closed via the close button */\n onClose?: () => void\n /** Width of the widget container (number = px, string = any CSS value). Default: \"100%\" */\n width?: string | number\n /** Height of the widget container (number = px, string = any CSS value). If omitted, uses 3:2 aspect ratio */\n height?: string | number\n /** Default image URL to display when no buyer has purchased the ad slot */\n defaultImage?: string\n /** Show a small \"Ad\" label with sparkle icon in the top-left corner */\n showAdSparkleLabel?: boolean\n /** Show a close button in the top-right corner */\n showCloseButton?: boolean\n /** Show the \"Buy Slot\" button (allows users to purchase the ad slot) */\n showBuySlotButton?: boolean\n /** Show the default CTA button */\n showCtaButton?: boolean\n /** Show an external link icon inside the CTA button */\n showCtaButtonIcon?: boolean\n /** Text label for the CTA button. Default: \"Learn More\" */\n ctaButtonText?: string\n /** If provided, these nodes will be rendered instead of the default CTA / Buy Slot buttons */\n ctaNodes?: React.ReactNode[]\n /** Called when a custom CTA node is clicked: (index, event, ctaDetails) */\n onCtaNodeClick?: (index: number, e: React.MouseEvent, ctaDetails: CtaDetails | null) => void\n /** Callback fired when the \"Buy Slot\" button is clicked, receives the buySlotUrl */\n onBuySlotClick?: (buySlotUrl: string) => void\n /** Callback fired when the ad (or CTA button) is clicked, receives the destination url */\n onAdClick?: (url: string) => void\n /** Position of the CTA buttons within the widget. Default: \"bottom-right\" */\n position?: CtaPosition\n /** Custom styles to merge into the widget container */\n containerStyle?: React.CSSProperties\n /** Custom styles to merge into the \"Buy Slot\" button */\n buySlotButtonStyle?: React.CSSProperties\n /** Custom styles to merge into the CTA button */\n ctaButtonStyle?: React.CSSProperties\n}\n\ninterface CtaButtonProps {\n label: string\n icon: React.ReactNode\n onClick: (e: React.MouseEvent) => void\n showLabel: boolean\n style?: React.CSSProperties\n}\n\nconst getPositionStyles = (position: CtaPosition): React.CSSProperties => {\n const baseStyles: React.CSSProperties = {\n position: \"absolute\",\n display: \"flex\",\n gap: 8,\n }\n\n const positionMap: Record<CtaPosition, React.CSSProperties> = {\n \"bottom-right\": { bottom: 12, right: 12 },\n \"bottom-left\": { bottom: 12, left: 12 },\n \"top-right\": { top: 12, right: 12 },\n \"top-left\": { top: 12, left: 12 },\n \"bottom-center\": { bottom: 12, left: \"50%\", transform: \"translateX(-50%)\" },\n \"top-center\": { top: 12, left: \"50%\", transform: \"translateX(-50%)\" },\n \"center-left\": { top: \"50%\", left: 12, transform: \"translateY(-50%)\" },\n \"center-right\": { top: \"50%\", right: 12, transform: \"translateY(-50%)\" },\n }\n\n return { ...baseStyles, ...positionMap[position] }\n}\n\nconst CtaButton: React.FC<CtaButtonProps> = ({ label, icon, onClick, showLabel, style = {} }) => {\n const defaultStyle: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: showLabel ? 6 : 0,\n padding: showLabel ? \"8px 14px\" : \"8px\",\n borderRadius: 20,\n background: \"rgba(255,255,255,0.9)\",\n backdropFilter: \"blur(8px)\",\n color: \"#0f172a\",\n fontSize: 13,\n fontWeight: 600,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\",\n cursor: \"pointer\",\n }\n\n const mergedStyle = { ...defaultStyle, ...style }\n\n return (\n <div onClick={onClick} style={mergedStyle}>\n {showLabel && label}\n <span style={{ display: \"flex\", alignItems: \"center\" }}>{icon}</span>\n </div>\n )\n}\n\nexport const AdsterixWidget: React.FC<AdsterixWidgetProps> = ({\n castHash,\n onClose,\n width = \"100%\",\n position = \"bottom-right\",\n height,\n defaultImage,\n showAdSparkleLabel = false,\n showCloseButton = false,\n showBuySlotButton = false,\n showCtaButton = false,\n showCtaButtonIcon = false,\n ctaButtonText = \"Learn More\",\n ctaButtonStyle,\n buySlotButtonStyle,\n onBuySlotClick,\n onAdClick,\n onCtaNodeClick,\n containerStyle: _containerStyle,\n ctaNodes,\n}) => {\n const { ctaDetails, loading, error } = useCtaDetails({ castHash })\n const [imageLoaded, setImageLoaded] = React.useState(false)\n const [visible, setVisible] = React.useState(true)\n const [isSmall, setIsSmall] = React.useState(true) // Start with true to avoid flash\n const containerRef = React.useRef<HTMLDivElement>(null)\n\n // Determine if the slot has a buyer\n const hasBuyer = Boolean(ctaDetails?.buyer)\n // if has buyer, use ad image; else use defaultImage if provided, else use ad image\n const displayImage = hasBuyer ? ctaDetails?.image : defaultImage ? defaultImage : ctaDetails?.image\n\n // Reset imageLoaded when the display image changes\n React.useEffect(() => {\n setImageLoaded(false)\n }, [displayImage])\n\n React.useEffect(() => {\n if (!containerRef.current) return\n\n const checkSize = (entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const width = entry.contentRect.width\n setIsSmall(width < 270)\n }\n }\n\n const resizeObserver = new ResizeObserver(checkSize)\n resizeObserver.observe(containerRef.current)\n\n // Initial check\n if (containerRef.current) {\n const width = containerRef.current.offsetWidth\n setIsSmall(width < 400)\n }\n\n return () => resizeObserver.disconnect()\n }, [loading, ctaDetails]) // Re-run when content changes\n\n const handleAdClick = () => {\n if (ctaDetails?.url) {\n window.open(ctaDetails.url, \"_blank\", \"noopener,noreferrer\")\n onAdClick?.(ctaDetails.url)\n }\n }\n\n const handleBuySlotClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n if (ctaDetails?.buySlotUrl) {\n window.open(ctaDetails.buySlotUrl, \"_blank\", \"noopener,noreferrer\")\n onBuySlotClick?.(ctaDetails?.buySlotUrl)\n }\n }\n\n const handleClose = (e: React.MouseEvent) => {\n e.stopPropagation()\n setVisible(false)\n onClose?.()\n }\n\n const containerStyle: React.CSSProperties = {\n position: \"relative\",\n width: typeof width === \"number\" ? `${width}px` : width,\n ...(height ? { height: typeof height === \"number\" ? `${height}px` : height } : { aspectRatio: \"3 / 2\" }),\n borderRadius: 12,\n overflow: \"hidden\",\n ..._containerStyle,\n }\n\n if (!visible) return null\n\n if (error) {\n return (\n <div\n style={{\n ...containerStyle,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n background: \"linear-gradient(135deg, #0f172a 0%, #1e293b 100%)\",\n color: \"#f87171\",\n fontSize: 14,\n fontWeight: 500,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n }}\n >\n Unable to load ad\n </div>\n )\n }\n\n if (loading || !ctaDetails) {\n return (\n <div\n ref={containerRef}\n style={{\n ...containerStyle,\n background: \"linear-gradient(135deg, #0f172a 0%, #1e293b 100%)\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%)\",\n }}\n />\n </div>\n )\n }\n\n return (\n <div\n style={{\n ...containerStyle,\n boxShadow: \"0 10px 30px rgba(0,0,0,0.2)\",\n cursor: \"pointer\",\n }}\n >\n <AnimatePresence>\n {imageLoaded && displayImage && (\n <motion.img\n src={displayImage}\n alt={hasBuyer ? \"Advertisement\" : \"Default placeholder\"}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.4 }}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n }}\n />\n )}\n </AnimatePresence>\n\n {displayImage && (\n <img src={displayImage} alt=\"\" onLoad={() => setImageLoaded(true)} style={{ display: \"none\" }} />\n )}\n\n {/* Close button */}\n {showCloseButton && (\n <motion.div\n onClick={handleClose}\n style={{\n position: \"absolute\",\n top: 10,\n right: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 28,\n height: 28,\n borderRadius: \"50%\",\n background: \"rgba(0,0,0,0.5)\",\n backdropFilter: \"blur(8px)\",\n color: \"rgba(255,255,255,0.8)\",\n cursor: \"pointer\",\n }}\n whileHover={{\n background: \"rgba(0,0,0,0.7)\",\n color: \"rgba(255,255,255,1)\",\n scale: 1.1,\n }}\n whileTap={{ scale: 0.95 }}\n transition={{ type: \"spring\", stiffness: 400, damping: 15 }}\n >\n <X size={14} strokeWidth={2.5} />\n </motion.div>\n )}\n\n <div style={getPositionStyles(position)}>\n {ctaNodes && ctaNodes.length > 0 ? (\n // Render custom nodes provided by the consumer. Each node is wrapped to\n // keep spacing consistent with the default layout and to avoid\n // accidental propagation of clicks to the ad container.\n ctaNodes.map((node, idx) => (\n <div\n key={idx}\n style={{ display: \"flex\", alignItems: \"center\" }}\n onClick={(e) => {\n e.stopPropagation()\n onCtaNodeClick?.(idx, e, ctaDetails)\n }}\n >\n {node}\n </div>\n ))\n ) : (\n <>\n {showBuySlotButton && (\n <CtaButton\n label=\"Buy Slot\"\n icon={<ShoppingBag size={14} strokeWidth={2.5} />}\n onClick={handleBuySlotClick}\n showLabel={!isSmall}\n style={buySlotButtonStyle}\n />\n )}\n {showCtaButton && (\n <CtaButton\n label={ctaButtonText}\n icon={showCtaButtonIcon && <ExternalLink size={14} strokeWidth={2.5} />}\n onClick={(e) => {\n e.stopPropagation()\n handleAdClick()\n }}\n showLabel={!isSmall}\n style={ctaButtonStyle}\n />\n )}\n </>\n )}\n </div>\n\n {showAdSparkleLabel && (\n <div\n style={{\n position: \"absolute\",\n top: 10,\n left: 10,\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"4px 8px\",\n borderRadius: 6,\n background: \"rgba(0,0,0,0.5)\",\n backdropFilter: \"blur(8px)\",\n color: \"rgba(255,255,255,0.8)\",\n fontSize: 10,\n fontWeight: 500,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n letterSpacing: \"0.5px\",\n textTransform: \"uppercase\",\n }}\n >\n <Sparkles size={10} />\n Ad\n </div>\n )}\n </div>\n )\n}\n"]}
|