@spectare-personalisation/react 0.2.2 → 0.5.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 +429 -156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +189 -5
- package/dist/index.d.ts +189 -5
- package/dist/index.js +357 -127
- 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.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
import { marked } from 'marked';
|
|
3
|
-
import DOMPurify from 'isomorphic-dompurify';
|
|
4
|
-
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
1
|
+
'use client';
|
|
5
2
|
|
|
6
3
|
// src/PersonalisedSection.tsx
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
|
|
6
|
+
// src/ComponentRenderer.tsx
|
|
7
|
+
import { marked } from "marked";
|
|
8
|
+
import DOMPurify from "isomorphic-dompurify";
|
|
7
9
|
|
|
8
10
|
// src/types.ts
|
|
9
11
|
var COMPONENT_ZONES = {
|
|
12
|
+
AnnouncementBar: "announce",
|
|
10
13
|
HeroStatement: "hero",
|
|
11
14
|
ImageCtaHero: "hero",
|
|
12
15
|
AtomCard: "body",
|
|
@@ -24,156 +27,284 @@ function filterAssemblyByZone(assembly, zone) {
|
|
|
24
27
|
return effectiveZone === zone;
|
|
25
28
|
});
|
|
26
29
|
}
|
|
30
|
+
var COMPONENT_CATEGORIES = {
|
|
31
|
+
AnnouncementBar: "conversion",
|
|
32
|
+
HeroStatement: "hero",
|
|
33
|
+
AtomCard: "content",
|
|
34
|
+
StatGrid: "content",
|
|
35
|
+
CodeBlock: "technical",
|
|
36
|
+
ComparisonTable: "evaluation",
|
|
37
|
+
FeatureList: "content",
|
|
38
|
+
TestimonialCard: "social-proof",
|
|
39
|
+
ImageCtaHero: "hero",
|
|
40
|
+
CtaStrip: "conversion"
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/tokens.ts
|
|
44
|
+
var DEFAULT_ACCENT = "#60a5fa";
|
|
45
|
+
var SP_ROOT = "sp-root";
|
|
46
|
+
var STYLESHEET_SCOPE = `:where(:root),.${SP_ROOT}`;
|
|
47
|
+
function palette(accent) {
|
|
48
|
+
return {
|
|
49
|
+
"--sp-accent": accent,
|
|
50
|
+
"--sp-accent-bg": `color-mix(in srgb,${accent} 10%,transparent)`,
|
|
51
|
+
"--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`,
|
|
52
|
+
"--sp-bg": "#18181b",
|
|
53
|
+
"--sp-surface": "#09090b",
|
|
54
|
+
"--sp-border": "#27272a",
|
|
55
|
+
"--sp-text": "#f4f4f5",
|
|
56
|
+
"--sp-text-sub": "#d4d4d8",
|
|
57
|
+
"--sp-text-strong": "#e4e4e7",
|
|
58
|
+
"--sp-text-muted": "#82828b",
|
|
59
|
+
"--sp-text-dim": "#6b6b74",
|
|
60
|
+
"--sp-text-body": "#a1a1aa",
|
|
61
|
+
"--sp-positive": "#6ee7b7",
|
|
62
|
+
"--sp-cta-bg": "#fff",
|
|
63
|
+
"--sp-cta-text": "#09090b",
|
|
64
|
+
"--sp-divider": "rgba(255,255,255,0.06)",
|
|
65
|
+
"--sp-code-bg": "rgba(255,255,255,0.07)",
|
|
66
|
+
"--sp-code-border": "rgba(255,255,255,0.08)",
|
|
67
|
+
"--sp-pre-bg": "rgba(0,0,0,0.4)"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function rules(unit) {
|
|
71
|
+
const gap = unit === "px" ? "20px" : "1.25rem";
|
|
72
|
+
return [
|
|
73
|
+
".sp-root .sp-prose p{margin-bottom:.625rem}",
|
|
74
|
+
".sp-root .sp-prose p:last-child{margin-bottom:0}",
|
|
75
|
+
".sp-root .sp-prose ul{list-style:disc;padding-left:1.25rem;margin-bottom:.625rem}",
|
|
76
|
+
".sp-root .sp-prose ol{list-style:decimal;padding-left:1.25rem;margin-bottom:.625rem}",
|
|
77
|
+
".sp-root .sp-prose li{margin-bottom:.25rem}",
|
|
78
|
+
".sp-root .sp-prose strong{color:var(--sp-text-strong);font-weight:600}",
|
|
79
|
+
".sp-root .sp-prose h2,.sp-root .sp-prose h3{color:var(--sp-text);font-weight:600;margin:.875rem 0 .375rem;font-size:1rem}",
|
|
80
|
+
".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)}",
|
|
81
|
+
".sp-root .sp-prose blockquote{border-left:3px solid var(--sp-border);padding-left:1rem;color:var(--sp-text-muted);margin:.75rem 0}",
|
|
82
|
+
`.sp-root .sp-pair{display:grid;grid-template-columns:1fr 1fr;gap:${gap}}`,
|
|
83
|
+
"@media(max-width:640px){.sp-root .sp-pair{grid-template-columns:1fr}}"
|
|
84
|
+
].join("");
|
|
85
|
+
}
|
|
86
|
+
function buildTokenCss({ accent = DEFAULT_ACCENT, unit = "px", scope = `.${SP_ROOT}` } = {}) {
|
|
87
|
+
const decls = Object.entries(palette(accent)).map(([k, v]) => `${k}:${v}`).join(";");
|
|
88
|
+
return `${scope}{${decls}}${rules(unit)}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/ComponentRenderer.tsx
|
|
92
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
27
93
|
function renderMarkdown(content) {
|
|
28
94
|
const raw = marked.parse(content != null ? content : "", { async: false });
|
|
29
95
|
return DOMPurify.sanitize(raw, { USE_PROFILES: { html: true } });
|
|
30
96
|
}
|
|
97
|
+
var scaler = (unit) => (n) => unit === "rem" ? `${n / 16}rem` : `${n}px`;
|
|
98
|
+
var PX = scaler("px");
|
|
31
99
|
var HALF_COMPONENTS = /* @__PURE__ */ new Set(["TestimonialCard"]);
|
|
32
100
|
var flexItems = (a) => a === "center" ? "center" : a === "right" ? "flex-end" : "flex-start";
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
101
|
+
function AnnouncementBar({ text, link, unit = "px" }) {
|
|
102
|
+
const u = scaler(unit);
|
|
103
|
+
if (!text) return null;
|
|
104
|
+
return /* @__PURE__ */ jsxs("div", { style: {
|
|
105
|
+
display: "flex",
|
|
106
|
+
alignItems: "center",
|
|
107
|
+
justifyContent: "center",
|
|
108
|
+
gap: u(10),
|
|
109
|
+
flexWrap: "wrap",
|
|
110
|
+
textAlign: "center",
|
|
111
|
+
background: "var(--sp-accent-bg)",
|
|
112
|
+
border: "1px solid var(--sp-accent-border)",
|
|
113
|
+
borderRadius: u(8),
|
|
114
|
+
padding: `${u(8)} ${u(16)}`,
|
|
115
|
+
fontSize: u(14),
|
|
116
|
+
lineHeight: 1.4,
|
|
117
|
+
color: "var(--sp-text-sub)"
|
|
118
|
+
}, children: [
|
|
119
|
+
/* @__PURE__ */ jsx("span", { children: text }),
|
|
120
|
+
(link == null ? void 0 : link.href) && (link == null ? void 0 : link.label) && /* @__PURE__ */ jsxs("a", { href: link.href, style: { color: "var(--sp-accent)", fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" }, children: [
|
|
121
|
+
link.label,
|
|
122
|
+
" \u2192"
|
|
123
|
+
] })
|
|
124
|
+
] });
|
|
125
|
+
}
|
|
126
|
+
function HeroStatement({ headline, subheading, align = "left", unit = "px" }) {
|
|
127
|
+
const u = scaler(unit);
|
|
128
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: flexItems(align), textAlign: align, paddingTop: u(24), paddingBottom: u(24) }, children: [
|
|
129
|
+
/* @__PURE__ */ jsx("h2", { style: { fontSize: u(32), fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: headline }),
|
|
130
|
+
subheading && /* @__PURE__ */ jsx("p", { style: { fontSize: u(18), color: "var(--sp-text-sub)", lineHeight: 1.6, maxWidth: u(672), margin: 0 }, children: subheading })
|
|
37
131
|
] });
|
|
38
132
|
}
|
|
39
133
|
var ATOM_LAYOUT_DEFAULT = ["title", "content", "stats", "cta"];
|
|
40
|
-
|
|
134
|
+
var ATOM_CLAMP_LINES = 4;
|
|
135
|
+
var clampStyle = {
|
|
136
|
+
display: "-webkit-box",
|
|
137
|
+
WebkitLineClamp: ATOM_CLAMP_LINES,
|
|
138
|
+
WebkitBoxOrient: "vertical",
|
|
139
|
+
overflow: "hidden"
|
|
140
|
+
};
|
|
141
|
+
function AtomCard({ title, content, layout, stats = [], ctaText, ctaUrl, full, unit = "px" }) {
|
|
142
|
+
const u = scaler(unit);
|
|
41
143
|
const order = layout && layout.length ? layout : ATOM_LAYOUT_DEFAULT;
|
|
42
144
|
const element = (name) => {
|
|
43
|
-
if (name === "title") return title ? /* @__PURE__ */ jsx("h3", { style: { fontSize:
|
|
44
|
-
if (name === "content") return content ? /* @__PURE__ */ jsx("div", { className: "sp-prose", style: { fontSize:
|
|
45
|
-
if (name === "stats") return stats.length ? /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap:
|
|
46
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize:
|
|
47
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize:
|
|
145
|
+
if (name === "title") return title ? /* @__PURE__ */ jsx("h3", { style: { fontSize: u(16), fontWeight: 600, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: title }, "title") : null;
|
|
146
|
+
if (name === "content") return content ? /* @__PURE__ */ jsx("div", { className: "sp-prose", style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, ...full ? {} : clampStyle }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } }, "content") : null;
|
|
147
|
+
if (name === "stats") return stats.length ? /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: u(20), margin: `0 0 ${u(12)}`, paddingBottom: u(12), borderBottom: "1px solid var(--sp-border)" }, children: stats.map((s, i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: u(2) }, children: [
|
|
148
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: u(22), fontWeight: 700, color: "var(--sp-text)", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: s.value }),
|
|
149
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: u(11), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
|
|
48
150
|
] }, i)) }, "stats") : null;
|
|
49
|
-
if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ jsxs("a", { href: ctaUrl, style: { display: "inline-flex", alignItems: "center", gap:
|
|
151
|
+
if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ jsxs("a", { href: ctaUrl, style: { display: "inline-flex", alignItems: "center", gap: u(4), marginTop: u(12), fontSize: u(13), fontWeight: 600, color: "var(--sp-accent)", textDecoration: "none" }, children: [
|
|
50
152
|
ctaText,
|
|
51
153
|
" \u2192"
|
|
52
154
|
] }, "cta") : null;
|
|
53
155
|
return null;
|
|
54
156
|
};
|
|
55
|
-
return /* @__PURE__ */ jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius:
|
|
157
|
+
return /* @__PURE__ */ jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24), height: "100%" }, children: order.map(element) });
|
|
56
158
|
}
|
|
57
|
-
function StatGrid({ stats = [], caption }) {
|
|
159
|
+
function StatGrid({ stats = [], caption, unit = "px" }) {
|
|
160
|
+
const u = scaler(unit);
|
|
58
161
|
const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;
|
|
59
162
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
60
|
-
/* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap:
|
|
61
|
-
/* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
62
|
-
/* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
163
|
+
/* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: u(12) }, children: stats.map(({ value, label }) => /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(10), padding: `${u(16)} ${u(20)}`, display: "flex", flexDirection: "column", justifyContent: "space-between", minHeight: u(88) }, children: [
|
|
164
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: u(11), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em", margin: `0 0 ${u(12)}`, lineHeight: 1.3 }, children: label }),
|
|
165
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: u(20), fontWeight: 500, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", lineHeight: 1, margin: 0 }, children: value })
|
|
63
166
|
] }, label)) }),
|
|
64
|
-
caption && /* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
167
|
+
caption && /* @__PURE__ */ jsx("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(12)} 0 0` }, children: caption })
|
|
65
168
|
] });
|
|
66
169
|
}
|
|
67
|
-
function CodeBlock({ code, lang = "typescript", caption }) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
170
|
+
function CodeBlock({ code, lang = "typescript", caption, unit = "px" }) {
|
|
171
|
+
const u = scaler(unit);
|
|
172
|
+
return /* @__PURE__ */ jsxs("div", { style: { borderRadius: u(12), overflow: "hidden", border: "1px solid var(--sp-border)" }, children: [
|
|
173
|
+
/* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", padding: `${u(10)} ${u(16)}`, display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid var(--sp-border)" }, children: [
|
|
174
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)", fontFamily: "monospace" }, children: lang }),
|
|
175
|
+
caption && /* @__PURE__ */ jsx("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)" }, children: caption })
|
|
72
176
|
] }),
|
|
73
|
-
/* @__PURE__ */ jsx("pre", { style: { background: "var(--sp-surface)", padding:
|
|
177
|
+
/* @__PURE__ */ jsx("pre", { style: { background: "var(--sp-surface)", padding: u(20), fontSize: u(13), color: "var(--sp-text-sub)", overflowX: "auto", lineHeight: 1.6, fontFamily: "monospace", whiteSpace: "pre", margin: 0 }, children: code })
|
|
74
178
|
] });
|
|
75
179
|
}
|
|
76
|
-
function ComparisonTable({ brand = "Us", competitor, rows = [] }) {
|
|
77
|
-
|
|
180
|
+
function ComparisonTable({ brand = "Us", competitor, rows = [], unit = "px" }) {
|
|
181
|
+
const u = scaler(unit);
|
|
182
|
+
const cell = { textAlign: "left", padding: `${u(12)} ${u(16)}` };
|
|
183
|
+
return /* @__PURE__ */ jsx("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: { width: "100%", fontSize: u(14), borderCollapse: "collapse" }, children: [
|
|
78
184
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
|
|
79
|
-
/* @__PURE__ */ jsx("th", { style: {
|
|
80
|
-
/* @__PURE__ */ jsx("th", {
|
|
81
|
-
/* @__PURE__ */ jsx("th", {
|
|
185
|
+
/* @__PURE__ */ jsx("th", { style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12), width: "33%" } }),
|
|
186
|
+
/* @__PURE__ */ jsx("th", { scope: "col", style: { ...cell, fontWeight: 600, color: "var(--sp-accent)", fontSize: u(12) }, children: brand }),
|
|
187
|
+
/* @__PURE__ */ jsx("th", { scope: "col", style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12) }, children: competitor })
|
|
82
188
|
] }) }),
|
|
83
189
|
/* @__PURE__ */ jsx("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
|
|
84
|
-
/* @__PURE__ */ jsx("
|
|
85
|
-
/* @__PURE__ */ jsx("td", { style: {
|
|
86
|
-
/* @__PURE__ */ jsx("td", { style: {
|
|
190
|
+
/* @__PURE__ */ jsx("th", { scope: "row", style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
|
|
191
|
+
/* @__PURE__ */ jsx("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
|
|
192
|
+
/* @__PURE__ */ jsx("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)" }, children: them })
|
|
87
193
|
] }, label)) })
|
|
88
194
|
] }) }) });
|
|
89
195
|
}
|
|
90
|
-
function FeatureList({ items = [] }) {
|
|
91
|
-
|
|
92
|
-
|
|
196
|
+
function FeatureList({ items = [], unit = "px" }) {
|
|
197
|
+
const u = scaler(unit);
|
|
198
|
+
return /* @__PURE__ */ jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24) }, children: /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: u(16) }, children: items.map(({ text, sub }) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: u(12) }, children: [
|
|
199
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: u(15), marginTop: u(2) }, children: "\u2713" }),
|
|
93
200
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
94
|
-
/* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
95
|
-
sub && /* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
201
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: u(15), fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
|
|
202
|
+
sub && /* @__PURE__ */ jsx("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", lineHeight: 1.5, margin: `${u(4)} 0 0` }, children: sub })
|
|
96
203
|
] })
|
|
97
204
|
] }, text)) }) });
|
|
98
205
|
}
|
|
99
|
-
function TestimonialCard({ quote, name, role, company }) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
206
|
+
function TestimonialCard({ quote, name, role, company, unit = "px" }) {
|
|
207
|
+
const u = scaler(unit);
|
|
208
|
+
return /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24), display: "flex", flexDirection: "column", gap: u(20), height: "100%" }, children: [
|
|
209
|
+
/* @__PURE__ */ jsxs("p", { style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, flex: 1, margin: 0 }, children: [
|
|
210
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: u(18), lineHeight: 1, marginRight: u(4) }, children: '"' }),
|
|
103
211
|
quote,
|
|
104
|
-
/* @__PURE__ */ jsx("span", { style: { color: "var(--sp-text-dim)", fontSize:
|
|
212
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: u(18), lineHeight: 1, marginLeft: u(4) }, children: '"' })
|
|
105
213
|
] }),
|
|
106
|
-
/* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop:
|
|
107
|
-
/* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
108
|
-
/* @__PURE__ */ jsxs("p", { style: { fontSize:
|
|
214
|
+
/* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: u(16) }, children: [
|
|
215
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: u(14), fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
|
|
216
|
+
/* @__PURE__ */ jsxs("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(2)} 0 0` }, children: [
|
|
109
217
|
role,
|
|
110
218
|
company ? `, ${company}` : ""
|
|
111
219
|
] })
|
|
112
220
|
] })
|
|
113
221
|
] });
|
|
114
222
|
}
|
|
115
|
-
function ImageCtaHero({ src, alt = "", headline, subheading, ctaLabel, ctaHref, align = "left" }) {
|
|
223
|
+
function ImageCtaHero({ src, alt = "", headline, subheading, ctaLabel, ctaHref, align = "left", unit = "px" }) {
|
|
224
|
+
const u = scaler(unit);
|
|
116
225
|
if (!src) return null;
|
|
117
|
-
return /* @__PURE__ */ jsxs("div", { style: { borderRadius:
|
|
226
|
+
return /* @__PURE__ */ jsxs("div", { style: { borderRadius: u(12), overflow: "hidden", position: "relative", width: "100%", paddingBottom: "56.25%" }, children: [
|
|
118
227
|
/* @__PURE__ */ jsx("img", { src, alt, style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" } }),
|
|
119
228
|
/* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.45)" } }),
|
|
120
229
|
/* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.2) 60%, transparent 100%)" } }),
|
|
121
|
-
/* @__PURE__ */ jsxs("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding:
|
|
122
|
-
headline && /* @__PURE__ */ jsx("h2", { style: { fontSize:
|
|
123
|
-
subheading && /* @__PURE__ */ jsx("p", { style: { fontSize:
|
|
124
|
-
ctaHref && ctaLabel && /* @__PURE__ */ jsx("a", { href: ctaHref, style: { display: "inline-block", background: "#fff", color: "#09090b", padding:
|
|
230
|
+
/* @__PURE__ */ jsxs("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding: u(28), textAlign: align }, children: [
|
|
231
|
+
headline && /* @__PURE__ */ jsx("h2", { style: { fontSize: u(24), fontWeight: 700, color: "#fff", lineHeight: 1.2, margin: `0 0 ${u(8)}`, letterSpacing: "-0.02em" }, children: headline }),
|
|
232
|
+
subheading && /* @__PURE__ */ jsx("p", { style: { fontSize: u(15), color: "rgba(255,255,255,0.75)", lineHeight: 1.5, margin: `0 0 ${u(20)}` }, children: subheading }),
|
|
233
|
+
ctaHref && ctaLabel && /* @__PURE__ */ jsx("a", { href: ctaHref, style: { display: "inline-block", background: "#fff", color: "#09090b", padding: `${u(8)} ${u(20)}`, borderRadius: u(8), fontWeight: 600, fontSize: u(14), textDecoration: "none" }, children: ctaLabel })
|
|
125
234
|
] })
|
|
126
235
|
] });
|
|
127
236
|
}
|
|
128
|
-
function CtaStrip({ headline, primary, secondary, align = "center" }) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/* @__PURE__ */
|
|
132
|
-
|
|
133
|
-
|
|
237
|
+
function CtaStrip({ headline, primary, secondary, align = "center", unit = "px" }) {
|
|
238
|
+
const u = scaler(unit);
|
|
239
|
+
return /* @__PURE__ */ jsxs("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(32), textAlign: align, background: "var(--sp-bg)" }, children: [
|
|
240
|
+
/* @__PURE__ */ jsx("h3", { style: { fontSize: u(24), fontWeight: 700, color: "var(--sp-text)", margin: `0 0 ${u(24)}` }, children: headline }),
|
|
241
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: flexItems(align), gap: u(16), flexWrap: "wrap" }, children: [
|
|
242
|
+
/* @__PURE__ */ jsx("a", { href: primary.href, style: { background: "var(--sp-cta-bg)", color: "var(--sp-cta-text)", padding: `${u(10)} ${u(24)}`, borderRadius: u(12), fontWeight: 600, fontSize: u(15), textDecoration: "none" }, children: primary.label }),
|
|
243
|
+
secondary && /* @__PURE__ */ jsxs("a", { href: secondary.href, style: { fontSize: u(15), color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
|
|
134
244
|
secondary.label,
|
|
135
245
|
" \u2192"
|
|
136
246
|
] })
|
|
137
247
|
] })
|
|
138
248
|
] });
|
|
139
249
|
}
|
|
140
|
-
function renderSingle(item, brand, align) {
|
|
250
|
+
function renderSingle(item, brand, align, unit = "px") {
|
|
141
251
|
var _a, _b;
|
|
142
252
|
const s = (_a = item.slots) != null ? _a : {};
|
|
143
253
|
switch (item.component) {
|
|
254
|
+
case "AnnouncementBar":
|
|
255
|
+
return /* @__PURE__ */ jsx(AnnouncementBar, { text: s.text, link: s.link, unit });
|
|
144
256
|
case "HeroStatement":
|
|
145
|
-
return /* @__PURE__ */ jsx(HeroStatement, { headline: s.headline, subheading: s.subheading, align });
|
|
257
|
+
return /* @__PURE__ */ jsx(HeroStatement, { headline: s.headline, subheading: s.subheading, align, unit });
|
|
258
|
+
// A full-width card has nothing beside it, so there is nothing for a clamp to protect.
|
|
146
259
|
case "AtomCard":
|
|
147
|
-
return /* @__PURE__ */ jsx(AtomCard, { title: s.title, content: s.content, layout: s.layout, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl });
|
|
260
|
+
return /* @__PURE__ */ 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", unit });
|
|
148
261
|
case "StatGrid":
|
|
149
|
-
return /* @__PURE__ */ jsx(StatGrid, { stats: s.stats, caption: s.caption });
|
|
262
|
+
return /* @__PURE__ */ jsx(StatGrid, { stats: s.stats, caption: s.caption, unit });
|
|
150
263
|
case "CodeBlock":
|
|
151
|
-
return /* @__PURE__ */ jsx(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption });
|
|
264
|
+
return /* @__PURE__ */ jsx(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption, unit });
|
|
152
265
|
case "ComparisonTable":
|
|
153
|
-
return /* @__PURE__ */ jsx(ComparisonTable, { brand: (_b = s.brand) != null ? _b : brand, competitor: s.competitor, rows: s.rows });
|
|
266
|
+
return /* @__PURE__ */ jsx(ComparisonTable, { brand: (_b = s.brand) != null ? _b : brand, competitor: s.competitor, rows: s.rows, unit });
|
|
154
267
|
case "FeatureList":
|
|
155
|
-
return /* @__PURE__ */ jsx(FeatureList, { items: s.items });
|
|
268
|
+
return /* @__PURE__ */ jsx(FeatureList, { items: s.items, unit });
|
|
156
269
|
case "TestimonialCard":
|
|
157
|
-
return /* @__PURE__ */ jsx(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company });
|
|
270
|
+
return /* @__PURE__ */ jsx(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company, unit });
|
|
158
271
|
case "ImageCtaHero":
|
|
159
|
-
return /* @__PURE__ */ jsx(ImageCtaHero, { src: s.src, alt: s.alt, headline: s.headline, subheading: s.subheading, ctaLabel: s.ctaLabel, ctaHref: s.ctaHref, align });
|
|
272
|
+
return /* @__PURE__ */ jsx(ImageCtaHero, { src: s.src, alt: s.alt, headline: s.headline, subheading: s.subheading, ctaLabel: s.ctaLabel, ctaHref: s.ctaHref, align, unit });
|
|
160
273
|
case "CtaStrip":
|
|
161
|
-
return /* @__PURE__ */ jsx(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary, align });
|
|
162
|
-
|
|
163
|
-
|
|
274
|
+
return /* @__PURE__ */ jsx(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary, align, unit });
|
|
275
|
+
// An unrecognised component name used to render nothing at all. A component needs a
|
|
276
|
+
// renderer here plus spectare.js plus the WordPress plugin, so missing one made its content
|
|
277
|
+
// silently absent on that surface only: no error, no warning, just a shorter page that
|
|
278
|
+
// looks deliberate. That is the failure mode to remove before the registry grows.
|
|
279
|
+
//
|
|
280
|
+
// Falls back to AtomCard when the slots carry something readable, since almost every
|
|
281
|
+
// component is built from an atom and title/content is the shape they share. When there
|
|
282
|
+
// is genuinely nothing to show it still renders nothing, because an empty card is worse
|
|
283
|
+
// than a gap, but the warning fires either way.
|
|
284
|
+
default: {
|
|
285
|
+
console.warn(`[spectare] ComponentRenderer: no renderer for "${item.component}", falling back to AtomCard`);
|
|
286
|
+
if (!s.title && !s.content) return null;
|
|
287
|
+
return /* @__PURE__ */ jsx(AtomCard, { title: s.title, content: s.content, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: true, unit });
|
|
288
|
+
}
|
|
164
289
|
}
|
|
165
290
|
}
|
|
166
291
|
function resolvedSize(item) {
|
|
167
292
|
if (item.size) return item.size;
|
|
168
293
|
return HALF_COMPONENTS.has(item.component) ? "half" : "full";
|
|
169
294
|
}
|
|
295
|
+
function pairable(a, b) {
|
|
296
|
+
const catOf = (x) => COMPONENT_CATEGORIES[x.component];
|
|
297
|
+
const ca = catOf(a);
|
|
298
|
+
const cb = catOf(b);
|
|
299
|
+
return ca !== void 0 && ca === cb;
|
|
300
|
+
}
|
|
170
301
|
function buildLayout(assembly) {
|
|
171
302
|
const groups = [];
|
|
172
303
|
let i = 0;
|
|
173
304
|
while (i < assembly.length) {
|
|
174
305
|
const cur = assembly[i];
|
|
175
306
|
const next = assembly[i + 1];
|
|
176
|
-
if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half") {
|
|
307
|
+
if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half" && pairable(cur, next)) {
|
|
177
308
|
groups.push({ type: "pair", items: [cur, next] });
|
|
178
309
|
i += 2;
|
|
179
310
|
} else if (resolvedSize(cur) === "half") {
|
|
@@ -187,44 +318,60 @@ function buildLayout(assembly) {
|
|
|
187
318
|
return groups;
|
|
188
319
|
}
|
|
189
320
|
function XrayBadge({ name, size }) {
|
|
190
|
-
return /* @__PURE__ */ jsxs("div", { style: { position: "absolute", top:
|
|
191
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize:
|
|
192
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize:
|
|
321
|
+
return /* @__PURE__ */ jsxs("div", { style: { position: "absolute", top: PX(8), left: PX(8), zIndex: 10, display: "flex", alignItems: "center", gap: PX(6), pointerEvents: "none", userSelect: "none" }, children: [
|
|
322
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: PX(10), fontFamily: "monospace", background: "rgba(59,130,246,0.9)", color: "#fff", padding: `${PX(2)} ${PX(6)}`, borderRadius: PX(4), lineHeight: 1 }, children: name }),
|
|
323
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: PX(10), fontFamily: "monospace", color: "#71717a", lineHeight: 1 }, children: size })
|
|
193
324
|
] });
|
|
194
325
|
}
|
|
195
|
-
|
|
196
|
-
|
|
326
|
+
function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent, unit = "px", renderOverride, renderItem, rootProps }) {
|
|
327
|
+
const u = scaler(unit);
|
|
197
328
|
const filtered = zone ? filterAssemblyByZone(assembly, zone) : assembly;
|
|
198
329
|
const layout = buildLayout(filtered);
|
|
199
|
-
|
|
200
|
-
|
|
330
|
+
const { className: extraClass, style: extraStyle, ...restRoot } = rootProps != null ? rootProps : {};
|
|
331
|
+
const renderOne = (item) => {
|
|
332
|
+
const override = renderOverride == null ? void 0 : renderOverride(item);
|
|
333
|
+
const node = override === void 0 ? renderSingle(item, brand, align, unit) : override;
|
|
334
|
+
return renderItem ? renderItem(item, node) : node;
|
|
335
|
+
};
|
|
336
|
+
return /* @__PURE__ */ jsxs("div", { className: extraClass ? `${SP_ROOT} ${extraClass}` : SP_ROOT, ...restRoot, style: { ...extraStyle, display: "flex", flexDirection: "column", gap: u(20), ...unit === "px" ? { fontSize: "16px" } : {} }, children: [
|
|
337
|
+
/* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent, unit }) } }),
|
|
201
338
|
layout.map((group, i) => {
|
|
202
|
-
if (group.type === "full") {
|
|
203
|
-
return /* @__PURE__ */ jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
204
|
-
xray && /* @__PURE__ */ jsx(XrayBadge, { name: group.item.component, size: "full" }),
|
|
205
|
-
renderSingle(group.item, brand, align)
|
|
206
|
-
] }, i);
|
|
207
|
-
}
|
|
208
339
|
if (group.type === "pair") {
|
|
209
340
|
return /* @__PURE__ */ jsxs("div", { className: "sp-pair", children: [
|
|
210
341
|
/* @__PURE__ */ jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
211
342
|
xray && /* @__PURE__ */ jsx(XrayBadge, { name: group.items[0].component, size: "half" }),
|
|
212
|
-
|
|
343
|
+
renderOne(group.items[0])
|
|
213
344
|
] }),
|
|
214
345
|
/* @__PURE__ */ jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
215
346
|
xray && /* @__PURE__ */ jsx(XrayBadge, { name: group.items[1].component, size: "half" }),
|
|
216
|
-
|
|
347
|
+
renderOne(group.items[1])
|
|
217
348
|
] })
|
|
218
349
|
] }, i);
|
|
219
350
|
}
|
|
220
351
|
return /* @__PURE__ */ jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
221
|
-
xray && /* @__PURE__ */ jsx(XrayBadge, { name: group.item.component, size: "full" }),
|
|
222
|
-
|
|
352
|
+
xray && /* @__PURE__ */ jsx(XrayBadge, { name: group.item.component, size: group.type === "half-solo" ? "half" : "full" }),
|
|
353
|
+
renderOne(group.item)
|
|
223
354
|
] }, i);
|
|
224
355
|
})
|
|
225
356
|
] });
|
|
226
357
|
}
|
|
227
|
-
|
|
358
|
+
|
|
359
|
+
// src/PersonalisedSection.tsx
|
|
360
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
361
|
+
var VARIANT_KEY = (orgSlug) => `_spectare_variant_${orgSlug}`;
|
|
362
|
+
function readVariantId(orgSlug) {
|
|
363
|
+
try {
|
|
364
|
+
return sessionStorage.getItem(VARIANT_KEY(orgSlug));
|
|
365
|
+
} catch (e) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function writeVariantId(orgSlug, variantId) {
|
|
370
|
+
try {
|
|
371
|
+
sessionStorage.setItem(VARIANT_KEY(orgSlug), variantId);
|
|
372
|
+
} catch (e) {
|
|
373
|
+
}
|
|
374
|
+
}
|
|
228
375
|
function buildSummary(pageHint, orgSlug) {
|
|
229
376
|
const parts = [pageHint];
|
|
230
377
|
const referrer = document.referrer;
|
|
@@ -260,11 +407,11 @@ function readVisitPath(orgSlug) {
|
|
|
260
407
|
}
|
|
261
408
|
}
|
|
262
409
|
function Shimmer() {
|
|
263
|
-
return /* @__PURE__ */
|
|
264
|
-
/* @__PURE__ */
|
|
265
|
-
/* @__PURE__ */
|
|
266
|
-
/* @__PURE__ */
|
|
267
|
-
/* @__PURE__ */
|
|
410
|
+
return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
411
|
+
/* @__PURE__ */ jsx2("div", { style: { height: "20px", background: "rgba(39,39,42,0.6)", borderRadius: "8px", width: "75%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
|
|
412
|
+
/* @__PURE__ */ jsx2("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "100%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
|
|
413
|
+
/* @__PURE__ */ jsx2("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "83%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
|
|
414
|
+
/* @__PURE__ */ jsx2("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "67%", animation: "sp-pulse 1.5s ease-in-out infinite" } })
|
|
268
415
|
] });
|
|
269
416
|
}
|
|
270
417
|
function PersonalisedSection({
|
|
@@ -276,32 +423,39 @@ function PersonalisedSection({
|
|
|
276
423
|
style,
|
|
277
424
|
initialAssembly,
|
|
278
425
|
initialIntent,
|
|
426
|
+
initialVariantId,
|
|
427
|
+
directSummary,
|
|
279
428
|
zone,
|
|
280
|
-
align
|
|
429
|
+
align,
|
|
430
|
+
accent
|
|
281
431
|
}) {
|
|
282
432
|
const [assembly, setAssembly] = useState(initialAssembly != null ? initialAssembly : []);
|
|
283
433
|
const [loading, setLoading] = useState(!initialAssembly);
|
|
284
434
|
const [orgName, setOrgName] = useState(void 0);
|
|
435
|
+
const [debugMode, setDebugMode] = useState(false);
|
|
436
|
+
const [debugIntent, setDebugIntent] = useState(null);
|
|
285
437
|
const tokenRef = useRef(null);
|
|
286
438
|
const conversionFiredRef = useRef(false);
|
|
439
|
+
useEffect(() => {
|
|
440
|
+
setDebugMode(new URLSearchParams(window.location.search).has("spectare_debug"));
|
|
441
|
+
if (initialIntent) setDebugIntent(initialIntent);
|
|
442
|
+
}, [initialIntent]);
|
|
443
|
+
useEffect(() => {
|
|
444
|
+
if (initialVariantId) writeVariantId(orgSlug, initialVariantId);
|
|
445
|
+
}, [orgSlug, initialVariantId]);
|
|
287
446
|
useEffect(() => {
|
|
288
447
|
let cancelled = false;
|
|
289
448
|
async function load() {
|
|
290
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
449
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
291
450
|
try {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}).filter(Boolean).join("_");
|
|
297
|
-
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
298
|
-
let token = sessionStorage.getItem(tokenKey);
|
|
299
|
-
if (!token) {
|
|
300
|
-
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
451
|
+
let token = null;
|
|
452
|
+
if (directSummary) {
|
|
453
|
+
setLoading(true);
|
|
454
|
+
setAssembly([]);
|
|
301
455
|
const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
302
456
|
method: "POST",
|
|
303
457
|
headers: { "Content-Type": "application/json" },
|
|
304
|
-
body: JSON.stringify({ summary })
|
|
458
|
+
body: JSON.stringify({ summary: directSummary, direct: true })
|
|
305
459
|
});
|
|
306
460
|
if (!res2.ok || cancelled) {
|
|
307
461
|
setLoading(false);
|
|
@@ -309,8 +463,30 @@ function PersonalisedSection({
|
|
|
309
463
|
}
|
|
310
464
|
const data = await res2.json();
|
|
311
465
|
token = (_a = data.token) != null ? _a : null;
|
|
312
|
-
|
|
313
|
-
|
|
466
|
+
} else {
|
|
467
|
+
const p = new URLSearchParams(window.location.search);
|
|
468
|
+
const utmSuffix = ["utm_source", "utm_medium", "utm_campaign", "utm_term"].map((k) => {
|
|
469
|
+
var _a2;
|
|
470
|
+
return (_a2 = p.get(k)) != null ? _a2 : "";
|
|
471
|
+
}).filter(Boolean).join("_");
|
|
472
|
+
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
473
|
+
token = sessionStorage.getItem(tokenKey);
|
|
474
|
+
if (!token) {
|
|
475
|
+
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
476
|
+
const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
477
|
+
method: "POST",
|
|
478
|
+
headers: { "Content-Type": "application/json" },
|
|
479
|
+
body: JSON.stringify({ summary })
|
|
480
|
+
});
|
|
481
|
+
if (!res2.ok || cancelled) {
|
|
482
|
+
setLoading(false);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const data = await res2.json();
|
|
486
|
+
token = (_b = data.token) != null ? _b : null;
|
|
487
|
+
if (token) sessionStorage.setItem(tokenKey, token);
|
|
488
|
+
if (data.orgName) setOrgName(data.orgName);
|
|
489
|
+
}
|
|
314
490
|
}
|
|
315
491
|
if (!token || cancelled) {
|
|
316
492
|
setLoading(false);
|
|
@@ -320,9 +496,19 @@ function PersonalisedSection({
|
|
|
320
496
|
let res = await fetch(`${baseUrl}/api/assemble/components`, {
|
|
321
497
|
method: "POST",
|
|
322
498
|
headers: { "Content-Type": "application/json" },
|
|
323
|
-
|
|
499
|
+
// Direct: flag it so the server cost-caps the build, and omit the seen-variant
|
|
500
|
+
// exclusion so it can read the shared cache instead of forcing a fresh build.
|
|
501
|
+
body: JSON.stringify(
|
|
502
|
+
directSummary ? { token, orgSlug, direct: true } : { token, orgSlug, excludeVariantId: readVariantId(orgSlug) }
|
|
503
|
+
)
|
|
324
504
|
});
|
|
325
|
-
if (res.status === 401 && !cancelled) {
|
|
505
|
+
if (res.status === 401 && !cancelled && !directSummary) {
|
|
506
|
+
const p = new URLSearchParams(window.location.search);
|
|
507
|
+
const utmSuffix = ["utm_source", "utm_medium", "utm_campaign", "utm_term"].map((k) => {
|
|
508
|
+
var _a2;
|
|
509
|
+
return (_a2 = p.get(k)) != null ? _a2 : "";
|
|
510
|
+
}).filter(Boolean).join("_");
|
|
511
|
+
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
326
512
|
sessionStorage.removeItem(tokenKey);
|
|
327
513
|
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
328
514
|
const qRes = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
@@ -335,7 +521,7 @@ function PersonalisedSection({
|
|
|
335
521
|
return;
|
|
336
522
|
}
|
|
337
523
|
const qData = await qRes.json();
|
|
338
|
-
token = (
|
|
524
|
+
token = (_c = qData.token) != null ? _c : null;
|
|
339
525
|
if (token) {
|
|
340
526
|
sessionStorage.setItem(tokenKey, token);
|
|
341
527
|
tokenRef.current = token;
|
|
@@ -347,14 +533,14 @@ function PersonalisedSection({
|
|
|
347
533
|
res = await fetch(`${baseUrl}/api/assemble/components`, {
|
|
348
534
|
method: "POST",
|
|
349
535
|
headers: { "Content-Type": "application/json" },
|
|
350
|
-
body: JSON.stringify({ token, orgSlug })
|
|
536
|
+
body: JSON.stringify({ token, orgSlug, excludeVariantId: readVariantId(orgSlug) })
|
|
351
537
|
});
|
|
352
538
|
}
|
|
353
539
|
if (!res.ok || cancelled) {
|
|
354
540
|
setLoading(false);
|
|
355
541
|
return;
|
|
356
542
|
}
|
|
357
|
-
const contentType = (
|
|
543
|
+
const contentType = (_d = res.headers.get("content-type")) != null ? _d : "";
|
|
358
544
|
if (contentType.includes("text/event-stream")) {
|
|
359
545
|
const reader = res.body.getReader();
|
|
360
546
|
const decoder = new TextDecoder();
|
|
@@ -366,13 +552,26 @@ function PersonalisedSection({
|
|
|
366
552
|
if (done || cancelled) break;
|
|
367
553
|
buf += decoder.decode(value, { stream: true });
|
|
368
554
|
const lines = buf.split("\n");
|
|
369
|
-
buf = (
|
|
555
|
+
buf = (_e = lines.pop()) != null ? _e : "";
|
|
370
556
|
for (const line of lines) {
|
|
371
557
|
if (!line.startsWith("data: ")) continue;
|
|
372
558
|
const payload = line.slice(6).trim();
|
|
373
559
|
if (payload === "[DONE]") break;
|
|
374
560
|
try {
|
|
375
|
-
const
|
|
561
|
+
const parsed = JSON.parse(payload);
|
|
562
|
+
if (parsed._variant && typeof parsed._variant === "string") {
|
|
563
|
+
writeVariantId(orgSlug, parsed._variant);
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
if (parsed._error) {
|
|
567
|
+
if (!loadingCleared) {
|
|
568
|
+
setLoading(false);
|
|
569
|
+
loadingCleared = true;
|
|
570
|
+
}
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (!parsed.component) continue;
|
|
574
|
+
const comp = parsed;
|
|
376
575
|
if (!loadingCleared) {
|
|
377
576
|
setLoading(false);
|
|
378
577
|
loadingCleared = true;
|
|
@@ -388,10 +587,14 @@ function PersonalisedSection({
|
|
|
388
587
|
}
|
|
389
588
|
} else {
|
|
390
589
|
const data = await res.json();
|
|
590
|
+
if (data.variantId) writeVariantId(orgSlug, data.variantId);
|
|
391
591
|
if (cancelled) return;
|
|
392
|
-
const clientAudience = (
|
|
393
|
-
const clientStage = (
|
|
592
|
+
const clientAudience = (_g = (_f = data.intent) == null ? void 0 : _f.userContext) == null ? void 0 : _g.audience;
|
|
593
|
+
const clientStage = (_i = (_h = data.intent) == null ? void 0 : _h.userContext) == null ? void 0 : _i.stage;
|
|
394
594
|
const ssrMatches = initialIntent && clientAudience === initialIntent.audience && clientStage === initialIntent.stage;
|
|
595
|
+
if (clientAudience && clientStage) {
|
|
596
|
+
setDebugIntent({ audience: clientAudience, stage: clientStage });
|
|
597
|
+
}
|
|
395
598
|
if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {
|
|
396
599
|
setAssembly(data.assembly);
|
|
397
600
|
}
|
|
@@ -405,7 +608,7 @@ function PersonalisedSection({
|
|
|
405
608
|
return () => {
|
|
406
609
|
cancelled = true;
|
|
407
610
|
};
|
|
408
|
-
}, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);
|
|
611
|
+
}, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent, directSummary]);
|
|
409
612
|
useEffect(() => {
|
|
410
613
|
if (!assembly.length || conversionFiredRef.current) return;
|
|
411
614
|
const token = tokenRef.current;
|
|
@@ -450,6 +653,7 @@ function PersonalisedSection({
|
|
|
450
653
|
token,
|
|
451
654
|
orgSlug,
|
|
452
655
|
url,
|
|
656
|
+
variantId: readVariantId(orgSlug),
|
|
453
657
|
...atomsShown.length ? { atomsShown } : {},
|
|
454
658
|
...visitPath.length > 1 ? { visitPath } : {},
|
|
455
659
|
...data.goalName ? { goalName: data.goalName } : {},
|
|
@@ -461,13 +665,39 @@ function PersonalisedSection({
|
|
|
461
665
|
});
|
|
462
666
|
}, [assembly, orgSlug, baseUrl]);
|
|
463
667
|
if (!loading && assembly.length === 0) return null;
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
/* @__PURE__ */
|
|
467
|
-
/* @__PURE__ */
|
|
668
|
+
const debugStyle = debugMode ? { outline: "2px solid rgba(96,165,250,0.5)", borderRadius: "0.5rem", position: "relative", padding: "0.5rem", ...style } : style;
|
|
669
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
670
|
+
/* @__PURE__ */ jsx2("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
|
|
671
|
+
/* @__PURE__ */ jsxs2("div", { className, style: debugStyle, children: [
|
|
672
|
+
debugMode && /* @__PURE__ */ jsxs2("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: [
|
|
673
|
+
"Personalised by Spectare",
|
|
674
|
+
debugIntent && /* @__PURE__ */ jsxs2("span", { style: { opacity: 0.75 }, children: [
|
|
675
|
+
" ",
|
|
676
|
+
debugIntent.audience,
|
|
677
|
+
"/",
|
|
678
|
+
debugIntent.stage
|
|
679
|
+
] })
|
|
680
|
+
] }),
|
|
681
|
+
loading && assembly.length === 0 ? /* @__PURE__ */ jsx2(Shimmer, {}) : /* @__PURE__ */ jsx2(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent })
|
|
682
|
+
] })
|
|
468
683
|
] });
|
|
469
684
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
685
|
+
export {
|
|
686
|
+
AnnouncementBar,
|
|
687
|
+
AtomCard,
|
|
688
|
+
CodeBlock,
|
|
689
|
+
ComparisonTable,
|
|
690
|
+
ComponentRenderer,
|
|
691
|
+
CtaStrip,
|
|
692
|
+
DEFAULT_ACCENT,
|
|
693
|
+
FeatureList,
|
|
694
|
+
HeroStatement,
|
|
695
|
+
ImageCtaHero,
|
|
696
|
+
PersonalisedSection,
|
|
697
|
+
SP_ROOT,
|
|
698
|
+
StatGrid,
|
|
699
|
+
TestimonialCard,
|
|
700
|
+
buildTokenCss,
|
|
701
|
+
filterAssemblyByZone
|
|
702
|
+
};
|
|
473
703
|
//# sourceMappingURL=index.js.map
|