@spectare-personalisation/react 0.1.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 ADDED
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/PersonalisedSection.tsx
7
+ var HALF_COMPONENTS = /* @__PURE__ */ new Set(["TestimonialCard"]);
8
+ function HeroStatement({ headline, subheading }) {
9
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { paddingTop: "1.5rem", paddingBottom: "1.5rem" }, children: [
10
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontSize: "2rem", fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2, color: "var(--sp-text)", margin: "0 0 0.75rem" }, children: headline }),
11
+ subheading && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "1.125rem", color: "var(--sp-text-sub)", lineHeight: 1.6, maxWidth: "42rem", margin: 0 }, children: subheading })
12
+ ] });
13
+ }
14
+ function AtomCard({ title, content }) {
15
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem", height: "100%" }, children: [
16
+ title && /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "1rem", fontWeight: 600, color: "var(--sp-text)", margin: "0 0 0.75rem" }, children: title }),
17
+ content && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.875rem", color: "var(--sp-text-sub)", lineHeight: 1.6, margin: 0 }, children: content })
18
+ ] });
19
+ }
20
+ function StatGrid({ stats, caption }) {
21
+ const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;
22
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem" }, children: [
23
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: "1.5rem" }, children: stats.map(({ value, label }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center" }, children: [
24
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "1.875rem", fontWeight: 700, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", margin: 0 }, children: value }),
25
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", marginTop: "0.375rem", textTransform: "uppercase", letterSpacing: "0.05em" }, children: label })
26
+ ] }, label)) }),
27
+ caption && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", textAlign: "center", marginTop: "1.25rem", borderTop: "1px solid var(--sp-border)", paddingTop: "1rem" }, children: caption })
28
+ ] });
29
+ }
30
+ function CodeBlock({ code, lang = "typescript", caption }) {
31
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRadius: "0.75rem", overflow: "hidden", border: "1px solid var(--sp-border)" }, children: [
32
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", padding: "0.625rem 1rem", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid var(--sp-border)" }, children: [
33
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", fontFamily: "monospace" }, children: lang }),
34
+ caption && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)" }, children: caption })
35
+ ] }),
36
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { style: { background: "var(--sp-surface)", padding: "1.25rem", fontSize: "0.75rem", color: "var(--sp-text-sub)", overflowX: "auto", lineHeight: 1.6, fontFamily: "monospace", whiteSpace: "pre", margin: 0 }, children: code })
37
+ ] });
38
+ }
39
+ function ComparisonTable({ brand = "Us", competitor, rows }) {
40
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "0.75rem", overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("table", { style: { width: "100%", fontSize: "0.875rem", borderCollapse: "collapse" }, children: [
41
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
42
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: { textAlign: "left", padding: "0.75rem 1rem", color: "var(--sp-text-muted)", fontWeight: 500, fontSize: "0.75rem", width: "33%" } }),
43
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: { textAlign: "left", padding: "0.75rem 1rem", fontWeight: 600, color: "var(--sp-accent)", fontSize: "0.75rem" }, children: brand }),
44
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: { textAlign: "left", padding: "0.75rem 1rem", color: "var(--sp-text-muted)", fontWeight: 500, fontSize: "0.75rem" }, children: competitor })
45
+ ] }) }),
46
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
47
+ /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "0.75rem 1rem", fontSize: "0.75rem", color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
48
+ /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "0.75rem 1rem", fontSize: "0.75rem", color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
49
+ /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "0.75rem 1rem", fontSize: "0.75rem", color: "var(--sp-text-muted)" }, children: them })
50
+ ] }, label)) })
51
+ ] }) }) });
52
+ }
53
+ function FeatureList({ items }) {
54
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "1rem" }, children: items.map(({ text, sub }) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: { display: "flex", gap: "0.75rem" }, children: [
55
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: "0.875rem", marginTop: "0.125rem" }, children: "\u2713" }),
56
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
57
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.875rem", fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
58
+ sub && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", marginTop: "0.25rem", lineHeight: 1.5, margin: "0.25rem 0 0" }, children: sub })
59
+ ] })
60
+ ] }, text)) }) });
61
+ }
62
+ function TestimonialCard({ quote, name, role, company }) {
63
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem", display: "flex", flexDirection: "column", gap: "1.25rem", height: "100%" }, children: [
64
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: "0.875rem", color: "var(--sp-text-sub)", lineHeight: 1.6, flex: 1, margin: 0 }, children: [
65
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: "1.125rem", lineHeight: 1, marginRight: "0.25rem" }, children: '"' }),
66
+ quote,
67
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: "1.125rem", lineHeight: 1, marginLeft: "0.25rem" }, children: '"' })
68
+ ] }),
69
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: "1rem" }, children: [
70
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.875rem", fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
71
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", marginTop: "0.125rem", margin: "0.125rem 0 0" }, children: [
72
+ role,
73
+ company ? `, ${company}` : ""
74
+ ] })
75
+ ] })
76
+ ] });
77
+ }
78
+ function ImageHero({ src, alt = "", ratio = "16:9" }) {
79
+ if (!src) return null;
80
+ const [w, h] = ratio.split(":").map(Number);
81
+ const paddingBottom = w && h ? `${h / w * 100}%` : "56.25%";
82
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { borderRadius: "0.75rem", overflow: "hidden", position: "relative", width: "100%", paddingBottom }, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" } }) });
83
+ }
84
+ function CtaStrip({ headline, primary, secondary }) {
85
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "2rem", textAlign: "center", background: "var(--sp-bg)" }, children: [
86
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "1.5rem", fontWeight: 700, color: "var(--sp-text)", margin: "0 0 1.5rem" }, children: headline }),
87
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "1rem", flexWrap: "wrap" }, children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: primary.href, style: { background: "#fff", color: "#09090b", padding: "0.625rem 1.5rem", borderRadius: "0.75rem", fontWeight: 600, fontSize: "0.875rem", textDecoration: "none" }, children: primary.label }),
89
+ secondary && /* @__PURE__ */ jsxRuntime.jsxs("a", { href: secondary.href, style: { fontSize: "0.875rem", color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
90
+ secondary.label,
91
+ " \u2192"
92
+ ] })
93
+ ] })
94
+ ] });
95
+ }
96
+ function renderSingle(item, brand) {
97
+ var _a;
98
+ const s = (_a = item.slots) != null ? _a : {};
99
+ switch (item.component) {
100
+ case "HeroStatement":
101
+ return /* @__PURE__ */ jsxRuntime.jsx(HeroStatement, { headline: s.headline, subheading: s.subheading });
102
+ case "AtomCard":
103
+ return /* @__PURE__ */ jsxRuntime.jsx(AtomCard, { title: s.title, content: s.content });
104
+ case "StatGrid":
105
+ return /* @__PURE__ */ jsxRuntime.jsx(StatGrid, { stats: s.stats, caption: s.caption });
106
+ case "CodeBlock":
107
+ return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption });
108
+ case "ComparisonTable":
109
+ return /* @__PURE__ */ jsxRuntime.jsx(ComparisonTable, { brand, competitor: s.competitor, rows: s.rows });
110
+ case "FeatureList":
111
+ return /* @__PURE__ */ jsxRuntime.jsx(FeatureList, { items: s.items });
112
+ case "TestimonialCard":
113
+ return /* @__PURE__ */ jsxRuntime.jsx(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company });
114
+ case "ImageHero":
115
+ return /* @__PURE__ */ jsxRuntime.jsx(ImageHero, { src: s.src, alt: s.alt, ratio: s.ratio });
116
+ case "CtaStrip":
117
+ return /* @__PURE__ */ jsxRuntime.jsx(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary });
118
+ default:
119
+ return null;
120
+ }
121
+ }
122
+ function resolvedSize(item) {
123
+ if (item.size) return item.size;
124
+ return HALF_COMPONENTS.has(item.component) ? "half" : "full";
125
+ }
126
+ function buildLayout(assembly) {
127
+ const groups = [];
128
+ let i = 0;
129
+ while (i < assembly.length) {
130
+ const cur = assembly[i];
131
+ const next = assembly[i + 1];
132
+ if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half") {
133
+ groups.push({ type: "pair", items: [cur, next] });
134
+ i += 2;
135
+ } else if (resolvedSize(cur) === "half") {
136
+ groups.push({ type: "half-solo", item: cur });
137
+ i++;
138
+ } else {
139
+ groups.push({ type: "full", item: cur });
140
+ i++;
141
+ }
142
+ }
143
+ return groups;
144
+ }
145
+ function ComponentRenderer({ assembly, brand }) {
146
+ const layout = buildLayout(assembly);
147
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "1.25rem" }, children: layout.map((group, i) => {
148
+ if (group.type === "full") {
149
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderSingle(group.item, brand) }, i);
150
+ }
151
+ if (group.type === "pair") {
152
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "1.25rem" }, children: [
153
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderSingle(group.items[0], brand) }),
154
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderSingle(group.items[1], brand) })
155
+ ] }, i);
156
+ }
157
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderSingle(group.item, brand) }, i);
158
+ }) });
159
+ }
160
+ var CSS_TOKENS = `:root{--sp-accent:#60a5fa;--sp-accent-bg:rgba(96,165,250,0.1);--sp-accent-border:rgba(96,165,250,0.2);--sp-bg:#18181b;--sp-surface:#09090b;--sp-border:#27272a;--sp-text:#f4f4f5;--sp-text-sub:#d4d4d8;--sp-text-strong:#e4e4e7;--sp-text-muted:#71717a;--sp-text-dim:#52525b;--sp-text-body:#a1a1aa;--sp-positive:#6ee7b7;--sp-divider:rgba(255,255,255,0.06);--sp-code-bg:rgba(255,255,255,0.07);--sp-code-border:rgba(255,255,255,0.08);--sp-pre-bg:rgba(0,0,0,0.4)}`;
161
+ function buildSummary(pageHint) {
162
+ const parts = [pageHint];
163
+ const referrer = document.referrer;
164
+ if (referrer) parts.push(`Arrived from: ${referrer}`);
165
+ const p = new URLSearchParams(window.location.search);
166
+ const source = p.get("utm_source");
167
+ const medium = p.get("utm_medium");
168
+ const campaign = p.get("utm_campaign");
169
+ const term = p.get("utm_term");
170
+ if (source) parts.push(`Source: ${source}`);
171
+ if (medium) parts.push(`Medium: ${medium}`);
172
+ if (campaign) parts.push(`Campaign: ${campaign}`);
173
+ if (term) parts.push(`Search term: ${term}`);
174
+ try {
175
+ const history = localStorage.getItem("_spectare_visits");
176
+ if (history) parts.push(`Previously visited: ${history}`);
177
+ } catch (e) {
178
+ }
179
+ return parts.filter(Boolean).join(". ");
180
+ }
181
+ function Shimmer() {
182
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "1.25rem", background: "rgba(39,39,42,0.6)", borderRadius: "0.5rem", width: "75%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
184
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.875rem", background: "rgba(39,39,42,0.4)", borderRadius: "0.5rem", width: "100%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
185
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.875rem", background: "rgba(39,39,42,0.4)", borderRadius: "0.5rem", width: "83%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
186
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "0.875rem", background: "rgba(39,39,42,0.4)", borderRadius: "0.5rem", width: "67%", animation: "sp-pulse 1.5s ease-in-out infinite" } })
187
+ ] });
188
+ }
189
+ function PersonalisedSection({
190
+ orgSlug,
191
+ baseUrl = "https://spectare.ai",
192
+ brand,
193
+ pageHint,
194
+ className,
195
+ style,
196
+ initialAssembly,
197
+ initialIntent
198
+ }) {
199
+ const [assembly, setAssembly] = react.useState(initialAssembly != null ? initialAssembly : null);
200
+ const [loading, setLoading] = react.useState(!initialAssembly);
201
+ react.useEffect(() => {
202
+ let cancelled = false;
203
+ async function load() {
204
+ var _a, _b, _c, _d, _e;
205
+ try {
206
+ const tokenKey = `_spectare_token_${orgSlug}`;
207
+ let token = sessionStorage.getItem(tokenKey);
208
+ if (!token) {
209
+ const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`);
210
+ const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
211
+ method: "POST",
212
+ headers: { "Content-Type": "application/json" },
213
+ body: JSON.stringify({ summary })
214
+ });
215
+ if (!res2.ok || cancelled) {
216
+ setLoading(false);
217
+ return;
218
+ }
219
+ const data2 = await res2.json();
220
+ token = (_a = data2.token) != null ? _a : null;
221
+ if (token) sessionStorage.setItem(tokenKey, token);
222
+ }
223
+ if (!token || cancelled) {
224
+ setLoading(false);
225
+ return;
226
+ }
227
+ const res = await fetch(`${baseUrl}/api/assemble/components`, {
228
+ method: "POST",
229
+ headers: { "Content-Type": "application/json" },
230
+ body: JSON.stringify({ token, orgSlug })
231
+ });
232
+ if (!res.ok || cancelled) {
233
+ setLoading(false);
234
+ return;
235
+ }
236
+ const data = await res.json();
237
+ if (cancelled) return;
238
+ const clientAudience = (_c = (_b = data.intent) == null ? void 0 : _b.userContext) == null ? void 0 : _c.audience;
239
+ const clientStage = (_e = (_d = data.intent) == null ? void 0 : _d.userContext) == null ? void 0 : _e.stage;
240
+ const ssrMatches = initialIntent && clientAudience === initialIntent.audience && clientStage === initialIntent.stage;
241
+ if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {
242
+ setAssembly(data.assembly);
243
+ }
244
+ } catch (e) {
245
+ } finally {
246
+ if (!cancelled) setLoading(false);
247
+ }
248
+ }
249
+ load();
250
+ return () => {
251
+ cancelled = true;
252
+ };
253
+ }, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);
254
+ if (!loading && !assembly) return null;
255
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
256
+ /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: CSS_TOKENS } }),
257
+ /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
258
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: loading ? /* @__PURE__ */ jsxRuntime.jsx(Shimmer, {}) : assembly && /* @__PURE__ */ jsxRuntime.jsx(ComponentRenderer, { assembly, brand }) })
259
+ ] });
260
+ }
261
+
262
+ exports.ComponentRenderer = ComponentRenderer;
263
+ exports.PersonalisedSection = PersonalisedSection;
264
+ //# sourceMappingURL=index.cjs.map
265
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ComponentRenderer.tsx","../src/PersonalisedSection.tsx"],"names":["jsxs","jsx","useState","useEffect","res","data","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["'use client';\n\nimport type { ComponentAssembly, ComponentName } from './types';\n\n// Default half-size components — used when assembly item omits size.\nconst HALF_COMPONENTS = new Set<ComponentName>(['TestimonialCard']);\n\n// ── Individual component renderers ────────────────────────────────────────────\n\nfunction HeroStatement({ headline, subheading }: { headline: string; subheading?: string }) {\n return (\n <div style={{ paddingTop: '1.5rem', paddingBottom: '1.5rem' }}>\n <h2 style={{ fontSize: '2rem', fontWeight: 700, letterSpacing: '-0.025em', lineHeight: 1.2, color: 'var(--sp-text)', margin: '0 0 0.75rem' }}>\n {headline}\n </h2>\n {subheading && (\n <p style={{ fontSize: '1.125rem', color: 'var(--sp-text-sub)', lineHeight: 1.6, maxWidth: '42rem', margin: 0 }}>{subheading}</p>\n )}\n </div>\n );\n}\n\nfunction AtomCard({ title, content }: { title?: string; content?: string }) {\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem', height: '100%' }}>\n {title && <h3 style={{ fontSize: '1rem', fontWeight: 600, color: 'var(--sp-text)', margin: '0 0 0.75rem' }}>{title}</h3>}\n {content && <p style={{ fontSize: '0.875rem', color: 'var(--sp-text-sub)', lineHeight: 1.6, margin: 0 }}>{content}</p>}\n </div>\n );\n}\n\nfunction StatGrid({ stats, caption }: { stats: { value: string; label: string }[]; caption?: string }) {\n const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem' }}>\n <div style={{ display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: '1.5rem' }}>\n {stats.map(({ value, label }) => (\n <div key={label} style={{ textAlign: 'center' }}>\n <p style={{ fontSize: '1.875rem', fontWeight: 700, color: 'var(--sp-text)', fontVariantNumeric: 'tabular-nums', margin: 0 }}>{value}</p>\n <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', marginTop: '0.375rem', textTransform: 'uppercase', letterSpacing: '0.05em' }}>{label}</p>\n </div>\n ))}\n </div>\n {caption && (\n <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', textAlign: 'center', marginTop: '1.25rem', borderTop: '1px solid var(--sp-border)', paddingTop: '1rem' }}>{caption}</p>\n )}\n </div>\n );\n}\n\nfunction CodeBlock({ code, lang = 'typescript', caption }: { code: string; lang?: string; caption?: string }) {\n return (\n <div style={{ borderRadius: '0.75rem', overflow: 'hidden', border: '1px solid var(--sp-border)' }}>\n <div style={{ background: 'var(--sp-bg)', padding: '0.625rem 1rem', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid var(--sp-border)' }}>\n <span style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', fontFamily: 'monospace' }}>{lang}</span>\n {caption && <span style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)' }}>{caption}</span>}\n </div>\n <pre style={{ background: 'var(--sp-surface)', padding: '1.25rem', fontSize: '0.75rem', color: 'var(--sp-text-sub)', overflowX: 'auto', lineHeight: 1.6, fontFamily: 'monospace', whiteSpace: 'pre', margin: 0 }}>\n {code}\n </pre>\n </div>\n );\n}\n\nfunction ComparisonTable({ brand = 'Us', competitor, rows }: { brand?: string; competitor: string; rows: { label: string; spectare: string; them: string }[] }) {\n return (\n <div style={{ border: '1px solid var(--sp-border)', borderRadius: '0.75rem', overflow: 'hidden' }}>\n <div style={{ overflowX: 'auto' }}>\n <table style={{ width: '100%', fontSize: '0.875rem', borderCollapse: 'collapse' }}>\n <thead>\n <tr style={{ borderBottom: '1px solid var(--sp-border)', background: 'var(--sp-bg)' }}>\n <th style={{ textAlign: 'left', padding: '0.75rem 1rem', color: 'var(--sp-text-muted)', fontWeight: 500, fontSize: '0.75rem', width: '33%' }} />\n <th style={{ textAlign: 'left', padding: '0.75rem 1rem', fontWeight: 600, color: 'var(--sp-accent)', fontSize: '0.75rem' }}>{brand}</th>\n <th style={{ textAlign: 'left', padding: '0.75rem 1rem', color: 'var(--sp-text-muted)', fontWeight: 500, fontSize: '0.75rem' }}>{competitor}</th>\n </tr>\n </thead>\n <tbody>\n {rows.map(({ label, spectare, them }) => (\n <tr key={label} style={{ borderBottom: '1px solid var(--sp-border)' }}>\n <td style={{ padding: '0.75rem 1rem', fontSize: '0.75rem', color: 'var(--sp-text-muted)', fontWeight: 500 }}>{label}</td>\n <td style={{ padding: '0.75rem 1rem', fontSize: '0.75rem', color: 'var(--sp-positive)', fontWeight: 500 }}>{spectare}</td>\n <td style={{ padding: '0.75rem 1rem', fontSize: '0.75rem', color: 'var(--sp-text-muted)' }}>{them}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n\nfunction FeatureList({ items }: { items: { text: string; sub?: string }[] }) {\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem' }}>\n <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: '1rem' }}>\n {items.map(({ text, sub }) => (\n <li key={text} style={{ display: 'flex', gap: '0.75rem' }}>\n <span style={{ color: 'var(--sp-accent)', flexShrink: 0, fontSize: '0.875rem', marginTop: '0.125rem' }}>✓</span>\n <div>\n <p style={{ fontSize: '0.875rem', fontWeight: 500, color: 'var(--sp-text)', lineHeight: 1.4, margin: 0 }}>{text}</p>\n {sub && <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', marginTop: '0.25rem', lineHeight: 1.5, margin: '0.25rem 0 0' }}>{sub}</p>}\n </div>\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\nfunction TestimonialCard({ quote, name, role, company }: { quote: string; name: string; role: string; company?: string }) {\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem', display: 'flex', flexDirection: 'column', gap: '1.25rem', height: '100%' }}>\n <p style={{ fontSize: '0.875rem', color: 'var(--sp-text-sub)', lineHeight: 1.6, flex: 1, margin: 0 }}>\n <span style={{ color: 'var(--sp-text-dim)', fontSize: '1.125rem', lineHeight: 1, marginRight: '0.25rem' }}>\"</span>\n {quote}\n <span style={{ color: 'var(--sp-text-dim)', fontSize: '1.125rem', lineHeight: 1, marginLeft: '0.25rem' }}>\"</span>\n </p>\n <div style={{ borderTop: '1px solid var(--sp-border)', paddingTop: '1rem' }}>\n <p style={{ fontSize: '0.875rem', fontWeight: 600, color: 'var(--sp-text)', margin: 0 }}>{name}</p>\n <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', marginTop: '0.125rem', margin: '0.125rem 0 0' }}>\n {role}{company ? `, ${company}` : ''}\n </p>\n </div>\n </div>\n );\n}\n\nfunction ImageHero({ src, alt = '', ratio = '16:9' }: { src?: string; alt?: string; ratio?: string }) {\n if (!src) return null;\n const [w, h] = ratio.split(':').map(Number);\n const paddingBottom = w && h ? `${(h / w) * 100}%` : '56.25%';\n return (\n <div style={{ borderRadius: '0.75rem', overflow: 'hidden', position: 'relative', width: '100%', paddingBottom }}>\n <img src={src} alt={alt} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />\n </div>\n );\n}\n\nfunction CtaStrip({ headline, primary, secondary }: { headline: string; primary: { label: string; href: string }; secondary?: { label: string; href: string } }) {\n return (\n <div style={{ border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '2rem', textAlign: 'center', background: 'var(--sp-bg)' }}>\n <h3 style={{ fontSize: '1.5rem', fontWeight: 700, color: 'var(--sp-text)', margin: '0 0 1.5rem' }}>{headline}</h3>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '1rem', flexWrap: 'wrap' }}>\n <a href={primary.href} style={{ background: '#fff', color: '#09090b', padding: '0.625rem 1.5rem', borderRadius: '0.75rem', fontWeight: 600, fontSize: '0.875rem', textDecoration: 'none' }}>\n {primary.label}\n </a>\n {secondary && (\n <a href={secondary.href} style={{ fontSize: '0.875rem', color: 'var(--sp-text-sub)', textDecoration: 'none' }}>\n {secondary.label} →\n </a>\n )}\n </div>\n </div>\n );\n}\n\n// ── Dispatch ──────────────────────────────────────────────────────────────────\n\nfunction renderSingle(item: ComponentAssembly[0], brand?: string): React.ReactNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const s = item.slots as Record<string, any> ?? {};\n\n switch (item.component as ComponentName) {\n case 'HeroStatement': return <HeroStatement headline={s.headline} subheading={s.subheading} />;\n case 'AtomCard': return <AtomCard title={s.title} content={s.content} />;\n case 'StatGrid': return <StatGrid stats={s.stats} caption={s.caption} />;\n case 'CodeBlock': return <CodeBlock code={s.code} lang={s.lang} caption={s.caption} />;\n case 'ComparisonTable': return <ComparisonTable brand={brand} competitor={s.competitor} rows={s.rows} />;\n case 'FeatureList': return <FeatureList items={s.items} />;\n case 'TestimonialCard': return <TestimonialCard quote={s.quote} name={s.name} role={s.role} company={s.company} />;\n case 'ImageHero': return <ImageHero src={s.src} alt={s.alt} ratio={s.ratio} />;\n case 'CtaStrip': return <CtaStrip headline={s.headline} primary={s.primary} secondary={s.secondary} />;\n default: return null;\n }\n}\n\n// ── Layout ────────────────────────────────────────────────────────────────────\n\nfunction resolvedSize(item: ComponentAssembly[0]): 'full' | 'half' {\n if (item.size) return item.size;\n return HALF_COMPONENTS.has(item.component as ComponentName) ? 'half' : 'full';\n}\n\ntype LayoutGroup =\n | { type: 'full'; item: ComponentAssembly[0] }\n | { type: 'pair'; items: [ComponentAssembly[0], ComponentAssembly[0]] }\n | { type: 'half-solo'; item: ComponentAssembly[0] };\n\nfunction buildLayout(assembly: ComponentAssembly): LayoutGroup[] {\n const groups: LayoutGroup[] = [];\n let i = 0;\n while (i < assembly.length) {\n const cur = assembly[i];\n const next = assembly[i + 1];\n if (resolvedSize(cur) === 'half' && next && resolvedSize(next) === 'half') {\n groups.push({ type: 'pair', items: [cur, next] });\n i += 2;\n } else if (resolvedSize(cur) === 'half') {\n groups.push({ type: 'half-solo', item: cur });\n i++;\n } else {\n groups.push({ type: 'full', item: cur });\n i++;\n }\n }\n return groups;\n}\n\n// ── Main export ───────────────────────────────────────────────────────────────\n\nexport interface ComponentRendererProps {\n assembly: ComponentAssembly;\n /** Your brand name, used as the left column header in ComparisonTable. Defaults to \"Us\". */\n brand?: string;\n}\n\nexport function ComponentRenderer({ assembly, brand }: ComponentRendererProps) {\n const layout = buildLayout(assembly);\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '1.25rem' }}>\n {layout.map((group, i) => {\n if (group.type === 'full') {\n return <div key={i}>{renderSingle(group.item, brand)}</div>;\n }\n if (group.type === 'pair') {\n return (\n <div key={i} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.25rem' }}>\n <div>{renderSingle(group.items[0], brand)}</div>\n <div>{renderSingle(group.items[1], brand)}</div>\n </div>\n );\n }\n return <div key={i}>{renderSingle(group.item, brand)}</div>;\n })}\n </div>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport { ComponentRenderer } from './ComponentRenderer';\nimport type { ComponentAssembly } from './types';\n\nconst CSS_TOKENS = `:root{--sp-accent:#60a5fa;--sp-accent-bg:rgba(96,165,250,0.1);--sp-accent-border:rgba(96,165,250,0.2);--sp-bg:#18181b;--sp-surface:#09090b;--sp-border:#27272a;--sp-text:#f4f4f5;--sp-text-sub:#d4d4d8;--sp-text-strong:#e4e4e7;--sp-text-muted:#71717a;--sp-text-dim:#52525b;--sp-text-body:#a1a1aa;--sp-positive:#6ee7b7;--sp-divider:rgba(255,255,255,0.06);--sp-code-bg:rgba(255,255,255,0.07);--sp-code-border:rgba(255,255,255,0.08);--sp-pre-bg:rgba(0,0,0,0.4)}`;\n\nfunction buildSummary(pageHint: string): string {\n const parts: string[] = [pageHint];\n const referrer = document.referrer;\n if (referrer) parts.push(`Arrived from: ${referrer}`);\n const p = new URLSearchParams(window.location.search);\n const source = p.get('utm_source');\n const medium = p.get('utm_medium');\n const campaign = p.get('utm_campaign');\n const term = p.get('utm_term');\n if (source) parts.push(`Source: ${source}`);\n if (medium) parts.push(`Medium: ${medium}`);\n if (campaign) parts.push(`Campaign: ${campaign}`);\n if (term) parts.push(`Search term: ${term}`);\n try {\n const history = localStorage.getItem('_spectare_visits');\n if (history) parts.push(`Previously visited: ${history}`);\n } catch { /* private browsing */ }\n return parts.filter(Boolean).join('. ');\n}\n\nfunction Shimmer() {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>\n <div style={{ height: '1.25rem', background: 'rgba(39,39,42,0.6)', borderRadius: '0.5rem', width: '75%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n <div style={{ height: '0.875rem', background: 'rgba(39,39,42,0.4)', borderRadius: '0.5rem', width: '100%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n <div style={{ height: '0.875rem', background: 'rgba(39,39,42,0.4)', borderRadius: '0.5rem', width: '83%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n <div style={{ height: '0.875rem', background: 'rgba(39,39,42,0.4)', borderRadius: '0.5rem', width: '67%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n </div>\n );\n}\n\nexport interface PersonalisedSectionProps {\n orgSlug: string;\n /** Base URL of your Spectare instance. Defaults to 'https://spectare.ai'. */\n baseUrl?: string;\n /** Your brand name, used in ComparisonTable column header. */\n brand?: string;\n pageHint?: string;\n className?: string;\n style?: React.CSSProperties;\n initialAssembly?: ComponentAssembly;\n initialIntent?: { audience: string; stage: string };\n}\n\nexport function PersonalisedSection({\n orgSlug,\n baseUrl = 'https://spectare.ai',\n brand,\n pageHint,\n className,\n style,\n initialAssembly,\n initialIntent,\n}: PersonalisedSectionProps) {\n const [assembly, setAssembly] = useState<ComponentAssembly | null>(initialAssembly ?? null);\n const [loading, setLoading] = useState(!initialAssembly);\n\n useEffect(() => {\n let cancelled = false;\n\n async function load() {\n try {\n const tokenKey = `_spectare_token_${orgSlug}`;\n let token = sessionStorage.getItem(tokenKey);\n\n if (!token) {\n const summary = buildSummary(pageHint ?? `Visiting ${document.title}`);\n const res = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ summary }),\n });\n if (!res.ok || cancelled) { setLoading(false); return; }\n const data = await res.json();\n token = data.token as string | undefined ?? null;\n if (token) sessionStorage.setItem(tokenKey, token);\n }\n\n if (!token || cancelled) { setLoading(false); return; }\n\n const res = await fetch(`${baseUrl}/api/assemble/components`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token, orgSlug }),\n });\n\n if (!res.ok || cancelled) { setLoading(false); return; }\n\n const data = await res.json() as {\n assembly?: ComponentAssembly;\n intent?: { userContext?: { audience?: string; stage?: string } };\n };\n\n if (cancelled) return;\n\n const clientAudience = data.intent?.userContext?.audience;\n const clientStage = data.intent?.userContext?.stage;\n const ssrMatches =\n initialIntent &&\n clientAudience === initialIntent.audience &&\n clientStage === initialIntent.stage;\n\n if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {\n setAssembly(data.assembly as ComponentAssembly);\n }\n } catch {\n // fail silently\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n\n load();\n return () => { cancelled = true; };\n }, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);\n\n if (!loading && !assembly) return null;\n\n return (\n <>\n <style dangerouslySetInnerHTML={{ __html: CSS_TOKENS }} />\n <style dangerouslySetInnerHTML={{ __html: '@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}' }} />\n <div className={className} style={style}>\n {loading ? <Shimmer /> : assembly && <ComponentRenderer assembly={assembly} brand={brand} />}\n </div>\n </>\n );\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import * as react from 'react';
2
+
3
+ type ComponentName = 'HeroStatement' | 'AtomCard' | 'StatGrid' | 'CodeBlock' | 'ComparisonTable' | 'FeatureList' | 'TestimonialCard' | 'ImageHero' | 'CtaStrip';
4
+ type ComponentAssembly = Array<{
5
+ component: ComponentName;
6
+ slots?: Record<string, unknown>;
7
+ size?: 'full' | 'half';
8
+ }>;
9
+
10
+ interface PersonalisedSectionProps {
11
+ orgSlug: string;
12
+ /** Base URL of your Spectare instance. Defaults to 'https://spectare.ai'. */
13
+ baseUrl?: string;
14
+ /** Your brand name, used in ComparisonTable column header. */
15
+ brand?: string;
16
+ pageHint?: string;
17
+ className?: string;
18
+ style?: React.CSSProperties;
19
+ initialAssembly?: ComponentAssembly;
20
+ initialIntent?: {
21
+ audience: string;
22
+ stage: string;
23
+ };
24
+ }
25
+ declare function PersonalisedSection({ orgSlug, baseUrl, brand, pageHint, className, style, initialAssembly, initialIntent, }: PersonalisedSectionProps): react.JSX.Element | null;
26
+
27
+ interface ComponentRendererProps {
28
+ assembly: ComponentAssembly;
29
+ /** Your brand name, used as the left column header in ComparisonTable. Defaults to "Us". */
30
+ brand?: string;
31
+ }
32
+ declare function ComponentRenderer({ assembly, brand }: ComponentRendererProps): react.JSX.Element;
33
+
34
+ export { type ComponentAssembly, type ComponentName, ComponentRenderer, type ComponentRendererProps, PersonalisedSection, type PersonalisedSectionProps };
@@ -0,0 +1,34 @@
1
+ import * as react from 'react';
2
+
3
+ type ComponentName = 'HeroStatement' | 'AtomCard' | 'StatGrid' | 'CodeBlock' | 'ComparisonTable' | 'FeatureList' | 'TestimonialCard' | 'ImageHero' | 'CtaStrip';
4
+ type ComponentAssembly = Array<{
5
+ component: ComponentName;
6
+ slots?: Record<string, unknown>;
7
+ size?: 'full' | 'half';
8
+ }>;
9
+
10
+ interface PersonalisedSectionProps {
11
+ orgSlug: string;
12
+ /** Base URL of your Spectare instance. Defaults to 'https://spectare.ai'. */
13
+ baseUrl?: string;
14
+ /** Your brand name, used in ComparisonTable column header. */
15
+ brand?: string;
16
+ pageHint?: string;
17
+ className?: string;
18
+ style?: React.CSSProperties;
19
+ initialAssembly?: ComponentAssembly;
20
+ initialIntent?: {
21
+ audience: string;
22
+ stage: string;
23
+ };
24
+ }
25
+ declare function PersonalisedSection({ orgSlug, baseUrl, brand, pageHint, className, style, initialAssembly, initialIntent, }: PersonalisedSectionProps): react.JSX.Element | null;
26
+
27
+ interface ComponentRendererProps {
28
+ assembly: ComponentAssembly;
29
+ /** Your brand name, used as the left column header in ComparisonTable. Defaults to "Us". */
30
+ brand?: string;
31
+ }
32
+ declare function ComponentRenderer({ assembly, brand }: ComponentRendererProps): react.JSX.Element;
33
+
34
+ export { type ComponentAssembly, type ComponentName, ComponentRenderer, type ComponentRendererProps, PersonalisedSection, type PersonalisedSectionProps };
package/dist/index.js ADDED
@@ -0,0 +1,262 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+
4
+ // src/PersonalisedSection.tsx
5
+ var HALF_COMPONENTS = /* @__PURE__ */ new Set(["TestimonialCard"]);
6
+ function HeroStatement({ headline, subheading }) {
7
+ return /* @__PURE__ */ jsxs("div", { style: { paddingTop: "1.5rem", paddingBottom: "1.5rem" }, children: [
8
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: "2rem", fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2, color: "var(--sp-text)", margin: "0 0 0.75rem" }, children: headline }),
9
+ subheading && /* @__PURE__ */ jsx("p", { style: { fontSize: "1.125rem", color: "var(--sp-text-sub)", lineHeight: 1.6, maxWidth: "42rem", margin: 0 }, children: subheading })
10
+ ] });
11
+ }
12
+ function AtomCard({ title, content }) {
13
+ return /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem", height: "100%" }, children: [
14
+ title && /* @__PURE__ */ jsx("h3", { style: { fontSize: "1rem", fontWeight: 600, color: "var(--sp-text)", margin: "0 0 0.75rem" }, children: title }),
15
+ content && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", color: "var(--sp-text-sub)", lineHeight: 1.6, margin: 0 }, children: content })
16
+ ] });
17
+ }
18
+ function StatGrid({ stats, caption }) {
19
+ const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;
20
+ return /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem" }, children: [
21
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: "1.5rem" }, children: stats.map(({ value, label }) => /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
22
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "1.875rem", fontWeight: 700, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", margin: 0 }, children: value }),
23
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", marginTop: "0.375rem", textTransform: "uppercase", letterSpacing: "0.05em" }, children: label })
24
+ ] }, label)) }),
25
+ caption && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", textAlign: "center", marginTop: "1.25rem", borderTop: "1px solid var(--sp-border)", paddingTop: "1rem" }, children: caption })
26
+ ] });
27
+ }
28
+ function CodeBlock({ code, lang = "typescript", caption }) {
29
+ return /* @__PURE__ */ jsxs("div", { style: { borderRadius: "0.75rem", overflow: "hidden", border: "1px solid var(--sp-border)" }, children: [
30
+ /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", padding: "0.625rem 1rem", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid var(--sp-border)" }, children: [
31
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", fontFamily: "monospace" }, children: lang }),
32
+ caption && /* @__PURE__ */ jsx("span", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)" }, children: caption })
33
+ ] }),
34
+ /* @__PURE__ */ jsx("pre", { style: { background: "var(--sp-surface)", padding: "1.25rem", fontSize: "0.75rem", color: "var(--sp-text-sub)", overflowX: "auto", lineHeight: 1.6, fontFamily: "monospace", whiteSpace: "pre", margin: 0 }, children: code })
35
+ ] });
36
+ }
37
+ function ComparisonTable({ brand = "Us", competitor, rows }) {
38
+ return /* @__PURE__ */ jsx("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "0.75rem", overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: { width: "100%", fontSize: "0.875rem", borderCollapse: "collapse" }, children: [
39
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
40
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.75rem 1rem", color: "var(--sp-text-muted)", fontWeight: 500, fontSize: "0.75rem", width: "33%" } }),
41
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.75rem 1rem", fontWeight: 600, color: "var(--sp-accent)", fontSize: "0.75rem" }, children: brand }),
42
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.75rem 1rem", color: "var(--sp-text-muted)", fontWeight: 500, fontSize: "0.75rem" }, children: competitor })
43
+ ] }) }),
44
+ /* @__PURE__ */ jsx("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
45
+ /* @__PURE__ */ jsx("td", { style: { padding: "0.75rem 1rem", fontSize: "0.75rem", color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
46
+ /* @__PURE__ */ jsx("td", { style: { padding: "0.75rem 1rem", fontSize: "0.75rem", color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
47
+ /* @__PURE__ */ jsx("td", { style: { padding: "0.75rem 1rem", fontSize: "0.75rem", color: "var(--sp-text-muted)" }, children: them })
48
+ ] }, label)) })
49
+ ] }) }) });
50
+ }
51
+ function FeatureList({ items }) {
52
+ return /* @__PURE__ */ jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem" }, children: /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "1rem" }, children: items.map(({ text, sub }) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem" }, children: [
53
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: "0.875rem", marginTop: "0.125rem" }, children: "\u2713" }),
54
+ /* @__PURE__ */ jsxs("div", { children: [
55
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
56
+ sub && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", marginTop: "0.25rem", lineHeight: 1.5, margin: "0.25rem 0 0" }, children: sub })
57
+ ] })
58
+ ] }, text)) }) });
59
+ }
60
+ function TestimonialCard({ quote, name, role, company }) {
61
+ return /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "1.5rem", display: "flex", flexDirection: "column", gap: "1.25rem", height: "100%" }, children: [
62
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.875rem", color: "var(--sp-text-sub)", lineHeight: 1.6, flex: 1, margin: 0 }, children: [
63
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: "1.125rem", lineHeight: 1, marginRight: "0.25rem" }, children: '"' }),
64
+ quote,
65
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: "1.125rem", lineHeight: 1, marginLeft: "0.25rem" }, children: '"' })
66
+ ] }),
67
+ /* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: "1rem" }, children: [
68
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
69
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.75rem", color: "var(--sp-text-muted)", marginTop: "0.125rem", margin: "0.125rem 0 0" }, children: [
70
+ role,
71
+ company ? `, ${company}` : ""
72
+ ] })
73
+ ] })
74
+ ] });
75
+ }
76
+ function ImageHero({ src, alt = "", ratio = "16:9" }) {
77
+ if (!src) return null;
78
+ const [w, h] = ratio.split(":").map(Number);
79
+ const paddingBottom = w && h ? `${h / w * 100}%` : "56.25%";
80
+ return /* @__PURE__ */ jsx("div", { style: { borderRadius: "0.75rem", overflow: "hidden", position: "relative", width: "100%", paddingBottom }, children: /* @__PURE__ */ jsx("img", { src, alt, style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" } }) });
81
+ }
82
+ function CtaStrip({ headline, primary, secondary }) {
83
+ return /* @__PURE__ */ jsxs("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "0.75rem", padding: "2rem", textAlign: "center", background: "var(--sp-bg)" }, children: [
84
+ /* @__PURE__ */ jsx("h3", { style: { fontSize: "1.5rem", fontWeight: 700, color: "var(--sp-text)", margin: "0 0 1.5rem" }, children: headline }),
85
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "1rem", flexWrap: "wrap" }, children: [
86
+ /* @__PURE__ */ jsx("a", { href: primary.href, style: { background: "#fff", color: "#09090b", padding: "0.625rem 1.5rem", borderRadius: "0.75rem", fontWeight: 600, fontSize: "0.875rem", textDecoration: "none" }, children: primary.label }),
87
+ secondary && /* @__PURE__ */ jsxs("a", { href: secondary.href, style: { fontSize: "0.875rem", color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
88
+ secondary.label,
89
+ " \u2192"
90
+ ] })
91
+ ] })
92
+ ] });
93
+ }
94
+ function renderSingle(item, brand) {
95
+ var _a;
96
+ const s = (_a = item.slots) != null ? _a : {};
97
+ switch (item.component) {
98
+ case "HeroStatement":
99
+ return /* @__PURE__ */ jsx(HeroStatement, { headline: s.headline, subheading: s.subheading });
100
+ case "AtomCard":
101
+ return /* @__PURE__ */ jsx(AtomCard, { title: s.title, content: s.content });
102
+ case "StatGrid":
103
+ return /* @__PURE__ */ jsx(StatGrid, { stats: s.stats, caption: s.caption });
104
+ case "CodeBlock":
105
+ return /* @__PURE__ */ jsx(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption });
106
+ case "ComparisonTable":
107
+ return /* @__PURE__ */ jsx(ComparisonTable, { brand, competitor: s.competitor, rows: s.rows });
108
+ case "FeatureList":
109
+ return /* @__PURE__ */ jsx(FeatureList, { items: s.items });
110
+ case "TestimonialCard":
111
+ return /* @__PURE__ */ jsx(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company });
112
+ case "ImageHero":
113
+ return /* @__PURE__ */ jsx(ImageHero, { src: s.src, alt: s.alt, ratio: s.ratio });
114
+ case "CtaStrip":
115
+ return /* @__PURE__ */ jsx(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary });
116
+ default:
117
+ return null;
118
+ }
119
+ }
120
+ function resolvedSize(item) {
121
+ if (item.size) return item.size;
122
+ return HALF_COMPONENTS.has(item.component) ? "half" : "full";
123
+ }
124
+ function buildLayout(assembly) {
125
+ const groups = [];
126
+ let i = 0;
127
+ while (i < assembly.length) {
128
+ const cur = assembly[i];
129
+ const next = assembly[i + 1];
130
+ if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half") {
131
+ groups.push({ type: "pair", items: [cur, next] });
132
+ i += 2;
133
+ } else if (resolvedSize(cur) === "half") {
134
+ groups.push({ type: "half-solo", item: cur });
135
+ i++;
136
+ } else {
137
+ groups.push({ type: "full", item: cur });
138
+ i++;
139
+ }
140
+ }
141
+ return groups;
142
+ }
143
+ function ComponentRenderer({ assembly, brand }) {
144
+ const layout = buildLayout(assembly);
145
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "1.25rem" }, children: layout.map((group, i) => {
146
+ if (group.type === "full") {
147
+ return /* @__PURE__ */ jsx("div", { children: renderSingle(group.item, brand) }, i);
148
+ }
149
+ if (group.type === "pair") {
150
+ return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "1.25rem" }, children: [
151
+ /* @__PURE__ */ jsx("div", { children: renderSingle(group.items[0], brand) }),
152
+ /* @__PURE__ */ jsx("div", { children: renderSingle(group.items[1], brand) })
153
+ ] }, i);
154
+ }
155
+ return /* @__PURE__ */ jsx("div", { children: renderSingle(group.item, brand) }, i);
156
+ }) });
157
+ }
158
+ var CSS_TOKENS = `:root{--sp-accent:#60a5fa;--sp-accent-bg:rgba(96,165,250,0.1);--sp-accent-border:rgba(96,165,250,0.2);--sp-bg:#18181b;--sp-surface:#09090b;--sp-border:#27272a;--sp-text:#f4f4f5;--sp-text-sub:#d4d4d8;--sp-text-strong:#e4e4e7;--sp-text-muted:#71717a;--sp-text-dim:#52525b;--sp-text-body:#a1a1aa;--sp-positive:#6ee7b7;--sp-divider:rgba(255,255,255,0.06);--sp-code-bg:rgba(255,255,255,0.07);--sp-code-border:rgba(255,255,255,0.08);--sp-pre-bg:rgba(0,0,0,0.4)}`;
159
+ function buildSummary(pageHint) {
160
+ const parts = [pageHint];
161
+ const referrer = document.referrer;
162
+ if (referrer) parts.push(`Arrived from: ${referrer}`);
163
+ const p = new URLSearchParams(window.location.search);
164
+ const source = p.get("utm_source");
165
+ const medium = p.get("utm_medium");
166
+ const campaign = p.get("utm_campaign");
167
+ const term = p.get("utm_term");
168
+ if (source) parts.push(`Source: ${source}`);
169
+ if (medium) parts.push(`Medium: ${medium}`);
170
+ if (campaign) parts.push(`Campaign: ${campaign}`);
171
+ if (term) parts.push(`Search term: ${term}`);
172
+ try {
173
+ const history = localStorage.getItem("_spectare_visits");
174
+ if (history) parts.push(`Previously visited: ${history}`);
175
+ } catch (e) {
176
+ }
177
+ return parts.filter(Boolean).join(". ");
178
+ }
179
+ function Shimmer() {
180
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
181
+ /* @__PURE__ */ jsx("div", { style: { height: "1.25rem", background: "rgba(39,39,42,0.6)", borderRadius: "0.5rem", width: "75%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
182
+ /* @__PURE__ */ jsx("div", { style: { height: "0.875rem", background: "rgba(39,39,42,0.4)", borderRadius: "0.5rem", width: "100%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
183
+ /* @__PURE__ */ jsx("div", { style: { height: "0.875rem", background: "rgba(39,39,42,0.4)", borderRadius: "0.5rem", width: "83%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
184
+ /* @__PURE__ */ jsx("div", { style: { height: "0.875rem", background: "rgba(39,39,42,0.4)", borderRadius: "0.5rem", width: "67%", animation: "sp-pulse 1.5s ease-in-out infinite" } })
185
+ ] });
186
+ }
187
+ function PersonalisedSection({
188
+ orgSlug,
189
+ baseUrl = "https://spectare.ai",
190
+ brand,
191
+ pageHint,
192
+ className,
193
+ style,
194
+ initialAssembly,
195
+ initialIntent
196
+ }) {
197
+ const [assembly, setAssembly] = useState(initialAssembly != null ? initialAssembly : null);
198
+ const [loading, setLoading] = useState(!initialAssembly);
199
+ useEffect(() => {
200
+ let cancelled = false;
201
+ async function load() {
202
+ var _a, _b, _c, _d, _e;
203
+ try {
204
+ const tokenKey = `_spectare_token_${orgSlug}`;
205
+ let token = sessionStorage.getItem(tokenKey);
206
+ if (!token) {
207
+ const summary = buildSummary(pageHint != null ? pageHint : `Visiting ${document.title}`);
208
+ const res2 = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {
209
+ method: "POST",
210
+ headers: { "Content-Type": "application/json" },
211
+ body: JSON.stringify({ summary })
212
+ });
213
+ if (!res2.ok || cancelled) {
214
+ setLoading(false);
215
+ return;
216
+ }
217
+ const data2 = await res2.json();
218
+ token = (_a = data2.token) != null ? _a : null;
219
+ if (token) sessionStorage.setItem(tokenKey, token);
220
+ }
221
+ if (!token || cancelled) {
222
+ setLoading(false);
223
+ return;
224
+ }
225
+ const res = await fetch(`${baseUrl}/api/assemble/components`, {
226
+ method: "POST",
227
+ headers: { "Content-Type": "application/json" },
228
+ body: JSON.stringify({ token, orgSlug })
229
+ });
230
+ if (!res.ok || cancelled) {
231
+ setLoading(false);
232
+ return;
233
+ }
234
+ const data = await res.json();
235
+ if (cancelled) return;
236
+ const clientAudience = (_c = (_b = data.intent) == null ? void 0 : _b.userContext) == null ? void 0 : _c.audience;
237
+ const clientStage = (_e = (_d = data.intent) == null ? void 0 : _d.userContext) == null ? void 0 : _e.stage;
238
+ const ssrMatches = initialIntent && clientAudience === initialIntent.audience && clientStage === initialIntent.stage;
239
+ if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {
240
+ setAssembly(data.assembly);
241
+ }
242
+ } catch (e) {
243
+ } finally {
244
+ if (!cancelled) setLoading(false);
245
+ }
246
+ }
247
+ load();
248
+ return () => {
249
+ cancelled = true;
250
+ };
251
+ }, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);
252
+ if (!loading && !assembly) return null;
253
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
254
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: CSS_TOKENS } }),
255
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
256
+ /* @__PURE__ */ jsx("div", { className, style, children: loading ? /* @__PURE__ */ jsx(Shimmer, {}) : assembly && /* @__PURE__ */ jsx(ComponentRenderer, { assembly, brand }) })
257
+ ] });
258
+ }
259
+
260
+ export { ComponentRenderer, PersonalisedSection };
261
+ //# sourceMappingURL=index.js.map
262
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ComponentRenderer.tsx","../src/PersonalisedSection.tsx"],"names":["jsxs","jsx","res","data"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport type { ComponentAssembly, ComponentName } from './types';\n\n// Default half-size components — used when assembly item omits size.\nconst HALF_COMPONENTS = new Set<ComponentName>(['TestimonialCard']);\n\n// ── Individual component renderers ────────────────────────────────────────────\n\nfunction HeroStatement({ headline, subheading }: { headline: string; subheading?: string }) {\n return (\n <div style={{ paddingTop: '1.5rem', paddingBottom: '1.5rem' }}>\n <h2 style={{ fontSize: '2rem', fontWeight: 700, letterSpacing: '-0.025em', lineHeight: 1.2, color: 'var(--sp-text)', margin: '0 0 0.75rem' }}>\n {headline}\n </h2>\n {subheading && (\n <p style={{ fontSize: '1.125rem', color: 'var(--sp-text-sub)', lineHeight: 1.6, maxWidth: '42rem', margin: 0 }}>{subheading}</p>\n )}\n </div>\n );\n}\n\nfunction AtomCard({ title, content }: { title?: string; content?: string }) {\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem', height: '100%' }}>\n {title && <h3 style={{ fontSize: '1rem', fontWeight: 600, color: 'var(--sp-text)', margin: '0 0 0.75rem' }}>{title}</h3>}\n {content && <p style={{ fontSize: '0.875rem', color: 'var(--sp-text-sub)', lineHeight: 1.6, margin: 0 }}>{content}</p>}\n </div>\n );\n}\n\nfunction StatGrid({ stats, caption }: { stats: { value: string; label: string }[]; caption?: string }) {\n const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem' }}>\n <div style={{ display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: '1.5rem' }}>\n {stats.map(({ value, label }) => (\n <div key={label} style={{ textAlign: 'center' }}>\n <p style={{ fontSize: '1.875rem', fontWeight: 700, color: 'var(--sp-text)', fontVariantNumeric: 'tabular-nums', margin: 0 }}>{value}</p>\n <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', marginTop: '0.375rem', textTransform: 'uppercase', letterSpacing: '0.05em' }}>{label}</p>\n </div>\n ))}\n </div>\n {caption && (\n <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', textAlign: 'center', marginTop: '1.25rem', borderTop: '1px solid var(--sp-border)', paddingTop: '1rem' }}>{caption}</p>\n )}\n </div>\n );\n}\n\nfunction CodeBlock({ code, lang = 'typescript', caption }: { code: string; lang?: string; caption?: string }) {\n return (\n <div style={{ borderRadius: '0.75rem', overflow: 'hidden', border: '1px solid var(--sp-border)' }}>\n <div style={{ background: 'var(--sp-bg)', padding: '0.625rem 1rem', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid var(--sp-border)' }}>\n <span style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', fontFamily: 'monospace' }}>{lang}</span>\n {caption && <span style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)' }}>{caption}</span>}\n </div>\n <pre style={{ background: 'var(--sp-surface)', padding: '1.25rem', fontSize: '0.75rem', color: 'var(--sp-text-sub)', overflowX: 'auto', lineHeight: 1.6, fontFamily: 'monospace', whiteSpace: 'pre', margin: 0 }}>\n {code}\n </pre>\n </div>\n );\n}\n\nfunction ComparisonTable({ brand = 'Us', competitor, rows }: { brand?: string; competitor: string; rows: { label: string; spectare: string; them: string }[] }) {\n return (\n <div style={{ border: '1px solid var(--sp-border)', borderRadius: '0.75rem', overflow: 'hidden' }}>\n <div style={{ overflowX: 'auto' }}>\n <table style={{ width: '100%', fontSize: '0.875rem', borderCollapse: 'collapse' }}>\n <thead>\n <tr style={{ borderBottom: '1px solid var(--sp-border)', background: 'var(--sp-bg)' }}>\n <th style={{ textAlign: 'left', padding: '0.75rem 1rem', color: 'var(--sp-text-muted)', fontWeight: 500, fontSize: '0.75rem', width: '33%' }} />\n <th style={{ textAlign: 'left', padding: '0.75rem 1rem', fontWeight: 600, color: 'var(--sp-accent)', fontSize: '0.75rem' }}>{brand}</th>\n <th style={{ textAlign: 'left', padding: '0.75rem 1rem', color: 'var(--sp-text-muted)', fontWeight: 500, fontSize: '0.75rem' }}>{competitor}</th>\n </tr>\n </thead>\n <tbody>\n {rows.map(({ label, spectare, them }) => (\n <tr key={label} style={{ borderBottom: '1px solid var(--sp-border)' }}>\n <td style={{ padding: '0.75rem 1rem', fontSize: '0.75rem', color: 'var(--sp-text-muted)', fontWeight: 500 }}>{label}</td>\n <td style={{ padding: '0.75rem 1rem', fontSize: '0.75rem', color: 'var(--sp-positive)', fontWeight: 500 }}>{spectare}</td>\n <td style={{ padding: '0.75rem 1rem', fontSize: '0.75rem', color: 'var(--sp-text-muted)' }}>{them}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n\nfunction FeatureList({ items }: { items: { text: string; sub?: string }[] }) {\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem' }}>\n <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: '1rem' }}>\n {items.map(({ text, sub }) => (\n <li key={text} style={{ display: 'flex', gap: '0.75rem' }}>\n <span style={{ color: 'var(--sp-accent)', flexShrink: 0, fontSize: '0.875rem', marginTop: '0.125rem' }}>✓</span>\n <div>\n <p style={{ fontSize: '0.875rem', fontWeight: 500, color: 'var(--sp-text)', lineHeight: 1.4, margin: 0 }}>{text}</p>\n {sub && <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', marginTop: '0.25rem', lineHeight: 1.5, margin: '0.25rem 0 0' }}>{sub}</p>}\n </div>\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\nfunction TestimonialCard({ quote, name, role, company }: { quote: string; name: string; role: string; company?: string }) {\n return (\n <div style={{ background: 'var(--sp-bg)', border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '1.5rem', display: 'flex', flexDirection: 'column', gap: '1.25rem', height: '100%' }}>\n <p style={{ fontSize: '0.875rem', color: 'var(--sp-text-sub)', lineHeight: 1.6, flex: 1, margin: 0 }}>\n <span style={{ color: 'var(--sp-text-dim)', fontSize: '1.125rem', lineHeight: 1, marginRight: '0.25rem' }}>\"</span>\n {quote}\n <span style={{ color: 'var(--sp-text-dim)', fontSize: '1.125rem', lineHeight: 1, marginLeft: '0.25rem' }}>\"</span>\n </p>\n <div style={{ borderTop: '1px solid var(--sp-border)', paddingTop: '1rem' }}>\n <p style={{ fontSize: '0.875rem', fontWeight: 600, color: 'var(--sp-text)', margin: 0 }}>{name}</p>\n <p style={{ fontSize: '0.75rem', color: 'var(--sp-text-muted)', marginTop: '0.125rem', margin: '0.125rem 0 0' }}>\n {role}{company ? `, ${company}` : ''}\n </p>\n </div>\n </div>\n );\n}\n\nfunction ImageHero({ src, alt = '', ratio = '16:9' }: { src?: string; alt?: string; ratio?: string }) {\n if (!src) return null;\n const [w, h] = ratio.split(':').map(Number);\n const paddingBottom = w && h ? `${(h / w) * 100}%` : '56.25%';\n return (\n <div style={{ borderRadius: '0.75rem', overflow: 'hidden', position: 'relative', width: '100%', paddingBottom }}>\n <img src={src} alt={alt} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />\n </div>\n );\n}\n\nfunction CtaStrip({ headline, primary, secondary }: { headline: string; primary: { label: string; href: string }; secondary?: { label: string; href: string } }) {\n return (\n <div style={{ border: '1px solid var(--sp-border)', borderRadius: '0.75rem', padding: '2rem', textAlign: 'center', background: 'var(--sp-bg)' }}>\n <h3 style={{ fontSize: '1.5rem', fontWeight: 700, color: 'var(--sp-text)', margin: '0 0 1.5rem' }}>{headline}</h3>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '1rem', flexWrap: 'wrap' }}>\n <a href={primary.href} style={{ background: '#fff', color: '#09090b', padding: '0.625rem 1.5rem', borderRadius: '0.75rem', fontWeight: 600, fontSize: '0.875rem', textDecoration: 'none' }}>\n {primary.label}\n </a>\n {secondary && (\n <a href={secondary.href} style={{ fontSize: '0.875rem', color: 'var(--sp-text-sub)', textDecoration: 'none' }}>\n {secondary.label} →\n </a>\n )}\n </div>\n </div>\n );\n}\n\n// ── Dispatch ──────────────────────────────────────────────────────────────────\n\nfunction renderSingle(item: ComponentAssembly[0], brand?: string): React.ReactNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const s = item.slots as Record<string, any> ?? {};\n\n switch (item.component as ComponentName) {\n case 'HeroStatement': return <HeroStatement headline={s.headline} subheading={s.subheading} />;\n case 'AtomCard': return <AtomCard title={s.title} content={s.content} />;\n case 'StatGrid': return <StatGrid stats={s.stats} caption={s.caption} />;\n case 'CodeBlock': return <CodeBlock code={s.code} lang={s.lang} caption={s.caption} />;\n case 'ComparisonTable': return <ComparisonTable brand={brand} competitor={s.competitor} rows={s.rows} />;\n case 'FeatureList': return <FeatureList items={s.items} />;\n case 'TestimonialCard': return <TestimonialCard quote={s.quote} name={s.name} role={s.role} company={s.company} />;\n case 'ImageHero': return <ImageHero src={s.src} alt={s.alt} ratio={s.ratio} />;\n case 'CtaStrip': return <CtaStrip headline={s.headline} primary={s.primary} secondary={s.secondary} />;\n default: return null;\n }\n}\n\n// ── Layout ────────────────────────────────────────────────────────────────────\n\nfunction resolvedSize(item: ComponentAssembly[0]): 'full' | 'half' {\n if (item.size) return item.size;\n return HALF_COMPONENTS.has(item.component as ComponentName) ? 'half' : 'full';\n}\n\ntype LayoutGroup =\n | { type: 'full'; item: ComponentAssembly[0] }\n | { type: 'pair'; items: [ComponentAssembly[0], ComponentAssembly[0]] }\n | { type: 'half-solo'; item: ComponentAssembly[0] };\n\nfunction buildLayout(assembly: ComponentAssembly): LayoutGroup[] {\n const groups: LayoutGroup[] = [];\n let i = 0;\n while (i < assembly.length) {\n const cur = assembly[i];\n const next = assembly[i + 1];\n if (resolvedSize(cur) === 'half' && next && resolvedSize(next) === 'half') {\n groups.push({ type: 'pair', items: [cur, next] });\n i += 2;\n } else if (resolvedSize(cur) === 'half') {\n groups.push({ type: 'half-solo', item: cur });\n i++;\n } else {\n groups.push({ type: 'full', item: cur });\n i++;\n }\n }\n return groups;\n}\n\n// ── Main export ───────────────────────────────────────────────────────────────\n\nexport interface ComponentRendererProps {\n assembly: ComponentAssembly;\n /** Your brand name, used as the left column header in ComparisonTable. Defaults to \"Us\". */\n brand?: string;\n}\n\nexport function ComponentRenderer({ assembly, brand }: ComponentRendererProps) {\n const layout = buildLayout(assembly);\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '1.25rem' }}>\n {layout.map((group, i) => {\n if (group.type === 'full') {\n return <div key={i}>{renderSingle(group.item, brand)}</div>;\n }\n if (group.type === 'pair') {\n return (\n <div key={i} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.25rem' }}>\n <div>{renderSingle(group.items[0], brand)}</div>\n <div>{renderSingle(group.items[1], brand)}</div>\n </div>\n );\n }\n return <div key={i}>{renderSingle(group.item, brand)}</div>;\n })}\n </div>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport { ComponentRenderer } from './ComponentRenderer';\nimport type { ComponentAssembly } from './types';\n\nconst CSS_TOKENS = `:root{--sp-accent:#60a5fa;--sp-accent-bg:rgba(96,165,250,0.1);--sp-accent-border:rgba(96,165,250,0.2);--sp-bg:#18181b;--sp-surface:#09090b;--sp-border:#27272a;--sp-text:#f4f4f5;--sp-text-sub:#d4d4d8;--sp-text-strong:#e4e4e7;--sp-text-muted:#71717a;--sp-text-dim:#52525b;--sp-text-body:#a1a1aa;--sp-positive:#6ee7b7;--sp-divider:rgba(255,255,255,0.06);--sp-code-bg:rgba(255,255,255,0.07);--sp-code-border:rgba(255,255,255,0.08);--sp-pre-bg:rgba(0,0,0,0.4)}`;\n\nfunction buildSummary(pageHint: string): string {\n const parts: string[] = [pageHint];\n const referrer = document.referrer;\n if (referrer) parts.push(`Arrived from: ${referrer}`);\n const p = new URLSearchParams(window.location.search);\n const source = p.get('utm_source');\n const medium = p.get('utm_medium');\n const campaign = p.get('utm_campaign');\n const term = p.get('utm_term');\n if (source) parts.push(`Source: ${source}`);\n if (medium) parts.push(`Medium: ${medium}`);\n if (campaign) parts.push(`Campaign: ${campaign}`);\n if (term) parts.push(`Search term: ${term}`);\n try {\n const history = localStorage.getItem('_spectare_visits');\n if (history) parts.push(`Previously visited: ${history}`);\n } catch { /* private browsing */ }\n return parts.filter(Boolean).join('. ');\n}\n\nfunction Shimmer() {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>\n <div style={{ height: '1.25rem', background: 'rgba(39,39,42,0.6)', borderRadius: '0.5rem', width: '75%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n <div style={{ height: '0.875rem', background: 'rgba(39,39,42,0.4)', borderRadius: '0.5rem', width: '100%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n <div style={{ height: '0.875rem', background: 'rgba(39,39,42,0.4)', borderRadius: '0.5rem', width: '83%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n <div style={{ height: '0.875rem', background: 'rgba(39,39,42,0.4)', borderRadius: '0.5rem', width: '67%', animation: 'sp-pulse 1.5s ease-in-out infinite' }} />\n </div>\n );\n}\n\nexport interface PersonalisedSectionProps {\n orgSlug: string;\n /** Base URL of your Spectare instance. Defaults to 'https://spectare.ai'. */\n baseUrl?: string;\n /** Your brand name, used in ComparisonTable column header. */\n brand?: string;\n pageHint?: string;\n className?: string;\n style?: React.CSSProperties;\n initialAssembly?: ComponentAssembly;\n initialIntent?: { audience: string; stage: string };\n}\n\nexport function PersonalisedSection({\n orgSlug,\n baseUrl = 'https://spectare.ai',\n brand,\n pageHint,\n className,\n style,\n initialAssembly,\n initialIntent,\n}: PersonalisedSectionProps) {\n const [assembly, setAssembly] = useState<ComponentAssembly | null>(initialAssembly ?? null);\n const [loading, setLoading] = useState(!initialAssembly);\n\n useEffect(() => {\n let cancelled = false;\n\n async function load() {\n try {\n const tokenKey = `_spectare_token_${orgSlug}`;\n let token = sessionStorage.getItem(tokenKey);\n\n if (!token) {\n const summary = buildSummary(pageHint ?? `Visiting ${document.title}`);\n const res = await fetch(`${baseUrl}/api/qualify/${orgSlug}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ summary }),\n });\n if (!res.ok || cancelled) { setLoading(false); return; }\n const data = await res.json();\n token = data.token as string | undefined ?? null;\n if (token) sessionStorage.setItem(tokenKey, token);\n }\n\n if (!token || cancelled) { setLoading(false); return; }\n\n const res = await fetch(`${baseUrl}/api/assemble/components`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token, orgSlug }),\n });\n\n if (!res.ok || cancelled) { setLoading(false); return; }\n\n const data = await res.json() as {\n assembly?: ComponentAssembly;\n intent?: { userContext?: { audience?: string; stage?: string } };\n };\n\n if (cancelled) return;\n\n const clientAudience = data.intent?.userContext?.audience;\n const clientStage = data.intent?.userContext?.stage;\n const ssrMatches =\n initialIntent &&\n clientAudience === initialIntent.audience &&\n clientStage === initialIntent.stage;\n\n if (!ssrMatches && Array.isArray(data.assembly) && data.assembly.length > 0) {\n setAssembly(data.assembly as ComponentAssembly);\n }\n } catch {\n // fail silently\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n\n load();\n return () => { cancelled = true; };\n }, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent]);\n\n if (!loading && !assembly) return null;\n\n return (\n <>\n <style dangerouslySetInnerHTML={{ __html: CSS_TOKENS }} />\n <style dangerouslySetInnerHTML={{ __html: '@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}' }} />\n <div className={className} style={style}>\n {loading ? <Shimmer /> : assembly && <ComponentRenderer assembly={assembly} brand={brand} />}\n </div>\n </>\n );\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /* src/styles.css */
2
+ .sp-root,
3
+ .sp-root * {
4
+ box-sizing: border-box;
5
+ }
6
+ /*# sourceMappingURL=styles.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @spectare-personalisation/react — optional import */\n/* Import with: import '@spectare-personalisation/react/styles.css' */\n/* All component styles use CSS custom properties injected by PersonalisedSection. */\n/* This file only provides box-sizing reset for the components. */\n\n.sp-root, .sp-root * {\n box-sizing: border-box;\n}\n"],"mappings":";AAKA,CAAC;AAAS,CAAT,QAAkB;AACjB,cAAY;AACd;","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@spectare-personalisation/react",
3
+ "version": "0.1.0",
4
+ "description": "React components for Spectare AI website personalisation",
5
+ "keywords": ["spectare", "personalisation", "react", "nextjs", "ai"],
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./styles.css": "./dist/styles.css"
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "dev": "tsup --watch"
25
+ },
26
+ "peerDependencies": {
27
+ "react": ">=18",
28
+ "react-dom": ">=18"
29
+ },
30
+ "devDependencies": {
31
+ "@types/react": "^19",
32
+ "@types/react-dom": "^19",
33
+ "tsup": "^8.0.0",
34
+ "typescript": "^5"
35
+ }
36
+ }