@nektarlabs/adsterix-widget 1.1.0 → 1.4.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/README.md +21 -6
- package/dist/index.d.mts +60 -2
- package/dist/index.mjs +167 -129
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,12 +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
|
|
57
|
-
|
|
|
58
|
-
| `castHash`
|
|
59
|
-
| `onClose`
|
|
60
|
-
| `width`
|
|
61
|
-
| `height`
|
|
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 |
|
|
62
77
|
|
|
63
78
|
## Example
|
|
64
79
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +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
|
+
|
|
26
|
+
type CtaPosition = "bottom-left" | "bottom-right" | "top-left" | "top-right" | "bottom-center" | "top-center" | "center-left" | "center-right";
|
|
3
27
|
interface AdsterixWidgetProps {
|
|
4
|
-
|
|
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 */
|
|
5
31
|
onClose?: () => void;
|
|
32
|
+
/** Width of the widget container (number = px, string = any CSS value). Default: "100%" */
|
|
6
33
|
width?: string | number;
|
|
34
|
+
/** Height of the widget container (number = px, string = any CSS value). If omitted, uses 3:2 aspect ratio */
|
|
7
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 */
|
|
39
|
+
showAdSparkleLabel?: boolean;
|
|
40
|
+
/** Show a close button in the top-right corner */
|
|
41
|
+
showCloseButton?: boolean;
|
|
42
|
+
/** Show the "Buy Slot" button (allows users to purchase the ad slot) */
|
|
43
|
+
showBuySlotButton?: boolean;
|
|
44
|
+
/** Show the default CTA button */
|
|
45
|
+
showCtaButton?: boolean;
|
|
46
|
+
/** Show an external link icon inside the CTA button */
|
|
47
|
+
showCtaButtonIcon?: boolean;
|
|
48
|
+
/** Text label for the CTA button. Default: "Learn More" */
|
|
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 */
|
|
55
|
+
onBuySlotClick?: (buySlotUrl: string) => void;
|
|
56
|
+
/** Callback fired when the ad (or CTA button) is clicked, receives the destination url */
|
|
57
|
+
onAdClick?: (url: string) => void;
|
|
58
|
+
/** Position of the CTA buttons within the widget. Default: "bottom-right" */
|
|
59
|
+
position?: CtaPosition;
|
|
60
|
+
/** Custom styles to merge into the widget container */
|
|
61
|
+
containerStyle?: React.CSSProperties;
|
|
62
|
+
/** Custom styles to merge into the "Buy Slot" button */
|
|
63
|
+
buySlotButtonStyle?: React.CSSProperties;
|
|
64
|
+
/** Custom styles to merge into the CTA button */
|
|
65
|
+
ctaButtonStyle?: React.CSSProperties;
|
|
8
66
|
}
|
|
9
67
|
declare const AdsterixWidget: React.FC<AdsterixWidgetProps>;
|
|
10
68
|
|
|
11
|
-
export { AdsterixWidget, type AdsterixWidgetProps };
|
|
69
|
+
export { AdsterixWidget, type AdsterixWidgetProps, type CtaDetails, type UseCtaDetailsReturn, useCtaDetails };
|
package/dist/index.mjs
CHANGED
|
@@ -1,76 +1,129 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
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
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
onClick,
|
|
11
|
-
style: {
|
|
12
|
-
display: "flex",
|
|
13
|
-
alignItems: "center",
|
|
14
|
-
gap: showLabel ? 6 : 0,
|
|
15
|
-
padding: showLabel ? "8px 14px" : "8px",
|
|
16
|
-
borderRadius: 20,
|
|
17
|
-
background: "rgba(255,255,255,0.9)",
|
|
18
|
-
backdropFilter: "blur(8px)",
|
|
19
|
-
color: "#0f172a",
|
|
20
|
-
fontSize: 13,
|
|
21
|
-
fontWeight: 600,
|
|
22
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
23
|
-
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
24
|
-
cursor: "pointer"
|
|
25
|
-
},
|
|
26
|
-
whileHover: {
|
|
27
|
-
y: -2,
|
|
28
|
-
background: "rgba(255,255,255,0.98)",
|
|
29
|
-
boxShadow: "0 8px 20px rgba(0,0,0,0.2)"
|
|
30
|
-
},
|
|
31
|
-
transition: { type: "spring", stiffness: 400, damping: 15 },
|
|
32
|
-
children: [
|
|
33
|
-
showLabel && label,
|
|
34
|
-
/* @__PURE__ */ jsx(
|
|
35
|
-
motion.span,
|
|
36
|
-
{
|
|
37
|
-
style: { display: "flex", alignItems: "center" },
|
|
38
|
-
whileHover: { x: showLabel ? 2 : 0 },
|
|
39
|
-
transition: { type: "spring", stiffness: 400, damping: 15 },
|
|
40
|
-
children: icon
|
|
41
|
-
}
|
|
42
|
-
)
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
7
|
+
var useCtaDetails = (params) => {
|
|
8
|
+
const { castHash } = params;
|
|
47
9
|
const [ctaDetails, setCtaDetails] = React.useState(null);
|
|
10
|
+
const [loading, setLoading] = React.useState(Boolean(castHash.trim()));
|
|
48
11
|
const [error, setError] = React.useState(null);
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
}
|
|
57
21
|
setLoading(true);
|
|
58
22
|
setError(null);
|
|
59
23
|
try {
|
|
60
|
-
const response = await fetch(`https://www.adsterix.xyz/api/ads/cta-details/${
|
|
24
|
+
const response = await fetch(`https://www.adsterix.xyz/api/ads/cta-details/${trimmedHash}`, { signal });
|
|
61
25
|
if (!response.ok) {
|
|
62
26
|
throw new Error(`Failed to fetch: ${response.status}`);
|
|
63
27
|
}
|
|
64
28
|
const data = await response.json();
|
|
65
29
|
setCtaDetails(data);
|
|
66
30
|
} catch (err) {
|
|
31
|
+
if ((err == null ? void 0 : err.name) === "AbortError") return;
|
|
67
32
|
setError(err instanceof Error ? err.message : "Unknown error");
|
|
33
|
+
setCtaDetails(null);
|
|
68
34
|
} finally {
|
|
69
35
|
setLoading(false);
|
|
70
36
|
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
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;
|
|
56
|
+
var getPositionStyles = (position) => {
|
|
57
|
+
const baseStyles = {
|
|
58
|
+
position: "absolute",
|
|
59
|
+
display: "flex",
|
|
60
|
+
gap: 8
|
|
61
|
+
};
|
|
62
|
+
const positionMap = {
|
|
63
|
+
"bottom-right": { bottom: 12, right: 12 },
|
|
64
|
+
"bottom-left": { bottom: 12, left: 12 },
|
|
65
|
+
"top-right": { top: 12, right: 12 },
|
|
66
|
+
"top-left": { top: 12, left: 12 },
|
|
67
|
+
"bottom-center": { bottom: 12, left: "50%", transform: "translateX(-50%)" },
|
|
68
|
+
"top-center": { top: 12, left: "50%", transform: "translateX(-50%)" },
|
|
69
|
+
"center-left": { top: "50%", left: 12, transform: "translateY(-50%)" },
|
|
70
|
+
"center-right": { top: "50%", right: 12, transform: "translateY(-50%)" }
|
|
71
|
+
};
|
|
72
|
+
return { ...baseStyles, ...positionMap[position] };
|
|
73
|
+
};
|
|
74
|
+
var CtaButton = ({ label, icon, onClick, showLabel, style = {} }) => {
|
|
75
|
+
const defaultStyle = {
|
|
76
|
+
display: "flex",
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
gap: showLabel ? 6 : 0,
|
|
79
|
+
padding: showLabel ? "8px 14px" : "8px",
|
|
80
|
+
borderRadius: 20,
|
|
81
|
+
background: "rgba(255,255,255,0.9)",
|
|
82
|
+
backdropFilter: "blur(8px)",
|
|
83
|
+
color: "#0f172a",
|
|
84
|
+
fontSize: 13,
|
|
85
|
+
fontWeight: 600,
|
|
86
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
87
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
88
|
+
cursor: "pointer"
|
|
89
|
+
};
|
|
90
|
+
const mergedStyle = { ...defaultStyle, ...style };
|
|
91
|
+
return /* @__PURE__ */ jsxs("div", { onClick, style: mergedStyle, children: [
|
|
92
|
+
showLabel && label,
|
|
93
|
+
/* @__PURE__ */ jsx("span", { style: { display: "flex", alignItems: "center" }, children: icon })
|
|
94
|
+
] });
|
|
95
|
+
};
|
|
96
|
+
var AdsterixWidget = ({
|
|
97
|
+
castHash,
|
|
98
|
+
onClose,
|
|
99
|
+
width = "100%",
|
|
100
|
+
position = "bottom-right",
|
|
101
|
+
height,
|
|
102
|
+
defaultImage,
|
|
103
|
+
showAdSparkleLabel = false,
|
|
104
|
+
showCloseButton = false,
|
|
105
|
+
showBuySlotButton = false,
|
|
106
|
+
showCtaButton = false,
|
|
107
|
+
showCtaButtonIcon = false,
|
|
108
|
+
ctaButtonText = "Learn More",
|
|
109
|
+
ctaButtonStyle,
|
|
110
|
+
buySlotButtonStyle,
|
|
111
|
+
onBuySlotClick,
|
|
112
|
+
onAdClick,
|
|
113
|
+
onCtaNodeClick,
|
|
114
|
+
containerStyle: _containerStyle,
|
|
115
|
+
ctaNodes
|
|
116
|
+
}) => {
|
|
117
|
+
const { ctaDetails, loading, error } = useCtaDetails_default({ castHash });
|
|
118
|
+
const [imageLoaded, setImageLoaded] = React.useState(false);
|
|
119
|
+
const [visible, setVisible] = React.useState(true);
|
|
120
|
+
const [isSmall, setIsSmall] = React.useState(true);
|
|
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;
|
|
124
|
+
React.useEffect(() => {
|
|
125
|
+
setImageLoaded(false);
|
|
126
|
+
}, [displayImage]);
|
|
74
127
|
React.useEffect(() => {
|
|
75
128
|
if (!containerRef.current) return;
|
|
76
129
|
const checkSize = (entries) => {
|
|
@@ -90,11 +143,15 @@ var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
|
90
143
|
const handleAdClick = () => {
|
|
91
144
|
if (ctaDetails == null ? void 0 : ctaDetails.url) {
|
|
92
145
|
window.open(ctaDetails.url, "_blank", "noopener,noreferrer");
|
|
146
|
+
onAdClick == null ? void 0 : onAdClick(ctaDetails.url);
|
|
93
147
|
}
|
|
94
148
|
};
|
|
95
149
|
const handleBuySlotClick = (e) => {
|
|
96
150
|
e.stopPropagation();
|
|
97
|
-
if (ctaDetails == null ? void 0 : ctaDetails.buySlotUrl)
|
|
151
|
+
if (ctaDetails == null ? void 0 : ctaDetails.buySlotUrl) {
|
|
152
|
+
window.open(ctaDetails.buySlotUrl, "_blank", "noopener,noreferrer");
|
|
153
|
+
onBuySlotClick == null ? void 0 : onBuySlotClick(ctaDetails == null ? void 0 : ctaDetails.buySlotUrl);
|
|
154
|
+
}
|
|
98
155
|
};
|
|
99
156
|
const handleClose = (e) => {
|
|
100
157
|
e.stopPropagation();
|
|
@@ -106,15 +163,14 @@ var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
|
106
163
|
width: typeof width === "number" ? `${width}px` : width,
|
|
107
164
|
...height ? { height: typeof height === "number" ? `${height}px` : height } : { aspectRatio: "3 / 2" },
|
|
108
165
|
borderRadius: 12,
|
|
109
|
-
overflow: "hidden"
|
|
166
|
+
overflow: "hidden",
|
|
167
|
+
..._containerStyle
|
|
110
168
|
};
|
|
111
169
|
if (!visible) return null;
|
|
112
170
|
if (error) {
|
|
113
171
|
return /* @__PURE__ */ jsx(
|
|
114
|
-
|
|
172
|
+
"div",
|
|
115
173
|
{
|
|
116
|
-
initial: { opacity: 0, y: 10 },
|
|
117
|
-
animate: { opacity: 1, y: 0 },
|
|
118
174
|
style: {
|
|
119
175
|
...containerStyle,
|
|
120
176
|
display: "flex",
|
|
@@ -141,42 +197,32 @@ var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
|
141
197
|
background: "linear-gradient(135deg, #0f172a 0%, #1e293b 100%)"
|
|
142
198
|
},
|
|
143
199
|
children: /* @__PURE__ */ jsx(
|
|
144
|
-
|
|
200
|
+
"div",
|
|
145
201
|
{
|
|
146
202
|
style: {
|
|
147
203
|
position: "absolute",
|
|
148
204
|
inset: 0,
|
|
149
205
|
background: "linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%)"
|
|
150
|
-
}
|
|
151
|
-
animate: { x: ["-100%", "100%"] },
|
|
152
|
-
transition: { duration: 1.5, repeat: Infinity, ease: "linear" }
|
|
206
|
+
}
|
|
153
207
|
}
|
|
154
208
|
)
|
|
155
209
|
}
|
|
156
210
|
);
|
|
157
211
|
}
|
|
158
212
|
return /* @__PURE__ */ jsxs(
|
|
159
|
-
|
|
213
|
+
"div",
|
|
160
214
|
{
|
|
161
|
-
ref: containerRef,
|
|
162
|
-
onClick: handleAdClick,
|
|
163
|
-
initial: { opacity: 0, scale: 0.95 },
|
|
164
|
-
animate: { opacity: 1, scale: 1 },
|
|
165
|
-
exit: { opacity: 0, scale: 0.95 },
|
|
166
|
-
whileHover: { scale: 1.02 },
|
|
167
|
-
whileTap: { scale: 0.98 },
|
|
168
|
-
transition: { type: "spring", stiffness: 300, damping: 20 },
|
|
169
215
|
style: {
|
|
170
216
|
...containerStyle,
|
|
171
|
-
|
|
172
|
-
|
|
217
|
+
boxShadow: "0 10px 30px rgba(0,0,0,0.2)",
|
|
218
|
+
cursor: "pointer"
|
|
173
219
|
},
|
|
174
220
|
children: [
|
|
175
|
-
/* @__PURE__ */ jsx(AnimatePresence, { children: imageLoaded && /* @__PURE__ */ jsx(
|
|
221
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: imageLoaded && displayImage && /* @__PURE__ */ jsx(
|
|
176
222
|
motion.img,
|
|
177
223
|
{
|
|
178
|
-
src:
|
|
179
|
-
alt: "Advertisement",
|
|
224
|
+
src: displayImage,
|
|
225
|
+
alt: hasBuyer ? "Advertisement" : "Default placeholder",
|
|
180
226
|
initial: { opacity: 0 },
|
|
181
227
|
animate: { opacity: 1 },
|
|
182
228
|
transition: { duration: 0.4 },
|
|
@@ -189,22 +235,8 @@ var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
|
189
235
|
}
|
|
190
236
|
}
|
|
191
237
|
) }),
|
|
192
|
-
/* @__PURE__ */ jsx("img", { src:
|
|
193
|
-
/* @__PURE__ */ jsx(
|
|
194
|
-
motion.div,
|
|
195
|
-
{
|
|
196
|
-
style: {
|
|
197
|
-
position: "absolute",
|
|
198
|
-
inset: 0,
|
|
199
|
-
background: "linear-gradient(to top, rgba(0,0,0,0.3) 0%, transparent 50%)"
|
|
200
|
-
},
|
|
201
|
-
whileHover: {
|
|
202
|
-
background: "linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 60%)"
|
|
203
|
-
},
|
|
204
|
-
transition: { duration: 0.3 }
|
|
205
|
-
}
|
|
206
|
-
),
|
|
207
|
-
/* @__PURE__ */ jsx(
|
|
238
|
+
displayImage && /* @__PURE__ */ jsx("img", { src: displayImage, alt: "", onLoad: () => setImageLoaded(true), style: { display: "none" } }),
|
|
239
|
+
showCloseButton && /* @__PURE__ */ jsx(
|
|
208
240
|
motion.div,
|
|
209
241
|
{
|
|
210
242
|
onClick: handleClose,
|
|
@@ -233,42 +265,48 @@ var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
|
233
265
|
children: /* @__PURE__ */ jsx(X, { size: 14, strokeWidth: 2.5 })
|
|
234
266
|
}
|
|
235
267
|
),
|
|
236
|
-
/* @__PURE__ */
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
display: "flex",
|
|
244
|
-
|
|
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
|
|
245
281
|
},
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
282
|
+
idx
|
|
283
|
+
))
|
|
284
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
285
|
+
showBuySlotButton && /* @__PURE__ */ jsx(
|
|
286
|
+
CtaButton,
|
|
287
|
+
{
|
|
288
|
+
label: "Buy Slot",
|
|
289
|
+
icon: /* @__PURE__ */ jsx(ShoppingBag, { size: 14, strokeWidth: 2.5 }),
|
|
290
|
+
onClick: handleBuySlotClick,
|
|
291
|
+
showLabel: !isSmall,
|
|
292
|
+
style: buySlotButtonStyle
|
|
293
|
+
}
|
|
294
|
+
),
|
|
295
|
+
showCtaButton && /* @__PURE__ */ jsx(
|
|
296
|
+
CtaButton,
|
|
297
|
+
{
|
|
298
|
+
label: ctaButtonText,
|
|
299
|
+
icon: showCtaButtonIcon && /* @__PURE__ */ jsx(ExternalLink, { size: 14, strokeWidth: 2.5 }),
|
|
300
|
+
onClick: (e) => {
|
|
301
|
+
e.stopPropagation();
|
|
302
|
+
handleAdClick();
|
|
303
|
+
},
|
|
304
|
+
showLabel: !isSmall,
|
|
305
|
+
style: ctaButtonStyle
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
] }) }),
|
|
309
|
+
showAdSparkleLabel && /* @__PURE__ */ jsxs(
|
|
272
310
|
"div",
|
|
273
311
|
{
|
|
274
312
|
style: {
|
|
@@ -300,6 +338,6 @@ var AdsterixWidget = ({ castHash, onClose, width = "100%", height }) => {
|
|
|
300
338
|
);
|
|
301
339
|
};
|
|
302
340
|
|
|
303
|
-
export { AdsterixWidget };
|
|
341
|
+
export { AdsterixWidget, useCtaDetails };
|
|
304
342
|
//# sourceMappingURL=index.mjs.map
|
|
305
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\nexport interface AdsterixWidgetProps {\n castHash?: string\n onClose?: () => void\n width?: string | number\n height?: string | number\n}\n\ninterface CtaDetails {\n image: string\n url: string\n buySlotUrl: string\n}\n\nconst CtaButton: React.FC<{\n label: string\n icon: React.ReactNode\n onClick: (e: React.MouseEvent) => void\n showLabel: boolean\n}> = ({ label, icon, onClick, showLabel }) => (\n <motion.div\n onClick={onClick}\n style={{\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 whileHover={{\n y: -2,\n background: \"rgba(255,255,255,0.98)\",\n boxShadow: \"0 8px 20px rgba(0,0,0,0.2)\",\n }}\n transition={{ type: \"spring\", stiffness: 400, damping: 15 }}\n >\n {showLabel && label}\n <motion.span\n style={{ display: \"flex\", alignItems: \"center\" }}\n whileHover={{ x: showLabel ? 2 : 0 }}\n transition={{ type: \"spring\", stiffness: 400, damping: 15 }}\n >\n {icon}\n </motion.span>\n </motion.div>\n)\n\nexport const AdsterixWidget: React.FC<AdsterixWidgetProps> = ({ castHash, onClose, width = \"100%\", height }) => {\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 }\n }\n\n const handleBuySlotClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n if (ctaDetails?.buySlotUrl) window.open(ctaDetails.buySlotUrl, \"_blank\", \"noopener,noreferrer\")\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 }\n\n if (!visible) return null\n\n if (error) {\n return (\n <motion.div\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\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 </motion.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 <motion.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 animate={{ x: [\"-100%\", \"100%\"] }}\n transition={{ duration: 1.5, repeat: Infinity, ease: \"linear\" }}\n />\n </div>\n )\n }\n\n return (\n <motion.div\n ref={containerRef}\n onClick={handleAdClick}\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n whileHover={{ scale: 1.02 }}\n whileTap={{ scale: 0.98 }}\n transition={{ type: \"spring\", stiffness: 300, damping: 20 }}\n style={{\n ...containerStyle,\n cursor: \"pointer\",\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 <motion.div\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"linear-gradient(to top, rgba(0,0,0,0.3) 0%, transparent 50%)\",\n }}\n whileHover={{\n background: \"linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 60%)\",\n }}\n transition={{ duration: 0.3 }}\n />\n\n {/* Close button */}\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 <div\n style={{\n position: \"absolute\",\n bottom: 12,\n right: 12,\n display: \"flex\",\n gap: 8,\n }}\n >\n <CtaButton\n label=\"Buy Slot\"\n icon={<ShoppingBag size={14} strokeWidth={2.5} />}\n onClick={handleBuySlotClick}\n showLabel={!isSmall}\n />\n <CtaButton\n label=\"Learn More\"\n icon={<ExternalLink size={14} strokeWidth={2.5} />}\n onClick={(e) => {\n e.stopPropagation()\n handleAdClick()\n }}\n showLabel={!isSmall}\n />\n </div>\n\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 </motion.div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useCtaDetails.ts","../src/AdsterixWidget.tsx"],"names":["React2","width"],"mappings":"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","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 // Use default image when no buyer, otherwise use the ad image\n const displayImage = hasBuyer ? ctaDetails?.image : defaultImage\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"]}
|