@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.cjs
CHANGED
|
@@ -1,18 +1,65 @@
|
|
|
1
|
-
'use
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
9
30
|
|
|
10
|
-
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var src_exports = {};
|
|
33
|
+
__export(src_exports, {
|
|
34
|
+
AnnouncementBar: () => AnnouncementBar,
|
|
35
|
+
AtomCard: () => AtomCard,
|
|
36
|
+
CodeBlock: () => CodeBlock,
|
|
37
|
+
ComparisonTable: () => ComparisonTable,
|
|
38
|
+
ComponentRenderer: () => ComponentRenderer,
|
|
39
|
+
CtaStrip: () => CtaStrip,
|
|
40
|
+
DEFAULT_ACCENT: () => DEFAULT_ACCENT,
|
|
41
|
+
FeatureList: () => FeatureList,
|
|
42
|
+
HeroStatement: () => HeroStatement,
|
|
43
|
+
ImageCtaHero: () => ImageCtaHero,
|
|
44
|
+
PersonalisedSection: () => PersonalisedSection,
|
|
45
|
+
SP_ROOT: () => SP_ROOT,
|
|
46
|
+
StatGrid: () => StatGrid,
|
|
47
|
+
TestimonialCard: () => TestimonialCard,
|
|
48
|
+
buildTokenCss: () => buildTokenCss,
|
|
49
|
+
filterAssemblyByZone: () => filterAssemblyByZone
|
|
50
|
+
});
|
|
51
|
+
module.exports = __toCommonJS(src_exports);
|
|
11
52
|
|
|
12
53
|
// src/PersonalisedSection.tsx
|
|
54
|
+
var import_react = require("react");
|
|
55
|
+
|
|
56
|
+
// src/ComponentRenderer.tsx
|
|
57
|
+
var import_marked = require("marked");
|
|
58
|
+
var import_isomorphic_dompurify = __toESM(require("isomorphic-dompurify"), 1);
|
|
13
59
|
|
|
14
60
|
// src/types.ts
|
|
15
61
|
var COMPONENT_ZONES = {
|
|
62
|
+
AnnouncementBar: "announce",
|
|
16
63
|
HeroStatement: "hero",
|
|
17
64
|
ImageCtaHero: "hero",
|
|
18
65
|
AtomCard: "body",
|
|
@@ -30,156 +77,284 @@ function filterAssemblyByZone(assembly, zone) {
|
|
|
30
77
|
return effectiveZone === zone;
|
|
31
78
|
});
|
|
32
79
|
}
|
|
80
|
+
var COMPONENT_CATEGORIES = {
|
|
81
|
+
AnnouncementBar: "conversion",
|
|
82
|
+
HeroStatement: "hero",
|
|
83
|
+
AtomCard: "content",
|
|
84
|
+
StatGrid: "content",
|
|
85
|
+
CodeBlock: "technical",
|
|
86
|
+
ComparisonTable: "evaluation",
|
|
87
|
+
FeatureList: "content",
|
|
88
|
+
TestimonialCard: "social-proof",
|
|
89
|
+
ImageCtaHero: "hero",
|
|
90
|
+
CtaStrip: "conversion"
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/tokens.ts
|
|
94
|
+
var DEFAULT_ACCENT = "#60a5fa";
|
|
95
|
+
var SP_ROOT = "sp-root";
|
|
96
|
+
var STYLESHEET_SCOPE = `:where(:root),.${SP_ROOT}`;
|
|
97
|
+
function palette(accent) {
|
|
98
|
+
return {
|
|
99
|
+
"--sp-accent": accent,
|
|
100
|
+
"--sp-accent-bg": `color-mix(in srgb,${accent} 10%,transparent)`,
|
|
101
|
+
"--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`,
|
|
102
|
+
"--sp-bg": "#18181b",
|
|
103
|
+
"--sp-surface": "#09090b",
|
|
104
|
+
"--sp-border": "#27272a",
|
|
105
|
+
"--sp-text": "#f4f4f5",
|
|
106
|
+
"--sp-text-sub": "#d4d4d8",
|
|
107
|
+
"--sp-text-strong": "#e4e4e7",
|
|
108
|
+
"--sp-text-muted": "#82828b",
|
|
109
|
+
"--sp-text-dim": "#6b6b74",
|
|
110
|
+
"--sp-text-body": "#a1a1aa",
|
|
111
|
+
"--sp-positive": "#6ee7b7",
|
|
112
|
+
"--sp-cta-bg": "#fff",
|
|
113
|
+
"--sp-cta-text": "#09090b",
|
|
114
|
+
"--sp-divider": "rgba(255,255,255,0.06)",
|
|
115
|
+
"--sp-code-bg": "rgba(255,255,255,0.07)",
|
|
116
|
+
"--sp-code-border": "rgba(255,255,255,0.08)",
|
|
117
|
+
"--sp-pre-bg": "rgba(0,0,0,0.4)"
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function rules(unit) {
|
|
121
|
+
const gap = unit === "px" ? "20px" : "1.25rem";
|
|
122
|
+
return [
|
|
123
|
+
".sp-root .sp-prose p{margin-bottom:.625rem}",
|
|
124
|
+
".sp-root .sp-prose p:last-child{margin-bottom:0}",
|
|
125
|
+
".sp-root .sp-prose ul{list-style:disc;padding-left:1.25rem;margin-bottom:.625rem}",
|
|
126
|
+
".sp-root .sp-prose ol{list-style:decimal;padding-left:1.25rem;margin-bottom:.625rem}",
|
|
127
|
+
".sp-root .sp-prose li{margin-bottom:.25rem}",
|
|
128
|
+
".sp-root .sp-prose strong{color:var(--sp-text-strong);font-weight:600}",
|
|
129
|
+
".sp-root .sp-prose h2,.sp-root .sp-prose h3{color:var(--sp-text);font-weight:600;margin:.875rem 0 .375rem;font-size:1rem}",
|
|
130
|
+
".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)}",
|
|
131
|
+
".sp-root .sp-prose blockquote{border-left:3px solid var(--sp-border);padding-left:1rem;color:var(--sp-text-muted);margin:.75rem 0}",
|
|
132
|
+
`.sp-root .sp-pair{display:grid;grid-template-columns:1fr 1fr;gap:${gap}}`,
|
|
133
|
+
"@media(max-width:640px){.sp-root .sp-pair{grid-template-columns:1fr}}"
|
|
134
|
+
].join("");
|
|
135
|
+
}
|
|
136
|
+
function buildTokenCss({ accent = DEFAULT_ACCENT, unit = "px", scope = `.${SP_ROOT}` } = {}) {
|
|
137
|
+
const decls = Object.entries(palette(accent)).map(([k, v]) => `${k}:${v}`).join(";");
|
|
138
|
+
return `${scope}{${decls}}${rules(unit)}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/ComponentRenderer.tsx
|
|
142
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
33
143
|
function renderMarkdown(content) {
|
|
34
|
-
const raw =
|
|
35
|
-
return
|
|
144
|
+
const raw = import_marked.marked.parse(content != null ? content : "", { async: false });
|
|
145
|
+
return import_isomorphic_dompurify.default.sanitize(raw, { USE_PROFILES: { html: true } });
|
|
36
146
|
}
|
|
147
|
+
var scaler = (unit) => (n) => unit === "rem" ? `${n / 16}rem` : `${n}px`;
|
|
148
|
+
var PX = scaler("px");
|
|
37
149
|
var HALF_COMPONENTS = /* @__PURE__ */ new Set(["TestimonialCard"]);
|
|
38
150
|
var flexItems = (a) => a === "center" ? "center" : a === "right" ? "flex-end" : "flex-start";
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
151
|
+
function AnnouncementBar({ text, link, unit = "px" }) {
|
|
152
|
+
const u = scaler(unit);
|
|
153
|
+
if (!text) return null;
|
|
154
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
155
|
+
display: "flex",
|
|
156
|
+
alignItems: "center",
|
|
157
|
+
justifyContent: "center",
|
|
158
|
+
gap: u(10),
|
|
159
|
+
flexWrap: "wrap",
|
|
160
|
+
textAlign: "center",
|
|
161
|
+
background: "var(--sp-accent-bg)",
|
|
162
|
+
border: "1px solid var(--sp-accent-border)",
|
|
163
|
+
borderRadius: u(8),
|
|
164
|
+
padding: `${u(8)} ${u(16)}`,
|
|
165
|
+
fontSize: u(14),
|
|
166
|
+
lineHeight: 1.4,
|
|
167
|
+
color: "var(--sp-text-sub)"
|
|
168
|
+
}, children: [
|
|
169
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: text }),
|
|
170
|
+
(link == null ? void 0 : link.href) && (link == null ? void 0 : link.label) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: link.href, style: { color: "var(--sp-accent)", fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" }, children: [
|
|
171
|
+
link.label,
|
|
172
|
+
" \u2192"
|
|
173
|
+
] })
|
|
174
|
+
] });
|
|
175
|
+
}
|
|
176
|
+
function HeroStatement({ headline, subheading, align = "left", unit = "px" }) {
|
|
177
|
+
const u = scaler(unit);
|
|
178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: flexItems(align), textAlign: align, paddingTop: u(24), paddingBottom: u(24) }, children: [
|
|
179
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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 }),
|
|
180
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(18), color: "var(--sp-text-sub)", lineHeight: 1.6, maxWidth: u(672), margin: 0 }, children: subheading })
|
|
43
181
|
] });
|
|
44
182
|
}
|
|
45
183
|
var ATOM_LAYOUT_DEFAULT = ["title", "content", "stats", "cta"];
|
|
46
|
-
|
|
184
|
+
var ATOM_CLAMP_LINES = 4;
|
|
185
|
+
var clampStyle = {
|
|
186
|
+
display: "-webkit-box",
|
|
187
|
+
WebkitLineClamp: ATOM_CLAMP_LINES,
|
|
188
|
+
WebkitBoxOrient: "vertical",
|
|
189
|
+
overflow: "hidden"
|
|
190
|
+
};
|
|
191
|
+
function AtomCard({ title, content, layout, stats = [], ctaText, ctaUrl, full, unit = "px" }) {
|
|
192
|
+
const u = scaler(unit);
|
|
47
193
|
const order = layout && layout.length ? layout : ATOM_LAYOUT_DEFAULT;
|
|
48
194
|
const element = (name) => {
|
|
49
|
-
if (name === "title") return title ? /* @__PURE__ */
|
|
50
|
-
if (name === "content") return content ? /* @__PURE__ */
|
|
51
|
-
if (name === "stats") return stats.length ? /* @__PURE__ */
|
|
52
|
-
/* @__PURE__ */
|
|
53
|
-
/* @__PURE__ */
|
|
195
|
+
if (name === "title") return title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { fontSize: u(16), fontWeight: 600, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: title }, "title") : null;
|
|
196
|
+
if (name === "content") return content ? /* @__PURE__ */ (0, import_jsx_runtime.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;
|
|
197
|
+
if (name === "stats") return stats.length ? /* @__PURE__ */ (0, import_jsx_runtime.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__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: u(2) }, children: [
|
|
198
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(22), fontWeight: 700, color: "var(--sp-text)", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: s.value }),
|
|
199
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(11), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
|
|
54
200
|
] }, i)) }, "stats") : null;
|
|
55
|
-
if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */
|
|
201
|
+
if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
56
202
|
ctaText,
|
|
57
203
|
" \u2192"
|
|
58
204
|
] }, "cta") : null;
|
|
59
205
|
return null;
|
|
60
206
|
};
|
|
61
|
-
return /* @__PURE__ */
|
|
207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.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) });
|
|
62
208
|
}
|
|
63
|
-
function StatGrid({ stats = [], caption }) {
|
|
209
|
+
function StatGrid({ stats = [], caption, unit = "px" }) {
|
|
210
|
+
const u = scaler(unit);
|
|
64
211
|
const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;
|
|
65
|
-
return /* @__PURE__ */
|
|
66
|
-
/* @__PURE__ */
|
|
67
|
-
/* @__PURE__ */
|
|
68
|
-
/* @__PURE__ */
|
|
212
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: u(12) }, children: stats.map(({ value, label }) => /* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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 }),
|
|
215
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(20), fontWeight: 500, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", lineHeight: 1, margin: 0 }, children: value })
|
|
69
216
|
] }, label)) }),
|
|
70
|
-
caption && /* @__PURE__ */
|
|
217
|
+
caption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(12)} 0 0` }, children: caption })
|
|
71
218
|
] });
|
|
72
219
|
}
|
|
73
|
-
function CodeBlock({ code, lang = "typescript", caption }) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
220
|
+
function CodeBlock({ code, lang = "typescript", caption, unit = "px" }) {
|
|
221
|
+
const u = scaler(unit);
|
|
222
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderRadius: u(12), overflow: "hidden", border: "1px solid var(--sp-border)" }, children: [
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)", fontFamily: "monospace" }, children: lang }),
|
|
225
|
+
caption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)" }, children: caption })
|
|
78
226
|
] }),
|
|
79
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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 })
|
|
80
228
|
] });
|
|
81
229
|
}
|
|
82
|
-
function ComparisonTable({ brand = "Us", competitor, rows = [] }) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/* @__PURE__ */
|
|
230
|
+
function ComparisonTable({ brand = "Us", competitor, rows = [], unit = "px" }) {
|
|
231
|
+
const u = scaler(unit);
|
|
232
|
+
const cell = { textAlign: "left", padding: `${u(12)} ${u(16)}` };
|
|
233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: { width: "100%", fontSize: u(14), borderCollapse: "collapse" }, children: [
|
|
234
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
|
|
235
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12), width: "33%" } }),
|
|
236
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", style: { ...cell, fontWeight: 600, color: "var(--sp-accent)", fontSize: u(12) }, children: brand }),
|
|
237
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12) }, children: competitor })
|
|
88
238
|
] }) }),
|
|
89
|
-
/* @__PURE__ */
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
/* @__PURE__ */
|
|
92
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
|
|
240
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "row", style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
|
|
242
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)" }, children: them })
|
|
93
243
|
] }, label)) })
|
|
94
244
|
] }) }) });
|
|
95
245
|
}
|
|
96
|
-
function FeatureList({ items = [] }) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/* @__PURE__ */
|
|
100
|
-
|
|
101
|
-
|
|
246
|
+
function FeatureList({ items = [], unit = "px" }) {
|
|
247
|
+
const u = scaler(unit);
|
|
248
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24) }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: u(16) }, children: items.map(({ text, sub }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { display: "flex", gap: u(12) }, children: [
|
|
249
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: u(15), marginTop: u(2) }, children: "\u2713" }),
|
|
250
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
251
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(15), fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
|
|
252
|
+
sub && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", lineHeight: 1.5, margin: `${u(4)} 0 0` }, children: sub })
|
|
102
253
|
] })
|
|
103
254
|
] }, text)) }) });
|
|
104
255
|
}
|
|
105
|
-
function TestimonialCard({ quote, name, role, company }) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
256
|
+
function TestimonialCard({ quote, name, role, company, unit = "px" }) {
|
|
257
|
+
const u = scaler(unit);
|
|
258
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, flex: 1, margin: 0 }, children: [
|
|
260
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--sp-text-dim)", fontSize: u(18), lineHeight: 1, marginRight: u(4) }, children: '"' }),
|
|
109
261
|
quote,
|
|
110
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--sp-text-dim)", fontSize: u(18), lineHeight: 1, marginLeft: u(4) }, children: '"' })
|
|
111
263
|
] }),
|
|
112
|
-
/* @__PURE__ */
|
|
113
|
-
/* @__PURE__ */
|
|
114
|
-
/* @__PURE__ */
|
|
264
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: u(16) }, children: [
|
|
265
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(14), fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
|
|
266
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(2)} 0 0` }, children: [
|
|
115
267
|
role,
|
|
116
268
|
company ? `, ${company}` : ""
|
|
117
269
|
] })
|
|
118
270
|
] })
|
|
119
271
|
] });
|
|
120
272
|
}
|
|
121
|
-
function ImageCtaHero({ src, alt = "", headline, subheading, ctaLabel, ctaHref, align = "left" }) {
|
|
273
|
+
function ImageCtaHero({ src, alt = "", headline, subheading, ctaLabel, ctaHref, align = "left", unit = "px" }) {
|
|
274
|
+
const u = scaler(unit);
|
|
122
275
|
if (!src) return null;
|
|
123
|
-
return /* @__PURE__ */
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
-
/* @__PURE__ */
|
|
127
|
-
/* @__PURE__ */
|
|
128
|
-
headline && /* @__PURE__ */
|
|
129
|
-
subheading && /* @__PURE__ */
|
|
130
|
-
ctaHref && ctaLabel && /* @__PURE__ */
|
|
276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderRadius: u(12), overflow: "hidden", position: "relative", width: "100%", paddingBottom: "56.25%" }, children: [
|
|
277
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src, alt, style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" } }),
|
|
278
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.45)" } }),
|
|
279
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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%)" } }),
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding: u(28), textAlign: align }, children: [
|
|
281
|
+
headline && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontSize: u(24), fontWeight: 700, color: "#fff", lineHeight: 1.2, margin: `0 0 ${u(8)}`, letterSpacing: "-0.02em" }, children: headline }),
|
|
282
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(15), color: "rgba(255,255,255,0.75)", lineHeight: 1.5, margin: `0 0 ${u(20)}` }, children: subheading }),
|
|
283
|
+
ctaHref && ctaLabel && /* @__PURE__ */ (0, import_jsx_runtime.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 })
|
|
131
284
|
] })
|
|
132
285
|
] });
|
|
133
286
|
}
|
|
134
|
-
function CtaStrip({ headline, primary, secondary, align = "center" }) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
/* @__PURE__ */
|
|
138
|
-
|
|
139
|
-
|
|
287
|
+
function CtaStrip({ headline, primary, secondary, align = "center", unit = "px" }) {
|
|
288
|
+
const u = scaler(unit);
|
|
289
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(32), textAlign: align, background: "var(--sp-bg)" }, children: [
|
|
290
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { fontSize: u(24), fontWeight: 700, color: "var(--sp-text)", margin: `0 0 ${u(24)}` }, children: headline }),
|
|
291
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: flexItems(align), gap: u(16), flexWrap: "wrap" }, children: [
|
|
292
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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 }),
|
|
293
|
+
secondary && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: secondary.href, style: { fontSize: u(15), color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
|
|
140
294
|
secondary.label,
|
|
141
295
|
" \u2192"
|
|
142
296
|
] })
|
|
143
297
|
] })
|
|
144
298
|
] });
|
|
145
299
|
}
|
|
146
|
-
function renderSingle(item, brand, align) {
|
|
300
|
+
function renderSingle(item, brand, align, unit = "px") {
|
|
147
301
|
var _a, _b;
|
|
148
302
|
const s = (_a = item.slots) != null ? _a : {};
|
|
149
303
|
switch (item.component) {
|
|
304
|
+
case "AnnouncementBar":
|
|
305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnouncementBar, { text: s.text, link: s.link, unit });
|
|
150
306
|
case "HeroStatement":
|
|
151
|
-
return /* @__PURE__ */
|
|
307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroStatement, { headline: s.headline, subheading: s.subheading, align, unit });
|
|
308
|
+
// A full-width card has nothing beside it, so there is nothing for a clamp to protect.
|
|
152
309
|
case "AtomCard":
|
|
153
|
-
return /* @__PURE__ */
|
|
310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.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 });
|
|
154
311
|
case "StatGrid":
|
|
155
|
-
return /* @__PURE__ */
|
|
312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatGrid, { stats: s.stats, caption: s.caption, unit });
|
|
156
313
|
case "CodeBlock":
|
|
157
|
-
return /* @__PURE__ */
|
|
314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption, unit });
|
|
158
315
|
case "ComparisonTable":
|
|
159
|
-
return /* @__PURE__ */
|
|
316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComparisonTable, { brand: (_b = s.brand) != null ? _b : brand, competitor: s.competitor, rows: s.rows, unit });
|
|
160
317
|
case "FeatureList":
|
|
161
|
-
return /* @__PURE__ */
|
|
318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FeatureList, { items: s.items, unit });
|
|
162
319
|
case "TestimonialCard":
|
|
163
|
-
return /* @__PURE__ */
|
|
320
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company, unit });
|
|
164
321
|
case "ImageCtaHero":
|
|
165
|
-
return /* @__PURE__ */
|
|
322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageCtaHero, { src: s.src, alt: s.alt, headline: s.headline, subheading: s.subheading, ctaLabel: s.ctaLabel, ctaHref: s.ctaHref, align, unit });
|
|
166
323
|
case "CtaStrip":
|
|
167
|
-
return /* @__PURE__ */
|
|
168
|
-
|
|
169
|
-
|
|
324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary, align, unit });
|
|
325
|
+
// An unrecognised component name used to render nothing at all. A component needs a
|
|
326
|
+
// renderer here plus spectare.js plus the WordPress plugin, so missing one made its content
|
|
327
|
+
// silently absent on that surface only: no error, no warning, just a shorter page that
|
|
328
|
+
// looks deliberate. That is the failure mode to remove before the registry grows.
|
|
329
|
+
//
|
|
330
|
+
// Falls back to AtomCard when the slots carry something readable, since almost every
|
|
331
|
+
// component is built from an atom and title/content is the shape they share. When there
|
|
332
|
+
// is genuinely nothing to show it still renders nothing, because an empty card is worse
|
|
333
|
+
// than a gap, but the warning fires either way.
|
|
334
|
+
default: {
|
|
335
|
+
console.warn(`[spectare] ComponentRenderer: no renderer for "${item.component}", falling back to AtomCard`);
|
|
336
|
+
if (!s.title && !s.content) return null;
|
|
337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AtomCard, { title: s.title, content: s.content, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: true, unit });
|
|
338
|
+
}
|
|
170
339
|
}
|
|
171
340
|
}
|
|
172
341
|
function resolvedSize(item) {
|
|
173
342
|
if (item.size) return item.size;
|
|
174
343
|
return HALF_COMPONENTS.has(item.component) ? "half" : "full";
|
|
175
344
|
}
|
|
345
|
+
function pairable(a, b) {
|
|
346
|
+
const catOf = (x) => COMPONENT_CATEGORIES[x.component];
|
|
347
|
+
const ca = catOf(a);
|
|
348
|
+
const cb = catOf(b);
|
|
349
|
+
return ca !== void 0 && ca === cb;
|
|
350
|
+
}
|
|
176
351
|
function buildLayout(assembly) {
|
|
177
352
|
const groups = [];
|
|
178
353
|
let i = 0;
|
|
179
354
|
while (i < assembly.length) {
|
|
180
355
|
const cur = assembly[i];
|
|
181
356
|
const next = assembly[i + 1];
|
|
182
|
-
if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half") {
|
|
357
|
+
if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half" && pairable(cur, next)) {
|
|
183
358
|
groups.push({ type: "pair", items: [cur, next] });
|
|
184
359
|
i += 2;
|
|
185
360
|
} else if (resolvedSize(cur) === "half") {
|
|
@@ -193,44 +368,60 @@ function buildLayout(assembly) {
|
|
|
193
368
|
return groups;
|
|
194
369
|
}
|
|
195
370
|
function XrayBadge({ name, size }) {
|
|
196
|
-
return /* @__PURE__ */
|
|
197
|
-
/* @__PURE__ */
|
|
198
|
-
/* @__PURE__ */
|
|
371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
372
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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 }),
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: PX(10), fontFamily: "monospace", color: "#71717a", lineHeight: 1 }, children: size })
|
|
199
374
|
] });
|
|
200
375
|
}
|
|
201
|
-
|
|
202
|
-
|
|
376
|
+
function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent, unit = "px", renderOverride, renderItem, rootProps }) {
|
|
377
|
+
const u = scaler(unit);
|
|
203
378
|
const filtered = zone ? filterAssemblyByZone(assembly, zone) : assembly;
|
|
204
379
|
const layout = buildLayout(filtered);
|
|
205
|
-
|
|
206
|
-
|
|
380
|
+
const { className: extraClass, style: extraStyle, ...restRoot } = rootProps != null ? rootProps : {};
|
|
381
|
+
const renderOne = (item) => {
|
|
382
|
+
const override = renderOverride == null ? void 0 : renderOverride(item);
|
|
383
|
+
const node = override === void 0 ? renderSingle(item, brand, align, unit) : override;
|
|
384
|
+
return renderItem ? renderItem(item, node) : node;
|
|
385
|
+
};
|
|
386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: extraClass ? `${SP_ROOT} ${extraClass}` : SP_ROOT, ...restRoot, style: { ...extraStyle, display: "flex", flexDirection: "column", gap: u(20), ...unit === "px" ? { fontSize: "16px" } : {} }, children: [
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent, unit }) } }),
|
|
207
388
|
layout.map((group, i) => {
|
|
208
|
-
if (group.type === "full") {
|
|
209
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
210
|
-
xray && /* @__PURE__ */ jsxRuntime.jsx(XrayBadge, { name: group.item.component, size: "full" }),
|
|
211
|
-
renderSingle(group.item, brand, align)
|
|
212
|
-
] }, i);
|
|
213
|
-
}
|
|
214
389
|
if (group.type === "pair") {
|
|
215
|
-
return /* @__PURE__ */
|
|
216
|
-
/* @__PURE__ */
|
|
217
|
-
xray && /* @__PURE__ */
|
|
218
|
-
|
|
390
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sp-pair", children: [
|
|
391
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
392
|
+
xray && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XrayBadge, { name: group.items[0].component, size: "half" }),
|
|
393
|
+
renderOne(group.items[0])
|
|
219
394
|
] }),
|
|
220
|
-
/* @__PURE__ */
|
|
221
|
-
xray && /* @__PURE__ */
|
|
222
|
-
|
|
395
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
396
|
+
xray && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XrayBadge, { name: group.items[1].component, size: "half" }),
|
|
397
|
+
renderOne(group.items[1])
|
|
223
398
|
] })
|
|
224
399
|
] }, i);
|
|
225
400
|
}
|
|
226
|
-
return /* @__PURE__ */
|
|
227
|
-
xray && /* @__PURE__ */
|
|
228
|
-
|
|
401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: xray ? { position: "relative" } : void 0, children: [
|
|
402
|
+
xray && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XrayBadge, { name: group.item.component, size: group.type === "half-solo" ? "half" : "full" }),
|
|
403
|
+
renderOne(group.item)
|
|
229
404
|
] }, i);
|
|
230
405
|
})
|
|
231
406
|
] });
|
|
232
407
|
}
|
|
233
|
-
|
|
408
|
+
|
|
409
|
+
// src/PersonalisedSection.tsx
|
|
410
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
411
|
+
var VARIANT_KEY = (orgSlug) => `_spectare_variant_${orgSlug}`;
|
|
412
|
+
function readVariantId(orgSlug) {
|
|
413
|
+
try {
|
|
414
|
+
return sessionStorage.getItem(VARIANT_KEY(orgSlug));
|
|
415
|
+
} catch (e) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function writeVariantId(orgSlug, variantId) {
|
|
420
|
+
try {
|
|
421
|
+
sessionStorage.setItem(VARIANT_KEY(orgSlug), variantId);
|
|
422
|
+
} catch (e) {
|
|
423
|
+
}
|
|
424
|
+
}
|
|
234
425
|
function buildSummary(pageHint, orgSlug) {
|
|
235
426
|
const parts = [pageHint];
|
|
236
427
|
const referrer = document.referrer;
|
|
@@ -266,11 +457,11 @@ function readVisitPath(orgSlug) {
|
|
|
266
457
|
}
|
|
267
458
|
}
|
|
268
459
|
function Shimmer() {
|
|
269
|
-
return /* @__PURE__ */
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
-
/* @__PURE__ */
|
|
272
|
-
/* @__PURE__ */
|
|
273
|
-
/* @__PURE__ */
|
|
460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
461
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "20px", background: "rgba(39,39,42,0.6)", borderRadius: "8px", width: "75%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
|
|
462
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "100%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
|
|
463
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "83%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
|
|
464
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "67%", animation: "sp-pulse 1.5s ease-in-out infinite" } })
|
|
274
465
|
] });
|
|
275
466
|
}
|
|
276
467
|
function PersonalisedSection({
|
|
@@ -282,32 +473,39 @@ function PersonalisedSection({
|
|
|
282
473
|
style,
|
|
283
474
|
initialAssembly,
|
|
284
475
|
initialIntent,
|
|
476
|
+
initialVariantId,
|
|
477
|
+
directSummary,
|
|
285
478
|
zone,
|
|
286
|
-
align
|
|
479
|
+
align,
|
|
480
|
+
accent
|
|
287
481
|
}) {
|
|
288
|
-
const [assembly, setAssembly] =
|
|
289
|
-
const [loading, setLoading] =
|
|
290
|
-
const [orgName, setOrgName] =
|
|
291
|
-
const
|
|
292
|
-
const
|
|
293
|
-
|
|
482
|
+
const [assembly, setAssembly] = (0, import_react.useState)(initialAssembly != null ? initialAssembly : []);
|
|
483
|
+
const [loading, setLoading] = (0, import_react.useState)(!initialAssembly);
|
|
484
|
+
const [orgName, setOrgName] = (0, import_react.useState)(void 0);
|
|
485
|
+
const [debugMode, setDebugMode] = (0, import_react.useState)(false);
|
|
486
|
+
const [debugIntent, setDebugIntent] = (0, import_react.useState)(null);
|
|
487
|
+
const tokenRef = (0, import_react.useRef)(null);
|
|
488
|
+
const conversionFiredRef = (0, import_react.useRef)(false);
|
|
489
|
+
(0, import_react.useEffect)(() => {
|
|
490
|
+
setDebugMode(new URLSearchParams(window.location.search).has("spectare_debug"));
|
|
491
|
+
if (initialIntent) setDebugIntent(initialIntent);
|
|
492
|
+
}, [initialIntent]);
|
|
493
|
+
(0, import_react.useEffect)(() => {
|
|
494
|
+
if (initialVariantId) writeVariantId(orgSlug, initialVariantId);
|
|
495
|
+
}, [orgSlug, initialVariantId]);
|
|
496
|
+
(0, import_react.useEffect)(() => {
|
|
294
497
|
let cancelled = false;
|
|
295
498
|
async function load() {
|
|
296
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
499
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
297
500
|
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);
|
|
501
|
+
let token = null;
|
|
502
|
+
if (directSummary) {
|
|
503
|
+
setLoading(true);
|
|
504
|
+
setAssembly([]);
|
|
307
505
|
const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
308
506
|
method: "POST",
|
|
309
507
|
headers: { "Content-Type": "application/json" },
|
|
310
|
-
body: JSON.stringify({ summary })
|
|
508
|
+
body: JSON.stringify({ summary: directSummary, direct: true })
|
|
311
509
|
});
|
|
312
510
|
if (!res2.ok || cancelled) {
|
|
313
511
|
setLoading(false);
|
|
@@ -315,8 +513,30 @@ function PersonalisedSection({
|
|
|
315
513
|
}
|
|
316
514
|
const data = await res2.json();
|
|
317
515
|
token = (_a = data.token) != null ? _a : null;
|
|
318
|
-
|
|
319
|
-
|
|
516
|
+
} else {
|
|
517
|
+
const p = new URLSearchParams(window.location.search);
|
|
518
|
+
const utmSuffix = ["utm_source", "utm_medium", "utm_campaign", "utm_term"].map((k) => {
|
|
519
|
+
var _a2;
|
|
520
|
+
return (_a2 = p.get(k)) != null ? _a2 : "";
|
|
521
|
+
}).filter(Boolean).join("_");
|
|
522
|
+
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
523
|
+
token = sessionStorage.getItem(tokenKey);
|
|
524
|
+
if (!token) {
|
|
525
|
+
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
526
|
+
const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
527
|
+
method: "POST",
|
|
528
|
+
headers: { "Content-Type": "application/json" },
|
|
529
|
+
body: JSON.stringify({ summary })
|
|
530
|
+
});
|
|
531
|
+
if (!res2.ok || cancelled) {
|
|
532
|
+
setLoading(false);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const data = await res2.json();
|
|
536
|
+
token = (_b = data.token) != null ? _b : null;
|
|
537
|
+
if (token) sessionStorage.setItem(tokenKey, token);
|
|
538
|
+
if (data.orgName) setOrgName(data.orgName);
|
|
539
|
+
}
|
|
320
540
|
}
|
|
321
541
|
if (!token || cancelled) {
|
|
322
542
|
setLoading(false);
|
|
@@ -326,9 +546,19 @@ function PersonalisedSection({
|
|
|
326
546
|
let res = await fetch(`${baseUrl}/api/assemble/components`, {
|
|
327
547
|
method: "POST",
|
|
328
548
|
headers: { "Content-Type": "application/json" },
|
|
329
|
-
|
|
549
|
+
// Direct: flag it so the server cost-caps the build, and omit the seen-variant
|
|
550
|
+
// exclusion so it can read the shared cache instead of forcing a fresh build.
|
|
551
|
+
body: JSON.stringify(
|
|
552
|
+
directSummary ? { token, orgSlug, direct: true } : { token, orgSlug, excludeVariantId: readVariantId(orgSlug) }
|
|
553
|
+
)
|
|
330
554
|
});
|
|
331
|
-
if (res.status === 401 && !cancelled) {
|
|
555
|
+
if (res.status === 401 && !cancelled && !directSummary) {
|
|
556
|
+
const p = new URLSearchParams(window.location.search);
|
|
557
|
+
const utmSuffix = ["utm_source", "utm_medium", "utm_campaign", "utm_term"].map((k) => {
|
|
558
|
+
var _a2;
|
|
559
|
+
return (_a2 = p.get(k)) != null ? _a2 : "";
|
|
560
|
+
}).filter(Boolean).join("_");
|
|
561
|
+
const tokenKey = `_spectare_token_${orgSlug}${utmSuffix ? "_" + utmSuffix : ""}`;
|
|
332
562
|
sessionStorage.removeItem(tokenKey);
|
|
333
563
|
const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`, orgSlug);
|
|
334
564
|
const qRes = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
|
|
@@ -341,7 +571,7 @@ function PersonalisedSection({
|
|
|
341
571
|
return;
|
|
342
572
|
}
|
|
343
573
|
const qData = await qRes.json();
|
|
344
|
-
token = (
|
|
574
|
+
token = (_c = qData.token) != null ? _c : null;
|
|
345
575
|
if (token) {
|
|
346
576
|
sessionStorage.setItem(tokenKey, token);
|
|
347
577
|
tokenRef.current = token;
|
|
@@ -353,14 +583,14 @@ function PersonalisedSection({
|
|
|
353
583
|
res = await fetch(`${baseUrl}/api/assemble/components`, {
|
|
354
584
|
method: "POST",
|
|
355
585
|
headers: { "Content-Type": "application/json" },
|
|
356
|
-
body: JSON.stringify({ token, orgSlug })
|
|
586
|
+
body: JSON.stringify({ token, orgSlug, excludeVariantId: readVariantId(orgSlug) })
|
|
357
587
|
});
|
|
358
588
|
}
|
|
359
589
|
if (!res.ok || cancelled) {
|
|
360
590
|
setLoading(false);
|
|
361
591
|
return;
|
|
362
592
|
}
|
|
363
|
-
const contentType = (
|
|
593
|
+
const contentType = (_d = res.headers.get("content-type")) != null ? _d : "";
|
|
364
594
|
if (contentType.includes("text/event-stream")) {
|
|
365
595
|
const reader = res.body.getReader();
|
|
366
596
|
const decoder = new TextDecoder();
|
|
@@ -372,13 +602,26 @@ function PersonalisedSection({
|
|
|
372
602
|
if (done || cancelled) break;
|
|
373
603
|
buf += decoder.decode(value, { stream: true });
|
|
374
604
|
const lines = buf.split("\n");
|
|
375
|
-
buf = (
|
|
605
|
+
buf = (_e = lines.pop()) != null ? _e : "";
|
|
376
606
|
for (const line of lines) {
|
|
377
607
|
if (!line.startsWith("data: ")) continue;
|
|
378
608
|
const payload = line.slice(6).trim();
|
|
379
609
|
if (payload === "[DONE]") break;
|
|
380
610
|
try {
|
|
381
|
-
const
|
|
611
|
+
const parsed = JSON.parse(payload);
|
|
612
|
+
if (parsed._variant && typeof parsed._variant === "string") {
|
|
613
|
+
writeVariantId(orgSlug, parsed._variant);
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
if (parsed._error) {
|
|
617
|
+
if (!loadingCleared) {
|
|
618
|
+
setLoading(false);
|
|
619
|
+
loadingCleared = true;
|
|
620
|
+
}
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
if (!parsed.component) continue;
|
|
624
|
+
const comp = parsed;
|
|
382
625
|
if (!loadingCleared) {
|
|
383
626
|
setLoading(false);
|
|
384
627
|
loadingCleared = true;
|
|
@@ -394,10 +637,14 @@ function PersonalisedSection({
|
|
|
394
637
|
}
|
|
395
638
|
} else {
|
|
396
639
|
const data = await res.json();
|
|
640
|
+
if (data.variantId) writeVariantId(orgSlug, data.variantId);
|
|
397
641
|
if (cancelled) return;
|
|
398
|
-
const clientAudience = (
|
|
399
|
-
const clientStage = (
|
|
642
|
+
const clientAudience = (_g = (_f = data.intent) == null ? void 0 : _f.userContext) == null ? void 0 : _g.audience;
|
|
643
|
+
const clientStage = (_i = (_h = data.intent) == null ? void 0 : _h.userContext) == null ? void 0 : _i.stage;
|
|
400
644
|
const ssrMatches = initialIntent && clientAudience === initialIntent.audience && clientStage === initialIntent.stage;
|
|
645
|
+
if (clientAudience && clientStage) {
|
|
646
|
+
setDebugIntent({ audience: clientAudience, stage: clientStage });
|
|
647
|
+
}
|
|
401
648
|
if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {
|
|
402
649
|
setAssembly(data.assembly);
|
|
403
650
|
}
|
|
@@ -411,8 +658,8 @@ function PersonalisedSection({
|
|
|
411
658
|
return () => {
|
|
412
659
|
cancelled = true;
|
|
413
660
|
};
|
|
414
|
-
}, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);
|
|
415
|
-
|
|
661
|
+
}, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent, directSummary]);
|
|
662
|
+
(0, import_react.useEffect)(() => {
|
|
416
663
|
if (!assembly.length || conversionFiredRef.current) return;
|
|
417
664
|
const token = tokenRef.current;
|
|
418
665
|
if (!token) return;
|
|
@@ -456,6 +703,7 @@ function PersonalisedSection({
|
|
|
456
703
|
token,
|
|
457
704
|
orgSlug,
|
|
458
705
|
url,
|
|
706
|
+
variantId: readVariantId(orgSlug),
|
|
459
707
|
...atomsShown.length ? { atomsShown } : {},
|
|
460
708
|
...visitPath.length > 1 ? { visitPath } : {},
|
|
461
709
|
...data.goalName ? { goalName: data.goalName } : {},
|
|
@@ -467,15 +715,40 @@ function PersonalisedSection({
|
|
|
467
715
|
});
|
|
468
716
|
}, [assembly, orgSlug, baseUrl]);
|
|
469
717
|
if (!loading && assembly.length === 0) return null;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
/* @__PURE__ */
|
|
473
|
-
/* @__PURE__ */
|
|
718
|
+
const debugStyle = debugMode ? { outline: "2px solid rgba(96,165,250,0.5)", borderRadius: "0.5rem", position: "relative", padding: "0.5rem", ...style } : style;
|
|
719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
|
|
721
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, style: debugStyle, children: [
|
|
722
|
+
debugMode && /* @__PURE__ */ (0, import_jsx_runtime2.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: [
|
|
723
|
+
"Personalised by Spectare",
|
|
724
|
+
debugIntent && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { opacity: 0.75 }, children: [
|
|
725
|
+
" ",
|
|
726
|
+
debugIntent.audience,
|
|
727
|
+
"/",
|
|
728
|
+
debugIntent.stage
|
|
729
|
+
] })
|
|
730
|
+
] }),
|
|
731
|
+
loading && assembly.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Shimmer, {}) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent })
|
|
732
|
+
] })
|
|
474
733
|
] });
|
|
475
734
|
}
|
|
476
|
-
|
|
477
|
-
exports
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
735
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
736
|
+
0 && (module.exports = {
|
|
737
|
+
AnnouncementBar,
|
|
738
|
+
AtomCard,
|
|
739
|
+
CodeBlock,
|
|
740
|
+
ComparisonTable,
|
|
741
|
+
ComponentRenderer,
|
|
742
|
+
CtaStrip,
|
|
743
|
+
DEFAULT_ACCENT,
|
|
744
|
+
FeatureList,
|
|
745
|
+
HeroStatement,
|
|
746
|
+
ImageCtaHero,
|
|
747
|
+
PersonalisedSection,
|
|
748
|
+
SP_ROOT,
|
|
749
|
+
StatGrid,
|
|
750
|
+
TestimonialCard,
|
|
751
|
+
buildTokenCss,
|
|
752
|
+
filterAssemblyByZone
|
|
753
|
+
});
|
|
481
754
|
//# sourceMappingURL=index.cjs.map
|