@spectare-personalisation/react 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +224 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +159 -5
- package/dist/index.d.ts +159 -5
- package/dist/index.js +212 -38
- package/dist/index.js.map +1 -1
- package/dist/tokens.css +78 -0
- package/dist/tokens.css.map +1 -0
- package/dist/tokens.d.cts +2 -0
- package/dist/tokens.d.ts +2 -0
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -13,6 +13,7 @@ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
|
|
|
13
13
|
|
|
14
14
|
// src/types.ts
|
|
15
15
|
var COMPONENT_ZONES = {
|
|
16
|
+
AnnouncementBar: "announce",
|
|
16
17
|
HeroStatement: "hero",
|
|
17
18
|
ImageCtaHero: "hero",
|
|
18
19
|
AtomCard: "body",
|
|
@@ -30,12 +31,83 @@ function filterAssemblyByZone(assembly, zone) {
|
|
|
30
31
|
return effectiveZone === zone;
|
|
31
32
|
});
|
|
32
33
|
}
|
|
34
|
+
|
|
35
|
+
// src/tokens.ts
|
|
36
|
+
var DEFAULT_ACCENT = "#60a5fa";
|
|
37
|
+
var SP_ROOT = "sp-root";
|
|
38
|
+
function palette(accent) {
|
|
39
|
+
return {
|
|
40
|
+
"--sp-accent": accent,
|
|
41
|
+
"--sp-accent-bg": `color-mix(in srgb,${accent} 10%,transparent)`,
|
|
42
|
+
"--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`,
|
|
43
|
+
"--sp-bg": "#18181b",
|
|
44
|
+
"--sp-surface": "#09090b",
|
|
45
|
+
"--sp-border": "#27272a",
|
|
46
|
+
"--sp-text": "#f4f4f5",
|
|
47
|
+
"--sp-text-sub": "#d4d4d8",
|
|
48
|
+
"--sp-text-strong": "#e4e4e7",
|
|
49
|
+
"--sp-text-muted": "#82828b",
|
|
50
|
+
"--sp-text-dim": "#6b6b74",
|
|
51
|
+
"--sp-text-body": "#a1a1aa",
|
|
52
|
+
"--sp-positive": "#6ee7b7",
|
|
53
|
+
"--sp-cta-bg": "#fff",
|
|
54
|
+
"--sp-cta-text": "#09090b",
|
|
55
|
+
"--sp-divider": "rgba(255,255,255,0.06)",
|
|
56
|
+
"--sp-code-bg": "rgba(255,255,255,0.07)",
|
|
57
|
+
"--sp-code-border": "rgba(255,255,255,0.08)",
|
|
58
|
+
"--sp-pre-bg": "rgba(0,0,0,0.4)"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function rules(unit) {
|
|
62
|
+
const gap = unit === "px" ? "20px" : "1.25rem";
|
|
63
|
+
return [
|
|
64
|
+
".sp-root .sp-prose p{margin-bottom:.625rem}",
|
|
65
|
+
".sp-root .sp-prose p:last-child{margin-bottom:0}",
|
|
66
|
+
".sp-root .sp-prose ul{list-style:disc;padding-left:1.25rem;margin-bottom:.625rem}",
|
|
67
|
+
".sp-root .sp-prose ol{list-style:decimal;padding-left:1.25rem;margin-bottom:.625rem}",
|
|
68
|
+
".sp-root .sp-prose li{margin-bottom:.25rem}",
|
|
69
|
+
".sp-root .sp-prose strong{color:var(--sp-text-strong);font-weight:600}",
|
|
70
|
+
".sp-root .sp-prose h2,.sp-root .sp-prose h3{color:var(--sp-text);font-weight:600;margin:.875rem 0 .375rem;font-size:1rem}",
|
|
71
|
+
".sp-root .sp-prose code{background:var(--sp-code-bg);border:1px solid var(--sp-code-border);padding:.1rem .35rem;border-radius:.25rem;font-size:.82em;color:var(--sp-text)}",
|
|
72
|
+
".sp-root .sp-prose blockquote{border-left:3px solid var(--sp-border);padding-left:1rem;color:var(--sp-text-muted);margin:.75rem 0}",
|
|
73
|
+
`.sp-root .sp-pair{display:grid;grid-template-columns:1fr 1fr;gap:${gap}}`,
|
|
74
|
+
"@media(max-width:640px){.sp-root .sp-pair{grid-template-columns:1fr}}"
|
|
75
|
+
].join("");
|
|
76
|
+
}
|
|
77
|
+
function buildTokenCss({ accent = DEFAULT_ACCENT, unit = "px", scope = `.${SP_ROOT}` } = {}) {
|
|
78
|
+
const decls = Object.entries(palette(accent)).map(([k, v]) => `${k}:${v}`).join(";");
|
|
79
|
+
return `${scope}{${decls}}${rules(unit)}`;
|
|
80
|
+
}
|
|
33
81
|
function renderMarkdown(content) {
|
|
34
82
|
const raw = marked.marked.parse(content != null ? content : "", { async: false });
|
|
35
83
|
return DOMPurify__default.default.sanitize(raw, { USE_PROFILES: { html: true } });
|
|
36
84
|
}
|
|
37
85
|
var HALF_COMPONENTS = /* @__PURE__ */ new Set(["TestimonialCard"]);
|
|
38
86
|
var flexItems = (a) => a === "center" ? "center" : a === "right" ? "flex-end" : "flex-start";
|
|
87
|
+
function AnnouncementBar({ text, link }) {
|
|
88
|
+
if (!text) return null;
|
|
89
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
90
|
+
display: "flex",
|
|
91
|
+
alignItems: "center",
|
|
92
|
+
justifyContent: "center",
|
|
93
|
+
gap: "10px",
|
|
94
|
+
flexWrap: "wrap",
|
|
95
|
+
textAlign: "center",
|
|
96
|
+
background: "var(--sp-accent-bg)",
|
|
97
|
+
border: "1px solid var(--sp-accent-border)",
|
|
98
|
+
borderRadius: "8px",
|
|
99
|
+
padding: "8px 16px",
|
|
100
|
+
fontSize: "14px",
|
|
101
|
+
lineHeight: 1.4,
|
|
102
|
+
color: "var(--sp-text-sub)"
|
|
103
|
+
}, children: [
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: text }),
|
|
105
|
+
(link == null ? void 0 : link.href) && (link == null ? void 0 : link.label) && /* @__PURE__ */ jsxRuntime.jsxs("a", { href: link.href, style: { color: "var(--sp-accent)", fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" }, children: [
|
|
106
|
+
link.label,
|
|
107
|
+
" \u2192"
|
|
108
|
+
] })
|
|
109
|
+
] });
|
|
110
|
+
}
|
|
39
111
|
function HeroStatement({ headline, subheading, align = "left" }) {
|
|
40
112
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: flexItems(align), textAlign: align, paddingTop: "24px", paddingBottom: "24px" }, children: [
|
|
41
113
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontSize: "32px", fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2, color: "var(--sp-text)", margin: "0 0 12px" }, children: headline }),
|
|
@@ -43,11 +115,18 @@ function HeroStatement({ headline, subheading, align = "left" }) {
|
|
|
43
115
|
] });
|
|
44
116
|
}
|
|
45
117
|
var ATOM_LAYOUT_DEFAULT = ["title", "content", "stats", "cta"];
|
|
46
|
-
|
|
118
|
+
var ATOM_CLAMP_LINES = 4;
|
|
119
|
+
var clampStyle = {
|
|
120
|
+
display: "-webkit-box",
|
|
121
|
+
WebkitLineClamp: ATOM_CLAMP_LINES,
|
|
122
|
+
WebkitBoxOrient: "vertical",
|
|
123
|
+
overflow: "hidden"
|
|
124
|
+
};
|
|
125
|
+
function AtomCard({ title, content, layout, stats = [], ctaText, ctaUrl, full }) {
|
|
47
126
|
const order = layout && layout.length ? layout : ATOM_LAYOUT_DEFAULT;
|
|
48
127
|
const element = (name) => {
|
|
49
128
|
if (name === "title") return title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "16px", fontWeight: 600, color: "var(--sp-text)", margin: "0 0 12px" }, children: title }, "title") : null;
|
|
50
|
-
if (name === "content") return content ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sp-prose", style: { fontSize: "15px", color: "var(--sp-text-sub)", lineHeight: 1.6 }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } }, "content") : null;
|
|
129
|
+
if (name === "content") return content ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sp-prose", style: { fontSize: "15px", color: "var(--sp-text-sub)", lineHeight: 1.6, ...full ? {} : clampStyle }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } }, "content") : null;
|
|
51
130
|
if (name === "stats") return stats.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "20px", margin: "0 0 12px", paddingBottom: "12px", borderBottom: "1px solid var(--sp-border)" }, children: stats.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
|
|
52
131
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "22px", fontWeight: 700, color: "var(--sp-text)", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: s.value }),
|
|
53
132
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "11px", color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
|
|
@@ -135,7 +214,7 @@ function CtaStrip({ headline, primary, secondary, align = "center" }) {
|
|
|
135
214
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "12px", padding: "32px", textAlign: align, background: "var(--sp-bg)" }, children: [
|
|
136
215
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "24px", fontWeight: 700, color: "var(--sp-text)", margin: "0 0 24px" }, children: headline }),
|
|
137
216
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: flexItems(align), gap: "16px", flexWrap: "wrap" }, children: [
|
|
138
|
-
/* @__PURE__ */ jsxRuntime.jsx("a", { href: primary.href, style: { background: "
|
|
217
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: primary.href, style: { background: "var(--sp-cta-bg)", color: "var(--sp-cta-text)", padding: "10px 24px", borderRadius: "12px", fontWeight: 600, fontSize: "15px", textDecoration: "none" }, children: primary.label }),
|
|
139
218
|
secondary && /* @__PURE__ */ jsxRuntime.jsxs("a", { href: secondary.href, style: { fontSize: "15px", color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
|
|
140
219
|
secondary.label,
|
|
141
220
|
" \u2192"
|
|
@@ -147,10 +226,13 @@ function renderSingle(item, brand, align) {
|
|
|
147
226
|
var _a, _b;
|
|
148
227
|
const s = (_a = item.slots) != null ? _a : {};
|
|
149
228
|
switch (item.component) {
|
|
229
|
+
case "AnnouncementBar":
|
|
230
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AnnouncementBar, { text: s.text, link: s.link });
|
|
150
231
|
case "HeroStatement":
|
|
151
232
|
return /* @__PURE__ */ jsxRuntime.jsx(HeroStatement, { headline: s.headline, subheading: s.subheading, align });
|
|
233
|
+
// A full-width card has nothing beside it, so there is nothing for a clamp to protect.
|
|
152
234
|
case "AtomCard":
|
|
153
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AtomCard, { title: s.title, content: s.content, layout: s.layout, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl });
|
|
235
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AtomCard, { title: s.title, content: s.content, layout: s.layout, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: s.full || resolvedSize(item) === "full" });
|
|
154
236
|
case "StatGrid":
|
|
155
237
|
return /* @__PURE__ */ jsxRuntime.jsx(StatGrid, { stats: s.stats, caption: s.caption });
|
|
156
238
|
case "CodeBlock":
|
|
@@ -165,8 +247,20 @@ function renderSingle(item, brand, align) {
|
|
|
165
247
|
return /* @__PURE__ */ jsxRuntime.jsx(ImageCtaHero, { src: s.src, alt: s.alt, headline: s.headline, subheading: s.subheading, ctaLabel: s.ctaLabel, ctaHref: s.ctaHref, align });
|
|
166
248
|
case "CtaStrip":
|
|
167
249
|
return /* @__PURE__ */ jsxRuntime.jsx(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary, align });
|
|
168
|
-
|
|
169
|
-
|
|
250
|
+
// An unrecognised component name used to render nothing at all. A component needs a
|
|
251
|
+
// renderer in three places plus the WordPress plugin, so missing one made its content
|
|
252
|
+
// silently absent on that surface only: no error, no warning, just a shorter page that
|
|
253
|
+
// looks deliberate. That is the failure mode to remove before the registry grows.
|
|
254
|
+
//
|
|
255
|
+
// Falls back to AtomCard when the slots carry something readable, since almost every
|
|
256
|
+
// component is built from an atom and title/content is the shape they share. When there
|
|
257
|
+
// is genuinely nothing to show it still renders nothing, because an empty card is worse
|
|
258
|
+
// than a gap, but the warning fires either way.
|
|
259
|
+
default: {
|
|
260
|
+
console.warn(`[spectare] ComponentRenderer: no renderer for "${item.component}", falling back to AtomCard`);
|
|
261
|
+
if (!s.title && !s.content) return null;
|
|
262
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AtomCard, { title: s.title, content: s.content, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: true });
|
|
263
|
+
}
|
|
170
264
|
}
|
|
171
265
|
}
|
|
172
266
|
function resolvedSize(item) {
|
|
@@ -198,12 +292,11 @@ function XrayBadge({ name, size }) {
|
|
|
198
292
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "10px", fontFamily: "monospace", color: "#71717a", lineHeight: 1 }, children: size })
|
|
199
293
|
] });
|
|
200
294
|
}
|
|
201
|
-
|
|
202
|
-
function ComponentRenderer({ assembly, brand, xray = false, zone, align }) {
|
|
295
|
+
function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent }) {
|
|
203
296
|
const filtered = zone ? filterAssemblyByZone(assembly, zone) : assembly;
|
|
204
297
|
const layout = buildLayout(filtered);
|
|
205
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "20px", fontSize: "16px" }, children: [
|
|
206
|
-
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html:
|
|
298
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: SP_ROOT, style: { display: "flex", flexDirection: "column", gap: "20px", fontSize: "16px" }, children: [
|
|
299
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent }) } }),
|
|
207
300
|
layout.map((group, i) => {
|
|
208
301
|
if (group.type === "full") {
|
|
209
302
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
@@ -230,7 +323,20 @@ function ComponentRenderer({ assembly, brand, xray = false, zone, align }) {
|
|
|
230
323
|
})
|
|
231
324
|
] });
|
|
232
325
|
}
|
|
233
|
-
var
|
|
326
|
+
var VARIANT_KEY = (orgSlug) => `_spectare_variant_${orgSlug}`;
|
|
327
|
+
function readVariantId(orgSlug) {
|
|
328
|
+
try {
|
|
329
|
+
return sessionStorage.getItem(VARIANT_KEY(orgSlug));
|
|
330
|
+
} catch (e) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function writeVariantId(orgSlug, variantId) {
|
|
335
|
+
try {
|
|
336
|
+
sessionStorage.setItem(VARIANT_KEY(orgSlug), variantId);
|
|
337
|
+
} catch (e) {
|
|
338
|
+
}
|
|
339
|
+
}
|
|
234
340
|
function buildSummary(pageHint, orgSlug) {
|
|
235
341
|
const parts = [pageHint];
|
|
236
342
|
const referrer = document.referrer;
|
|
@@ -282,32 +388,39 @@ function PersonalisedSection({
|
|
|
282
388
|
style,
|
|
283
389
|
initialAssembly,
|
|
284
390
|
initialIntent,
|
|
391
|
+
initialVariantId,
|
|
392
|
+
directSummary,
|
|
285
393
|
zone,
|
|
286
|
-
align
|
|
394
|
+
align,
|
|
395
|
+
accent
|
|
287
396
|
}) {
|
|
288
397
|
const [assembly, setAssembly] = react.useState(initialAssembly != null ? initialAssembly : []);
|
|
289
398
|
const [loading, setLoading] = react.useState(!initialAssembly);
|
|
290
399
|
const [orgName, setOrgName] = react.useState(void 0);
|
|
400
|
+
const [debugMode, setDebugMode] = react.useState(false);
|
|
401
|
+
const [debugIntent, setDebugIntent] = react.useState(null);
|
|
291
402
|
const tokenRef = react.useRef(null);
|
|
292
403
|
const conversionFiredRef = react.useRef(false);
|
|
404
|
+
react.useEffect(() => {
|
|
405
|
+
setDebugMode(new URLSearchParams(window.location.search).has("spectare_debug"));
|
|
406
|
+
if (initialIntent) setDebugIntent(initialIntent);
|
|
407
|
+
}, [initialIntent]);
|
|
408
|
+
react.useEffect(() => {
|
|
409
|
+
if (initialVariantId) writeVariantId(orgSlug, initialVariantId);
|
|
410
|
+
}, [orgSlug, initialVariantId]);
|
|
293
411
|
react.useEffect(() => {
|
|
294
412
|
let cancelled = false;
|
|
295
413
|
async function load() {
|
|
296
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
414
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
297
415
|
try {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}).filter(Boolean).join("_");
|
|
303
|
-
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
304
|
-
let token = sessionStorage.getItem(tokenKey);
|
|
305
|
-
if (!token) {
|
|
306
|
-
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
416
|
+
let token = null;
|
|
417
|
+
if (directSummary) {
|
|
418
|
+
setLoading(true);
|
|
419
|
+
setAssembly([]);
|
|
307
420
|
const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
308
421
|
method: "POST",
|
|
309
422
|
headers: { "Content-Type": "application/json" },
|
|
310
|
-
body: JSON.stringify({ summary })
|
|
423
|
+
body: JSON.stringify({ summary: directSummary, direct: true })
|
|
311
424
|
});
|
|
312
425
|
if (!res2.ok || cancelled) {
|
|
313
426
|
setLoading(false);
|
|
@@ -315,8 +428,30 @@ function PersonalisedSection({
|
|
|
315
428
|
}
|
|
316
429
|
const data = await res2.json();
|
|
317
430
|
token = (_a = data.token) != null ? _a : null;
|
|
318
|
-
|
|
319
|
-
|
|
431
|
+
} else {
|
|
432
|
+
const p = new URLSearchParams(window.location.search);
|
|
433
|
+
const utmSuffix = ["utm_source", "utm_medium", "utm_campaign", "utm_term"].map((k) => {
|
|
434
|
+
var _a2;
|
|
435
|
+
return (_a2 = p.get(k)) != null ? _a2 : "";
|
|
436
|
+
}).filter(Boolean).join("_");
|
|
437
|
+
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
438
|
+
token = sessionStorage.getItem(tokenKey);
|
|
439
|
+
if (!token) {
|
|
440
|
+
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
441
|
+
const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
442
|
+
method: "POST",
|
|
443
|
+
headers: { "Content-Type": "application/json" },
|
|
444
|
+
body: JSON.stringify({ summary })
|
|
445
|
+
});
|
|
446
|
+
if (!res2.ok || cancelled) {
|
|
447
|
+
setLoading(false);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const data = await res2.json();
|
|
451
|
+
token = (_b = data.token) != null ? _b : null;
|
|
452
|
+
if (token) sessionStorage.setItem(tokenKey, token);
|
|
453
|
+
if (data.orgName) setOrgName(data.orgName);
|
|
454
|
+
}
|
|
320
455
|
}
|
|
321
456
|
if (!token || cancelled) {
|
|
322
457
|
setLoading(false);
|
|
@@ -326,9 +461,19 @@ function PersonalisedSection({
|
|
|
326
461
|
let res = await fetch(`${baseUrl}/api/assemble/components`, {
|
|
327
462
|
method: "POST",
|
|
328
463
|
headers: { "Content-Type": "application/json" },
|
|
329
|
-
|
|
464
|
+
// Direct: flag it so the server cost-caps the build, and omit the seen-variant
|
|
465
|
+
// exclusion so it can read the shared cache instead of forcing a fresh build.
|
|
466
|
+
body: JSON.stringify(
|
|
467
|
+
directSummary ? { token, orgSlug, direct: true } : { token, orgSlug, excludeVariantId: readVariantId(orgSlug) }
|
|
468
|
+
)
|
|
330
469
|
});
|
|
331
|
-
if (res.status === 401 && !cancelled) {
|
|
470
|
+
if (res.status === 401 && !cancelled && !directSummary) {
|
|
471
|
+
const p = new URLSearchParams(window.location.search);
|
|
472
|
+
const utmSuffix = ["utm_source", "utm_medium", "utm_campaign", "utm_term"].map((k) => {
|
|
473
|
+
var _a2;
|
|
474
|
+
return (_a2 = p.get(k)) != null ? _a2 : "";
|
|
475
|
+
}).filter(Boolean).join("_");
|
|
476
|
+
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
332
477
|
sessionStorage.removeItem(tokenKey);
|
|
333
478
|
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
334
479
|
const qRes = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
@@ -341,7 +486,7 @@ function PersonalisedSection({
|
|
|
341
486
|
return;
|
|
342
487
|
}
|
|
343
488
|
const qData = await qRes.json();
|
|
344
|
-
token = (
|
|
489
|
+
token = (_c = qData.token) != null ? _c : null;
|
|
345
490
|
if (token) {
|
|
346
491
|
sessionStorage.setItem(tokenKey, token);
|
|
347
492
|
tokenRef.current = token;
|
|
@@ -353,14 +498,14 @@ function PersonalisedSection({
|
|
|
353
498
|
res = await fetch(`${baseUrl}/api/assemble/components`, {
|
|
354
499
|
method: "POST",
|
|
355
500
|
headers: { "Content-Type": "application/json" },
|
|
356
|
-
body: JSON.stringify({ token, orgSlug })
|
|
501
|
+
body: JSON.stringify({ token, orgSlug, excludeVariantId: readVariantId(orgSlug) })
|
|
357
502
|
});
|
|
358
503
|
}
|
|
359
504
|
if (!res.ok || cancelled) {
|
|
360
505
|
setLoading(false);
|
|
361
506
|
return;
|
|
362
507
|
}
|
|
363
|
-
const contentType = (
|
|
508
|
+
const contentType = (_d = res.headers.get("content-type")) != null ? _d : "";
|
|
364
509
|
if (contentType.includes("text/event-stream")) {
|
|
365
510
|
const reader = res.body.getReader();
|
|
366
511
|
const decoder = new TextDecoder();
|
|
@@ -372,13 +517,26 @@ function PersonalisedSection({
|
|
|
372
517
|
if (done || cancelled) break;
|
|
373
518
|
buf += decoder.decode(value, { stream: true });
|
|
374
519
|
const lines = buf.split("\n");
|
|
375
|
-
buf = (
|
|
520
|
+
buf = (_e = lines.pop()) != null ? _e : "";
|
|
376
521
|
for (const line of lines) {
|
|
377
522
|
if (!line.startsWith("data: ")) continue;
|
|
378
523
|
const payload = line.slice(6).trim();
|
|
379
524
|
if (payload === "[DONE]") break;
|
|
380
525
|
try {
|
|
381
|
-
const
|
|
526
|
+
const parsed = JSON.parse(payload);
|
|
527
|
+
if (parsed._variant && typeof parsed._variant === "string") {
|
|
528
|
+
writeVariantId(orgSlug, parsed._variant);
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
if (parsed._error) {
|
|
532
|
+
if (!loadingCleared) {
|
|
533
|
+
setLoading(false);
|
|
534
|
+
loadingCleared = true;
|
|
535
|
+
}
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (!parsed.component) continue;
|
|
539
|
+
const comp = parsed;
|
|
382
540
|
if (!loadingCleared) {
|
|
383
541
|
setLoading(false);
|
|
384
542
|
loadingCleared = true;
|
|
@@ -394,10 +552,14 @@ function PersonalisedSection({
|
|
|
394
552
|
}
|
|
395
553
|
} else {
|
|
396
554
|
const data = await res.json();
|
|
555
|
+
if (data.variantId) writeVariantId(orgSlug, data.variantId);
|
|
397
556
|
if (cancelled) return;
|
|
398
|
-
const clientAudience = (
|
|
399
|
-
const clientStage = (
|
|
557
|
+
const clientAudience = (_g = (_f = data.intent) == null ? void 0 : _f.userContext) == null ? void 0 : _g.audience;
|
|
558
|
+
const clientStage = (_i = (_h = data.intent) == null ? void 0 : _h.userContext) == null ? void 0 : _i.stage;
|
|
400
559
|
const ssrMatches = initialIntent && clientAudience === initialIntent.audience && clientStage === initialIntent.stage;
|
|
560
|
+
if (clientAudience && clientStage) {
|
|
561
|
+
setDebugIntent({ audience: clientAudience, stage: clientStage });
|
|
562
|
+
}
|
|
401
563
|
if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {
|
|
402
564
|
setAssembly(data.assembly);
|
|
403
565
|
}
|
|
@@ -411,7 +573,7 @@ function PersonalisedSection({
|
|
|
411
573
|
return () => {
|
|
412
574
|
cancelled = true;
|
|
413
575
|
};
|
|
414
|
-
}, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);
|
|
576
|
+
}, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent, directSummary]);
|
|
415
577
|
react.useEffect(() => {
|
|
416
578
|
if (!assembly.length || conversionFiredRef.current) return;
|
|
417
579
|
const token = tokenRef.current;
|
|
@@ -456,6 +618,7 @@ function PersonalisedSection({
|
|
|
456
618
|
token,
|
|
457
619
|
orgSlug,
|
|
458
620
|
url,
|
|
621
|
+
variantId: readVariantId(orgSlug),
|
|
459
622
|
...atomsShown.length ? { atomsShown } : {},
|
|
460
623
|
...visitPath.length > 1 ? { visitPath } : {},
|
|
461
624
|
...data.goalName ? { goalName: data.goalName } : {},
|
|
@@ -467,15 +630,39 @@ function PersonalisedSection({
|
|
|
467
630
|
});
|
|
468
631
|
}, [assembly, orgSlug, baseUrl]);
|
|
469
632
|
if (!loading && assembly.length === 0) return null;
|
|
633
|
+
const debugStyle = debugMode ? { outline: "2px solid rgba(96,165,250,0.5)", borderRadius: "0.5rem", position: "relative", padding: "0.5rem", ...style } : style;
|
|
470
634
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
471
|
-
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: CSS_TOKENS } }),
|
|
472
635
|
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
|
|
473
|
-
/* @__PURE__ */ jsxRuntime.
|
|
636
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: debugStyle, children: [
|
|
637
|
+
debugMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "absolute", top: "-1px", right: "-1px", zIndex: 20, display: "flex", alignItems: "center", gap: "0.375rem", background: "rgba(96,165,250,0.9)", borderRadius: "0 0.5rem 0 0.375rem", padding: "0.25rem 0.625rem", fontSize: "0.625rem", fontFamily: "monospace", color: "#fff", pointerEvents: "none", userSelect: "none" }, children: [
|
|
638
|
+
"Personalised by Spectare",
|
|
639
|
+
debugIntent && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.75 }, children: [
|
|
640
|
+
" ",
|
|
641
|
+
debugIntent.audience,
|
|
642
|
+
"/",
|
|
643
|
+
debugIntent.stage
|
|
644
|
+
] })
|
|
645
|
+
] }),
|
|
646
|
+
loading && assembly.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Shimmer, {}) : /* @__PURE__ */ jsxRuntime.jsx(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent })
|
|
647
|
+
] })
|
|
474
648
|
] });
|
|
475
649
|
}
|
|
476
650
|
|
|
651
|
+
exports.AnnouncementBar = AnnouncementBar;
|
|
652
|
+
exports.AtomCard = AtomCard;
|
|
653
|
+
exports.CodeBlock = CodeBlock;
|
|
654
|
+
exports.ComparisonTable = ComparisonTable;
|
|
477
655
|
exports.ComponentRenderer = ComponentRenderer;
|
|
656
|
+
exports.CtaStrip = CtaStrip;
|
|
657
|
+
exports.DEFAULT_ACCENT = DEFAULT_ACCENT;
|
|
658
|
+
exports.FeatureList = FeatureList;
|
|
659
|
+
exports.HeroStatement = HeroStatement;
|
|
660
|
+
exports.ImageCtaHero = ImageCtaHero;
|
|
478
661
|
exports.PersonalisedSection = PersonalisedSection;
|
|
662
|
+
exports.SP_ROOT = SP_ROOT;
|
|
663
|
+
exports.StatGrid = StatGrid;
|
|
664
|
+
exports.TestimonialCard = TestimonialCard;
|
|
665
|
+
exports.buildTokenCss = buildTokenCss;
|
|
479
666
|
exports.filterAssemblyByZone = filterAssemblyByZone;
|
|
480
667
|
//# sourceMappingURL=index.cjs.map
|
|
481
668
|
//# sourceMappingURL=index.cjs.map
|