@active-reach/web-sdk 1.20.0 → 1.22.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/aegis-sw.js +1 -1
- package/dist/aegis.min.js +1 -1
- package/dist/aegis.min.js.map +1 -1
- package/dist/{analytics-DblhjFhs.mjs → analytics-0p0p56H0.mjs} +11 -6
- package/dist/analytics-0p0p56H0.mjs.map +1 -0
- package/dist/cdn.d.ts.map +1 -1
- package/dist/chat/AegisChat.d.ts +24 -0
- package/dist/chat/AegisChat.d.ts.map +1 -1
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.d.ts.map +1 -1
- package/dist/core/prefetch-bundle-client.d.ts.map +1 -1
- package/dist/inapp/AegisInAppManager.d.ts +38 -1
- package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
- package/dist/inapp/lucide-svg.d.ts +46 -0
- package/dist/inapp/lucide-svg.d.ts.map +1 -0
- package/dist/inapp/renderPreview.d.ts +16 -1
- package/dist/inapp/renderPreview.d.ts.map +1 -1
- package/dist/inapp/renderers/active-web-chat.d.ts +7 -0
- package/dist/inapp/renderers/active-web-chat.d.ts.map +1 -1
- package/dist/inapp/renderers/card-style.d.ts +28 -0
- package/dist/inapp/renderers/card-style.d.ts.map +1 -0
- package/dist/inapp/renderers/card-template.d.ts +107 -0
- package/dist/inapp/renderers/card-template.d.ts.map +1 -0
- package/dist/inapp/renderers/carousel-cards.d.ts.map +1 -1
- package/dist/inapp/renderers/games.d.ts.map +1 -1
- package/dist/inapp/renderers/hero.d.ts +23 -0
- package/dist/inapp/renderers/hero.d.ts.map +1 -0
- package/dist/inapp/renderers/index.d.ts +4 -1
- package/dist/inapp/renderers/index.d.ts.map +1 -1
- package/dist/inapp/renderers/product-recommendation.d.ts +19 -5
- package/dist/inapp/renderers/product-recommendation.d.ts.map +1 -1
- package/dist/inapp/renderers/progress-bar.d.ts.map +1 -1
- package/dist/inapp/renderers/sticky-bar.d.ts.map +1 -1
- package/dist/inapp/renderers/stories.d.ts.map +1 -1
- package/dist/inapp/renderers/types.d.ts +10 -0
- package/dist/inapp/renderers/types.d.ts.map +1 -1
- package/dist/inapp/renderers/video.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1726 -391
- package/dist/index.js.map +1 -1
- package/dist/push/AegisWebPush.d.ts +1 -6
- package/dist/push/AegisWebPush.d.ts.map +1 -1
- package/dist/push/AegisWebPush.js +20 -1
- package/dist/push/AegisWebPush.js.map +1 -1
- package/dist/react.js +1 -1
- package/dist/runtime/AegisMessageRuntime.d.ts +11 -1
- package/dist/runtime/AegisMessageRuntime.d.ts.map +1 -1
- package/dist/triggers/IntentRuleEvaluator.d.ts +21 -0
- package/dist/triggers/IntentRuleEvaluator.d.ts.map +1 -1
- package/dist/utils/consent.d.ts.map +1 -1
- package/dist/widgets/AegisWidgetManager.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/analytics-DblhjFhs.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as Storage, l as logger, A as Aegis } from "./analytics-
|
|
2
|
-
import { B, E, N, R, U, m } from "./analytics-
|
|
1
|
+
import { S as Storage, l as logger, A as Aegis } from "./analytics-0p0p56H0.mjs";
|
|
2
|
+
import { B, E, N, R, U, m } from "./analytics-0p0p56H0.mjs";
|
|
3
3
|
import { AegisWebPush } from "./push/AegisWebPush.js";
|
|
4
4
|
function debounce(func, wait) {
|
|
5
5
|
let timeoutId = null;
|
|
@@ -25,9 +25,700 @@ function throttle(func, limit) {
|
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
const ICONS = {
|
|
29
|
+
x: [
|
|
30
|
+
["path", { d: "M18 6 6 18" }],
|
|
31
|
+
["path", { d: "m6 6 12 12" }]
|
|
32
|
+
],
|
|
33
|
+
check: [["path", { d: "M20 6 9 17l-5-5" }]],
|
|
34
|
+
info: [
|
|
35
|
+
["circle", { cx: "12", cy: "12", r: "10" }],
|
|
36
|
+
["path", { d: "M12 16v-4" }],
|
|
37
|
+
["path", { d: "M12 8h.01" }]
|
|
38
|
+
],
|
|
39
|
+
"triangle-alert": [
|
|
40
|
+
["path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }],
|
|
41
|
+
["path", { d: "M12 9v4" }],
|
|
42
|
+
["path", { d: "M12 17h.01" }]
|
|
43
|
+
],
|
|
44
|
+
"volume-2": [
|
|
45
|
+
[
|
|
46
|
+
"path",
|
|
47
|
+
{
|
|
48
|
+
d: "M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
["path", { d: "M16 9a5 5 0 0 1 0 6" }],
|
|
52
|
+
["path", { d: "M19.364 18.364a9 9 0 0 0 0-12.728" }]
|
|
53
|
+
],
|
|
54
|
+
"volume-x": [
|
|
55
|
+
[
|
|
56
|
+
"path",
|
|
57
|
+
{
|
|
58
|
+
d: "M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
["line", { x1: "22", x2: "16", y1: "9", y2: "15" }],
|
|
62
|
+
["line", { x1: "16", x2: "22", y1: "9", y2: "15" }]
|
|
63
|
+
],
|
|
64
|
+
clock: [
|
|
65
|
+
["circle", { cx: "12", cy: "12", r: "10" }],
|
|
66
|
+
["polyline", { points: "12 6 12 12 16 14" }]
|
|
67
|
+
],
|
|
68
|
+
play: [["polygon", { points: "6 3 20 12 6 21 6 3" }]],
|
|
69
|
+
pause: [
|
|
70
|
+
["rect", { x: "14", y: "4", width: "4", height: "16", rx: "1" }],
|
|
71
|
+
["rect", { x: "6", y: "4", width: "4", height: "16", rx: "1" }]
|
|
72
|
+
],
|
|
73
|
+
square: [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }]],
|
|
74
|
+
"square-check": [
|
|
75
|
+
["path", { d: "M21 10.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h12.5" }],
|
|
76
|
+
["path", { d: "m9 11 3 3L22 4" }]
|
|
77
|
+
],
|
|
78
|
+
truck: [
|
|
79
|
+
["path", { d: "M14 18V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v11a1 1 0 0 0 1 1h2" }],
|
|
80
|
+
["path", { d: "M15 18H9" }],
|
|
81
|
+
[
|
|
82
|
+
"path",
|
|
83
|
+
{
|
|
84
|
+
d: "M19 18h2a1 1 0 0 0 1-1v-3.65a1 1 0 0 0-.22-.624l-3.48-4.35A1 1 0 0 0 17.52 8H14"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
["circle", { cx: "17", cy: "18", r: "2" }],
|
|
88
|
+
["circle", { cx: "7", cy: "18", r: "2" }]
|
|
89
|
+
],
|
|
90
|
+
"circle-check": [
|
|
91
|
+
["circle", { cx: "12", cy: "12", r: "10" }],
|
|
92
|
+
["path", { d: "m9 12 2 2 4-4" }]
|
|
93
|
+
],
|
|
94
|
+
// ── Commerce / value-bar set (rich card editor picker) ───────────────────
|
|
95
|
+
"shopping-cart": [
|
|
96
|
+
["circle", { cx: "8", cy: "21", r: "1" }],
|
|
97
|
+
["circle", { cx: "19", cy: "21", r: "1" }],
|
|
98
|
+
["path", { d: "M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12" }]
|
|
99
|
+
],
|
|
100
|
+
"shopping-bag": [
|
|
101
|
+
["path", { d: "M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z" }],
|
|
102
|
+
["path", { d: "M3 6h18" }],
|
|
103
|
+
["path", { d: "M16 10a4 4 0 0 1-8 0" }]
|
|
104
|
+
],
|
|
105
|
+
gift: [
|
|
106
|
+
["rect", { x: "3", y: "8", width: "18", height: "4", rx: "1" }],
|
|
107
|
+
["path", { d: "M12 8v13" }],
|
|
108
|
+
["path", { d: "M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7" }],
|
|
109
|
+
["path", { d: "M7.5 8a2.5 2.5 0 0 1 0-5A4.8 8 0 0 1 12 8a4.8 8 0 0 1 4.5-5 2.5 2.5 0 0 1 0 5" }]
|
|
110
|
+
],
|
|
111
|
+
tag: [
|
|
112
|
+
["path", { d: "M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z" }],
|
|
113
|
+
["circle", { cx: "7.5", cy: "7.5", r: ".5", fill: "currentColor" }]
|
|
114
|
+
],
|
|
115
|
+
percent: [
|
|
116
|
+
["line", { x1: "19", x2: "5", y1: "5", y2: "19" }],
|
|
117
|
+
["circle", { cx: "6.5", cy: "6.5", r: "2.5" }],
|
|
118
|
+
["circle", { cx: "17.5", cy: "17.5", r: "2.5" }]
|
|
119
|
+
],
|
|
120
|
+
star: [
|
|
121
|
+
["path", { d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" }]
|
|
122
|
+
],
|
|
123
|
+
sparkles: [
|
|
124
|
+
["path", { d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" }],
|
|
125
|
+
["path", { d: "M20 3v4" }],
|
|
126
|
+
["path", { d: "M22 5h-4" }]
|
|
127
|
+
],
|
|
128
|
+
zap: [
|
|
129
|
+
["path", { d: "M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z" }]
|
|
130
|
+
],
|
|
131
|
+
heart: [
|
|
132
|
+
["path", { d: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" }]
|
|
133
|
+
],
|
|
134
|
+
bell: [
|
|
135
|
+
["path", { d: "M10.268 21a2 2 0 0 0 3.464 0" }],
|
|
136
|
+
["path", { d: "M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326" }]
|
|
137
|
+
],
|
|
138
|
+
lock: [
|
|
139
|
+
["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2" }],
|
|
140
|
+
["path", { d: "M7 11V7a5 5 0 0 1 10 0v4" }]
|
|
141
|
+
],
|
|
142
|
+
"badge-check": [
|
|
143
|
+
["path", { d: "M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" }],
|
|
144
|
+
["path", { d: "m9 12 2 2 4-4" }]
|
|
145
|
+
],
|
|
146
|
+
package: [
|
|
147
|
+
["path", { d: "M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" }],
|
|
148
|
+
["path", { d: "M12 22V12" }],
|
|
149
|
+
["path", { d: "m3.3 7 8.7 5 8.7-5" }],
|
|
150
|
+
["path", { d: "m7.5 4.27 9 5.15" }]
|
|
151
|
+
],
|
|
152
|
+
flame: [
|
|
153
|
+
["path", { d: "M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z" }]
|
|
154
|
+
],
|
|
155
|
+
crown: [
|
|
156
|
+
["path", { d: "M11.562 3.266a.5.5 0 0 1 .876 0L15.39 8.87a1 1 0 0 0 1.516.294L21.183 5.5a.5.5 0 0 1 .798.519l-2.834 10.246a1 1 0 0 1-.956.734H5.81a1 1 0 0 1-.957-.734L2.02 6.02a.5.5 0 0 1 .798-.519l4.276 3.664a1 1 0 0 0 1.516-.294z" }],
|
|
157
|
+
["path", { d: "M5 21h14" }]
|
|
158
|
+
],
|
|
159
|
+
ticket: [
|
|
160
|
+
["path", { d: "M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z" }],
|
|
161
|
+
["path", { d: "M13 5v2" }],
|
|
162
|
+
["path", { d: "M13 17v2" }],
|
|
163
|
+
["path", { d: "M13 11v2" }]
|
|
164
|
+
],
|
|
165
|
+
wallet: [
|
|
166
|
+
["path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }],
|
|
167
|
+
["path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" }]
|
|
168
|
+
],
|
|
169
|
+
coins: [
|
|
170
|
+
["circle", { cx: "8", cy: "8", r: "6" }],
|
|
171
|
+
["path", { d: "M18.09 10.37A6 6 0 1 1 10.34 18" }],
|
|
172
|
+
["path", { d: "M7 6h1v4" }],
|
|
173
|
+
["path", { d: "m16.71 13.88.7.71-2.82 2.82" }]
|
|
174
|
+
],
|
|
175
|
+
trophy: [
|
|
176
|
+
["path", { d: "M6 9H4.5a2.5 2.5 0 0 1 0-5H6" }],
|
|
177
|
+
["path", { d: "M18 9h1.5a2.5 2.5 0 0 0 0-5H18" }],
|
|
178
|
+
["path", { d: "M4 22h16" }],
|
|
179
|
+
["path", { d: "M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22" }],
|
|
180
|
+
["path", { d: "M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22" }],
|
|
181
|
+
["path", { d: "M18 2H6v7a6 6 0 0 0 12 0V2Z" }]
|
|
182
|
+
],
|
|
183
|
+
timer: [
|
|
184
|
+
["line", { x1: "10", x2: "14", y1: "2", y2: "2" }],
|
|
185
|
+
["line", { x1: "12", x2: "15", y1: "14", y2: "11" }],
|
|
186
|
+
["circle", { cx: "12", cy: "14", r: "8" }]
|
|
187
|
+
],
|
|
188
|
+
"map-pin": [
|
|
189
|
+
["path", { d: "M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0" }],
|
|
190
|
+
["circle", { cx: "12", cy: "10", r: "3" }]
|
|
191
|
+
],
|
|
192
|
+
user: [
|
|
193
|
+
["path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }],
|
|
194
|
+
["circle", { cx: "12", cy: "7", r: "4" }]
|
|
195
|
+
],
|
|
196
|
+
"thumbs-up": [
|
|
197
|
+
["path", { d: "M7 10v12" }],
|
|
198
|
+
["path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z" }]
|
|
199
|
+
],
|
|
200
|
+
"arrow-right": [
|
|
201
|
+
["path", { d: "M5 12h14" }],
|
|
202
|
+
["path", { d: "m12 5 7 7-7 7" }]
|
|
203
|
+
],
|
|
204
|
+
"chevron-right": [["path", { d: "m9 18 6-6-6-6" }]],
|
|
205
|
+
plus: [
|
|
206
|
+
["path", { d: "M5 12h14" }],
|
|
207
|
+
["path", { d: "M12 5v14" }]
|
|
208
|
+
],
|
|
209
|
+
store: [
|
|
210
|
+
["path", { d: "m2 7 4.41-4.41A2 2 0 0 1 7.83 2h8.34a2 2 0 0 1 1.42.59L22 7" }],
|
|
211
|
+
["path", { d: "M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" }],
|
|
212
|
+
["path", { d: "M15 22v-4a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2v4" }],
|
|
213
|
+
["path", { d: "M2 7h20" }],
|
|
214
|
+
["path", { d: "M22 7v3a2 2 0 0 1-2 2a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 16 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 12 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 8 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 4 12a2 2 0 0 1-2-2V7" }]
|
|
215
|
+
],
|
|
216
|
+
rocket: [
|
|
217
|
+
["path", { d: "M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z" }],
|
|
218
|
+
["path", { d: "m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z" }],
|
|
219
|
+
["path", { d: "M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0" }],
|
|
220
|
+
["path", { d: "M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5" }]
|
|
221
|
+
]
|
|
222
|
+
};
|
|
223
|
+
function escapeAttr(value) {
|
|
224
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
225
|
+
}
|
|
226
|
+
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
227
|
+
function lucideSvgEl(name, opts = {}) {
|
|
228
|
+
const node = ICONS[name];
|
|
229
|
+
if (!node || typeof document === "undefined") return null;
|
|
230
|
+
const size = opts.size ?? 24;
|
|
231
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
232
|
+
svg.setAttribute("width", String(size));
|
|
233
|
+
svg.setAttribute("height", String(size));
|
|
234
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
235
|
+
svg.setAttribute("fill", "none");
|
|
236
|
+
svg.setAttribute("stroke", opts.color ?? "currentColor");
|
|
237
|
+
svg.setAttribute("stroke-width", String(opts.strokeWidth ?? 2));
|
|
238
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
239
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
240
|
+
if (opts.className) svg.setAttribute("class", opts.className);
|
|
241
|
+
if (opts.ariaLabel) {
|
|
242
|
+
svg.setAttribute("role", "img");
|
|
243
|
+
svg.setAttribute("aria-label", opts.ariaLabel);
|
|
244
|
+
} else {
|
|
245
|
+
svg.setAttribute("aria-hidden", "true");
|
|
246
|
+
}
|
|
247
|
+
for (const [tag, attrs] of node) {
|
|
248
|
+
const child = document.createElementNS(SVG_NS, tag);
|
|
249
|
+
for (const [k, v] of Object.entries(attrs)) child.setAttribute(k, String(v));
|
|
250
|
+
svg.appendChild(child);
|
|
251
|
+
}
|
|
252
|
+
return svg;
|
|
253
|
+
}
|
|
254
|
+
function lucideSvg(name, opts = {}) {
|
|
255
|
+
const node = ICONS[name];
|
|
256
|
+
if (!node) return "";
|
|
257
|
+
const size = opts.size ?? 24;
|
|
258
|
+
const color = opts.color ?? "currentColor";
|
|
259
|
+
const strokeWidth = opts.strokeWidth ?? 2;
|
|
260
|
+
const a11y = opts.ariaLabel ? `role="img" aria-label="${escapeAttr(opts.ariaLabel)}"` : 'aria-hidden="true"';
|
|
261
|
+
const cls = opts.className ? ` class="${escapeAttr(opts.className)}"` : "";
|
|
262
|
+
const children = node.map(([tag, attrs]) => {
|
|
263
|
+
const attrStr = Object.entries(attrs).map(([k, v]) => `${k}="${escapeAttr(String(v))}"`).join(" ");
|
|
264
|
+
return `<${tag} ${attrStr}/>`;
|
|
265
|
+
}).join("");
|
|
266
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="${escapeAttr(color)}" stroke-width="${strokeWidth}" stroke-linecap="round" stroke-linejoin="round"${cls} ${a11y}>${children}</svg>`;
|
|
267
|
+
}
|
|
268
|
+
const WEIGHT = {
|
|
269
|
+
regular: "400",
|
|
270
|
+
medium: "500",
|
|
271
|
+
semibold: "600",
|
|
272
|
+
bold: "700"
|
|
273
|
+
};
|
|
274
|
+
const ICON_PX = { sm: 22, md: 30, lg: 40 };
|
|
275
|
+
const TEXT_PX = { sm: 11.5, md: 13, lg: 15 };
|
|
276
|
+
function interpolateTokens(s, ctx) {
|
|
277
|
+
if (!s || s.indexOf("{") === -1) return s;
|
|
278
|
+
const props = ctx.properties && ctx.properties() || {};
|
|
279
|
+
const cart = ctx.getCartState && ctx.getCartState();
|
|
280
|
+
return s.replace(/\{([a-z0-9_.]+)\}/gi, (_m, key) => {
|
|
281
|
+
let v = props[key];
|
|
282
|
+
if (v == null) {
|
|
283
|
+
if (key === "cart.total") v = cart == null ? void 0 : cart.total;
|
|
284
|
+
else if (key === "cart.count") v = cart == null ? void 0 : cart.itemCount;
|
|
285
|
+
}
|
|
286
|
+
return v == null || v === "" ? "" : String(v);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const ASPECT$2 = { "1/1": "1 / 1", "4/3": "4 / 3", "16/9": "16 / 9" };
|
|
290
|
+
const DEFAULT_CARD_TEMPLATE = {
|
|
291
|
+
id: "clean",
|
|
292
|
+
frame: { bg: "#ffffff", border: "#f1f1f3", radius: 14 },
|
|
293
|
+
elements: [
|
|
294
|
+
{ type: "image", aspect: "1/1", radius: 10 },
|
|
295
|
+
{ type: "price", variant: "pill", color: "#059669" },
|
|
296
|
+
{ type: "title", lines: 2 },
|
|
297
|
+
{ type: "rating" },
|
|
298
|
+
// Zepto/Blinkit-style ADD: a single OUTLINED pill (white fill, brand
|
|
299
|
+
// border + brand text) overlaid on the bottom-right of the product image —
|
|
300
|
+
// NOT a solid filled bar. `overlay:true` anchors it onto the image; the
|
|
301
|
+
// outline variant paints the white/border look. The rail's tile-body click
|
|
302
|
+
// still opens the product, so this one CTA owns add-to-cart.
|
|
303
|
+
{ type: "cta", variant: "outline", overlay: true }
|
|
304
|
+
]
|
|
305
|
+
};
|
|
306
|
+
function asLook(v) {
|
|
307
|
+
return v && typeof v === "object" ? v : {};
|
|
308
|
+
}
|
|
309
|
+
function templateFromCardStyle(look) {
|
|
310
|
+
const elements = [{ type: "image", aspect: "1/1", radius: 10 }];
|
|
311
|
+
if (look.badge) elements.push({ type: "badge", text: look.badge, color: look.badge_color });
|
|
312
|
+
if (!look.hide_price) elements.push({ type: "price", variant: "pill", color: "#059669" });
|
|
313
|
+
elements.push({ type: "title", lines: 2 });
|
|
314
|
+
if (!look.hide_rating) elements.push({ type: "rating" });
|
|
315
|
+
if (!look.hide_cta) elements.push({ type: "cta", variant: "fill", text: look.cta_text });
|
|
316
|
+
return {
|
|
317
|
+
id: "legacy",
|
|
318
|
+
frame: {
|
|
319
|
+
bg: look.background,
|
|
320
|
+
border: look.border_color,
|
|
321
|
+
radius: look.radius,
|
|
322
|
+
accent: look.accent ?? null
|
|
323
|
+
},
|
|
324
|
+
elements
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function resolveGlobalTemplate(ic) {
|
|
328
|
+
const t = ic.card_template;
|
|
329
|
+
if (t && typeof t === "object" && Array.isArray(t.elements)) {
|
|
330
|
+
return t;
|
|
331
|
+
}
|
|
332
|
+
const legacy = ic.card_style;
|
|
333
|
+
if (legacy && typeof legacy === "object") {
|
|
334
|
+
return templateFromCardStyle(asLook(legacy));
|
|
335
|
+
}
|
|
336
|
+
return DEFAULT_CARD_TEMPLATE;
|
|
337
|
+
}
|
|
338
|
+
function applyPerCardOverride(tpl, look) {
|
|
339
|
+
if (!look || Object.keys(look).length === 0) return tpl;
|
|
340
|
+
const frame = { ...tpl.frame || {} };
|
|
341
|
+
if (look.accent) frame.accent = look.accent;
|
|
342
|
+
if (look.radius !== void 0) frame.radius = look.radius;
|
|
343
|
+
let elements = (tpl.elements || []).slice();
|
|
344
|
+
const drop = (type) => elements = elements.filter((e) => e.type !== type);
|
|
345
|
+
if (look.hide_price) drop("price");
|
|
346
|
+
if (look.hide_cta) drop("cta");
|
|
347
|
+
if (look.hide_rating) drop("rating");
|
|
348
|
+
if (look.cta_text) elements = elements.map((e) => e.type === "cta" ? { ...e, text: look.cta_text } : e);
|
|
349
|
+
if (look.badge) {
|
|
350
|
+
const badgeEl = { type: "badge", text: look.badge, color: look.badge_color };
|
|
351
|
+
elements = elements.some((e) => e.type === "badge") ? elements.map((e) => e.type === "badge" ? badgeEl : e) : [elements[0], badgeEl, ...elements.slice(1)].filter(Boolean);
|
|
352
|
+
}
|
|
353
|
+
return { ...tpl, frame, elements };
|
|
354
|
+
}
|
|
355
|
+
function priceText(card) {
|
|
356
|
+
const meta = card.metadata || {};
|
|
357
|
+
const p = meta.price;
|
|
358
|
+
if (p !== void 0 && p !== null) return String(p);
|
|
359
|
+
if (card.body && /\d/.test(card.body)) return card.body;
|
|
360
|
+
return void 0;
|
|
361
|
+
}
|
|
362
|
+
function paintPrice(card, el, accent, ctx) {
|
|
363
|
+
const price = priceText(card);
|
|
364
|
+
if (price === void 0) return null;
|
|
365
|
+
const meta = card.metadata || {};
|
|
366
|
+
const compareAt = meta.compare_at_price ?? meta.compare_at ?? meta.original_price;
|
|
367
|
+
const row = document.createElement("div");
|
|
368
|
+
row.style.cssText = "display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;";
|
|
369
|
+
const p = document.createElement("span");
|
|
370
|
+
p.textContent = price;
|
|
371
|
+
if (el.variant === "plain") {
|
|
372
|
+
p.style.cssText = `color:${accent};font-weight:700;font-size:13px;`;
|
|
373
|
+
} else {
|
|
374
|
+
const pillBg = el.color ? ctx.sanitizeColor(el.color) : "#059669";
|
|
375
|
+
p.style.cssText = `background:${pillBg};color:#fff;font-weight:800;font-size:12px;padding:2px 7px;border-radius:6px;`;
|
|
376
|
+
}
|
|
377
|
+
row.appendChild(p);
|
|
378
|
+
const pNum = parseFloat(price.replace(/[^0-9.]/g, ""));
|
|
379
|
+
const cNum = compareAt !== void 0 ? parseFloat(String(compareAt).replace(/[^0-9.]/g, "")) : NaN;
|
|
380
|
+
if (isFinite(cNum) && isFinite(pNum) && cNum > pNum) {
|
|
381
|
+
const orig = document.createElement("span");
|
|
382
|
+
orig.textContent = String(compareAt);
|
|
383
|
+
orig.style.cssText = "text-decoration:line-through;opacity:0.5;font-size:11px;";
|
|
384
|
+
row.appendChild(orig);
|
|
385
|
+
const off = document.createElement("span");
|
|
386
|
+
off.textContent = `-${Math.round((1 - pNum / cNum) * 100)}%`;
|
|
387
|
+
off.style.cssText = "background:#ef444422;color:#ef4444;font-weight:700;font-size:10px;padding:1px 5px;border-radius:999px;";
|
|
388
|
+
row.appendChild(off);
|
|
389
|
+
}
|
|
390
|
+
return row;
|
|
391
|
+
}
|
|
392
|
+
function paintRating(card) {
|
|
393
|
+
const meta = card.metadata || {};
|
|
394
|
+
const avg = Number(meta.avg_rating ?? 0);
|
|
395
|
+
if (!(avg > 0)) return null;
|
|
396
|
+
const count = Number(meta.review_count ?? 0);
|
|
397
|
+
const rr = document.createElement("div");
|
|
398
|
+
rr.style.cssText = "display:flex;align-items:center;gap:3px;font-size:11px;line-height:1;";
|
|
399
|
+
const star = document.createElement("span");
|
|
400
|
+
star.textContent = "★";
|
|
401
|
+
star.style.cssText = "color:#059669;";
|
|
402
|
+
const val = document.createElement("span");
|
|
403
|
+
val.textContent = avg.toFixed(1);
|
|
404
|
+
val.style.cssText = "color:#059669;font-weight:700;";
|
|
405
|
+
rr.appendChild(star);
|
|
406
|
+
rr.appendChild(val);
|
|
407
|
+
if (count > 0) {
|
|
408
|
+
const c = document.createElement("span");
|
|
409
|
+
c.textContent = `(${count})`;
|
|
410
|
+
c.style.cssText = "color:#94a3b8;";
|
|
411
|
+
rr.appendChild(c);
|
|
412
|
+
}
|
|
413
|
+
return rr;
|
|
414
|
+
}
|
|
415
|
+
function contrastFg(bg) {
|
|
416
|
+
const raw = bg.replace("#", "");
|
|
417
|
+
if (raw.length < 3) return "#1f2937";
|
|
418
|
+
const h = raw.length === 3 ? raw.split("").map((c) => c + c).join("") : raw.slice(0, 6);
|
|
419
|
+
const r = parseInt(h.slice(0, 2), 16);
|
|
420
|
+
const g = parseInt(h.slice(2, 4), 16);
|
|
421
|
+
const b = parseInt(h.slice(4, 6), 16);
|
|
422
|
+
if ([r, g, b].some((n) => Number.isNaN(n))) return "#1f2937";
|
|
423
|
+
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
424
|
+
return lum < 0.5 ? "#ffffff" : "#1f2937";
|
|
425
|
+
}
|
|
426
|
+
function buildProgressElement(el, ctx, accent, muted) {
|
|
427
|
+
const { trackEvent, campaign, sanitizeColor } = ctx;
|
|
428
|
+
const goal = el.goal_type || "cart_total";
|
|
429
|
+
const moneyGoal = goal === "cart_total";
|
|
430
|
+
const fill = el.fill ? sanitizeColor(el.fill) : accent;
|
|
431
|
+
const props = () => ctx.properties && ctx.properties() || {};
|
|
432
|
+
const sym = () => {
|
|
433
|
+
var _a;
|
|
434
|
+
if (el.currency_symbol) return el.currency_symbol;
|
|
435
|
+
const code = ctx.getCartState && ((_a = ctx.getCartState()) == null ? void 0 : _a.currency);
|
|
436
|
+
const M = { INR: "₹", USD: "$", EUR: "€", GBP: "£" };
|
|
437
|
+
return code && M[code] || "";
|
|
438
|
+
};
|
|
439
|
+
const threshold = () => {
|
|
440
|
+
if (typeof el.threshold === "number" && el.threshold > 0) return el.threshold;
|
|
441
|
+
if (el.threshold_source === "free_delivery_setting") {
|
|
442
|
+
const v = Number(props()["cart.free_delivery_above"]);
|
|
443
|
+
if (v > 0) return v;
|
|
444
|
+
}
|
|
445
|
+
return 0;
|
|
446
|
+
};
|
|
447
|
+
const readCur = () => {
|
|
448
|
+
const cart = ctx.getCartState && ctx.getCartState();
|
|
449
|
+
if (goal === "items_in_cart") return Number(cart == null ? void 0 : cart.itemCount) || 0;
|
|
450
|
+
if (goal === "cart_total") return Number(cart == null ? void 0 : cart.total) || 0;
|
|
451
|
+
const p = props();
|
|
452
|
+
if (goal === "loyalty_points") return Number(p["loyalty.points"]) || 0;
|
|
453
|
+
if (goal === "referrals") return Number(p["referrals.count"]) || 0;
|
|
454
|
+
return 0;
|
|
455
|
+
};
|
|
456
|
+
const wrap = document.createElement("div");
|
|
457
|
+
wrap.style.cssText = "display:flex;flex-direction:column;gap:3px;min-width:0;width:100%;";
|
|
458
|
+
const sub = document.createElement("div");
|
|
459
|
+
sub.style.cssText = `font-size:11.5px;line-height:1.2;color:${muted};white-space:nowrap;overflow:hidden;text-overflow:ellipsis;`;
|
|
460
|
+
const shell = document.createElement("div");
|
|
461
|
+
shell.style.cssText = `height:3px;border-radius:999px;background:color-mix(in srgb, ${fill} 16%, transparent);overflow:hidden;`;
|
|
462
|
+
const bar = document.createElement("div");
|
|
463
|
+
bar.style.cssText = `height:100%;border-radius:999px;background:${fill};width:0%;transition:width .4s cubic-bezier(.4,0,.2,1);`;
|
|
464
|
+
shell.appendChild(bar);
|
|
465
|
+
wrap.appendChild(sub);
|
|
466
|
+
wrap.appendChild(shell);
|
|
467
|
+
let firedUnlock = false;
|
|
468
|
+
const update = () => {
|
|
469
|
+
const th = threshold();
|
|
470
|
+
const cur = readCur();
|
|
471
|
+
const pct = th > 0 ? Math.max(0, Math.min(100, cur / th * 100)) : 0;
|
|
472
|
+
bar.style.width = `${pct}%`;
|
|
473
|
+
if (th > 0 && pct >= 100) {
|
|
474
|
+
sub.textContent = el.reward_text || "Unlocked!";
|
|
475
|
+
sub.style.color = "#34d399";
|
|
476
|
+
if (!firedUnlock) {
|
|
477
|
+
firedUnlock = true;
|
|
478
|
+
trackEvent(campaign.id, "clicked", { stepId: el.id || "unlocked" });
|
|
479
|
+
}
|
|
480
|
+
} else {
|
|
481
|
+
sub.style.color = muted;
|
|
482
|
+
const remaining = Math.max(0, th - cur);
|
|
483
|
+
const pre = moneyGoal ? sym() : "";
|
|
484
|
+
const pctStr = el.show_pct && th > 0 ? ` · ${Math.round(pct)}%` : "";
|
|
485
|
+
sub.textContent = th > 0 ? `Shop for ${pre}${remaining.toFixed(0)} more${pctStr}` : el.reward_text || "";
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
update();
|
|
489
|
+
const timer = setInterval(update, 1e3);
|
|
490
|
+
if (typeof window !== "undefined") {
|
|
491
|
+
window.addEventListener("beforeunload", () => clearInterval(timer), { once: true });
|
|
492
|
+
}
|
|
493
|
+
return wrap;
|
|
494
|
+
}
|
|
495
|
+
function renderCardFromTemplate(card, opts) {
|
|
496
|
+
const { ctx, action, layout, layoutAccent } = opts;
|
|
497
|
+
const inline = action === "cart";
|
|
498
|
+
const { campaign, trackEvent, sanitizeUrl, sanitizeColor } = ctx;
|
|
499
|
+
const tpl = applyPerCardOverride(opts.template, asLook(card.style));
|
|
500
|
+
const frame = tpl.frame || {};
|
|
501
|
+
const meta = card.metadata || {};
|
|
502
|
+
const accent = typeof frame.accent === "string" && frame.accent ? sanitizeColor(frame.accent) : layoutAccent;
|
|
503
|
+
const brand = `var(--aegis-brand-accent, ${accent})`;
|
|
504
|
+
const fg = contrastFg(frame.bg ? sanitizeColor(frame.bg) : "#ffffff");
|
|
505
|
+
const muted = fg === "#ffffff" ? "rgba(255,255,255,0.72)" : "#6b7280";
|
|
506
|
+
const tile = document.createElement("div");
|
|
507
|
+
const radius = frame.radius !== void 0 ? `${parseInt(String(frame.radius), 10) || 12}px` : "12px";
|
|
508
|
+
const fLayout = frame.layout;
|
|
509
|
+
const dir = fLayout === "row" ? "row" : "column";
|
|
510
|
+
const tileGap = frame.gap != null ? frame.gap : 6;
|
|
511
|
+
const sizing = fLayout ? frame.width != null ? `width:${typeof frame.width === "number" ? `${frame.width}px` : frame.width};` : "flex:1 1 auto; width:100%;" : layout === "grid" ? "" : "flex:0 0 150px; scroll-snap-align:start;";
|
|
512
|
+
tile.style.cssText = `
|
|
513
|
+
box-sizing:border-box; display:flex; flex-direction:${dir}; ${fLayout === "row" ? "align-items:center;" : ""} gap:${tileGap}px; position:relative;
|
|
514
|
+
color:${fg};
|
|
515
|
+
background:${frame.bg ? sanitizeColor(frame.bg) : "#ffffff"};
|
|
516
|
+
border:1px solid ${frame.border ? sanitizeColor(frame.border) : "transparent"};
|
|
517
|
+
border-radius:${radius}; padding:8px;
|
|
518
|
+
${frame.max_width ? `max-width:${frame.max_width}px;` : ""}${frame.min_width ? `min-width:${frame.min_width}px;` : ""}
|
|
519
|
+
${sizing}
|
|
520
|
+
cursor:${card.cta_url || inline ? "pointer" : "default"}; transition:transform 0.15s ease;
|
|
521
|
+
`;
|
|
522
|
+
const elements = tpl.elements && tpl.elements.length ? tpl.elements : DEFAULT_CARD_TEMPLATE.elements;
|
|
523
|
+
let imageWrap = null;
|
|
524
|
+
const paintInto = (container, els) => {
|
|
525
|
+
for (const el of els) {
|
|
526
|
+
switch (el.type) {
|
|
527
|
+
case "image": {
|
|
528
|
+
const wrap = document.createElement("div");
|
|
529
|
+
wrap.style.cssText = `position:relative;width:100%;aspect-ratio:${ASPECT$2[el.aspect || "1/1"] || "1 / 1"};border-radius:${el.radius ?? 10}px;overflow:hidden;background:#f7f8fa;`;
|
|
530
|
+
const safeVideo = card.video_url ? sanitizeUrl(card.video_url) : "";
|
|
531
|
+
if (safeVideo) {
|
|
532
|
+
const v = document.createElement("video");
|
|
533
|
+
v.src = safeVideo;
|
|
534
|
+
v.muted = true;
|
|
535
|
+
v.loop = true;
|
|
536
|
+
v.autoplay = true;
|
|
537
|
+
v.playsInline = true;
|
|
538
|
+
v.setAttribute("playsinline", "");
|
|
539
|
+
v.style.cssText = "width:100%;height:100%;object-fit:cover;display:block;";
|
|
540
|
+
wrap.appendChild(v);
|
|
541
|
+
} else if (card.image_url) {
|
|
542
|
+
const safe = sanitizeUrl(card.image_url);
|
|
543
|
+
if (safe) {
|
|
544
|
+
const img = document.createElement("img");
|
|
545
|
+
img.src = safe;
|
|
546
|
+
img.alt = "";
|
|
547
|
+
img.loading = "lazy";
|
|
548
|
+
img.style.cssText = "width:100%;height:100%;object-fit:cover;display:block;";
|
|
549
|
+
wrap.appendChild(img);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
imageWrap = wrap;
|
|
553
|
+
container.appendChild(wrap);
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case "badge": {
|
|
557
|
+
const text = el.text;
|
|
558
|
+
if (!text) break;
|
|
559
|
+
const badge = document.createElement("span");
|
|
560
|
+
badge.textContent = text;
|
|
561
|
+
const bg = el.color ? sanitizeColor(el.color) : brand;
|
|
562
|
+
badge.style.cssText = `position:absolute;top:6px;left:6px;z-index:1;background:${bg};color:#fff;font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:0.03em;padding:3px 6px;border-radius:5px;`;
|
|
563
|
+
(imageWrap || container).appendChild(badge);
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
case "price": {
|
|
567
|
+
const node = paintPrice(card, el, accent, ctx);
|
|
568
|
+
if (node) container.appendChild(node);
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
case "title": {
|
|
572
|
+
if (!card.title) break;
|
|
573
|
+
const t = document.createElement("div");
|
|
574
|
+
t.textContent = card.title;
|
|
575
|
+
const lines = el.lines && el.lines > 0 ? el.lines : 2;
|
|
576
|
+
t.style.cssText = `font-size:12.5px;font-weight:600;line-height:1.3;text-align:${el.align ?? "left"};color:${el.color ? sanitizeColor(el.color) : fg};display:-webkit-box;-webkit-line-clamp:${lines};-webkit-box-orient:vertical;overflow:hidden;`;
|
|
577
|
+
container.appendChild(t);
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
case "subtitle": {
|
|
581
|
+
if (!card.body) break;
|
|
582
|
+
const s = document.createElement("div");
|
|
583
|
+
s.textContent = card.body;
|
|
584
|
+
const lines = el.lines && el.lines > 0 ? el.lines : 2;
|
|
585
|
+
s.style.cssText = `font-size:11px;color:${el.color ? sanitizeColor(el.color) : muted};line-height:1.3;text-align:${el.align ?? "left"};display:-webkit-box;-webkit-line-clamp:${lines};-webkit-box-orient:vertical;overflow:hidden;`;
|
|
586
|
+
container.appendChild(s);
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
case "rating": {
|
|
590
|
+
const node = paintRating(card);
|
|
591
|
+
if (node) container.appendChild(node);
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
case "category": {
|
|
595
|
+
const cat = meta.category;
|
|
596
|
+
if (typeof cat !== "string" || !cat) break;
|
|
597
|
+
const chip = document.createElement("span");
|
|
598
|
+
chip.textContent = cat;
|
|
599
|
+
chip.style.cssText = "align-self:flex-start;background:#f3f4f6;color:#6b7280;font-size:10px;font-weight:500;padding:2px 7px;border-radius:6px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";
|
|
600
|
+
container.appendChild(chip);
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
// ── rich-card-editor elements (P0) ──────────────────────────────────
|
|
604
|
+
case "icon": {
|
|
605
|
+
const px = ICON_PX[el.size || "md"] || 30;
|
|
606
|
+
const node = document.createElement("div");
|
|
607
|
+
const iconColor = el.color ? sanitizeColor(el.color) : fg;
|
|
608
|
+
if (el.bubble) {
|
|
609
|
+
const bubbleTint = el.color ? sanitizeColor(el.color) : brand;
|
|
610
|
+
node.style.cssText = `flex:0 0 auto;width:${px}px;height:${px}px;border-radius:999px;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb, ${bubbleTint} 16%, transparent);`;
|
|
611
|
+
} else {
|
|
612
|
+
node.style.cssText = "flex:0 0 auto;display:flex;align-items:center;";
|
|
613
|
+
}
|
|
614
|
+
const svg = lucideSvgEl(el.icon_name || "circle-check", {
|
|
615
|
+
size: el.bubble ? Math.round(px * 0.55) : Math.round(px * 0.7),
|
|
616
|
+
color: iconColor,
|
|
617
|
+
strokeWidth: 2
|
|
618
|
+
});
|
|
619
|
+
if (svg) node.appendChild(svg);
|
|
620
|
+
container.appendChild(node);
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
case "text": {
|
|
624
|
+
const t = document.createElement("div");
|
|
625
|
+
const fs = TEXT_PX[el.size || "md"] || 13;
|
|
626
|
+
t.style.cssText = `font-size:${fs}px;font-weight:${WEIGHT[el.weight ?? "medium"]};text-align:${el.align ?? "left"};color:${el.color ? sanitizeColor(el.color) : fg};line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;`;
|
|
627
|
+
t.textContent = interpolateTokens(el.content ?? "", ctx);
|
|
628
|
+
container.appendChild(t);
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
case "spacer": {
|
|
632
|
+
const sp = document.createElement("div");
|
|
633
|
+
sp.style.height = `${el.height ?? 8}px`;
|
|
634
|
+
container.appendChild(sp);
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
case "progress": {
|
|
638
|
+
container.appendChild(buildProgressElement(el, ctx, brand, muted));
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
case "group": {
|
|
642
|
+
const g = document.createElement("div");
|
|
643
|
+
const gdir = el.layout === "row" ? "row" : "column";
|
|
644
|
+
g.style.cssText = `display:flex;flex-direction:${gdir};${el.layout === "row" ? "align-items:center;" : ""}gap:${el.gap ?? 4}px;min-width:0;${el.layout === "row" ? "" : "flex:1 1 auto;"}`;
|
|
645
|
+
paintInto(g, el.elements || []);
|
|
646
|
+
container.appendChild(g);
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
case "cta": {
|
|
650
|
+
const label = el.text || card.cta_text || (inline ? "Add" : "Shop");
|
|
651
|
+
const cta = document.createElement("button");
|
|
652
|
+
cta.className = "aegis-cta";
|
|
653
|
+
cta.textContent = label;
|
|
654
|
+
const overlayOnImage = !!el.overlay && !!imageWrap;
|
|
655
|
+
if (overlayOnImage) {
|
|
656
|
+
cta.style.cssText = el.variant === "outline" ? `position:absolute;right:6px;bottom:6px;background:#fff;color:${brand};border:1px solid ${brand};border-radius:9px;padding:5px 18px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:0.04em;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.14);` : `position:absolute;right:6px;bottom:6px;background:${brand};color:#fff;border:none;border-radius:9px;padding:5px 18px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:0.04em;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.14);`;
|
|
657
|
+
} else {
|
|
658
|
+
cta.style.cssText = el.variant === "outline" ? `margin-top:${fLayout === "row" ? "0" : "auto"};background:transparent;color:${brand};border:1px solid ${brand};border-radius:999px;padding:6px 10px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;` : `margin-top:${fLayout === "row" ? "0" : "auto"};background:${brand};color:#fff;border:none;border-radius:999px;padding:7px 10px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;`;
|
|
659
|
+
}
|
|
660
|
+
cta.addEventListener("click", (e) => {
|
|
661
|
+
e.stopPropagation();
|
|
662
|
+
trackEvent(campaign.id, "clicked", { stepId: el.id || "add" });
|
|
663
|
+
if (inline) {
|
|
664
|
+
if (typeof window !== "undefined") {
|
|
665
|
+
window.dispatchEvent(
|
|
666
|
+
new CustomEvent("aegis:add-to-cart", {
|
|
667
|
+
detail: {
|
|
668
|
+
campaign_id: campaign.id,
|
|
669
|
+
product_id: meta.product_id,
|
|
670
|
+
sku: meta.sku,
|
|
671
|
+
title: card.title,
|
|
672
|
+
price: meta.price ?? card.body,
|
|
673
|
+
image_url: card.image_url,
|
|
674
|
+
cta_url: card.cta_url
|
|
675
|
+
}
|
|
676
|
+
})
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
if (card.cta_url) {
|
|
682
|
+
const safe = sanitizeUrl(card.cta_url);
|
|
683
|
+
if (safe) ctx.navigate ? ctx.navigate(safe) : window.location.href = safe;
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
(overlayOnImage ? imageWrap : container).appendChild(cta);
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
paintInto(tile, elements);
|
|
693
|
+
const open = (e) => {
|
|
694
|
+
e.stopPropagation();
|
|
695
|
+
trackEvent(campaign.id, "clicked");
|
|
696
|
+
if (inline) {
|
|
697
|
+
if (typeof window !== "undefined") {
|
|
698
|
+
window.dispatchEvent(
|
|
699
|
+
new CustomEvent("aegis:open-product", {
|
|
700
|
+
detail: {
|
|
701
|
+
campaign_id: campaign.id,
|
|
702
|
+
product_id: meta.product_id,
|
|
703
|
+
sku: meta.sku,
|
|
704
|
+
cta_url: card.cta_url
|
|
705
|
+
}
|
|
706
|
+
})
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
if (card.cta_url) {
|
|
712
|
+
const safe = sanitizeUrl(card.cta_url);
|
|
713
|
+
if (safe) ctx.navigate ? ctx.navigate(safe) : window.location.href = safe;
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
if (inline || card.cta_url) tile.addEventListener("click", open);
|
|
717
|
+
return tile;
|
|
718
|
+
}
|
|
28
719
|
const MAX_CARDS_RENDERED = 10;
|
|
29
720
|
function renderCarouselCards(ctx) {
|
|
30
|
-
const { campaign, trackEvent,
|
|
721
|
+
const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;
|
|
31
722
|
const ic = campaign.interactive_config || {};
|
|
32
723
|
const rawCards = Array.isArray(ic.cards) ? ic.cards : [];
|
|
33
724
|
const cards = rawCards.slice(0, MAX_CARDS_RENDERED);
|
|
@@ -70,7 +761,7 @@ function renderCarouselCards(ctx) {
|
|
|
70
761
|
headerText.appendChild(body);
|
|
71
762
|
header.appendChild(headerText);
|
|
72
763
|
const closeBtn = document.createElement("button");
|
|
73
|
-
closeBtn.
|
|
764
|
+
closeBtn.innerHTML = lucideSvg("x", { size: 16 });
|
|
74
765
|
closeBtn.setAttribute("aria-label", "Close");
|
|
75
766
|
closeBtn.style.cssText = `
|
|
76
767
|
background: transparent; border: none; color: inherit;
|
|
@@ -89,68 +780,16 @@ function renderCarouselCards(ctx) {
|
|
|
89
780
|
padding-bottom: 4px; -webkit-overflow-scrolling: touch;
|
|
90
781
|
`;
|
|
91
782
|
track.style.msOverflowStyle = "none";
|
|
783
|
+
const template = resolveGlobalTemplate(ic);
|
|
92
784
|
cards.forEach((c, i) => {
|
|
93
|
-
const tile =
|
|
785
|
+
const tile = renderCardFromTemplate(c, {
|
|
786
|
+
template,
|
|
787
|
+
ctx,
|
|
788
|
+
action: "navigate",
|
|
789
|
+
layout: "row",
|
|
790
|
+
layoutAccent: accent
|
|
791
|
+
});
|
|
94
792
|
tile.setAttribute("data-card-index", String(i));
|
|
95
|
-
tile.style.cssText = `
|
|
96
|
-
flex: 0 0 auto; width: 140px; scroll-snap-align: start;
|
|
97
|
-
background: ${fg}0a; border-radius: 12px; padding: 10px;
|
|
98
|
-
display: flex; flex-direction: column; gap: 6px;
|
|
99
|
-
cursor: ${c.cta_url ? "pointer" : "default"};
|
|
100
|
-
`;
|
|
101
|
-
const safeVideo = c.video_url ? sanitizeUrl(c.video_url) : "";
|
|
102
|
-
if (safeVideo) {
|
|
103
|
-
const vid = document.createElement("video");
|
|
104
|
-
vid.src = safeVideo;
|
|
105
|
-
vid.muted = true;
|
|
106
|
-
vid.loop = true;
|
|
107
|
-
vid.autoplay = true;
|
|
108
|
-
vid.playsInline = true;
|
|
109
|
-
vid.setAttribute("playsinline", "");
|
|
110
|
-
vid.style.cssText = "width: 100%; height: 96px; border-radius: 8px; object-fit: cover;";
|
|
111
|
-
tile.appendChild(vid);
|
|
112
|
-
} else if (c.image_url) {
|
|
113
|
-
const img = document.createElement("img");
|
|
114
|
-
const safe = sanitizeUrl(c.image_url);
|
|
115
|
-
if (safe) {
|
|
116
|
-
img.src = safe;
|
|
117
|
-
img.alt = "";
|
|
118
|
-
img.loading = "lazy";
|
|
119
|
-
img.style.cssText = "width: 100%; height: 96px; border-radius: 8px; object-fit: cover;";
|
|
120
|
-
tile.appendChild(img);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
if (c.title) {
|
|
124
|
-
const t = document.createElement("div");
|
|
125
|
-
t.textContent = c.title;
|
|
126
|
-
t.style.cssText = "font-weight: 600; font-size: 13px; line-height: 1.3;";
|
|
127
|
-
tile.appendChild(t);
|
|
128
|
-
}
|
|
129
|
-
if (c.body) {
|
|
130
|
-
const b = document.createElement("div");
|
|
131
|
-
b.textContent = c.body;
|
|
132
|
-
b.style.cssText = "font-size: 11.5px; opacity: 0.72; line-height: 1.3;";
|
|
133
|
-
tile.appendChild(b);
|
|
134
|
-
}
|
|
135
|
-
if (c.cta_text && c.cta_url) {
|
|
136
|
-
const cta = document.createElement("button");
|
|
137
|
-
cta.className = "aegis-cta";
|
|
138
|
-
cta.textContent = c.cta_text;
|
|
139
|
-
cta.style.cssText = `
|
|
140
|
-
margin-top: auto; background: ${accent}; color: #fff;
|
|
141
|
-
border: none; padding: 6px 10px; border-radius: 999px;
|
|
142
|
-
font-size: 12px; font-weight: 600; cursor: pointer;
|
|
143
|
-
`;
|
|
144
|
-
const goto2 = (e) => {
|
|
145
|
-
e.stopPropagation();
|
|
146
|
-
trackEvent(campaign.id, "clicked", { stepId: `card_${i}` });
|
|
147
|
-
const safe = sanitizeUrl(c.cta_url);
|
|
148
|
-
if (safe) window.location.href = safe;
|
|
149
|
-
};
|
|
150
|
-
cta.addEventListener("click", goto2);
|
|
151
|
-
tile.appendChild(cta);
|
|
152
|
-
tile.addEventListener("click", goto2);
|
|
153
|
-
}
|
|
154
793
|
track.appendChild(tile);
|
|
155
794
|
});
|
|
156
795
|
card.appendChild(track);
|
|
@@ -314,7 +953,7 @@ function renderStickyBar(ctx) {
|
|
|
314
953
|
};
|
|
315
954
|
if (dismissible) {
|
|
316
955
|
const close = document.createElement("button");
|
|
317
|
-
close.
|
|
956
|
+
close.innerHTML = lucideSvg("x", { size: 16 });
|
|
318
957
|
close.setAttribute("aria-label", "Dismiss");
|
|
319
958
|
close.style.cssText = `
|
|
320
959
|
background: transparent; border: none; color: inherit;
|
|
@@ -344,13 +983,12 @@ function buildProgressBar(ctx, inline) {
|
|
|
344
983
|
const source = ic.progress_source === "sse" ? "sse" : "client";
|
|
345
984
|
addAnimationStyles();
|
|
346
985
|
const brand = sanitizeColor(campaign.background_color || "#4169e1");
|
|
986
|
+
const accentVar = `var(--aegis-brand-accent, ${brand})`;
|
|
347
987
|
const branded = ic.surface_style === "branded";
|
|
348
|
-
const bg = branded ?
|
|
988
|
+
const bg = branded ? accentVar : "#ffffff";
|
|
349
989
|
const fg = sanitizeColor(campaign.text_color || (branded ? "#ffffff" : "#0f172a"));
|
|
350
|
-
const fill = sanitizeColor(
|
|
351
|
-
|
|
352
|
-
);
|
|
353
|
-
const track = branded ? "rgba(255,255,255,0.25)" : `${fill}22`;
|
|
990
|
+
const fill = ic.progress_fill_color ? sanitizeColor(ic.progress_fill_color) : branded ? "#ffffff" : accentVar;
|
|
991
|
+
const track = branded ? "rgba(255,255,255,0.25)" : `color-mix(in srgb, ${fill} 14%, transparent)`;
|
|
354
992
|
const bar = document.createElement("div");
|
|
355
993
|
bar.className = "aegis-in-app-progress-bar";
|
|
356
994
|
bar.setAttribute("data-campaign-id", campaign.id);
|
|
@@ -730,7 +1368,7 @@ function renderCoachmarkTour(ctx) {
|
|
|
730
1368
|
}
|
|
731
1369
|
const MAX_PRODUCTS = 24;
|
|
732
1370
|
function renderProductRecommendation(ctx) {
|
|
733
|
-
const { campaign, trackEvent,
|
|
1371
|
+
const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;
|
|
734
1372
|
const ic = campaign.interactive_config || {};
|
|
735
1373
|
const rawCards = Array.isArray(ic.cards) ? ic.cards : [];
|
|
736
1374
|
const cards = rawCards.slice(0, MAX_PRODUCTS);
|
|
@@ -739,7 +1377,7 @@ function renderProductRecommendation(ctx) {
|
|
|
739
1377
|
return;
|
|
740
1378
|
}
|
|
741
1379
|
const layout = ic.rec_layout || "grid";
|
|
742
|
-
const
|
|
1380
|
+
const template = resolveGlobalTemplate(ic);
|
|
743
1381
|
addAnimationStyles();
|
|
744
1382
|
const bg = "#ffffff";
|
|
745
1383
|
const fg = "#0f172a";
|
|
@@ -782,7 +1420,7 @@ function renderProductRecommendation(ctx) {
|
|
|
782
1420
|
headerText.appendChild(body);
|
|
783
1421
|
header.appendChild(headerText);
|
|
784
1422
|
const close = document.createElement("button");
|
|
785
|
-
close.
|
|
1423
|
+
close.innerHTML = lucideSvg("x", { size: 18 });
|
|
786
1424
|
close.setAttribute("aria-label", "Close");
|
|
787
1425
|
close.style.cssText = `
|
|
788
1426
|
background: transparent; border: none; color: inherit;
|
|
@@ -807,82 +1445,9 @@ function renderProductRecommendation(ctx) {
|
|
|
807
1445
|
`;
|
|
808
1446
|
}
|
|
809
1447
|
cards.forEach((c) => {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
background: ${fg}08; border-radius: 12px;
|
|
814
|
-
padding: 10px; display: flex; flex-direction: column; gap: 6px;
|
|
815
|
-
cursor: ${c.cta_url ? "pointer" : "default"};
|
|
816
|
-
${isRow ? "flex: 0 0 150px; scroll-snap-align: start;" : ""}
|
|
817
|
-
transition: transform 0.15s ease;
|
|
818
|
-
`;
|
|
819
|
-
if (c.image_url) {
|
|
820
|
-
const img = document.createElement("img");
|
|
821
|
-
const safe = sanitizeUrl(c.image_url);
|
|
822
|
-
if (safe) {
|
|
823
|
-
img.src = safe;
|
|
824
|
-
img.alt = "";
|
|
825
|
-
img.loading = "lazy";
|
|
826
|
-
img.style.cssText = "width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: cover;";
|
|
827
|
-
tile.appendChild(img);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
if (c.title) {
|
|
831
|
-
const t = document.createElement("div");
|
|
832
|
-
t.textContent = c.title;
|
|
833
|
-
t.style.cssText = "font-weight: 600; font-size: 13px; line-height: 1.3;";
|
|
834
|
-
tile.appendChild(t);
|
|
835
|
-
}
|
|
836
|
-
const meta = c.metadata && typeof c.metadata === "object" ? c.metadata : {};
|
|
837
|
-
const price = meta.price;
|
|
838
|
-
const compareAt = meta.compare_at_price ?? meta.compare_at ?? meta.original_price;
|
|
839
|
-
if (price !== void 0) {
|
|
840
|
-
const priceRow = document.createElement("div");
|
|
841
|
-
priceRow.style.cssText = "display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;";
|
|
842
|
-
const p = document.createElement("span");
|
|
843
|
-
p.textContent = String(price);
|
|
844
|
-
p.style.cssText = `color: ${accent}; font-weight: 700; font-size: 13px;`;
|
|
845
|
-
priceRow.appendChild(p);
|
|
846
|
-
const pNum = parseFloat(String(price).replace(/[^0-9.]/g, ""));
|
|
847
|
-
const cNum = compareAt !== void 0 ? parseFloat(String(compareAt).replace(/[^0-9.]/g, "")) : NaN;
|
|
848
|
-
if (isFinite(cNum) && isFinite(pNum) && cNum > pNum) {
|
|
849
|
-
const orig = document.createElement("span");
|
|
850
|
-
orig.textContent = String(compareAt);
|
|
851
|
-
orig.style.cssText = "text-decoration: line-through; opacity: 0.5; font-size: 11px;";
|
|
852
|
-
priceRow.appendChild(orig);
|
|
853
|
-
const off = document.createElement("span");
|
|
854
|
-
off.textContent = `-${Math.round((1 - pNum / cNum) * 100)}%`;
|
|
855
|
-
off.style.cssText = "background: #ef444422; color: #ef4444; font-weight: 700; font-size: 10px; padding: 1px 5px; border-radius: 999px;";
|
|
856
|
-
priceRow.appendChild(off);
|
|
857
|
-
}
|
|
858
|
-
tile.appendChild(priceRow);
|
|
859
|
-
} else if (c.body) {
|
|
860
|
-
const b = document.createElement("div");
|
|
861
|
-
b.textContent = c.body;
|
|
862
|
-
b.style.cssText = "font-size: 11.5px; opacity: 0.72; line-height: 1.3;";
|
|
863
|
-
tile.appendChild(b);
|
|
864
|
-
}
|
|
865
|
-
const cta = document.createElement("button");
|
|
866
|
-
cta.className = "aegis-cta";
|
|
867
|
-
cta.textContent = c.cta_text || ctaDefault;
|
|
868
|
-
cta.style.cssText = `
|
|
869
|
-
margin-top: auto;
|
|
870
|
-
background: ${accent}; color: #fff;
|
|
871
|
-
border: none; padding: 7px 10px; border-radius: 999px;
|
|
872
|
-
font-size: 12px; font-weight: 600; cursor: pointer;
|
|
873
|
-
`;
|
|
874
|
-
const go = (e) => {
|
|
875
|
-
e.stopPropagation();
|
|
876
|
-
trackEvent(campaign.id, "clicked");
|
|
877
|
-
if (c.cta_url) {
|
|
878
|
-
const safe = sanitizeUrl(c.cta_url);
|
|
879
|
-
if (safe) window.location.href = safe;
|
|
880
|
-
}
|
|
881
|
-
};
|
|
882
|
-
cta.addEventListener("click", go);
|
|
883
|
-
tile.appendChild(cta);
|
|
884
|
-
if (c.cta_url) tile.addEventListener("click", go);
|
|
885
|
-
grid.appendChild(tile);
|
|
1448
|
+
grid.appendChild(
|
|
1449
|
+
renderCardFromTemplate(c, { template, ctx, action: "navigate", layout, layoutAccent: accent })
|
|
1450
|
+
);
|
|
886
1451
|
});
|
|
887
1452
|
sheet.appendChild(grid);
|
|
888
1453
|
overlay.appendChild(sheet);
|
|
@@ -894,6 +1459,88 @@ function renderProductRecommendation(ctx) {
|
|
|
894
1459
|
});
|
|
895
1460
|
document.body.appendChild(overlay);
|
|
896
1461
|
}
|
|
1462
|
+
function renderProductRecommendationInline(ctx, target) {
|
|
1463
|
+
const { campaign, sanitizeColor, addAnimationStyles, log } = ctx;
|
|
1464
|
+
const ic = campaign.interactive_config || {};
|
|
1465
|
+
const rawCards = Array.isArray(ic.cards) ? ic.cards : [];
|
|
1466
|
+
const cards = rawCards.slice(0, MAX_PRODUCTS);
|
|
1467
|
+
if (cards.length === 0) {
|
|
1468
|
+
log("product_recommendation (inline) rendered with zero products — skipping", "warn");
|
|
1469
|
+
return false;
|
|
1470
|
+
}
|
|
1471
|
+
const layout = ic.rec_layout || "row";
|
|
1472
|
+
const template = resolveGlobalTemplate(ic);
|
|
1473
|
+
const fg = "#0f172a";
|
|
1474
|
+
const accent = sanitizeColor(campaign.background_color || "#4169e1");
|
|
1475
|
+
addAnimationStyles();
|
|
1476
|
+
const section = document.createElement("section");
|
|
1477
|
+
section.className = "aegis-in-app-product-rec-inline";
|
|
1478
|
+
section.setAttribute("data-campaign-id", campaign.id);
|
|
1479
|
+
section.style.cssText = `
|
|
1480
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1481
|
+
color: ${fg};
|
|
1482
|
+
`;
|
|
1483
|
+
if (campaign.title) {
|
|
1484
|
+
const title = document.createElement("h2");
|
|
1485
|
+
title.textContent = campaign.title;
|
|
1486
|
+
title.style.cssText = "font-weight: 700; font-size: 16px; margin: 0 0 2px;";
|
|
1487
|
+
section.appendChild(title);
|
|
1488
|
+
}
|
|
1489
|
+
if (campaign.body) {
|
|
1490
|
+
const body = document.createElement("div");
|
|
1491
|
+
body.textContent = campaign.body;
|
|
1492
|
+
body.style.cssText = "font-size: 13px; opacity: 0.65; line-height: 1.4; margin-bottom: 10px;";
|
|
1493
|
+
section.appendChild(body);
|
|
1494
|
+
}
|
|
1495
|
+
const grid = document.createElement("div");
|
|
1496
|
+
const isRow = layout !== "grid";
|
|
1497
|
+
if (layout === "grid") {
|
|
1498
|
+
grid.style.cssText = "display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;";
|
|
1499
|
+
} else {
|
|
1500
|
+
grid.style.cssText = `
|
|
1501
|
+
display: flex; gap: 10px; overflow-x: auto;
|
|
1502
|
+
scroll-snap-type: x proximity; padding: 0 0 6px;
|
|
1503
|
+
-webkit-overflow-scrolling: touch; scrollbar-width: none;
|
|
1504
|
+
`;
|
|
1505
|
+
grid.style.msOverflowStyle = "none";
|
|
1506
|
+
}
|
|
1507
|
+
cards.forEach((c) => {
|
|
1508
|
+
grid.appendChild(
|
|
1509
|
+
renderCardFromTemplate(c, { template, ctx, action: "cart", layout, layoutAccent: accent })
|
|
1510
|
+
);
|
|
1511
|
+
});
|
|
1512
|
+
if (isRow && cards.length > 2) {
|
|
1513
|
+
const wrap = document.createElement("div");
|
|
1514
|
+
wrap.style.cssText = "position: relative;";
|
|
1515
|
+
wrap.appendChild(grid);
|
|
1516
|
+
const arrow = document.createElement("button");
|
|
1517
|
+
arrow.setAttribute("aria-label", "Scroll for more");
|
|
1518
|
+
arrow.innerHTML = "›";
|
|
1519
|
+
arrow.style.cssText = `
|
|
1520
|
+
position: absolute; top: 50%; right: 0; transform: translateY(-50%);
|
|
1521
|
+
width: 30px; height: 30px; border-radius: 999px; border: 1px solid ${fg}1a;
|
|
1522
|
+
background: #fff; color: ${fg}; font-size: 18px; line-height: 1; cursor: pointer;
|
|
1523
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.12); display: flex; align-items: center;
|
|
1524
|
+
justify-content: center; z-index: 2;
|
|
1525
|
+
`;
|
|
1526
|
+
arrow.addEventListener("click", (e) => {
|
|
1527
|
+
e.stopPropagation();
|
|
1528
|
+
grid.scrollBy({ left: Math.round(grid.clientWidth * 0.8), behavior: "smooth" });
|
|
1529
|
+
});
|
|
1530
|
+
const syncArrow = () => {
|
|
1531
|
+
const atEnd = grid.scrollLeft + grid.clientWidth >= grid.scrollWidth - 8;
|
|
1532
|
+
arrow.style.display = atEnd ? "none" : "flex";
|
|
1533
|
+
};
|
|
1534
|
+
grid.addEventListener("scroll", syncArrow, { passive: true });
|
|
1535
|
+
setTimeout(syncArrow, 0);
|
|
1536
|
+
wrap.appendChild(arrow);
|
|
1537
|
+
section.appendChild(wrap);
|
|
1538
|
+
} else {
|
|
1539
|
+
section.appendChild(grid);
|
|
1540
|
+
}
|
|
1541
|
+
target.appendChild(section);
|
|
1542
|
+
return true;
|
|
1543
|
+
}
|
|
897
1544
|
const MAX_GROUPS = 12;
|
|
898
1545
|
const MAX_FRAMES = 20;
|
|
899
1546
|
const DEFAULT_DURATION_MS = 5e3;
|
|
@@ -997,7 +1644,7 @@ function renderLauncherBar(ctx, cfg, target) {
|
|
|
997
1644
|
if (floating) {
|
|
998
1645
|
const dismiss = document.createElement("button");
|
|
999
1646
|
dismiss.type = "button";
|
|
1000
|
-
dismiss.
|
|
1647
|
+
dismiss.innerHTML = lucideSvg("x", { size: 14 });
|
|
1001
1648
|
dismiss.setAttribute("aria-label", "Dismiss stories");
|
|
1002
1649
|
dismiss.style.cssText = `
|
|
1003
1650
|
flex: 0 0 auto; align-self: center; margin-left: auto;
|
|
@@ -1141,7 +1788,7 @@ function openViewer(ctx, cfg, startGroupIndex, startFrameIndex = 0) {
|
|
|
1141
1788
|
};
|
|
1142
1789
|
const close = document.createElement("button");
|
|
1143
1790
|
close.type = "button";
|
|
1144
|
-
close.
|
|
1791
|
+
close.innerHTML = lucideSvg("x", { size: 18 });
|
|
1145
1792
|
close.setAttribute("aria-label", "Close");
|
|
1146
1793
|
close.style.cssText = "position: absolute; top: 12px; right: 10px; z-index: 5; width: 34px; height: 34px; border: none; border-radius: 999px; background: rgba(0,0,0,0.32); color: #fff; font-size: 18px; cursor: pointer; display: flex; align-items: center; justify-content: center; line-height: 1;";
|
|
1147
1794
|
stage.appendChild(close);
|
|
@@ -1418,7 +2065,7 @@ function openGameModal(ctx, className, maxWidth = 360) {
|
|
|
1418
2065
|
};
|
|
1419
2066
|
const close = document.createElement("button");
|
|
1420
2067
|
close.type = "button";
|
|
1421
|
-
close.
|
|
2068
|
+
close.innerHTML = lucideSvg("x", { size: 15 });
|
|
1422
2069
|
close.setAttribute("aria-label", "Close");
|
|
1423
2070
|
close.style.cssText = `position:absolute;top:10px;right:10px;width:30px;height:30px;border:none;border-radius:999px;background:${branded ? "rgba(255,255,255,0.18)" : "rgba(0,0,0,0.05)"};color:${branded ? "#fff" : "#475569"};font-size:15px;cursor:pointer;z-index:1;`;
|
|
1424
2071
|
close.addEventListener("click", () => dismiss(true));
|
|
@@ -2095,7 +2742,7 @@ function renderGame(ctx, subType) {
|
|
|
2095
2742
|
fn(ctx);
|
|
2096
2743
|
return true;
|
|
2097
2744
|
}
|
|
2098
|
-
const ASPECT = { "16:9": "16 / 9", "9:16": "9 / 16", "1:1": "1 / 1", "4:5": "4 / 5" };
|
|
2745
|
+
const ASPECT$1 = { "16:9": "16 / 9", "9:16": "9 / 16", "1:1": "1 / 1", "4:5": "4 / 5" };
|
|
2099
2746
|
function buildVideo(ctx, aspect, autoplay, loop) {
|
|
2100
2747
|
var _a;
|
|
2101
2748
|
const { campaign, sanitizeUrl } = ctx;
|
|
@@ -2103,7 +2750,7 @@ function buildVideo(ctx, aspect, autoplay, loop) {
|
|
|
2103
2750
|
const videoUrl = sanitizeUrl(ic.video_url || campaign.video_url || "");
|
|
2104
2751
|
const poster = campaign.image_url ? sanitizeUrl(campaign.image_url) : null;
|
|
2105
2752
|
const wrap = document.createElement("div");
|
|
2106
|
-
wrap.style.cssText = `position:relative;width:100%;aspect-ratio:${ASPECT[aspect] || ASPECT["16:9"]};background:#0b1220;border-radius:14px;overflow:hidden;`;
|
|
2753
|
+
wrap.style.cssText = `position:relative;width:100%;aspect-ratio:${ASPECT$1[aspect] || ASPECT$1["16:9"]};background:#0b1220;border-radius:14px;overflow:hidden;`;
|
|
2107
2754
|
if (videoUrl) {
|
|
2108
2755
|
const vid = document.createElement("video");
|
|
2109
2756
|
vid.src = videoUrl;
|
|
@@ -2136,14 +2783,15 @@ function buildVideo(ctx, aspect, autoplay, loop) {
|
|
|
2136
2783
|
});
|
|
2137
2784
|
const pill = document.createElement("button");
|
|
2138
2785
|
pill.type = "button";
|
|
2139
|
-
pill.
|
|
2786
|
+
pill.innerHTML = lucideSvg("volume-x", { size: 14 });
|
|
2140
2787
|
pill.setAttribute("aria-label", "Unmute");
|
|
2141
2788
|
pill.style.cssText = "position:absolute;bottom:10px;right:10px;z-index:2;width:34px;height:34px;border:none;border-radius:999px;background:rgba(0,0,0,0.45);color:#fff;font-size:14px;cursor:pointer;";
|
|
2142
2789
|
pill.addEventListener("click", (e) => {
|
|
2143
2790
|
var _a2;
|
|
2144
2791
|
e.stopPropagation();
|
|
2145
2792
|
vid.muted = !vid.muted;
|
|
2146
|
-
pill.
|
|
2793
|
+
pill.innerHTML = lucideSvg(vid.muted ? "volume-x" : "volume-2", { size: 14 });
|
|
2794
|
+
pill.setAttribute("aria-label", vid.muted ? "Unmute" : "Mute");
|
|
2147
2795
|
if (!vid.muted) void ((_a2 = vid.play) == null ? void 0 : _a2.call(vid).catch(() => {
|
|
2148
2796
|
}));
|
|
2149
2797
|
});
|
|
@@ -2231,7 +2879,7 @@ function renderVideo(ctx) {
|
|
|
2231
2879
|
}
|
|
2232
2880
|
const close = document.createElement("button");
|
|
2233
2881
|
close.type = "button";
|
|
2234
|
-
close.
|
|
2882
|
+
close.innerHTML = lucideSvg("x", { size: 15 });
|
|
2235
2883
|
close.setAttribute("aria-label", "Close");
|
|
2236
2884
|
close.style.cssText = "position:absolute;top:10px;left:10px;z-index:3;width:32px;height:32px;border:none;border-radius:999px;background:rgba(0,0,0,0.4);color:#fff;font-size:15px;cursor:pointer;";
|
|
2237
2885
|
close.addEventListener("click", () => {
|
|
@@ -2272,11 +2920,187 @@ function renderVideoInline(ctx, target) {
|
|
|
2272
2920
|
target.appendChild(banner);
|
|
2273
2921
|
return true;
|
|
2274
2922
|
}
|
|
2923
|
+
const HEX = /^#[0-9a-fA-F]{3,8}$/;
|
|
2924
|
+
function safeColor(c, fallback) {
|
|
2925
|
+
return c && HEX.test(c) ? c : fallback;
|
|
2926
|
+
}
|
|
2927
|
+
const ASPECT = { "16:9": "16 / 9", "4:3": "4 / 3", "21:9": "21 / 9" };
|
|
2928
|
+
function _injectHeroResponsiveCss() {
|
|
2929
|
+
if (typeof document === "undefined") return;
|
|
2930
|
+
if (document.getElementById("aegis-hero-style")) return;
|
|
2931
|
+
const style = document.createElement("style");
|
|
2932
|
+
style.id = "aegis-hero-style";
|
|
2933
|
+
style.textContent = ".aegis-hero-root{border-radius:16px;}@media (min-width:768px){.aegis-hero-root{border-radius:0;min-height:45vh;max-height:70vh;}}";
|
|
2934
|
+
document.head.appendChild(style);
|
|
2935
|
+
}
|
|
2936
|
+
function cardHeadline(c) {
|
|
2937
|
+
return c.headline ?? c.title ?? "";
|
|
2938
|
+
}
|
|
2939
|
+
function cardSub(c) {
|
|
2940
|
+
return c.subhead ?? c.body ?? "";
|
|
2941
|
+
}
|
|
2942
|
+
function cardCta(c) {
|
|
2943
|
+
return c.cta_label ?? c.cta_text ?? "";
|
|
2944
|
+
}
|
|
2945
|
+
function cardUrl(c) {
|
|
2946
|
+
if (c.cta_url) return c.cta_url;
|
|
2947
|
+
const t = c.cta_target;
|
|
2948
|
+
if (t && t.value) return t.type === "category" ? `?category=${encodeURIComponent(t.value)}` : t.value;
|
|
2949
|
+
return "";
|
|
2950
|
+
}
|
|
2951
|
+
function renderHeroInline(ctx, target) {
|
|
2952
|
+
const { campaign, sanitizeUrl, trackEvent } = ctx;
|
|
2953
|
+
const ic = campaign.interactive_config || {};
|
|
2954
|
+
const cards = Array.isArray(ic.cards) ? ic.cards : [];
|
|
2955
|
+
if (cards.length === 0) return false;
|
|
2956
|
+
const chrome = ic.chrome || {};
|
|
2957
|
+
const accent = safeColor(
|
|
2958
|
+
chrome.accent && chrome.accent !== "brand" ? chrome.accent : campaign.background_color,
|
|
2959
|
+
"#4169e1"
|
|
2960
|
+
);
|
|
2961
|
+
const variant = chrome.variant ?? "hero_fullbleed";
|
|
2962
|
+
if (variant === "announcement_bar") {
|
|
2963
|
+
const c = cards[0];
|
|
2964
|
+
const bar = document.createElement("div");
|
|
2965
|
+
bar.style.cssText = `display:flex;align-items:center;justify-content:center;gap:10px;background:${accent};color:#fff;padding:8px 14px;font:600 13px/1.3 Inter,system-ui,sans-serif;text-align:center;`;
|
|
2966
|
+
bar.textContent = [cardHeadline(c), cardSub(c)].filter(Boolean).join(" · ");
|
|
2967
|
+
const url = sanitizeUrl(cardUrl(c));
|
|
2968
|
+
if (url && cardCta(c)) {
|
|
2969
|
+
const a = document.createElement("span");
|
|
2970
|
+
a.style.cssText = "text-decoration:underline;cursor:pointer;white-space:nowrap;";
|
|
2971
|
+
a.textContent = cardCta(c);
|
|
2972
|
+
a.addEventListener("click", () => {
|
|
2973
|
+
var _a;
|
|
2974
|
+
trackEvent(campaign.id, "clicked");
|
|
2975
|
+
(_a = ctx.navigate) == null ? void 0 : _a.call(ctx, url);
|
|
2976
|
+
});
|
|
2977
|
+
bar.appendChild(a);
|
|
2978
|
+
}
|
|
2979
|
+
target.appendChild(bar);
|
|
2980
|
+
trackEvent(campaign.id, "impression");
|
|
2981
|
+
return true;
|
|
2982
|
+
}
|
|
2983
|
+
_injectHeroResponsiveCss();
|
|
2984
|
+
const root = document.createElement("div");
|
|
2985
|
+
root.className = "aegis-hero-root";
|
|
2986
|
+
root.style.cssText = `position:relative;width:100%;overflow:hidden;box-shadow:0 1px 2px rgba(16,24,40,0.06);${chrome.aspect_ratio && ASPECT[chrome.aspect_ratio] ? `aspect-ratio:${ASPECT[chrome.aspect_ratio]};` : "min-height:300px;"}`;
|
|
2987
|
+
root.setAttribute("data-campaign-id", campaign.id);
|
|
2988
|
+
const track = document.createElement("div");
|
|
2989
|
+
track.style.cssText = "display:flex;height:100%;width:100%;transition:transform 0.5s ease;";
|
|
2990
|
+
root.appendChild(track);
|
|
2991
|
+
const overlayCss = chrome.overlay === "none" ? "" : chrome.overlay === "full-scrim" ? "background:linear-gradient(0deg,rgba(0,0,0,0.55),rgba(0,0,0,0.25));" : "background:linear-gradient(to top right,rgba(0,0,0,0.7),rgba(0,0,0,0.25) 45%,transparent);";
|
|
2992
|
+
const justify = chrome.text_position === "center" ? "center" : "flex-end";
|
|
2993
|
+
const align = chrome.text_position === "bottom-left" || !chrome.text_position ? "flex-start" : "center";
|
|
2994
|
+
cards.forEach((c, i) => {
|
|
2995
|
+
const slide = document.createElement("div");
|
|
2996
|
+
slide.style.cssText = "position:relative;flex:0 0 100%;width:100%;height:100%;min-height:inherit;background:#f1f5f9;";
|
|
2997
|
+
const videoUrl = sanitizeUrl(c.video_url ?? "");
|
|
2998
|
+
const isVideo = !!videoUrl || c.media_type === "video";
|
|
2999
|
+
const mediaUrl = isVideo ? videoUrl || sanitizeUrl(c.media_url ?? "") : sanitizeUrl(c.image_url ?? c.media_url ?? "");
|
|
3000
|
+
if (mediaUrl) {
|
|
3001
|
+
if (isVideo) {
|
|
3002
|
+
const v = document.createElement("video");
|
|
3003
|
+
v.src = mediaUrl;
|
|
3004
|
+
v.autoplay = true;
|
|
3005
|
+
v.muted = true;
|
|
3006
|
+
v.loop = true;
|
|
3007
|
+
v.playsInline = true;
|
|
3008
|
+
v.style.cssText = "position:absolute;inset:0;width:100%;height:100%;object-fit:cover;";
|
|
3009
|
+
slide.appendChild(v);
|
|
3010
|
+
} else {
|
|
3011
|
+
const img = document.createElement("div");
|
|
3012
|
+
img.style.cssText = `position:absolute;inset:0;background:url("${mediaUrl}") center/cover no-repeat;`;
|
|
3013
|
+
slide.appendChild(img);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
if (overlayCss) {
|
|
3017
|
+
const scrim = document.createElement("div");
|
|
3018
|
+
scrim.style.cssText = `position:absolute;inset:0;${overlayCss}`;
|
|
3019
|
+
slide.appendChild(scrim);
|
|
3020
|
+
}
|
|
3021
|
+
const content = document.createElement("div");
|
|
3022
|
+
content.style.cssText = `position:absolute;inset:0;display:flex;flex-direction:column;justify-content:${justify};align-items:${align};gap:6px;padding:24px;text-align:${align === "center" ? "center" : "left"};`;
|
|
3023
|
+
const h = cardHeadline(c);
|
|
3024
|
+
if (h) {
|
|
3025
|
+
const head = document.createElement("h2");
|
|
3026
|
+
head.textContent = h;
|
|
3027
|
+
head.style.cssText = "margin:0;color:#fff;font:800 24px/1.2 Inter Tight,Inter,system-ui,sans-serif;letter-spacing:-0.02em;text-shadow:0 1px 8px rgba(0,0,0,0.35);max-width:90%;";
|
|
3028
|
+
content.appendChild(head);
|
|
3029
|
+
}
|
|
3030
|
+
const s = cardSub(c);
|
|
3031
|
+
if (s) {
|
|
3032
|
+
const sub = document.createElement("p");
|
|
3033
|
+
sub.textContent = s;
|
|
3034
|
+
sub.style.cssText = "margin:0;color:rgba(255,255,255,0.92);font:500 14px/1.4 Inter,system-ui,sans-serif;text-shadow:0 1px 6px rgba(0,0,0,0.3);max-width:90%;";
|
|
3035
|
+
content.appendChild(sub);
|
|
3036
|
+
}
|
|
3037
|
+
const cta = cardCta(c);
|
|
3038
|
+
const url = sanitizeUrl(cardUrl(c));
|
|
3039
|
+
if (cta && chrome.cta_style !== "none") {
|
|
3040
|
+
const btn = document.createElement("button");
|
|
3041
|
+
btn.textContent = cta;
|
|
3042
|
+
btn.style.cssText = chrome.cta_style === "underline" ? `margin-top:6px;background:none;border:none;color:#fff;font:700 14px Inter,system-ui,sans-serif;text-decoration:underline;cursor:pointer;padding:0;` : `margin-top:8px;background:${accent};color:#fff;border:none;border-radius:999px;padding:9px 18px;font:700 13px Inter,system-ui,sans-serif;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,0.2);`;
|
|
3043
|
+
btn.addEventListener("click", () => {
|
|
3044
|
+
var _a;
|
|
3045
|
+
trackEvent(campaign.id, "clicked", { stepId: `card_${i}` });
|
|
3046
|
+
if (url) (_a = ctx.navigate) == null ? void 0 : _a.call(ctx, url);
|
|
3047
|
+
});
|
|
3048
|
+
content.appendChild(btn);
|
|
3049
|
+
}
|
|
3050
|
+
slide.appendChild(content);
|
|
3051
|
+
track.appendChild(slide);
|
|
3052
|
+
});
|
|
3053
|
+
const dotEls = [];
|
|
3054
|
+
let activeIdx = 0;
|
|
3055
|
+
const goto = (idx) => {
|
|
3056
|
+
activeIdx = (idx % cards.length + cards.length) % cards.length;
|
|
3057
|
+
track.style.transform = `translateX(-${activeIdx * 100}%)`;
|
|
3058
|
+
dotEls.forEach((d, i) => {
|
|
3059
|
+
d.style.width = i === activeIdx ? "18px" : "6px";
|
|
3060
|
+
d.style.background = i === activeIdx ? accent : "rgba(255,255,255,0.7)";
|
|
3061
|
+
});
|
|
3062
|
+
};
|
|
3063
|
+
const dots = document.createElement("div");
|
|
3064
|
+
dots.style.cssText = "position:absolute;bottom:8px;left:50%;transform:translateX(-50%);display:flex;gap:6px;z-index:2;";
|
|
3065
|
+
if (cards.length > 1) {
|
|
3066
|
+
cards.forEach((_, i) => {
|
|
3067
|
+
const dot = document.createElement("span");
|
|
3068
|
+
dot.style.cssText = "width:6px;height:6px;border-radius:999px;background:rgba(255,255,255,0.7);transition:all 0.25s;cursor:pointer;";
|
|
3069
|
+
dot.addEventListener("click", () => goto(i));
|
|
3070
|
+
dotEls.push(dot);
|
|
3071
|
+
dots.appendChild(dot);
|
|
3072
|
+
});
|
|
3073
|
+
root.appendChild(dots);
|
|
3074
|
+
}
|
|
3075
|
+
target.appendChild(root);
|
|
3076
|
+
goto(0);
|
|
3077
|
+
if (cards.length > 1 && chrome.loop !== false) {
|
|
3078
|
+
const ms = typeof chrome.autoplay_ms === "number" && chrome.autoplay_ms >= 1500 ? chrome.autoplay_ms : 4e3;
|
|
3079
|
+
let timer = window.setInterval(() => goto(activeIdx + 1), ms);
|
|
3080
|
+
root.addEventListener("mouseenter", () => window.clearInterval(timer));
|
|
3081
|
+
root.addEventListener("mouseleave", () => {
|
|
3082
|
+
timer = window.setInterval(() => goto(activeIdx + 1), ms);
|
|
3083
|
+
});
|
|
3084
|
+
}
|
|
3085
|
+
trackEvent(campaign.id, "impression");
|
|
3086
|
+
return true;
|
|
3087
|
+
}
|
|
2275
3088
|
const STYLE_ID = "aegis-chat-styles";
|
|
2276
3089
|
const POLL_INTERVAL_MS = 5e3;
|
|
3090
|
+
let currentLauncher = null;
|
|
3091
|
+
function getCurrentLauncher() {
|
|
3092
|
+
return currentLauncher;
|
|
3093
|
+
}
|
|
3094
|
+
function openChat(prefill) {
|
|
3095
|
+
currentLauncher == null ? void 0 : currentLauncher.openPanel(prefill);
|
|
3096
|
+
}
|
|
3097
|
+
function closeChat() {
|
|
3098
|
+
currentLauncher == null ? void 0 : currentLauncher.closePanel();
|
|
3099
|
+
}
|
|
2277
3100
|
const ATTENTION_DELAY_MS = 4500;
|
|
2278
3101
|
class AegisChat {
|
|
2279
3102
|
constructor(config) {
|
|
3103
|
+
this.sessionResumed = false;
|
|
2280
3104
|
this.open = false;
|
|
2281
3105
|
this.initialized = false;
|
|
2282
3106
|
this.unread = 0;
|
|
@@ -2294,12 +3118,14 @@ class AegisChat {
|
|
|
2294
3118
|
this.icon = config.icon ?? "sparkle";
|
|
2295
3119
|
this.logoUrl = config.logoUrl;
|
|
2296
3120
|
this.position = config.position ?? "bottom-right";
|
|
3121
|
+
this.displayMode = config.displayMode ?? "bubble";
|
|
2297
3122
|
this.agentPersona = config.agentPersona;
|
|
2298
3123
|
this.quickReplies = config.quickReplies;
|
|
2299
3124
|
this.onSessionStart = config.onSessionStart;
|
|
2300
3125
|
this.onSessionEnd = config.onSessionEnd;
|
|
2301
3126
|
this.onMessageSent = config.onMessageSent;
|
|
2302
3127
|
this.anonymousId = this.readAnonId();
|
|
3128
|
+
this.contactId = this.contactId ?? this.readStoredContactId();
|
|
2303
3129
|
}
|
|
2304
3130
|
// ── Lifecycle ────────────────────────────────────────────────────────────
|
|
2305
3131
|
initialize() {
|
|
@@ -2307,7 +3133,8 @@ class AegisChat {
|
|
|
2307
3133
|
this.initialized = true;
|
|
2308
3134
|
this.injectStyles();
|
|
2309
3135
|
this.mount();
|
|
2310
|
-
this
|
|
3136
|
+
currentLauncher = this;
|
|
3137
|
+
if (this.displayMode !== "nav") this.scheduleAttention();
|
|
2311
3138
|
}
|
|
2312
3139
|
/** Called by the runtime when the visitor identifies. */
|
|
2313
3140
|
updateContactId(contactId) {
|
|
@@ -2330,7 +3157,7 @@ class AegisChat {
|
|
|
2330
3157
|
(_c = this.bubble) == null ? void 0 : _c.classList.add("aegis-chat-bubble--hidden");
|
|
2331
3158
|
this.clearUnread();
|
|
2332
3159
|
if (prefill && this.input) this.input.value = prefill;
|
|
2333
|
-
void this.
|
|
3160
|
+
void this.resumeSession();
|
|
2334
3161
|
this.startPolling();
|
|
2335
3162
|
(_d = this.input) == null ? void 0 : _d.focus();
|
|
2336
3163
|
}
|
|
@@ -2355,13 +3182,22 @@ class AegisChat {
|
|
|
2355
3182
|
this.stopPolling();
|
|
2356
3183
|
(_a = this.root) == null ? void 0 : _a.remove();
|
|
2357
3184
|
this.initialized = false;
|
|
3185
|
+
if (currentLauncher === this) currentLauncher = null;
|
|
2358
3186
|
}
|
|
2359
3187
|
// ── Send ─────────────────────────────────────────────────────────────────
|
|
2360
|
-
async send(text) {
|
|
3188
|
+
async send(text, media) {
|
|
2361
3189
|
var _a;
|
|
2362
|
-
const
|
|
2363
|
-
if (!
|
|
2364
|
-
|
|
3190
|
+
const caption2 = text.trim();
|
|
3191
|
+
if (!caption2 && !media) return;
|
|
3192
|
+
const message = caption2 || (media ? media.type === "image" ? "Sent a photo 📷" : "Sent a file 📎" : "");
|
|
3193
|
+
this.appendBubble({
|
|
3194
|
+
id: `local_${Date.now()}`,
|
|
3195
|
+
sender: "customer",
|
|
3196
|
+
role: "user",
|
|
3197
|
+
content: message,
|
|
3198
|
+
media_url: (media == null ? void 0 : media.url) ?? null,
|
|
3199
|
+
media_type: (media == null ? void 0 : media.type) ?? null
|
|
3200
|
+
});
|
|
2365
3201
|
this.pendingEcho.push(message);
|
|
2366
3202
|
if (this.input) {
|
|
2367
3203
|
this.input.value = "";
|
|
@@ -2377,6 +3213,8 @@ class AegisChat {
|
|
|
2377
3213
|
channel: this.channel,
|
|
2378
3214
|
anonymous_id: this.anonymousId,
|
|
2379
3215
|
contact_id: this.contactId,
|
|
3216
|
+
media_url: media == null ? void 0 : media.url,
|
|
3217
|
+
media_type: media == null ? void 0 : media.type,
|
|
2380
3218
|
// Active Web Chat — binds the campaign-configured persona. Optional;
|
|
2381
3219
|
// the backend falls back to the tenant default if unknown/absent
|
|
2382
3220
|
// (honored server-side in Phase E). JSON.stringify drops it if absent.
|
|
@@ -2395,6 +3233,7 @@ class AegisChat {
|
|
|
2395
3233
|
} catch {
|
|
2396
3234
|
}
|
|
2397
3235
|
this.contactId = data.contact_id;
|
|
3236
|
+
this.persistContactId(data.contact_id);
|
|
2398
3237
|
this.sseTicket = data.sse_ticket;
|
|
2399
3238
|
this.connectSSE(data.sse_ticket);
|
|
2400
3239
|
void this.refreshHistory();
|
|
@@ -2403,6 +3242,51 @@ class AegisChat {
|
|
|
2403
3242
|
this.appendSystem("Sorry — your message could not be delivered. Please try again.");
|
|
2404
3243
|
}
|
|
2405
3244
|
}
|
|
3245
|
+
// ── Media attachments ─────────────────────────────────────────────────────
|
|
3246
|
+
/** Validate + upload a picked file, then send it as a media message. */
|
|
3247
|
+
async handleFile(file) {
|
|
3248
|
+
var _a;
|
|
3249
|
+
const allowed = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/gif", "image/webp", "application/pdf"]);
|
|
3250
|
+
if (!allowed.has(file.type)) {
|
|
3251
|
+
this.appendSystem("That file type isn’t supported (images or PDF only).");
|
|
3252
|
+
return;
|
|
3253
|
+
}
|
|
3254
|
+
if (file.size > 8 * 1024 * 1024) {
|
|
3255
|
+
this.appendSystem("That file is too large (max 8 MB).");
|
|
3256
|
+
return;
|
|
3257
|
+
}
|
|
3258
|
+
try {
|
|
3259
|
+
const data = await this.fileToBase64(file);
|
|
3260
|
+
const res = await fetch(`${this.apiHost}/v1/chat/upload`, {
|
|
3261
|
+
method: "POST",
|
|
3262
|
+
headers: { "Content-Type": "application/json", "X-Aegis-Write-Key": this.writeKey },
|
|
3263
|
+
body: JSON.stringify({ data, content_type: file.type, filename: file.name })
|
|
3264
|
+
});
|
|
3265
|
+
if (!res.ok) {
|
|
3266
|
+
this.log("upload failed", res.status);
|
|
3267
|
+
this.appendSystem("Sorry — that attachment couldn’t be uploaded.");
|
|
3268
|
+
return;
|
|
3269
|
+
}
|
|
3270
|
+
const out = await res.json();
|
|
3271
|
+
await this.send(((_a = this.input) == null ? void 0 : _a.value) ?? "", { url: out.media_url, type: out.media_type });
|
|
3272
|
+
} catch (err) {
|
|
3273
|
+
this.log("upload error", err);
|
|
3274
|
+
this.appendSystem("Sorry — that attachment couldn’t be uploaded.");
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
/** Read a File as bare base64 (strip the `data:…;base64,` prefix). */
|
|
3278
|
+
fileToBase64(file) {
|
|
3279
|
+
return new Promise((resolve, reject) => {
|
|
3280
|
+
const reader = new FileReader();
|
|
3281
|
+
reader.onload = () => {
|
|
3282
|
+
const result = String(reader.result || "");
|
|
3283
|
+
const comma = result.indexOf(",");
|
|
3284
|
+
resolve(comma >= 0 ? result.slice(comma + 1) : result);
|
|
3285
|
+
};
|
|
3286
|
+
reader.onerror = () => reject(reader.error);
|
|
3287
|
+
reader.readAsDataURL(file);
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
2406
3290
|
// ── Reply transport: SSE nudge + history refetch (poll fallback) ──────────
|
|
2407
3291
|
connectSSE(ticket) {
|
|
2408
3292
|
if (!this.open) return;
|
|
@@ -2522,7 +3406,7 @@ class AegisChat {
|
|
|
2522
3406
|
const closeBtn = document.createElement("button");
|
|
2523
3407
|
closeBtn.className = "aegis-chat-close";
|
|
2524
3408
|
closeBtn.setAttribute("aria-label", "Close chat");
|
|
2525
|
-
closeBtn.
|
|
3409
|
+
closeBtn.innerHTML = lucideSvg("x", { size: 16 });
|
|
2526
3410
|
closeBtn.addEventListener("click", () => this.closePanel());
|
|
2527
3411
|
header.appendChild(titleEl);
|
|
2528
3412
|
header.appendChild(closeBtn);
|
|
@@ -2540,6 +3424,21 @@ class AegisChat {
|
|
|
2540
3424
|
void this.send(input.value);
|
|
2541
3425
|
}
|
|
2542
3426
|
});
|
|
3427
|
+
const fileInput = document.createElement("input");
|
|
3428
|
+
fileInput.type = "file";
|
|
3429
|
+
fileInput.accept = "image/*,application/pdf";
|
|
3430
|
+
fileInput.className = "aegis-chat-fileinput";
|
|
3431
|
+
fileInput.addEventListener("change", () => {
|
|
3432
|
+
const f = fileInput.files && fileInput.files[0];
|
|
3433
|
+
if (f) void this.handleFile(f);
|
|
3434
|
+
fileInput.value = "";
|
|
3435
|
+
});
|
|
3436
|
+
const attachBtn = document.createElement("button");
|
|
3437
|
+
attachBtn.type = "button";
|
|
3438
|
+
attachBtn.className = "aegis-chat-attach";
|
|
3439
|
+
attachBtn.setAttribute("aria-label", "Attach a file");
|
|
3440
|
+
attachBtn.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>';
|
|
3441
|
+
attachBtn.addEventListener("click", () => fileInput.click());
|
|
2543
3442
|
const sendBtn = document.createElement("button");
|
|
2544
3443
|
sendBtn.type = "submit";
|
|
2545
3444
|
sendBtn.className = "aegis-chat-send";
|
|
@@ -2549,8 +3448,10 @@ class AegisChat {
|
|
|
2549
3448
|
e.preventDefault();
|
|
2550
3449
|
void this.send(input.value);
|
|
2551
3450
|
});
|
|
3451
|
+
composer.appendChild(attachBtn);
|
|
2552
3452
|
composer.appendChild(input);
|
|
2553
3453
|
composer.appendChild(sendBtn);
|
|
3454
|
+
composer.appendChild(fileInput);
|
|
2554
3455
|
panel.appendChild(header);
|
|
2555
3456
|
panel.appendChild(thread);
|
|
2556
3457
|
panel.appendChild(composer);
|
|
@@ -2561,7 +3462,7 @@ class AegisChat {
|
|
|
2561
3462
|
const tipClose = document.createElement("button");
|
|
2562
3463
|
tipClose.className = "aegis-chat-tip-close";
|
|
2563
3464
|
tipClose.setAttribute("aria-label", "Dismiss");
|
|
2564
|
-
tipClose.
|
|
3465
|
+
tipClose.innerHTML = lucideSvg("x", { size: 14 });
|
|
2565
3466
|
tipClose.addEventListener("click", (e) => {
|
|
2566
3467
|
e.stopPropagation();
|
|
2567
3468
|
this.dismissAttention();
|
|
@@ -2570,8 +3471,10 @@ class AegisChat {
|
|
|
2570
3471
|
tip.appendChild(tipClose);
|
|
2571
3472
|
tip.addEventListener("click", () => this.openPanel());
|
|
2572
3473
|
root.appendChild(panel);
|
|
2573
|
-
|
|
2574
|
-
|
|
3474
|
+
if (this.displayMode !== "nav") {
|
|
3475
|
+
root.appendChild(tip);
|
|
3476
|
+
root.appendChild(bubble);
|
|
3477
|
+
}
|
|
2575
3478
|
document.body.appendChild(root);
|
|
2576
3479
|
this.greetingTip = tip;
|
|
2577
3480
|
this.root = root;
|
|
@@ -2609,6 +3512,26 @@ class AegisChat {
|
|
|
2609
3512
|
if (msg.id) this.renderedIds.add(msg.id);
|
|
2610
3513
|
const row = document.createElement("div");
|
|
2611
3514
|
row.className = `aegis-chat-msg aegis-chat-msg--${msg.sender}`;
|
|
3515
|
+
if (msg.media_url) {
|
|
3516
|
+
if (msg.media_type === "image") {
|
|
3517
|
+
const img = document.createElement("img");
|
|
3518
|
+
img.className = "aegis-chat-media-img";
|
|
3519
|
+
img.src = msg.media_url;
|
|
3520
|
+
img.alt = "attachment";
|
|
3521
|
+
img.loading = "lazy";
|
|
3522
|
+
const url = msg.media_url;
|
|
3523
|
+
img.addEventListener("click", () => window.open(url, "_blank", "noopener"));
|
|
3524
|
+
row.appendChild(img);
|
|
3525
|
+
} else {
|
|
3526
|
+
const a = document.createElement("a");
|
|
3527
|
+
a.className = "aegis-chat-media-file";
|
|
3528
|
+
a.href = msg.media_url;
|
|
3529
|
+
a.target = "_blank";
|
|
3530
|
+
a.rel = "noopener noreferrer";
|
|
3531
|
+
a.textContent = "📎 Attachment";
|
|
3532
|
+
row.appendChild(a);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
2612
3535
|
if (msg.content) {
|
|
2613
3536
|
const bubble = document.createElement("div");
|
|
2614
3537
|
bubble.className = "aegis-chat-bubbletext";
|
|
@@ -2700,6 +3623,54 @@ class AegisChat {
|
|
|
2700
3623
|
return void 0;
|
|
2701
3624
|
}
|
|
2702
3625
|
}
|
|
3626
|
+
readStoredContactId() {
|
|
3627
|
+
if (typeof document === "undefined") return void 0;
|
|
3628
|
+
try {
|
|
3629
|
+
return new Storage().get("aegis_chat_cid") ?? void 0;
|
|
3630
|
+
} catch {
|
|
3631
|
+
return void 0;
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
persistContactId(id) {
|
|
3635
|
+
if (!id || typeof document === "undefined") return;
|
|
3636
|
+
try {
|
|
3637
|
+
new Storage().set("aegis_chat_cid", id, 365);
|
|
3638
|
+
} catch {
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
/** Restore a returning visitor's thread on open. Resolves an existing contact
|
|
3642
|
+
* + mints a per-session ticket WITHOUT sending a message (history is ticket-
|
|
3643
|
+
* gated). No-ops for brand-new visitors and once a ticket is already held. */
|
|
3644
|
+
async resumeSession() {
|
|
3645
|
+
if (this.sseTicket) {
|
|
3646
|
+
void this.refreshHistory();
|
|
3647
|
+
return;
|
|
3648
|
+
}
|
|
3649
|
+
if (this.sessionResumed) return;
|
|
3650
|
+
this.sessionResumed = true;
|
|
3651
|
+
if (!this.contactId && !this.anonymousId) return;
|
|
3652
|
+
try {
|
|
3653
|
+
const res = await fetch(`${this.apiHost}/v1/chat/session`, {
|
|
3654
|
+
method: "POST",
|
|
3655
|
+
headers: { "Content-Type": "application/json", "X-Aegis-Write-Key": this.writeKey },
|
|
3656
|
+
body: JSON.stringify({
|
|
3657
|
+
anonymous_id: this.anonymousId,
|
|
3658
|
+
contact_id: this.contactId,
|
|
3659
|
+
channel: this.channel
|
|
3660
|
+
})
|
|
3661
|
+
});
|
|
3662
|
+
if (!res.ok) return;
|
|
3663
|
+
const data = await res.json();
|
|
3664
|
+
if (!data.contact_id || !data.sse_ticket) return;
|
|
3665
|
+
this.contactId = data.contact_id;
|
|
3666
|
+
this.sseTicket = data.sse_ticket;
|
|
3667
|
+
this.persistContactId(data.contact_id);
|
|
3668
|
+
await this.refreshHistory();
|
|
3669
|
+
if (this.open) this.connectSSE(data.sse_ticket);
|
|
3670
|
+
} catch (err) {
|
|
3671
|
+
this.log("resume session failed", err);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
2703
3674
|
// ── Typing indicator ───────────────────────────────────────────────────────
|
|
2704
3675
|
showTyping() {
|
|
2705
3676
|
if (!this.thread || this.typingEl) return;
|
|
@@ -2800,11 +3771,19 @@ const CHAT_CSS = `
|
|
|
2800
3771
|
.aegis-chat-input{flex:1;resize:none;border:1px solid #e2e8f0;border-radius:12px;padding:9px 12px;font-size:14px;font-family:inherit;max-height:96px;outline:none}
|
|
2801
3772
|
.aegis-chat-input:focus{border-color:var(--aegis-chat-accent,#4169e1)}
|
|
2802
3773
|
.aegis-chat-send{width:40px;height:40px;border-radius:9999px;border:none;background:var(--aegis-chat-accent,#4169e1);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:0 0 auto}
|
|
3774
|
+
.aegis-chat-attach{width:38px;height:38px;border-radius:9999px;border:none;background:transparent;color:#64748b;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:0 0 auto;transition:background .15s ease,color .15s ease}
|
|
3775
|
+
.aegis-chat-attach:hover{background:#f1f5f9;color:var(--aegis-chat-accent,#4169e1)}
|
|
3776
|
+
.aegis-chat-fileinput{display:none}
|
|
3777
|
+
.aegis-chat-media-img{max-width:200px;max-height:200px;border-radius:12px;object-fit:cover;cursor:pointer;display:block}
|
|
3778
|
+
.aegis-chat-media-file{display:inline-flex;align-items:center;gap:6px;padding:8px 12px;border-radius:12px;background:#fff;border:1px solid #e2e8f0;font-size:13px;color:#0f172a;text-decoration:none;max-width:220px}
|
|
3779
|
+
.aegis-chat-msg--customer .aegis-chat-media-file{background:rgba(255,255,255,.18);border-color:transparent;color:#fff}
|
|
2803
3780
|
/* Mobile: raise the bubble above the storefront's full-width cart bar so they
|
|
2804
3781
|
never overlap; widen the panel and reduce the tooltip width. */
|
|
2805
|
-
@media (max-width:
|
|
3782
|
+
@media (max-width:767px){
|
|
2806
3783
|
.aegis-chat-root{bottom:84px;right:16px}
|
|
2807
|
-
|
|
3784
|
+
/* Full-page chat on mobile — the open panel covers the whole viewport (incl.
|
|
3785
|
+
the bottom nav) like a native chat screen, instead of a floating card. */
|
|
3786
|
+
.aegis-chat-panel{position:fixed;inset:0;left:0;right:0;width:100vw;height:100vh;height:100dvh;max-width:none;max-height:none;border-radius:0}
|
|
2808
3787
|
.aegis-chat-tip{max-width:200px}
|
|
2809
3788
|
}
|
|
2810
3789
|
`;
|
|
@@ -3376,6 +4355,10 @@ function renderActiveWebChat(ctx, creds) {
|
|
|
3376
4355
|
icon: icon === "sparkle" || icon === "chat" || icon === "logo" ? icon : void 0,
|
|
3377
4356
|
logoUrl: logo ? ctx.sanitizeUrl(logo) ?? void 0 : void 0,
|
|
3378
4357
|
position: ic.chat_position === "bottom-left" ? "bottom-left" : void 0,
|
|
4358
|
+
// 'nav' = headless (no bubble); the host opens it via aegis.chat.open() or a
|
|
4359
|
+
// client_trigger. Defaults to 'bubble'. Per-device override via device_type
|
|
4360
|
+
// targeting on the campaign (e.g. a mobile campaign with chat_display_mode='nav').
|
|
4361
|
+
displayMode: ic.chat_display_mode === "nav" ? "nav" : void 0,
|
|
3379
4362
|
agentPersona: str(ic.chat_agent_persona),
|
|
3380
4363
|
quickReplies: Array.isArray(ic.chat_quick_replies) ? ic.chat_quick_replies.filter((q) => typeof q === "string") : void 0,
|
|
3381
4364
|
// Bridge the engine's session lifecycle to campaign analytics. Per the
|
|
@@ -3436,6 +4419,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
3436
4419
|
constructor(config) {
|
|
3437
4420
|
this.campaigns = [];
|
|
3438
4421
|
this.displayedCampaigns = /* @__PURE__ */ new Set();
|
|
4422
|
+
this._displaySizeMul = 1;
|
|
3439
4423
|
this.suppressedUntil = /* @__PURE__ */ new Map();
|
|
3440
4424
|
this.isInitialized = false;
|
|
3441
4425
|
this.reconnectAttempts = 0;
|
|
@@ -3444,10 +4428,15 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
3444
4428
|
this.ready = new Promise((resolve) => {
|
|
3445
4429
|
this.readyResolve = resolve;
|
|
3446
4430
|
});
|
|
4431
|
+
this.pendingPreInitRefresh = false;
|
|
3447
4432
|
this.currentSurface = null;
|
|
3448
4433
|
this.currentScreen = null;
|
|
3449
4434
|
this.currentLocationId = null;
|
|
3450
4435
|
this.filledSlots = /* @__PURE__ */ new WeakSet();
|
|
4436
|
+
this.slotSignatures = /* @__PURE__ */ new WeakMap();
|
|
4437
|
+
this.slotTimers = /* @__PURE__ */ new WeakMap();
|
|
4438
|
+
this.slotObserver = null;
|
|
4439
|
+
this.slotRenderScheduled = false;
|
|
3451
4440
|
this.writeKey = config.writeKey;
|
|
3452
4441
|
this.apiHost = config.apiHost || "https://api.aegis.ai";
|
|
3453
4442
|
this.userId = config.userId ?? readAnonIdFromStorage$1();
|
|
@@ -3559,6 +4548,11 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
3559
4548
|
this.connectSSE();
|
|
3560
4549
|
}
|
|
3561
4550
|
this.isInitialized = true;
|
|
4551
|
+
if (this.pendingPreInitRefresh) {
|
|
4552
|
+
this.pendingPreInitRefresh = false;
|
|
4553
|
+
this.log("Re-fetching campaigns for surface/screen declared during init");
|
|
4554
|
+
void this.refreshCampaigns();
|
|
4555
|
+
}
|
|
3562
4556
|
this.log("AegisInApp initialized successfully");
|
|
3563
4557
|
}
|
|
3564
4558
|
updateUserId(userId) {
|
|
@@ -3607,16 +4601,17 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
3607
4601
|
* change `currentSurface`, so arbitrary events never poison the surface gate.
|
|
3608
4602
|
*/
|
|
3609
4603
|
refreshOnEvent(eventName, isScreenDeclaration = false) {
|
|
3610
|
-
if (!this.isInitialized) {
|
|
3611
|
-
this.log(`refreshOnEvent(${eventName}) before initialize — ignored`);
|
|
3612
|
-
return;
|
|
3613
|
-
}
|
|
3614
4604
|
if (eventName && _AegisInAppManager.KNOWN_SURFACES.has(eventName)) {
|
|
3615
4605
|
this.currentSurface = eventName;
|
|
3616
4606
|
}
|
|
3617
4607
|
if (isScreenDeclaration && eventName && eventName !== "page_view") {
|
|
3618
4608
|
this.currentScreen = eventName;
|
|
3619
4609
|
}
|
|
4610
|
+
if (!this.isInitialized) {
|
|
4611
|
+
this.pendingPreInitRefresh = true;
|
|
4612
|
+
this.log(`refreshOnEvent(${eventName}) before initialize — surface captured, refetch deferred to initialize()`);
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
3620
4615
|
if (this.refreshDebounceTimer) {
|
|
3621
4616
|
clearTimeout(this.refreshDebounceTimer);
|
|
3622
4617
|
}
|
|
@@ -3834,7 +4829,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
3834
4829
|
try {
|
|
3835
4830
|
const context = new URLSearchParams({
|
|
3836
4831
|
device_type: this.detectDeviceType(),
|
|
3837
|
-
page_url: typeof window !== "undefined" ? window.location.pathname : "/"
|
|
4832
|
+
page_url: typeof window !== "undefined" ? window.location.pathname + window.location.search : "/"
|
|
3838
4833
|
});
|
|
3839
4834
|
context.set("is_new_user", this.isNewUser() ? "true" : "false");
|
|
3840
4835
|
if (this.currentSurface) {
|
|
@@ -3992,34 +4987,92 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
3992
4987
|
if (!c.surface || c.surface.length === 0) return screenOk;
|
|
3993
4988
|
return screenOk || this.matchesCurrentSurface(c);
|
|
3994
4989
|
}
|
|
4990
|
+
// Re-fill slots that mount after a poll (SPA route changes). Observes the DOM
|
|
4991
|
+
// once; when a new [data-aegis-slot] appears it re-runs renderIntoSlots from
|
|
4992
|
+
// the cached campaigns (idempotent — already-filled slots are skipped). Does
|
|
4993
|
+
// NOT loop on the SDK's own injections (those add content INTO a slot, not a
|
|
4994
|
+
// new slot element).
|
|
4995
|
+
ensureSlotObserver() {
|
|
4996
|
+
if (this.slotObserver || typeof MutationObserver === "undefined" || typeof document === "undefined") {
|
|
4997
|
+
return;
|
|
4998
|
+
}
|
|
4999
|
+
this.slotObserver = new MutationObserver((mutations) => {
|
|
5000
|
+
let sawSlot = false;
|
|
5001
|
+
for (const m2 of mutations) {
|
|
5002
|
+
m2.addedNodes.forEach((n) => {
|
|
5003
|
+
var _a, _b;
|
|
5004
|
+
if (sawSlot || n.nodeType !== 1) return;
|
|
5005
|
+
const el = n;
|
|
5006
|
+
if (((_a = el.matches) == null ? void 0 : _a.call(el, "[data-aegis-slot]")) || ((_b = el.querySelector) == null ? void 0 : _b.call(el, "[data-aegis-slot]"))) {
|
|
5007
|
+
sawSlot = true;
|
|
5008
|
+
}
|
|
5009
|
+
});
|
|
5010
|
+
if (sawSlot) break;
|
|
5011
|
+
}
|
|
5012
|
+
if (!sawSlot || this.slotRenderScheduled) return;
|
|
5013
|
+
this.slotRenderScheduled = true;
|
|
5014
|
+
const run = () => {
|
|
5015
|
+
this.slotRenderScheduled = false;
|
|
5016
|
+
this.renderIntoSlots();
|
|
5017
|
+
};
|
|
5018
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(run);
|
|
5019
|
+
else setTimeout(run, 0);
|
|
5020
|
+
});
|
|
5021
|
+
this.slotObserver.observe(document.body, { childList: true, subtree: true });
|
|
5022
|
+
}
|
|
3995
5023
|
renderIntoSlots() {
|
|
3996
5024
|
if (typeof document === "undefined") return;
|
|
5025
|
+
this.ensureSlotObserver();
|
|
3997
5026
|
const slots = document.querySelectorAll("[data-aegis-slot]");
|
|
3998
5027
|
if (slots.length === 0) return;
|
|
3999
5028
|
const eligibleByCategory = /* @__PURE__ */ new Map();
|
|
5029
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
4000
5030
|
for (const c of this.campaigns) {
|
|
4001
5031
|
if (!this.matchesCurrentScreenOrSurface(c)) continue;
|
|
4002
5032
|
const modes = c.delivery_modes;
|
|
4003
5033
|
const category = c.widget_category;
|
|
4004
5034
|
if (!modes || !modes.includes("embedded_card")) continue;
|
|
4005
5035
|
if (!category) continue;
|
|
5036
|
+
if (seenIds.has(c.id)) continue;
|
|
5037
|
+
seenIds.add(c.id);
|
|
4006
5038
|
const arr2 = eligibleByCategory.get(category);
|
|
4007
5039
|
if (arr2) arr2.push(c);
|
|
4008
5040
|
else eligibleByCategory.set(category, [c]);
|
|
4009
5041
|
}
|
|
4010
5042
|
if (eligibleByCategory.size === 0) return;
|
|
4011
5043
|
slots.forEach((slot) => {
|
|
4012
|
-
if (this.filledSlots.has(slot)) return;
|
|
4013
5044
|
const key = slot.getAttribute("data-aegis-slot");
|
|
4014
5045
|
if (!key) return;
|
|
4015
5046
|
const list = eligibleByCategory.get(key);
|
|
4016
5047
|
if (!list || list.length === 0) return;
|
|
5048
|
+
const sig = list.map((c) => `${c.id}:${c.assigned_variant_id ?? ""}`).join(",");
|
|
5049
|
+
if (this.filledSlots.has(slot) && this.slotSignatures.get(slot) === sig) return;
|
|
5050
|
+
const oldTimer = this.slotTimers.get(slot);
|
|
5051
|
+
if (oldTimer) {
|
|
5052
|
+
clearInterval(oldTimer);
|
|
5053
|
+
this.slotTimers.delete(slot);
|
|
5054
|
+
}
|
|
5055
|
+
slot.querySelectorAll(
|
|
5056
|
+
":scope > [data-aegis-rotate-pane], :scope > [data-aegis-slot-rendered], :scope > [data-aegis-rotate-dots]"
|
|
5057
|
+
).forEach((n) => n.remove());
|
|
5058
|
+
this.slotSignatures.set(slot, sig);
|
|
4017
5059
|
slot.querySelectorAll(":scope > [data-aegis-slot-default]").forEach((d) => d.remove());
|
|
4018
|
-
const
|
|
5060
|
+
const attrMs = parseInt(slot.getAttribute("data-aegis-slot-rotate") || "0", 10);
|
|
5061
|
+
const declaredMs = list.reduce((m2, c) => {
|
|
5062
|
+
var _a;
|
|
5063
|
+
const v = Number((_a = c.interactive_config) == null ? void 0 : _a.slot_rotate_ms);
|
|
5064
|
+
return Number.isFinite(v) && v > m2 ? v : m2;
|
|
5065
|
+
}, 0);
|
|
5066
|
+
const rotateMs = attrMs > 0 ? attrMs : declaredMs;
|
|
5067
|
+
const flush = slot.hasAttribute("data-aegis-slot-flush");
|
|
4019
5068
|
if (rotateMs > 0 && list.length > 1) {
|
|
4020
|
-
this.renderRotatingSlot(slot, list, rotateMs);
|
|
5069
|
+
this.renderRotatingSlot(slot, list, rotateMs, flush);
|
|
4021
5070
|
} else {
|
|
4022
|
-
|
|
5071
|
+
const host = document.createElement("div");
|
|
5072
|
+
host.setAttribute("data-aegis-slot-rendered", list[0].id);
|
|
5073
|
+
slot.appendChild(host);
|
|
5074
|
+
this.renderCampaignIntoSlot(list[0], host);
|
|
5075
|
+
if (flush) this._flattenSlotCard(host);
|
|
4023
5076
|
}
|
|
4024
5077
|
this.filledSlots.add(slot);
|
|
4025
5078
|
});
|
|
@@ -4032,7 +5085,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4032
5085
|
* is deferred at render and fired per campaign on FIRST visibility, so hidden
|
|
4033
5086
|
* panes never over-count. One rendered pane → no rotation (just shows it).
|
|
4034
5087
|
*/
|
|
4035
|
-
renderRotatingSlot(slot, campaigns, rotateMs) {
|
|
5088
|
+
renderRotatingSlot(slot, campaigns, rotateMs, flush = false) {
|
|
4036
5089
|
const panes = [];
|
|
4037
5090
|
for (const c of campaigns) {
|
|
4038
5091
|
const pane = document.createElement("div");
|
|
@@ -4040,8 +5093,10 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4040
5093
|
pane.style.display = "none";
|
|
4041
5094
|
slot.appendChild(pane);
|
|
4042
5095
|
this.renderCampaignIntoSlot(c, pane, { deferImpression: true });
|
|
4043
|
-
if (pane.childElementCount > 0)
|
|
4044
|
-
|
|
5096
|
+
if (pane.childElementCount > 0) {
|
|
5097
|
+
if (flush) this._flattenSlotCard(pane);
|
|
5098
|
+
panes.push({ el: pane, campaign: c });
|
|
5099
|
+
} else pane.remove();
|
|
4045
5100
|
}
|
|
4046
5101
|
if (panes.length === 0) return;
|
|
4047
5102
|
const impressed = /* @__PURE__ */ new Set();
|
|
@@ -4052,17 +5107,59 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4052
5107
|
this.emit("campaign-shown", c);
|
|
4053
5108
|
};
|
|
4054
5109
|
let idx = 0;
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
5110
|
+
const dots = [];
|
|
5111
|
+
if (panes.length > 1) {
|
|
5112
|
+
const bar = document.createElement("div");
|
|
5113
|
+
bar.setAttribute("data-aegis-rotate-dots", "");
|
|
5114
|
+
bar.setAttribute("role", "tablist");
|
|
5115
|
+
bar.setAttribute("aria-label", "Offers");
|
|
5116
|
+
bar.style.cssText = "display:flex;align-items:center;justify-content:center;gap:5px;padding:2px 0 8px;";
|
|
5117
|
+
panes.forEach((_, i) => {
|
|
5118
|
+
const dot = document.createElement("button");
|
|
5119
|
+
dot.type = "button";
|
|
5120
|
+
dot.setAttribute("role", "tab");
|
|
5121
|
+
dot.setAttribute("aria-label", `Offer ${i + 1} of ${panes.length}`);
|
|
5122
|
+
dot.style.cssText = "border:none;padding:0;cursor:pointer;height:6px;width:6px;border-radius:999px;background:rgba(15,23,42,0.2);transition:width .25s ease,background .25s ease;";
|
|
5123
|
+
dot.addEventListener("click", (e) => {
|
|
5124
|
+
e.stopPropagation();
|
|
5125
|
+
show(i, true);
|
|
5126
|
+
});
|
|
5127
|
+
dots.push(dot);
|
|
5128
|
+
bar.appendChild(dot);
|
|
5129
|
+
});
|
|
5130
|
+
slot.appendChild(bar);
|
|
5131
|
+
}
|
|
5132
|
+
const paintDots = () => {
|
|
5133
|
+
dots.forEach((d, i) => {
|
|
5134
|
+
const active = i === idx;
|
|
5135
|
+
d.style.width = active ? "16px" : "6px";
|
|
5136
|
+
d.style.background = active ? "var(--aegis-brand-accent, #4169e1)" : "rgba(15,23,42,0.2)";
|
|
5137
|
+
d.setAttribute("aria-selected", active ? "true" : "false");
|
|
5138
|
+
});
|
|
5139
|
+
};
|
|
5140
|
+
let timer = null;
|
|
5141
|
+
const start = () => setInterval(() => {
|
|
5142
|
+
show(idx + 1);
|
|
5143
|
+
}, rotateMs);
|
|
5144
|
+
function show(i, fromClick = false) {
|
|
4059
5145
|
panes[idx].el.style.display = "none";
|
|
4060
|
-
idx = (
|
|
5146
|
+
idx = (i % panes.length + panes.length) % panes.length;
|
|
4061
5147
|
panes[idx].el.style.display = "";
|
|
4062
5148
|
markVisible(panes[idx].campaign);
|
|
4063
|
-
|
|
5149
|
+
paintDots();
|
|
5150
|
+
if (fromClick && timer) {
|
|
5151
|
+
clearInterval(timer);
|
|
5152
|
+
timer = start();
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
panes[0].el.style.display = "";
|
|
5156
|
+
markVisible(panes[0].campaign);
|
|
5157
|
+
paintDots();
|
|
5158
|
+
if (panes.length === 1) return;
|
|
5159
|
+
timer = start();
|
|
5160
|
+
this.slotTimers.set(slot, timer);
|
|
4064
5161
|
if (typeof window !== "undefined") {
|
|
4065
|
-
window.addEventListener("beforeunload", () => clearInterval(timer), { once: true });
|
|
5162
|
+
window.addEventListener("beforeunload", () => timer && clearInterval(timer), { once: true });
|
|
4066
5163
|
}
|
|
4067
5164
|
}
|
|
4068
5165
|
/**
|
|
@@ -4116,6 +5213,14 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4116
5213
|
target.querySelectorAll(":scope > [data-aegis-slot-default]").forEach((d) => d.remove());
|
|
4117
5214
|
}
|
|
4118
5215
|
}
|
|
5216
|
+
const spacing = Number(anchor == null ? void 0 : anchor.element_spacing);
|
|
5217
|
+
if (spacing > 0) {
|
|
5218
|
+
if (position === "before" || position === "after") {
|
|
5219
|
+
target.style.margin = `${spacing}px`;
|
|
5220
|
+
} else {
|
|
5221
|
+
target.style.padding = `${spacing}px`;
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
4119
5224
|
if (this.filledSlots.has(target)) continue;
|
|
4120
5225
|
this.renderCampaignIntoSlot(c, target);
|
|
4121
5226
|
this.filledSlots.add(target);
|
|
@@ -4198,6 +5303,13 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4198
5303
|
this.displayedCampaigns.add(campaign.id);
|
|
4199
5304
|
this.addAnimationStyles();
|
|
4200
5305
|
const ic = campaign.interactive_config || {};
|
|
5306
|
+
const inlineMul = this._sizeMul(ic);
|
|
5307
|
+
if (inlineMul !== 1) {
|
|
5308
|
+
const sizer = document.createElement("div");
|
|
5309
|
+
sizer.style.cssText = `transform: scale(${inlineMul}); transform-origin: top center;`;
|
|
5310
|
+
target.appendChild(sizer);
|
|
5311
|
+
target = sizer;
|
|
5312
|
+
}
|
|
4201
5313
|
const { bg, text } = this._surfacePalette(campaign);
|
|
4202
5314
|
const submitUrl = options == null ? void 0 : options.submitUrl;
|
|
4203
5315
|
const _formFields = Array.isArray(ic.form_fields) ? ic.form_fields : null;
|
|
@@ -4214,70 +5326,81 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4214
5326
|
}
|
|
4215
5327
|
return;
|
|
4216
5328
|
}
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
5329
|
+
const _tpl = ic.card_template;
|
|
5330
|
+
const _hasComposedTemplate = !!_tpl && typeof _tpl === "object" && Array.isArray(_tpl.elements);
|
|
5331
|
+
const _isMultiCard = campaign.sub_type === "product_recommendation" || campaign.sub_type === "carousel_cards";
|
|
5332
|
+
if (_hasComposedTemplate && !_isMultiCard) {
|
|
5333
|
+
rendered = this.renderComposedCardSlot(campaign, ic, target);
|
|
5334
|
+
} else if (campaign.widget_category === "hero") {
|
|
5335
|
+
rendered = renderHeroInline(this.buildRenderContext(campaign), target);
|
|
5336
|
+
} else
|
|
5337
|
+
switch (campaign.sub_type) {
|
|
5338
|
+
case "star_rating":
|
|
5339
|
+
rendered = this.renderStarRatingSlot(
|
|
5340
|
+
campaign,
|
|
5341
|
+
ic,
|
|
5342
|
+
bg,
|
|
5343
|
+
text,
|
|
5344
|
+
target,
|
|
5345
|
+
submitUrl
|
|
5346
|
+
);
|
|
5347
|
+
break;
|
|
5348
|
+
case "nps_survey":
|
|
5349
|
+
rendered = this.renderNPSSurveySlot(
|
|
5350
|
+
campaign,
|
|
5351
|
+
ic,
|
|
5352
|
+
bg,
|
|
5353
|
+
text,
|
|
5354
|
+
target,
|
|
5355
|
+
submitUrl
|
|
5356
|
+
);
|
|
5357
|
+
break;
|
|
5358
|
+
// Parity tracker — built-in embedded gamification renderers (no
|
|
5359
|
+
// AegisMessageRuntime callback needed, so they work on the bill).
|
|
5360
|
+
case "spin_wheel":
|
|
5361
|
+
rendered = this.renderSpinWheelSlot(campaign, ic, bg, text, target);
|
|
5362
|
+
break;
|
|
5363
|
+
case "quick_poll":
|
|
5364
|
+
rendered = this.renderQuickPollSlot(campaign, ic, bg, text, target);
|
|
5365
|
+
break;
|
|
5366
|
+
case "carousel_cards":
|
|
5367
|
+
rendered = this.renderCarouselCardsSlot(campaign, ic, bg, text, target);
|
|
5368
|
+
break;
|
|
5369
|
+
case "countdown_offer":
|
|
5370
|
+
rendered = this.renderCountdownSlot(campaign, ic, bg, text, target);
|
|
5371
|
+
break;
|
|
5372
|
+
case "scratch_card":
|
|
5373
|
+
rendered = this.renderScratchCardSlot(campaign, ic, bg, text, target);
|
|
5374
|
+
break;
|
|
5375
|
+
case "custom_html":
|
|
5376
|
+
rendered = this.renderCustomHtmlSlot(campaign, ic, bg, text, target);
|
|
5377
|
+
break;
|
|
5378
|
+
case "stories":
|
|
5379
|
+
rendered = renderStoriesRings(this.buildRenderContext(campaign), target);
|
|
5380
|
+
break;
|
|
5381
|
+
case "video":
|
|
5382
|
+
rendered = renderVideoInline(this.buildRenderContext(campaign), target);
|
|
5383
|
+
break;
|
|
5384
|
+
case "progress_bar":
|
|
5385
|
+
rendered = renderProgressBarInline(this.buildRenderContext(campaign), target);
|
|
5386
|
+
break;
|
|
5387
|
+
case "product_recommendation":
|
|
5388
|
+
rendered = renderProductRecommendationInline(this.buildRenderContext(campaign), target);
|
|
5389
|
+
break;
|
|
5390
|
+
case "quiz":
|
|
5391
|
+
rendered = this.renderQuizSlot(campaign, ic, bg, text, target);
|
|
5392
|
+
if (!rendered) {
|
|
5393
|
+
rendered = this.renderGenericCardSlot(campaign, ic, bg, text, target);
|
|
5394
|
+
}
|
|
5395
|
+
break;
|
|
5396
|
+
// Remaining sub_types (sticky_bar, progress_bar,
|
|
5397
|
+
// product_recommendation) render as a generic card on the bill slot
|
|
5398
|
+
// (overlay path handles their full UX); dedicated slot variants get added
|
|
5399
|
+
// here as merchants need them.
|
|
5400
|
+
default:
|
|
4270
5401
|
rendered = this.renderGenericCardSlot(campaign, ic, bg, text, target);
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
// Remaining sub_types (sticky_bar, progress_bar,
|
|
4274
|
-
// product_recommendation) render as a generic card on the bill slot
|
|
4275
|
-
// (overlay path handles their full UX); dedicated slot variants get added
|
|
4276
|
-
// here as merchants need them.
|
|
4277
|
-
default:
|
|
4278
|
-
rendered = this.renderGenericCardSlot(campaign, ic, bg, text, target);
|
|
4279
|
-
break;
|
|
4280
|
-
}
|
|
5402
|
+
break;
|
|
5403
|
+
}
|
|
4281
5404
|
if (!rendered) return;
|
|
4282
5405
|
if (!(options == null ? void 0 : options.deferImpression)) {
|
|
4283
5406
|
this.trackEvent(campaign.id, "impression");
|
|
@@ -4326,6 +5449,34 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4326
5449
|
* The catch-all for banner + nudge sub_types (birthday, referral, app-install,
|
|
4327
5450
|
* win-back, etc.) so EVERY gallery nudge renders on the bill (previously only
|
|
4328
5451
|
* star_rating / nps_survey / form were handled → nudges never appeared). */
|
|
5452
|
+
/**
|
|
5453
|
+
* Composed single card — renders a campaign's top-level `card_template`
|
|
5454
|
+
* (frame + elements: icon/text/progress/image/cta/group/…) through the generic
|
|
5455
|
+
* `renderCardFromTemplate` engine. The canonical path for the rich card editor:
|
|
5456
|
+
* the storefront value bar, loyalty nudges, and any operator-composed card all
|
|
5457
|
+
* render here from declarative JSON, on ACS / custom / third-party sites.
|
|
5458
|
+
*/
|
|
5459
|
+
renderComposedCardSlot(campaign, ic, target) {
|
|
5460
|
+
const c = campaign;
|
|
5461
|
+
const card = {
|
|
5462
|
+
image_url: typeof c.image_url === "string" ? c.image_url : void 0,
|
|
5463
|
+
title: campaign.title,
|
|
5464
|
+
body: campaign.body,
|
|
5465
|
+
cta_text: typeof c.button_text === "string" ? c.button_text : void 0,
|
|
5466
|
+
cta_url: typeof c.action_url === "string" ? c.action_url : void 0,
|
|
5467
|
+
metadata: ic.card_meta || {}
|
|
5468
|
+
};
|
|
5469
|
+
const template = resolveGlobalTemplate(ic);
|
|
5470
|
+
const { accent } = this._surfacePalette(campaign);
|
|
5471
|
+
const tile = renderCardFromTemplate(card, {
|
|
5472
|
+
template,
|
|
5473
|
+
ctx: this.buildRenderContext(campaign),
|
|
5474
|
+
action: "navigate",
|
|
5475
|
+
layoutAccent: this.sanitizeColor(campaign.background_color || accent)
|
|
5476
|
+
});
|
|
5477
|
+
target.appendChild(tile);
|
|
5478
|
+
return true;
|
|
5479
|
+
}
|
|
4329
5480
|
renderGenericCardSlot(campaign, ic, bg, text, target) {
|
|
4330
5481
|
const st = this._slotStyle(campaign);
|
|
4331
5482
|
const card = this._wrapInSlotCard("aegis-in-app-generic-card", campaign.id, bg, text, st.radius);
|
|
@@ -4341,6 +5492,45 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4341
5492
|
im.style.cssText = "width: 100%; height: 96px; object-fit: cover; display: block;";
|
|
4342
5493
|
card.appendChild(im);
|
|
4343
5494
|
}
|
|
5495
|
+
const widgetCat = typeof c.widget_category === "string" ? c.widget_category : "";
|
|
5496
|
+
if (widgetCat === "promo" && !img) {
|
|
5497
|
+
const row = document.createElement("div");
|
|
5498
|
+
row.style.cssText = `display:flex; align-items:center; gap:12px; min-height:46px; padding:${st.padY ?? 10}px ${st.padX ?? 14}px;`;
|
|
5499
|
+
const colL = document.createElement("div");
|
|
5500
|
+
colL.style.cssText = "flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:2px;";
|
|
5501
|
+
if (campaign.title) {
|
|
5502
|
+
const t = document.createElement("div");
|
|
5503
|
+
t.style.cssText = `font-size:13px; font-weight:${st.weight ?? "700"}; line-height:1.25; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;`;
|
|
5504
|
+
t.textContent = campaign.title;
|
|
5505
|
+
colL.appendChild(t);
|
|
5506
|
+
}
|
|
5507
|
+
if (campaign.body) {
|
|
5508
|
+
const b = document.createElement("div");
|
|
5509
|
+
b.style.cssText = "font-size:11.5px; opacity:0.7; line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;";
|
|
5510
|
+
b.textContent = campaign.body;
|
|
5511
|
+
colL.appendChild(b);
|
|
5512
|
+
}
|
|
5513
|
+
row.appendChild(colL);
|
|
5514
|
+
if (buttonText) {
|
|
5515
|
+
const btn = document.createElement("button");
|
|
5516
|
+
btn.type = "button";
|
|
5517
|
+
btn.textContent = buttonText;
|
|
5518
|
+
const accentTok = `var(--aegis-brand-accent, ${text})`;
|
|
5519
|
+
btn.style.cssText = `flex:0 0 auto; align-self:center; cursor:pointer; white-space:nowrap;background:color-mix(in srgb, ${accentTok} 12%, #fff); color:${accentTok}; border:none;border-radius:999px; padding:7px 16px; font-size:12.5px; font-weight:700;`;
|
|
5520
|
+
btn.addEventListener("click", () => {
|
|
5521
|
+
void this.trackEvent(campaign.id, "clicked");
|
|
5522
|
+
if (actionUrl) {
|
|
5523
|
+
window.open(actionUrl, "_blank", "noopener");
|
|
5524
|
+
} else if (typeof window !== "undefined") {
|
|
5525
|
+
window.dispatchEvent(new CustomEvent("aegis:open-login", { detail: { campaign_id: campaign.id } }));
|
|
5526
|
+
}
|
|
5527
|
+
});
|
|
5528
|
+
row.appendChild(btn);
|
|
5529
|
+
}
|
|
5530
|
+
card.appendChild(row);
|
|
5531
|
+
target.appendChild(card);
|
|
5532
|
+
return true;
|
|
5533
|
+
}
|
|
4344
5534
|
const cbody = document.createElement("div");
|
|
4345
5535
|
cbody.style.cssText = `padding: ${st.padY ?? 12}px ${st.padX ?? 12}px; display: flex; flex-direction: column; gap: 6px;`;
|
|
4346
5536
|
if (campaign.title) {
|
|
@@ -4484,8 +5674,14 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4484
5674
|
body.style.alignItems = "center";
|
|
4485
5675
|
body.style.justifyContent = "center";
|
|
4486
5676
|
const done = document.createElement("div");
|
|
4487
|
-
done.style.cssText = "padding: 8px 0; font-size: 13px; font-weight: 600; text-align: center;";
|
|
4488
|
-
|
|
5677
|
+
done.style.cssText = "padding: 8px 0; font-size: 13px; font-weight: 600; text-align: center; display: inline-flex; align-items: center; justify-content: center; gap: 6px;";
|
|
5678
|
+
const customThanks = typeof ((_a = campaign.interactive_config) == null ? void 0 : _a.thank_you_message) === "string" ? campaign.interactive_config.thank_you_message : null;
|
|
5679
|
+
if (customThanks) {
|
|
5680
|
+
done.textContent = customThanks;
|
|
5681
|
+
} else {
|
|
5682
|
+
done.innerHTML = lucideSvg("check", { size: 14 });
|
|
5683
|
+
done.appendChild(document.createTextNode("Thanks — your details are saved."));
|
|
5684
|
+
}
|
|
4489
5685
|
body.appendChild(done);
|
|
4490
5686
|
this._playReaction(body, "affirm", "check.json", campaign.interactive_config);
|
|
4491
5687
|
});
|
|
@@ -4618,6 +5814,8 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4618
5814
|
const hubImg = cfgStr("spin_hub_image_url");
|
|
4619
5815
|
const wheelBgImg = cfgStr("wheel_background_url");
|
|
4620
5816
|
const pointerImg = cfgStr("pointer_image_url");
|
|
5817
|
+
const pointerCenter = (cfgStr("spin_pointer_position") || "top") === "center";
|
|
5818
|
+
const pointerBase = pointerCenter ? "translate(-50%, -100%)" : "translateX(-50%)";
|
|
4621
5819
|
const isUrl = (s) => /^https?:\/\//i.test(s);
|
|
4622
5820
|
const now = () => typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
4623
5821
|
let rotation = 0;
|
|
@@ -4677,7 +5875,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4677
5875
|
vibrate(18);
|
|
4678
5876
|
};
|
|
4679
5877
|
const body = document.createElement("div");
|
|
4680
|
-
body.style.cssText = `padding: ${st.padY ?? 22}px ${st.padX ?? 20}px 20px; display: flex; flex-direction: column; align-items: center; gap:
|
|
5878
|
+
body.style.cssText = `padding: ${st.padY ?? 22}px ${st.padX ?? 20}px 20px; display: flex; flex-direction: column; align-items: center; gap: 10px;`;
|
|
4681
5879
|
if (campaign.title) {
|
|
4682
5880
|
const t = document.createElement("div");
|
|
4683
5881
|
t.style.cssText = `font-size: 18px; font-weight: 800; letter-spacing: -0.01em; text-align: center; font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif;`;
|
|
@@ -4695,11 +5893,55 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4695
5893
|
const wheelWrap = document.createElement("div");
|
|
4696
5894
|
wheelWrap.style.cssText = `position: relative; width: ${SIZE}px; height: ${SIZE}px; filter: drop-shadow(0 10px 22px rgba(0,0,0,0.30));`;
|
|
4697
5895
|
const pointer = document.createElement("div");
|
|
4698
|
-
|
|
5896
|
+
if (pointerCenter) {
|
|
5897
|
+
const needleH = Math.round(radius * 0.42);
|
|
5898
|
+
pointer.style.cssText = `position: absolute; left: 50%; top: 50%; width: 20px; height: ${needleH}px; transform: ${pointerBase}; transform-origin: 50% 100%; z-index: 6; pointer-events: none;`;
|
|
5899
|
+
if (pointerImg) {
|
|
5900
|
+
const pim = document.createElement("img");
|
|
5901
|
+
pim.src = pointerImg;
|
|
5902
|
+
pim.alt = "";
|
|
5903
|
+
pim.style.cssText = "width: 100%; height: 100%; object-fit: contain; object-position: top; display: block; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.4));";
|
|
5904
|
+
pointer.appendChild(pim);
|
|
5905
|
+
} else {
|
|
5906
|
+
const stem = document.createElement("div");
|
|
5907
|
+
stem.style.cssText = `position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); width: 4px; height: 100%; background: ${pointerColor}; border-radius: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.35);`;
|
|
5908
|
+
const head = document.createElement("div");
|
|
5909
|
+
head.style.cssText = `position: absolute; left: 50%; top: -1px; transform: translateX(-50%); width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-bottom: 14px solid ${pointerColor}; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.4));`;
|
|
5910
|
+
pointer.appendChild(stem);
|
|
5911
|
+
pointer.appendChild(head);
|
|
5912
|
+
}
|
|
5913
|
+
} else if (pointerImg) {
|
|
5914
|
+
pointer.style.cssText = `position: absolute; left: 50%; top: -12px; transform: ${pointerBase}; transform-origin: 50% 0; width: 30px; height: 34px; z-index: 5;`;
|
|
5915
|
+
const pim = document.createElement("img");
|
|
5916
|
+
pim.src = pointerImg;
|
|
5917
|
+
pim.alt = "";
|
|
5918
|
+
pim.style.cssText = "width: 100%; height: 100%; object-fit: contain; display: block; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.35));";
|
|
5919
|
+
pointer.appendChild(pim);
|
|
5920
|
+
} else {
|
|
5921
|
+
pointer.style.cssText = `position: absolute; left: 50%; top: -7px; transform: ${pointerBase}; transform-origin: 50% 0; width: 0; height: 0; border-left: 9px solid transparent; border-right: 9px solid transparent; border-top: 16px solid ${pointerColor}; z-index: 5; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.35));`;
|
|
5922
|
+
}
|
|
4699
5923
|
const wheel = document.createElement("div");
|
|
4700
5924
|
const wheelFace = wheelBgImg ? `center / cover no-repeat url("${wheelBgImg}")` : `conic-gradient(${stops})`;
|
|
4701
|
-
|
|
5925
|
+
const wheelRim = wheelBgImg ? "0" : "5px solid #ffffff";
|
|
5926
|
+
const wheelShadow = wheelBgImg ? `0 0 0 2px ${text}2e` : `0 0 0 2px ${text}2e, inset 0 0 22px rgba(0,0,0,0.20)`;
|
|
5927
|
+
wheel.style.cssText = `position: relative; width: ${SIZE}px; height: ${SIZE}px; border-radius: 50%; border: ${wheelRim}; box-shadow: ${wheelShadow}; background: ${wheelFace}; overflow: hidden; will-change: transform; touch-action: none; cursor: ${spinMode === "button" ? "default" : "grab"};`;
|
|
4702
5928
|
if (idleAnim === "wobble") wheel.style.animation = "aegisSpinWobble 3s ease-in-out infinite";
|
|
5929
|
+
const sliceImgFrac = Math.max(40, Math.min(100, Number(ic.spin_slice_image_size) || 100)) / 100;
|
|
5930
|
+
if (!wheelBgImg) shown.forEach((s, i) => {
|
|
5931
|
+
const simg = typeof s.image_url === "string" ? s.image_url : "";
|
|
5932
|
+
if (!simg || !isUrl(simg)) return;
|
|
5933
|
+
const pts = ["50% 50%"];
|
|
5934
|
+
const steps = Math.max(2, Math.ceil(spans[i] / 6));
|
|
5935
|
+
for (let st2 = 0; st2 <= steps; st2++) {
|
|
5936
|
+
const a = (starts[i] + spans[i] * st2 / steps) * Math.PI / 180;
|
|
5937
|
+
const x = 50 + 50 * sliceImgFrac * Math.sin(a);
|
|
5938
|
+
const y = 50 - 50 * sliceImgFrac * Math.cos(a);
|
|
5939
|
+
pts.push(`${x.toFixed(2)}% ${y.toFixed(2)}%`);
|
|
5940
|
+
}
|
|
5941
|
+
const segEl = document.createElement("div");
|
|
5942
|
+
segEl.style.cssText = `position: absolute; inset: 0; background: center / cover no-repeat url("${simg}"); clip-path: polygon(${pts.join(",")}); pointer-events: none;`;
|
|
5943
|
+
wheel.appendChild(segEl);
|
|
5944
|
+
});
|
|
4703
5945
|
if (!wheelBgImg) starts.forEach((b) => {
|
|
4704
5946
|
const ln = document.createElement("div");
|
|
4705
5947
|
ln.style.cssText = `position: absolute; left: 50%; top: 0; width: 1.5px; height: 50%; background: rgba(255,255,255,0.55); transform-origin: bottom center; transform: translateX(-50%) rotate(${b}deg); pointer-events: none;`;
|
|
@@ -4711,17 +5953,6 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4711
5953
|
const rText = (rHub + rRim) / 2;
|
|
4712
5954
|
if (!wheelBgImg) labels.forEach((label, i) => {
|
|
4713
5955
|
const mid = midOf(i);
|
|
4714
|
-
const wedgeImg = shown[i] && typeof shown[i].image_url === "string" ? shown[i].image_url : "";
|
|
4715
|
-
if (wedgeImg && isUrl(wedgeImg)) {
|
|
4716
|
-
const flipImg = mid > 180 && mid < 360;
|
|
4717
|
-
const isz = Math.max(18, Math.min(40, bandLen * 0.62));
|
|
4718
|
-
const wim = document.createElement("img");
|
|
4719
|
-
wim.src = wedgeImg;
|
|
4720
|
-
wim.alt = label || "";
|
|
4721
|
-
wim.style.cssText = `position: absolute; left: 50%; top: 50%; width: ${isz}px; height: ${isz}px; object-fit: contain; transform: translate(-50%, -50%) rotate(${mid}deg) translateY(-${rText}px) rotate(${flipImg ? 90 : -90}deg); filter: drop-shadow(0 1px 3px rgba(0,0,0,0.55)); pointer-events: none;`;
|
|
4722
|
-
wheel.appendChild(wim);
|
|
4723
|
-
return;
|
|
4724
|
-
}
|
|
4725
5956
|
const icoVal = shown[i] && typeof shown[i].icon === "string" ? shown[i].icon : "";
|
|
4726
5957
|
const chord = 2 * rText * Math.sin(spans[i] * Math.PI / 180 / 2);
|
|
4727
5958
|
const byThickness = chord * 0.6;
|
|
@@ -4765,28 +5996,13 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4765
5996
|
const hub = document.createElement("div");
|
|
4766
5997
|
hub.style.cssText = `position: absolute; left: 50%; top: 50%; width: 40px; height: 40px; transform: translate(-50%, -50%); border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ffffff, #e9edf5); border: 3px solid #fff; box-shadow: 0 3px 8px rgba(0,0,0,0.30); z-index: 4; overflow: hidden; display: flex; align-items: center; justify-content: center;`;
|
|
4767
5998
|
if (hubImg) {
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
hc.style.cssText = "width: 100%; height: 100%;";
|
|
4772
|
-
const hcx = hc.getContext("2d");
|
|
4773
|
-
const him = new Image();
|
|
4774
|
-
him.crossOrigin = "anonymous";
|
|
4775
|
-
him.onload = () => {
|
|
4776
|
-
if (!hcx) return;
|
|
4777
|
-
const ar = him.width / him.height || 1;
|
|
4778
|
-
let w = 32, h = 32;
|
|
4779
|
-
if (ar > 1) h = 32 / ar;
|
|
4780
|
-
else w = 32 * ar;
|
|
4781
|
-
hcx.drawImage(him, (40 - w) / 2, (40 - h) / 2, w, h);
|
|
4782
|
-
hcx.globalCompositeOperation = "source-in";
|
|
4783
|
-
hcx.fillStyle = "#5b626e";
|
|
4784
|
-
hcx.fillRect(0, 0, 40, 40);
|
|
4785
|
-
};
|
|
4786
|
-
him.onerror = () => {
|
|
4787
|
-
};
|
|
5999
|
+
hub.style.border = "none";
|
|
6000
|
+
hub.style.background = "transparent";
|
|
6001
|
+
const him = document.createElement("img");
|
|
4788
6002
|
him.src = hubImg;
|
|
4789
|
-
|
|
6003
|
+
him.alt = "";
|
|
6004
|
+
him.style.cssText = "width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block;";
|
|
6005
|
+
hub.appendChild(him);
|
|
4790
6006
|
} else {
|
|
4791
6007
|
const hubDot = document.createElement("div");
|
|
4792
6008
|
hubDot.style.cssText = `width: 11px; height: 11px; border-radius: 50%; background: ${bg};`;
|
|
@@ -4800,22 +6016,22 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4800
6016
|
body.appendChild(wheelWrap);
|
|
4801
6017
|
if (!card.style.position) card.style.position = "relative";
|
|
4802
6018
|
const result = document.createElement("div");
|
|
4803
|
-
result.style.cssText = "font-size: 14px; font-weight: 800; min-height:
|
|
6019
|
+
result.style.cssText = "font-size: 14px; font-weight: 800; min-height: 0; text-align: center; letter-spacing: 0.2px;";
|
|
4804
6020
|
if (ic.spin_sound_enabled !== false) {
|
|
4805
6021
|
const soundBtn = document.createElement("button");
|
|
4806
6022
|
soundBtn.type = "button";
|
|
4807
6023
|
soundBtn.setAttribute("aria-label", "Toggle sound");
|
|
4808
|
-
soundBtn.
|
|
6024
|
+
soundBtn.innerHTML = lucideSvg(soundOn ? "volume-2" : "volume-x", { size: 15 });
|
|
4809
6025
|
soundBtn.style.cssText = "position: absolute; top: 10px; left: 12px; background: transparent; border: none; font-size: 15px; cursor: pointer; opacity: 0.65; z-index: 6; line-height: 1;";
|
|
4810
6026
|
soundBtn.addEventListener("click", () => {
|
|
4811
6027
|
soundOn = !soundOn;
|
|
4812
|
-
soundBtn.
|
|
6028
|
+
soundBtn.innerHTML = lucideSvg(soundOn ? "volume-2" : "volume-x", { size: 15 });
|
|
4813
6029
|
});
|
|
4814
6030
|
card.appendChild(soundBtn);
|
|
4815
6031
|
}
|
|
4816
6032
|
const btn = document.createElement("button");
|
|
4817
6033
|
btn.textContent = campaign.button_text || "Spin the wheel";
|
|
4818
|
-
btn.style.cssText = `padding:
|
|
6034
|
+
btn.style.cssText = `padding: 9px 22px; border-radius: 999px; border: none; background: ${text}; color: ${bg}; font-size: 13px; font-weight: 700; letter-spacing: 0.2px; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.20); transition: transform 0.15s, box-shadow 0.15s; font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif;`;
|
|
4819
6035
|
btn.addEventListener("mouseenter", () => {
|
|
4820
6036
|
if (btn.disabled) return;
|
|
4821
6037
|
btn.style.transform = "translateY(-1px)";
|
|
@@ -4844,12 +6060,12 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4844
6060
|
pVel *= 0.7;
|
|
4845
6061
|
pDefl += pVel;
|
|
4846
6062
|
if (Math.abs(pDefl) > 0.06 || Math.abs(pVel) > 0.06) {
|
|
4847
|
-
pointer.style.transform =
|
|
6063
|
+
pointer.style.transform = `${pointerBase} rotate(${pDefl.toFixed(2)}deg)`;
|
|
4848
6064
|
pointerRaf = requestAnimationFrame(stepPointer);
|
|
4849
6065
|
} else {
|
|
4850
6066
|
pDefl = 0;
|
|
4851
6067
|
pVel = 0;
|
|
4852
|
-
pointer.style.transform =
|
|
6068
|
+
pointer.style.transform = `${pointerBase} rotate(0deg)`;
|
|
4853
6069
|
pointerRaf = 0;
|
|
4854
6070
|
}
|
|
4855
6071
|
};
|
|
@@ -4924,7 +6140,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4924
6140
|
var _a;
|
|
4925
6141
|
try {
|
|
4926
6142
|
void ((_a = navigator.clipboard) == null ? void 0 : _a.writeText(r.code));
|
|
4927
|
-
chip.textContent = "Copied
|
|
6143
|
+
chip.textContent = "Copied";
|
|
4928
6144
|
} catch {
|
|
4929
6145
|
}
|
|
4930
6146
|
});
|
|
@@ -4970,7 +6186,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4970
6186
|
var _a;
|
|
4971
6187
|
try {
|
|
4972
6188
|
void ((_a = navigator.clipboard) == null ? void 0 : _a.writeText(r.code));
|
|
4973
|
-
chip.textContent = "Copied
|
|
6189
|
+
chip.textContent = "Copied";
|
|
4974
6190
|
} catch {
|
|
4975
6191
|
}
|
|
4976
6192
|
});
|
|
@@ -5211,7 +6427,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5211
6427
|
pctLabel.textContent = `${pct}%`;
|
|
5212
6428
|
pctLabel.style.opacity = "0.8";
|
|
5213
6429
|
} else if (pctLabel && i === selected) {
|
|
5214
|
-
pctLabel.
|
|
6430
|
+
pctLabel.innerHTML = lucideSvg("check", { size: 14 });
|
|
5215
6431
|
pctLabel.style.opacity = "0.8";
|
|
5216
6432
|
}
|
|
5217
6433
|
});
|
|
@@ -5234,59 +6450,18 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5234
6450
|
}
|
|
5235
6451
|
const strip = document.createElement("div");
|
|
5236
6452
|
strip.style.cssText = `display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x mandatory; padding: ${st.padY ?? 12}px ${st.padX ?? 12}px;`;
|
|
6453
|
+
const template = resolveGlobalTemplate(ic);
|
|
6454
|
+
const ctx = this.buildRenderContext(campaign);
|
|
6455
|
+
const accent = this.sanitizeColor(campaign.background_color || text);
|
|
5237
6456
|
cards.forEach((c, i) => {
|
|
5238
|
-
const tile =
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
v.muted = true;
|
|
5247
|
-
v.loop = true;
|
|
5248
|
-
v.autoplay = true;
|
|
5249
|
-
v.playsInline = true;
|
|
5250
|
-
v.setAttribute("playsinline", "");
|
|
5251
|
-
v.style.cssText = "width: 100%; height: 90px; object-fit: cover; display: block;";
|
|
5252
|
-
tile.appendChild(v);
|
|
5253
|
-
} else if (imageUrl) {
|
|
5254
|
-
const im = document.createElement("img");
|
|
5255
|
-
im.src = imageUrl;
|
|
5256
|
-
im.alt = "";
|
|
5257
|
-
im.loading = "lazy";
|
|
5258
|
-
im.style.cssText = "width: 100%; height: 90px; object-fit: cover; display: block;";
|
|
5259
|
-
tile.appendChild(im);
|
|
5260
|
-
}
|
|
5261
|
-
const tb = document.createElement("div");
|
|
5262
|
-
tb.style.cssText = "padding: 0 8px 8px; display: flex; flex-direction: column; gap: 4px;";
|
|
5263
|
-
if (typeof c.title === "string" && c.title) {
|
|
5264
|
-
const tt = document.createElement("div");
|
|
5265
|
-
tt.style.cssText = "font-size: 12px; font-weight: 600; line-height: 1.3;";
|
|
5266
|
-
tt.textContent = c.title;
|
|
5267
|
-
tb.appendChild(tt);
|
|
5268
|
-
}
|
|
5269
|
-
if (typeof c.body === "string" && c.body) {
|
|
5270
|
-
const tbd = document.createElement("div");
|
|
5271
|
-
tbd.style.cssText = "font-size: 10.5px; opacity: 0.72; line-height: 1.3;";
|
|
5272
|
-
tbd.textContent = c.body;
|
|
5273
|
-
tb.appendChild(tbd);
|
|
5274
|
-
}
|
|
5275
|
-
const ctaText = typeof c.cta_text === "string" ? c.cta_text : "";
|
|
5276
|
-
if (ctaText && ctaUrl) {
|
|
5277
|
-
const cta = document.createElement("button");
|
|
5278
|
-
cta.textContent = ctaText;
|
|
5279
|
-
cta.style.cssText = `margin-top: auto; align-self: flex-start; background: ${text}; color: ${bg}; border: none; padding: 5px 10px; border-radius: ${st.btnRadius ?? 999}px; font-size: 11px; font-weight: 600; cursor: pointer;`;
|
|
5280
|
-
const goto = (e) => {
|
|
5281
|
-
e.stopPropagation();
|
|
5282
|
-
void this.trackEvent(campaign.id, "clicked", { stepId: `card_${i}` });
|
|
5283
|
-
window.open(ctaUrl, "_blank", "noopener");
|
|
5284
|
-
};
|
|
5285
|
-
cta.addEventListener("click", goto);
|
|
5286
|
-
tile.addEventListener("click", goto);
|
|
5287
|
-
tb.appendChild(cta);
|
|
5288
|
-
}
|
|
5289
|
-
tile.appendChild(tb);
|
|
6457
|
+
const tile = renderCardFromTemplate(c, {
|
|
6458
|
+
template,
|
|
6459
|
+
ctx,
|
|
6460
|
+
action: "navigate",
|
|
6461
|
+
layout: "row",
|
|
6462
|
+
layoutAccent: accent
|
|
6463
|
+
});
|
|
6464
|
+
tile.setAttribute("data-card-index", String(i));
|
|
5290
6465
|
strip.appendChild(tile);
|
|
5291
6466
|
});
|
|
5292
6467
|
card.appendChild(strip);
|
|
@@ -5383,6 +6558,34 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5383
6558
|
target.appendChild(card);
|
|
5384
6559
|
return true;
|
|
5385
6560
|
}
|
|
6561
|
+
/** Foil palette — a brushed-metal gradient + a contrast "ink" (for the
|
|
6562
|
+
* SCRATCH-HERE text, sparkle motif, and logo tint) derived from the operator's
|
|
6563
|
+
* chosen foil colour (brand primary / custom hex). Unset / invalid → the
|
|
6564
|
+
* default silver. Light foils get dark ink, dark foils get white ink, so the
|
|
6565
|
+
* prompt stays legible on any colour. */
|
|
6566
|
+
_scratchFoilPalette(hex) {
|
|
6567
|
+
const clean = (hex || "").trim().replace(/^#/, "");
|
|
6568
|
+
if (!/^[0-9a-fA-F]{6}$/.test(clean)) {
|
|
6569
|
+
return { g0: "#d7dbe2", g1: "#b4bac4", g2: "#c9cdd6", ink: "#6b7280" };
|
|
6570
|
+
}
|
|
6571
|
+
const r = parseInt(clean.slice(0, 2), 16);
|
|
6572
|
+
const g = parseInt(clean.slice(2, 4), 16);
|
|
6573
|
+
const b = parseInt(clean.slice(4, 6), 16);
|
|
6574
|
+
const toward = (amt) => {
|
|
6575
|
+
const m2 = (c) => Math.round(c + (255 - c) * amt);
|
|
6576
|
+
return `rgb(${m2(r)}, ${m2(g)}, ${m2(b)})`;
|
|
6577
|
+
};
|
|
6578
|
+
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
6579
|
+
return {
|
|
6580
|
+
g0: toward(0.34),
|
|
6581
|
+
// bright sheen
|
|
6582
|
+
g1: `#${clean}`,
|
|
6583
|
+
// base colour
|
|
6584
|
+
g2: toward(0.18),
|
|
6585
|
+
// soft sheen
|
|
6586
|
+
ink: lum > 0.62 ? "#5b6270" : "rgba(255,255,255,0.92)"
|
|
6587
|
+
};
|
|
6588
|
+
}
|
|
5386
6589
|
/** Built-in embedded SCRATCH CARD — a canvas foil the customer scratches to
|
|
5387
6590
|
* reveal the server-picked prize, then submits (records + grants). Confetti
|
|
5388
6591
|
* on reveal. No AegisMessageRuntime callback dependency (works on the bill). */
|
|
@@ -5400,6 +6603,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5400
6603
|
let soundOn = ic.scratch_sound_enabled !== false;
|
|
5401
6604
|
const revealImg = cfgStr("reveal_image_url");
|
|
5402
6605
|
const foilImg = cfgStr("scratch_foil_image_url");
|
|
6606
|
+
const foilPal = this._scratchFoilPalette(cfgStr("scratch_foil_color"));
|
|
5403
6607
|
const pool = Array.isArray(ic.prize_pool) ? ic.prize_pool : [];
|
|
5404
6608
|
const isUrl = (s) => /^https?:\/\//i.test(s);
|
|
5405
6609
|
const sampleWin = pool.find(
|
|
@@ -5509,11 +6713,11 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5509
6713
|
const sb = document.createElement("button");
|
|
5510
6714
|
sb.type = "button";
|
|
5511
6715
|
sb.setAttribute("aria-label", "Toggle sound");
|
|
5512
|
-
sb.
|
|
6716
|
+
sb.innerHTML = lucideSvg(soundOn ? "volume-2" : "volume-x", { size: 15 });
|
|
5513
6717
|
sb.style.cssText = "position: absolute; top: 10px; left: 12px; background: transparent; border: none; font-size: 15px; cursor: pointer; opacity: 0.65; z-index: 6; line-height: 1;";
|
|
5514
6718
|
sb.addEventListener("click", () => {
|
|
5515
6719
|
soundOn = !soundOn;
|
|
5516
|
-
sb.
|
|
6720
|
+
sb.innerHTML = lucideSvg(soundOn ? "volume-2" : "volume-x", { size: 15 });
|
|
5517
6721
|
});
|
|
5518
6722
|
card.appendChild(sb);
|
|
5519
6723
|
}
|
|
@@ -5542,9 +6746,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5542
6746
|
if (!ctx) return;
|
|
5543
6747
|
ctx.globalCompositeOperation = "source-over";
|
|
5544
6748
|
const foil = ctx.createLinearGradient(0, 0, CW, CH);
|
|
5545
|
-
foil.addColorStop(0,
|
|
5546
|
-
foil.addColorStop(0.5,
|
|
5547
|
-
foil.addColorStop(1,
|
|
6749
|
+
foil.addColorStop(0, foilPal.g0);
|
|
6750
|
+
foil.addColorStop(0.5, foilPal.g1);
|
|
6751
|
+
foil.addColorStop(1, foilPal.g2);
|
|
5548
6752
|
ctx.fillStyle = foil;
|
|
5549
6753
|
ctx.fillRect(0, 0, CW, CH);
|
|
5550
6754
|
ctx.textAlign = "center";
|
|
@@ -5553,17 +6757,19 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5553
6757
|
ctx.globalAlpha = 0.6;
|
|
5554
6758
|
ctx.drawImage(logo, (CW - logo.width) / 2, CH * 0.42 - logo.height / 2, logo.width, logo.height);
|
|
5555
6759
|
ctx.globalAlpha = 1;
|
|
5556
|
-
ctx.fillStyle =
|
|
6760
|
+
ctx.fillStyle = foilPal.ink;
|
|
5557
6761
|
ctx.font = "700 12px system-ui, sans-serif";
|
|
5558
6762
|
ctx.fillText("SCRATCH HERE", CW / 2, CH * 0.84);
|
|
5559
6763
|
} else {
|
|
5560
|
-
ctx.
|
|
6764
|
+
ctx.globalAlpha = 0.22;
|
|
6765
|
+
ctx.fillStyle = foilPal.ink;
|
|
5561
6766
|
ctx.font = "12px system-ui, sans-serif";
|
|
5562
6767
|
for (let gy = 18; gy < CH; gy += 30) {
|
|
5563
6768
|
const off = (gy / 30 | 0) % 2 ? 16 : 0;
|
|
5564
6769
|
for (let gx = 16 + off; gx < CW; gx += 32) ctx.fillText("✦", gx, gy);
|
|
5565
6770
|
}
|
|
5566
|
-
ctx.
|
|
6771
|
+
ctx.globalAlpha = 1;
|
|
6772
|
+
ctx.fillStyle = foilPal.ink;
|
|
5567
6773
|
ctx.font = "700 13px system-ui, sans-serif";
|
|
5568
6774
|
ctx.fillText("SCRATCH HERE", CW / 2, CH / 2);
|
|
5569
6775
|
}
|
|
@@ -5590,7 +6796,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5590
6796
|
if (!lctx) return;
|
|
5591
6797
|
lctx.drawImage(im, 0, 0, lc.width, lc.height);
|
|
5592
6798
|
lctx.globalCompositeOperation = "source-in";
|
|
5593
|
-
lctx.fillStyle =
|
|
6799
|
+
lctx.fillStyle = foilPal.ink;
|
|
5594
6800
|
lctx.fillRect(0, 0, lc.width, lc.height);
|
|
5595
6801
|
paintFoil(lc);
|
|
5596
6802
|
};
|
|
@@ -5680,7 +6886,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5680
6886
|
var _a;
|
|
5681
6887
|
try {
|
|
5682
6888
|
void ((_a = navigator.clipboard) == null ? void 0 : _a.writeText(code));
|
|
5683
|
-
chip.textContent = "Copied
|
|
6889
|
+
chip.textContent = "Copied";
|
|
5684
6890
|
} catch {
|
|
5685
6891
|
}
|
|
5686
6892
|
});
|
|
@@ -5868,6 +7074,19 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5868
7074
|
`;
|
|
5869
7075
|
return card;
|
|
5870
7076
|
}
|
|
7077
|
+
/**
|
|
7078
|
+
* Flush a rendered slot card into its host card — drop the per-campaign radius
|
|
7079
|
+
* + shadow so it reads as one unit with the host wrapper (used for the
|
|
7080
|
+
* storefront value bar via `data-aegis-slot-flush`). Targets every
|
|
7081
|
+
* `[data-campaign-id]` card inside `container` (or the container itself).
|
|
7082
|
+
*/
|
|
7083
|
+
_flattenSlotCard(container) {
|
|
7084
|
+
const cards = container.matches("[data-campaign-id]") ? [container] : Array.from(container.querySelectorAll("[data-campaign-id]"));
|
|
7085
|
+
for (const el of cards) {
|
|
7086
|
+
el.style.borderRadius = "0";
|
|
7087
|
+
el.style.boxShadow = "none";
|
|
7088
|
+
}
|
|
7089
|
+
}
|
|
5871
7090
|
// Optional header/brand image atop a survey-style widget (star / nps).
|
|
5872
7091
|
_appendHeaderImage(body, ic) {
|
|
5873
7092
|
const url = ic.header_image_url;
|
|
@@ -6309,12 +7528,18 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6309
7528
|
}
|
|
6310
7529
|
}
|
|
6311
7530
|
displayCampaign(campaign) {
|
|
7531
|
+
if (Array.isArray(campaign.delivery_modes) && campaign.delivery_modes.length > 0 && !campaign.delivery_modes.includes("in_app_overlay")) {
|
|
7532
|
+
return;
|
|
7533
|
+
}
|
|
6312
7534
|
const proceed = this.emit("campaign-will-show", campaign);
|
|
6313
7535
|
if (!proceed) {
|
|
6314
7536
|
this.log(`campaign ${campaign.id} suppressed by campaign-will-show handler`);
|
|
6315
7537
|
return;
|
|
6316
7538
|
}
|
|
6317
7539
|
this.displayedCampaigns.add(campaign.id);
|
|
7540
|
+
this._displaySizeMul = this._sizeMul(
|
|
7541
|
+
campaign.interactive_config
|
|
7542
|
+
);
|
|
6318
7543
|
const interactiveSubTypes = /* @__PURE__ */ new Set([
|
|
6319
7544
|
"spin_wheel",
|
|
6320
7545
|
"scratch_card",
|
|
@@ -6435,6 +7660,16 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6435
7660
|
return {
|
|
6436
7661
|
campaign,
|
|
6437
7662
|
getCartState: this.getCartState,
|
|
7663
|
+
properties: () => {
|
|
7664
|
+
var _a, _b;
|
|
7665
|
+
const cart = (_a = this.getCartState) == null ? void 0 : _a.call(this);
|
|
7666
|
+
const ctxObj = ((_b = campaign.interactive_config) == null ? void 0 : _b.card_context) || {};
|
|
7667
|
+
return {
|
|
7668
|
+
"cart.total": cart == null ? void 0 : cart.total,
|
|
7669
|
+
"cart.count": cart == null ? void 0 : cart.itemCount,
|
|
7670
|
+
...ctxObj
|
|
7671
|
+
};
|
|
7672
|
+
},
|
|
6438
7673
|
trackEvent: (id, evt, extra) => {
|
|
6439
7674
|
void this.trackEvent(id, evt, extra);
|
|
6440
7675
|
},
|
|
@@ -6507,6 +7742,14 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6507
7742
|
* slot renderers (`renderSpinWheelSlot` / `renderScratchCardSlot`) in a modal
|
|
6508
7743
|
* so the gamified widget is fully playable — not a dead frame.
|
|
6509
7744
|
*/
|
|
7745
|
+
/** Display-size multiplier — operator control over how big a bounded overlay
|
|
7746
|
+
* renders (small 0.82 / medium 1 / large 1.18). Default medium = prior size.
|
|
7747
|
+
* Read from interactive_config.display_size; mirrors the schema enum + the
|
|
7748
|
+
* dashboard preview harness so the operator's choice is honored identically. */
|
|
7749
|
+
_sizeMul(ic) {
|
|
7750
|
+
const s = ic && typeof ic.display_size === "string" ? ic.display_size : "medium";
|
|
7751
|
+
return s === "small" ? 0.82 : s === "large" ? 1.18 : 1;
|
|
7752
|
+
}
|
|
6510
7753
|
renderGamificationOverlay(campaign, ic, bg, text) {
|
|
6511
7754
|
const overlay = this.createOverlay(`aegis-in-app-${campaign.sub_type}-overlay`);
|
|
6512
7755
|
const modal = document.createElement("div");
|
|
@@ -6521,7 +7764,11 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6521
7764
|
this.renderSpinWheelSlot(campaign, ic, bg, text, modal);
|
|
6522
7765
|
}
|
|
6523
7766
|
this._addCornerClose(modal, overlay, campaign.id, text);
|
|
6524
|
-
|
|
7767
|
+
const mul = this._sizeMul(ic);
|
|
7768
|
+
const sizer = document.createElement("div");
|
|
7769
|
+
sizer.style.cssText = `display: flex; justify-content: center; align-items: center; width: 100%; transform: scale(${mul}); transform-origin: center;`;
|
|
7770
|
+
sizer.appendChild(modal);
|
|
7771
|
+
overlay.appendChild(sizer);
|
|
6525
7772
|
this.addAnimationStyles();
|
|
6526
7773
|
document.body.appendChild(overlay);
|
|
6527
7774
|
}
|
|
@@ -6533,7 +7780,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6533
7780
|
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>'
|
|
6534
7781
|
);
|
|
6535
7782
|
if (closeIcon) x.appendChild(closeIcon);
|
|
6536
|
-
else x.
|
|
7783
|
+
else x.innerHTML = lucideSvg("x", { size: 14 });
|
|
6537
7784
|
x.style.cssText = `
|
|
6538
7785
|
position: absolute; top: 12px; right: 12px; z-index: 4; width: 28px; height: 28px;
|
|
6539
7786
|
display: flex; align-items: center; justify-content: center; border: none;
|
|
@@ -7184,8 +8431,30 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7184
8431
|
background: rgba(0,0,0,0.5); display: flex; align-items: center;
|
|
7185
8432
|
justify-content: center; z-index: 99999; animation: aegisFadeIn 0.3s ease;
|
|
7186
8433
|
`;
|
|
8434
|
+
if (this._displaySizeMul !== 1) {
|
|
8435
|
+
const mul = this._displaySizeMul;
|
|
8436
|
+
queueMicrotask(() => {
|
|
8437
|
+
const card = overlay.firstElementChild;
|
|
8438
|
+
if (!card || card.dataset.aegisSized) return;
|
|
8439
|
+
card.dataset.aegisSized = "1";
|
|
8440
|
+
const wrap = document.createElement("div");
|
|
8441
|
+
wrap.style.cssText = `display: flex; align-items: center; justify-content: center; transform: scale(${mul}); transform-origin: center;`;
|
|
8442
|
+
overlay.insertBefore(wrap, card);
|
|
8443
|
+
wrap.appendChild(card);
|
|
8444
|
+
});
|
|
8445
|
+
}
|
|
7187
8446
|
return overlay;
|
|
7188
8447
|
}
|
|
8448
|
+
/** Wrap a card in a display-size scaling container (no-op at medium/×1). Used
|
|
8449
|
+
* by formats that build their overlay inline (renderModal) rather than via
|
|
8450
|
+
* createOverlay, so size is honored identically. */
|
|
8451
|
+
_wrapScaled(card) {
|
|
8452
|
+
if (this._displaySizeMul === 1) return card;
|
|
8453
|
+
const wrap = document.createElement("div");
|
|
8454
|
+
wrap.style.cssText = `display: flex; align-items: center; justify-content: center; transform: scale(${this._displaySizeMul}); transform-origin: center;`;
|
|
8455
|
+
wrap.appendChild(card);
|
|
8456
|
+
return wrap;
|
|
8457
|
+
}
|
|
7189
8458
|
createCTAButton(campaign, bg, text) {
|
|
7190
8459
|
const btn = document.createElement("button");
|
|
7191
8460
|
btn.className = "aegis-cta";
|
|
@@ -7349,12 +8618,17 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7349
8618
|
_surfacePalette(campaign) {
|
|
7350
8619
|
const ic = campaign.interactive_config || {};
|
|
7351
8620
|
const brand = this.sanitizeColor(campaign.background_color || "#4169e1");
|
|
7352
|
-
const
|
|
7353
|
-
if (branded) {
|
|
8621
|
+
const surface = ic.surface_style;
|
|
8622
|
+
if (surface === "branded") {
|
|
7354
8623
|
const bg = brand;
|
|
7355
8624
|
const text = campaign.text_color ? this.sanitizeColor(campaign.text_color) : "#ffffff";
|
|
7356
8625
|
return { bg, text, btnBg: text, btnText: bg, accent: text, branded: true };
|
|
7357
8626
|
}
|
|
8627
|
+
if (surface === "dark") {
|
|
8628
|
+
const bg = this.sanitizeColor(campaign.background_color || "#0f172a");
|
|
8629
|
+
const text = campaign.text_color ? this.sanitizeColor(campaign.text_color) : "#ffffff";
|
|
8630
|
+
return { bg, text, btnBg: "#ffffff", btnText: bg, accent: text, branded: false };
|
|
8631
|
+
}
|
|
7358
8632
|
return { bg: "#ffffff", text: "#0f172a", btnBg: brand, btnText: this._contrastText(brand), accent: brand, branded: false };
|
|
7359
8633
|
}
|
|
7360
8634
|
inAppStyle(campaign) {
|
|
@@ -7458,7 +8732,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7458
8732
|
actionsContainer.appendChild(ctaButton);
|
|
7459
8733
|
}
|
|
7460
8734
|
const closeButton = document.createElement("button");
|
|
7461
|
-
closeButton.
|
|
8735
|
+
closeButton.innerHTML = lucideSvg("x", { size: 18 });
|
|
7462
8736
|
closeButton.setAttribute("aria-label", "Close");
|
|
7463
8737
|
closeButton.style.cssText = `
|
|
7464
8738
|
background: transparent;
|
|
@@ -7618,7 +8892,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7618
8892
|
actions.appendChild(closeButton);
|
|
7619
8893
|
content.appendChild(actions);
|
|
7620
8894
|
modal.appendChild(content);
|
|
7621
|
-
overlay.appendChild(modal);
|
|
8895
|
+
overlay.appendChild(this._wrapScaled(modal));
|
|
7622
8896
|
if (ic.modal_dismiss_on_overlay !== false) {
|
|
7623
8897
|
overlay.addEventListener("click", (e) => {
|
|
7624
8898
|
if (e.target === overlay) {
|
|
@@ -7656,7 +8930,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7656
8930
|
pill.replaceChildren();
|
|
7657
8931
|
const ic = document.createElement("span");
|
|
7658
8932
|
ic.style.fontSize = "13px";
|
|
7659
|
-
ic.
|
|
8933
|
+
ic.innerHTML = lucideSvg(v.muted ? "volume-x" : "volume-2", { size: 13 });
|
|
7660
8934
|
pill.appendChild(ic);
|
|
7661
8935
|
if (v.muted) {
|
|
7662
8936
|
const t = document.createElement("span");
|
|
@@ -7786,7 +9060,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7786
9060
|
}
|
|
7787
9061
|
overlay.appendChild(contentContainer);
|
|
7788
9062
|
const closeButton = document.createElement("button");
|
|
7789
|
-
closeButton.
|
|
9063
|
+
closeButton.innerHTML = lucideSvg("x", { size: isBg ? 18 : 28 });
|
|
7790
9064
|
closeButton.setAttribute("aria-label", "Close");
|
|
7791
9065
|
closeButton.style.cssText = `
|
|
7792
9066
|
position: absolute; top: 20px; right: 20px; z-index: 3; background: ${isBg ? "rgba(0,0,0,0.45)" : "transparent"};
|
|
@@ -7914,7 +9188,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7914
9188
|
}
|
|
7915
9189
|
modal.appendChild(content);
|
|
7916
9190
|
const closeButton = document.createElement("button");
|
|
7917
|
-
closeButton.
|
|
9191
|
+
closeButton.innerHTML = lucideSvg("x", { size: 22 });
|
|
7918
9192
|
closeButton.setAttribute("aria-label", "Close");
|
|
7919
9193
|
closeButton.style.cssText = `
|
|
7920
9194
|
position: absolute;
|
|
@@ -7987,16 +9261,16 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7987
9261
|
const ic = campaign.interactive_config || {};
|
|
7988
9262
|
const variant = ic.alert_variant || "";
|
|
7989
9263
|
const VARIANTS = {
|
|
7990
|
-
info: {
|
|
7991
|
-
success: {
|
|
7992
|
-
warning: {
|
|
7993
|
-
error: {
|
|
9264
|
+
info: { icon: "info", color: "#3b82f6" },
|
|
9265
|
+
success: { icon: "check", color: "#10b981" },
|
|
9266
|
+
warning: { icon: "triangle-alert", color: "#f59e0b" },
|
|
9267
|
+
error: { icon: "x", color: "#ef4444" }
|
|
7994
9268
|
};
|
|
7995
9269
|
const vspec = VARIANTS[variant];
|
|
7996
9270
|
if (vspec) {
|
|
7997
9271
|
const badge = document.createElement("div");
|
|
7998
9272
|
badge.style.cssText = `width: 48px; height: 48px; border-radius: 50%; margin: 0 auto 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 800; background: ${vspec.color}22; color: ${vspec.color};`;
|
|
7999
|
-
badge.
|
|
9273
|
+
badge.innerHTML = lucideSvg(vspec.icon, { size: 24 });
|
|
8000
9274
|
content.appendChild(badge);
|
|
8001
9275
|
}
|
|
8002
9276
|
const title = document.createElement("h3");
|
|
@@ -8138,7 +9412,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8138
9412
|
if (!hasMedia) {
|
|
8139
9413
|
const placeholder = document.createElement("div");
|
|
8140
9414
|
placeholder.style.cssText = "width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #1f2937, #0f172a); color: rgba(255,255,255,0.35); font-size: 34px;";
|
|
8141
|
-
placeholder.
|
|
9415
|
+
placeholder.innerHTML = lucideSvg("play", { size: 34 });
|
|
8142
9416
|
mediaWrap.appendChild(placeholder);
|
|
8143
9417
|
}
|
|
8144
9418
|
pip.appendChild(mediaWrap);
|
|
@@ -8149,7 +9423,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8149
9423
|
playGlyph.setAttribute("aria-label", "Play or pause");
|
|
8150
9424
|
playGlyph.style.cssText = "position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 52px; height: 52px; border-radius: 50%; border: none; background: rgba(0,0,0,0.45); color: #fff; font-size: 22px; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.25s ease; backdrop-filter: blur(2px);";
|
|
8151
9425
|
const syncGlyph = () => {
|
|
8152
|
-
playGlyph.
|
|
9426
|
+
playGlyph.innerHTML = lucideSvg(v.paused ? "play" : "pause", { size: 22 });
|
|
8153
9427
|
playGlyph.style.opacity = v.paused ? "1" : "0";
|
|
8154
9428
|
};
|
|
8155
9429
|
const togglePlay = () => {
|
|
@@ -8176,7 +9450,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8176
9450
|
mutePill.replaceChildren();
|
|
8177
9451
|
const ic2 = document.createElement("span");
|
|
8178
9452
|
ic2.style.fontSize = "13px";
|
|
8179
|
-
ic2.
|
|
9453
|
+
ic2.innerHTML = lucideSvg(v.muted ? "volume-x" : "volume-2", { size: 13 });
|
|
8180
9454
|
mutePill.appendChild(ic2);
|
|
8181
9455
|
if (v.muted) {
|
|
8182
9456
|
const t = document.createElement("span");
|
|
@@ -8271,7 +9545,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8271
9545
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
8272
9546
|
`;
|
|
8273
9547
|
if (expandBtn) {
|
|
8274
|
-
expandBtn.
|
|
9548
|
+
expandBtn.innerHTML = lucideSvg("x", { size: 16 });
|
|
8275
9549
|
expandBtn.setAttribute("aria-label", "Minimize");
|
|
8276
9550
|
}
|
|
8277
9551
|
if (video && video.muted) {
|
|
@@ -8294,7 +9568,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8294
9568
|
}
|
|
8295
9569
|
const closeButton = document.createElement("button");
|
|
8296
9570
|
closeButton.type = "button";
|
|
8297
|
-
closeButton.
|
|
9571
|
+
closeButton.innerHTML = lucideSvg("x", { size: 16 });
|
|
8298
9572
|
closeButton.setAttribute("aria-label", "Close");
|
|
8299
9573
|
closeButton.style.cssText = ctrlBtnCss;
|
|
8300
9574
|
closeButton.addEventListener("click", (e) => {
|
|
@@ -9054,7 +10328,7 @@ _AegisInAppManager.KNOWN_SURFACES = /* @__PURE__ */ new Set([
|
|
|
9054
10328
|
]);
|
|
9055
10329
|
_AegisInAppManager.SERVED_DEDUP_PREFIX = "aegis_served_fired:";
|
|
9056
10330
|
let AegisInAppManager = _AegisInAppManager;
|
|
9057
|
-
function renderPreview(config) {
|
|
10331
|
+
function renderPreview(config, opts) {
|
|
9058
10332
|
document.querySelectorAll(
|
|
9059
10333
|
'[class^="aegis-in-app-"]'
|
|
9060
10334
|
).forEach((el) => {
|
|
@@ -9078,12 +10352,33 @@ function renderPreview(config) {
|
|
|
9078
10352
|
writeKey: "preview-mode",
|
|
9079
10353
|
apiHost: "",
|
|
9080
10354
|
debugMode: false,
|
|
9081
|
-
enableSSE: false
|
|
10355
|
+
enableSSE: false,
|
|
10356
|
+
...(opts == null ? void 0 : opts.cart) ? { getCartState: () => opts.cart } : {}
|
|
9082
10357
|
});
|
|
9083
10358
|
const m2 = manager;
|
|
9084
10359
|
m2.trackEvent = async () => {
|
|
9085
10360
|
};
|
|
9086
10361
|
m2.addAnimationStyles();
|
|
10362
|
+
const cfgRec = config;
|
|
10363
|
+
const deliveryModes = Array.isArray(cfgRec.delivery_modes) ? cfgRec.delivery_modes : [];
|
|
10364
|
+
const widgetCategory = typeof cfgRec.widget_category === "string" ? cfgRec.widget_category : "";
|
|
10365
|
+
const inline = deliveryModes.includes("embedded_card") && !!widgetCategory;
|
|
10366
|
+
const coGroup = (opts == null ? void 0 : opts.coGroup) ?? [];
|
|
10367
|
+
if (typeof document !== "undefined" && (coGroup.length > 0 || inline)) {
|
|
10368
|
+
const anchors = document.querySelectorAll("[data-aegis-slot]");
|
|
10369
|
+
if (anchors.length > 0) {
|
|
10370
|
+
try {
|
|
10371
|
+
anchors.forEach((slot) => {
|
|
10372
|
+
slot.querySelectorAll(":scope > :not([data-aegis-slot-default])").forEach((el) => el.remove());
|
|
10373
|
+
});
|
|
10374
|
+
const mm = manager;
|
|
10375
|
+
mm.campaigns = (inline ? [config, ...coGroup] : coGroup).map((c) => ({ ...c, surface: void 0, target_screens: void 0 })).sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
10376
|
+
mm.renderIntoSlots();
|
|
10377
|
+
if (inline) return;
|
|
10378
|
+
} catch {
|
|
10379
|
+
}
|
|
10380
|
+
}
|
|
10381
|
+
}
|
|
9087
10382
|
if (config.type === "stories" || config.sub_type === "stories") {
|
|
9088
10383
|
const host = document.createElement("div");
|
|
9089
10384
|
host.className = "aegis-in-app-stories-host";
|
|
@@ -9293,13 +10588,29 @@ function evaluateRule(rule, snapshot, namespaces) {
|
|
|
9293
10588
|
const result = evaluateExpr(rule.when, snapshot, namespaces);
|
|
9294
10589
|
return result === true;
|
|
9295
10590
|
}
|
|
9296
|
-
class
|
|
10591
|
+
const _IntentRuleEvaluator = class _IntentRuleEvaluator {
|
|
9297
10592
|
constructor() {
|
|
9298
10593
|
this.armed = [];
|
|
9299
10594
|
this.snapshot = {};
|
|
9300
10595
|
this.namespaces = {};
|
|
9301
10596
|
this.firedThisSession = /* @__PURE__ */ new Set();
|
|
9302
10597
|
this.silencedThisSession = /* @__PURE__ */ new Set();
|
|
10598
|
+
this.oneInterruptionPerSession = false;
|
|
10599
|
+
this.interruptiveBudgetSpent = false;
|
|
10600
|
+
this.ttfiMs = 0;
|
|
10601
|
+
this.sessionStartMs = Date.now();
|
|
10602
|
+
this.nowFn = () => Date.now();
|
|
10603
|
+
}
|
|
10604
|
+
/** Tune governance. `now` also (re)bases the TTFI session clock. */
|
|
10605
|
+
setGovernance(opts) {
|
|
10606
|
+
if (opts.oneInterruptionPerSession !== void 0) {
|
|
10607
|
+
this.oneInterruptionPerSession = opts.oneInterruptionPerSession;
|
|
10608
|
+
}
|
|
10609
|
+
if (opts.ttfiMs !== void 0) this.ttfiMs = opts.ttfiMs;
|
|
10610
|
+
if (opts.now) {
|
|
10611
|
+
this.nowFn = opts.now;
|
|
10612
|
+
this.sessionStartMs = opts.now();
|
|
10613
|
+
}
|
|
9303
10614
|
}
|
|
9304
10615
|
// ─── snapshot management ───
|
|
9305
10616
|
updateSignal(signal, value) {
|
|
@@ -9335,12 +10646,15 @@ class IntentRuleEvaluator {
|
|
|
9335
10646
|
}
|
|
9336
10647
|
markFired(campaignId) {
|
|
9337
10648
|
this.firedThisSession.add(campaignId);
|
|
10649
|
+
this.interruptiveBudgetSpent = true;
|
|
9338
10650
|
}
|
|
9339
10651
|
/** Clear all per-session state. Caller invokes on logout or explicit
|
|
9340
10652
|
* session reset. */
|
|
9341
10653
|
reset() {
|
|
9342
10654
|
this.firedThisSession.clear();
|
|
9343
10655
|
this.silencedThisSession.clear();
|
|
10656
|
+
this.interruptiveBudgetSpent = false;
|
|
10657
|
+
this.sessionStartMs = this.nowFn();
|
|
9344
10658
|
}
|
|
9345
10659
|
// ─── the main dispatch ───
|
|
9346
10660
|
/**
|
|
@@ -9363,6 +10677,11 @@ class IntentRuleEvaluator {
|
|
|
9363
10677
|
* 5. If nothing matches, return 'none'.
|
|
9364
10678
|
*/
|
|
9365
10679
|
onSignalChanged(signal) {
|
|
10680
|
+
if (this.oneInterruptionPerSession && this.interruptiveBudgetSpent) {
|
|
10681
|
+
return { kind: "none" };
|
|
10682
|
+
}
|
|
10683
|
+
const sessionElapsedMs = this.nowFn() - this.sessionStartMs;
|
|
10684
|
+
const exemptFromTtfi = _IntentRuleEvaluator.EXIT_SIGNALS.includes(signal);
|
|
9366
10685
|
const candidates = this.armed.filter((c) => c.rule.fire_on.includes(signal)).filter((c) => !this.firedThisSession.has(c.id)).filter((c) => !this.silencedThisSession.has(c.id)).sort((a, b) => {
|
|
9367
10686
|
if (b.rule.priority !== a.rule.priority) {
|
|
9368
10687
|
return b.rule.priority - a.rule.priority;
|
|
@@ -9372,6 +10691,9 @@ class IntentRuleEvaluator {
|
|
|
9372
10691
|
for (let i = 0; i < candidates.length; i++) {
|
|
9373
10692
|
const c = candidates[i];
|
|
9374
10693
|
if (!evaluateRule(c.rule, this.snapshot, this.namespaces)) continue;
|
|
10694
|
+
if (this.ttfiMs > 0 && sessionElapsedMs < this.ttfiMs && !exemptFromTtfi) {
|
|
10695
|
+
continue;
|
|
10696
|
+
}
|
|
9375
10697
|
if (c.rule.suppress_competing) {
|
|
9376
10698
|
const suppressIds = this.armed.filter((other) => other.id !== c.id).map((other) => other.id);
|
|
9377
10699
|
suppressIds.forEach((id) => this.silencedThisSession.add(id));
|
|
@@ -9385,7 +10707,12 @@ class IntentRuleEvaluator {
|
|
|
9385
10707
|
}
|
|
9386
10708
|
return { kind: "none" };
|
|
9387
10709
|
}
|
|
9388
|
-
}
|
|
10710
|
+
};
|
|
10711
|
+
_IntentRuleEvaluator.EXIT_SIGNALS = [
|
|
10712
|
+
"exit_intent",
|
|
10713
|
+
"back_button"
|
|
10714
|
+
];
|
|
10715
|
+
let IntentRuleEvaluator = _IntentRuleEvaluator;
|
|
9389
10716
|
class ContactScoresFetcher {
|
|
9390
10717
|
constructor(cfg) {
|
|
9391
10718
|
this.lastFetchedAt = 0;
|
|
@@ -9739,7 +11066,7 @@ class PrefetchBundleClient {
|
|
|
9739
11066
|
}
|
|
9740
11067
|
let response;
|
|
9741
11068
|
try {
|
|
9742
|
-
response = await fetch(url, { method: "GET", headers });
|
|
11069
|
+
response = await fetch(url, { method: "GET", headers, cache: "no-cache" });
|
|
9743
11070
|
} catch (err) {
|
|
9744
11071
|
logger.warn("prefetch-bundle fetch network error:", err);
|
|
9745
11072
|
return this.currentBundle;
|
|
@@ -10764,8 +12091,8 @@ class AegisWidgetManager {
|
|
|
10764
12091
|
{ label: "Prize 3", color: "#48dbfb" },
|
|
10765
12092
|
{ label: "Prize 4", color: "#ff6348" }
|
|
10766
12093
|
];
|
|
10767
|
-
const
|
|
10768
|
-
const wheel = document.createElementNS(
|
|
12094
|
+
const SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
12095
|
+
const wheel = document.createElementNS(SVG_NS2, "svg");
|
|
10769
12096
|
wheel.setAttribute("viewBox", "-160 -160 320 320");
|
|
10770
12097
|
wheel.setAttribute("width", "300");
|
|
10771
12098
|
wheel.setAttribute("height", "300");
|
|
@@ -10781,7 +12108,7 @@ class AegisWidgetManager {
|
|
|
10781
12108
|
const x2 = Math.cos(end) * radius;
|
|
10782
12109
|
const y2 = Math.sin(end) * radius;
|
|
10783
12110
|
const largeArc = anglePer > Math.PI ? 1 : 0;
|
|
10784
|
-
const path = document.createElementNS(
|
|
12111
|
+
const path = document.createElementNS(SVG_NS2, "path");
|
|
10785
12112
|
path.setAttribute(
|
|
10786
12113
|
"d",
|
|
10787
12114
|
`M 0 0 L ${x1.toFixed(2)} ${y1.toFixed(2)} A ${radius} ${radius} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)} Z`
|
|
@@ -10793,7 +12120,7 @@ class AegisWidgetManager {
|
|
|
10793
12120
|
const labelAngle = start + anglePer / 2;
|
|
10794
12121
|
const lx = Math.cos(labelAngle) * radius * 0.65;
|
|
10795
12122
|
const ly = Math.sin(labelAngle) * radius * 0.65;
|
|
10796
|
-
const text = document.createElementNS(
|
|
12123
|
+
const text = document.createElementNS(SVG_NS2, "text");
|
|
10797
12124
|
text.setAttribute("x", lx.toFixed(2));
|
|
10798
12125
|
text.setAttribute("y", ly.toFixed(2));
|
|
10799
12126
|
text.setAttribute("fill", "#ffffff");
|
|
@@ -10905,7 +12232,8 @@ class AegisWidgetManager {
|
|
|
10905
12232
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
10906
12233
|
`;
|
|
10907
12234
|
const closeBtn = document.createElement("button");
|
|
10908
|
-
closeBtn.innerHTML = "
|
|
12235
|
+
closeBtn.innerHTML = lucideSvg("x", { size: 16 });
|
|
12236
|
+
closeBtn.setAttribute("aria-label", "Close");
|
|
10909
12237
|
closeBtn.className = "aegis-spin-wheel-close";
|
|
10910
12238
|
closeBtn.style.cssText = `
|
|
10911
12239
|
position: absolute;
|
|
@@ -11885,8 +13213,9 @@ class AegisWidgetManager {
|
|
|
11885
13213
|
}
|
|
11886
13214
|
if (config.show_timer && config.timer_minutes) {
|
|
11887
13215
|
const timer = document.createElement("div");
|
|
11888
|
-
timer.style.cssText = "margin: 0 0 24px 0;
|
|
11889
|
-
timer.
|
|
13216
|
+
timer.style.cssText = "margin: 0 0 24px 0; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 14px; color: #999;";
|
|
13217
|
+
timer.innerHTML = lucideSvg("clock", { size: 14 });
|
|
13218
|
+
timer.appendChild(document.createTextNode(`Offer expires in ${config.timer_minutes} minutes`));
|
|
11890
13219
|
modal.appendChild(timer);
|
|
11891
13220
|
}
|
|
11892
13221
|
const ctaButton = document.createElement("button");
|
|
@@ -12017,7 +13346,7 @@ class AegisWidgetManager {
|
|
|
12017
13346
|
});
|
|
12018
13347
|
modal.innerHTML = `
|
|
12019
13348
|
<div style="text-align: center; padding: 20px;">
|
|
12020
|
-
<div style="
|
|
13349
|
+
<div style="margin-bottom: 16px; color: #10b981;">${lucideSvg("check", { size: 48 })}</div>
|
|
12021
13350
|
<h3 style="margin: 0 0 12px 0; color: #1a73e8;">Thank You!</h3>
|
|
12022
13351
|
<p style="margin: 0; color: #666;">Check your email for your discount code!</p>
|
|
12023
13352
|
</div>
|
|
@@ -12263,6 +13592,9 @@ class AegisMessageRuntime {
|
|
|
12263
13592
|
getCartState: () => this.deriveCartState()
|
|
12264
13593
|
});
|
|
12265
13594
|
this.intentRuleEvaluator = new IntentRuleEvaluator();
|
|
13595
|
+
if (config.governance) {
|
|
13596
|
+
this.intentRuleEvaluator.setGovernance(config.governance);
|
|
13597
|
+
}
|
|
12266
13598
|
this.contactScores = new ContactScoresFetcher({
|
|
12267
13599
|
// Falls back to same-origin when no apiHost configured (storefront
|
|
12268
13600
|
// typical case) — matches WidgetManager/InAppManager handling
|
|
@@ -12592,10 +13924,13 @@ export {
|
|
|
12592
13924
|
TriggerEngine,
|
|
12593
13925
|
U as UserNamespace,
|
|
12594
13926
|
bootstrap,
|
|
13927
|
+
closeChat,
|
|
12595
13928
|
debounce,
|
|
12596
13929
|
aegis as default,
|
|
12597
13930
|
deriveDeviceFingerprint,
|
|
13931
|
+
getCurrentLauncher,
|
|
12598
13932
|
m as murmurhash3_x86_32,
|
|
13933
|
+
openChat,
|
|
12599
13934
|
readFirstPartyCookie,
|
|
12600
13935
|
renderPreview,
|
|
12601
13936
|
throttle,
|