@sprintup-cms/sdk 1.5.1 → 1.7.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/CHANGELOG.md +39 -0
- package/dist/next/index.cjs +168 -54
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.js +168 -54
- package/dist/next/index.js.map +1 -1
- package/dist/react/index.cjs +168 -54
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +168 -54
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@sprintup-cms/sdk` will be documented here.
|
|
4
4
|
|
|
5
|
+
## [1.7.0] — 2026-03-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `ProductListBlock` — dynamic block that fetches products from an external API endpoint.
|
|
9
|
+
Supports configuration: `endpoint`, `title`, `subtitle`, `columns`, `showPrice`, `showRating`,
|
|
10
|
+
`limit`, `currency`. Includes loading skeleton, error state, and empty state. Normalises
|
|
11
|
+
both generic `{ id, price }` shape and iRead school product shape (`_id`, `plans[0].price`,
|
|
12
|
+
`type`, `duration`).
|
|
13
|
+
- `product-list` registered in the `BUILT_IN` renderer map — external apps now render
|
|
14
|
+
product list blocks out of the box without custom configuration.
|
|
15
|
+
|
|
16
|
+
## [1.6.0] — 2026-03-07
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `StructuredBlock` component: dedicated renderer for `__structured__` page type blocks.
|
|
20
|
+
Iterates nested `{ sectionName: { fieldName: value } }` content using the `pageType`
|
|
21
|
+
schema for correct field type rendering (richtext, image, boolean, url, arrays).
|
|
22
|
+
- `FieldValue` helper component for consistent field-level rendering across both
|
|
23
|
+
`StructuredBlock` and `SectionBlock`.
|
|
24
|
+
- `__structured__` registered in the `BUILT_IN` renderer map — structured page type
|
|
25
|
+
instances now render correctly on external apps without any custom configuration.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- `SectionBlock` fallback no longer intercepts `__structured__` blocks.
|
|
29
|
+
- Arrays and nested objects in block data no longer render as `[object Object]`.
|
|
30
|
+
|
|
31
|
+
## [1.5.2] — 2026-03-07
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- `CMSBlocks` now correctly renders `__structured__` blocks (structured page types).
|
|
35
|
+
Previously the block fell through to `SectionBlock`'s generic fallback, printing raw
|
|
36
|
+
`sectionName.fieldName: value` text. Now a dedicated `StructuredBlock` component
|
|
37
|
+
iterates the nested `{ sectionName: { fieldName: value } }` shape returned by the API,
|
|
38
|
+
using the `pageType` schema for field types when available, and rendering richtext
|
|
39
|
+
values via `dangerouslySetInnerHTML`, images as `<img>`, and arrays as comma-separated
|
|
40
|
+
text — instead of `[object Object]` or raw key dumps.
|
|
41
|
+
- `__structured__` registered in the `BUILT_IN` renderer map so custom renderers and the
|
|
42
|
+
`SectionBlock` fallback no longer intercept structured page content.
|
|
43
|
+
|
|
5
44
|
## [1.5.1] — 2026-03-07
|
|
6
45
|
|
|
7
46
|
### Fixed
|
package/dist/next/index.cjs
CHANGED
|
@@ -460,52 +460,173 @@ function VideoBlock({ block }) {
|
|
|
460
460
|
const embedUrl = url.replace("youtube.com/watch?v=", "youtube.com/embed/").replace("youtu.be/", "youtube.com/embed/").replace("vimeo.com/", "player.vimeo.com/video/");
|
|
461
461
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-video rounded-lg overflow-hidden border bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx("iframe", { src: embedUrl, allow: "autoplay; fullscreen", allowFullScreen: true, className: "w-full h-full", title: d.title || "Video" }) });
|
|
462
462
|
}
|
|
463
|
+
function normaliseProduct(raw) {
|
|
464
|
+
if (raw.id !== void 0 && raw.price !== void 0) return raw;
|
|
465
|
+
const firstPlan = Array.isArray(raw.plans) && raw.plans.length > 0 ? raw.plans[0] : null;
|
|
466
|
+
return {
|
|
467
|
+
id: raw._id ?? raw.id ?? String(Math.random()),
|
|
468
|
+
name: raw.name ?? "Unnamed",
|
|
469
|
+
description: raw.description,
|
|
470
|
+
price: firstPlan?.price ?? 0,
|
|
471
|
+
image: raw.image ?? raw.thumbnail ?? void 0,
|
|
472
|
+
rating: raw.rating ?? void 0,
|
|
473
|
+
category: raw.type ? raw.type.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) : void 0,
|
|
474
|
+
badge: raw.duration ? `${raw.duration} months` : void 0
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
function ProductListBlock({ block }) {
|
|
478
|
+
const d = getData(block);
|
|
479
|
+
const { title, subtitle, endpoint, columns = 3, showPrice = true, showRating = true, limit = 6, currency = "$" } = d;
|
|
480
|
+
const cols = parseInt(String(columns), 10);
|
|
481
|
+
const [state, setState] = React__default.default.useState({
|
|
482
|
+
data: null,
|
|
483
|
+
loading: true,
|
|
484
|
+
error: null
|
|
485
|
+
});
|
|
486
|
+
React__default.default.useEffect(() => {
|
|
487
|
+
if (!endpoint) {
|
|
488
|
+
setState({ data: [], loading: false, error: null });
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
let cancelled = false;
|
|
492
|
+
async function fetchData() {
|
|
493
|
+
try {
|
|
494
|
+
const res = await fetch(endpoint);
|
|
495
|
+
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
|
496
|
+
const json = await res.json();
|
|
497
|
+
if (cancelled) return;
|
|
498
|
+
const items = Array.isArray(json) ? json : json.data ?? json.products ?? [];
|
|
499
|
+
setState({ data: items.map(normaliseProduct), loading: false, error: null });
|
|
500
|
+
} catch (err) {
|
|
501
|
+
if (!cancelled) setState({ data: null, loading: false, error: err.message });
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
fetchData();
|
|
505
|
+
return () => {
|
|
506
|
+
cancelled = true;
|
|
507
|
+
};
|
|
508
|
+
}, [endpoint]);
|
|
509
|
+
const gridCols = cols === 2 ? "sm:grid-cols-2" : cols === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : "sm:grid-cols-2 lg:grid-cols-3";
|
|
510
|
+
if (state.loading) {
|
|
511
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-6xl mx-auto px-4", children: [
|
|
512
|
+
(title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-8", children: [
|
|
513
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 w-64 bg-muted animate-pulse rounded mx-auto" }),
|
|
514
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-96 max-w-full bg-muted/60 animate-pulse rounded mx-auto mt-2" })
|
|
515
|
+
] }),
|
|
516
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: Array.from({ length: Math.min(limit, 6) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg overflow-hidden", children: [
|
|
517
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-square bg-muted animate-pulse" }),
|
|
518
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-3", children: [
|
|
519
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-20 bg-muted/60 animate-pulse rounded" }),
|
|
520
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 w-full bg-muted animate-pulse rounded" }),
|
|
521
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-16 bg-muted animate-pulse rounded" })
|
|
522
|
+
] })
|
|
523
|
+
] }, i)) })
|
|
524
|
+
] }) });
|
|
525
|
+
}
|
|
526
|
+
if (state.error) {
|
|
527
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-6xl mx-auto px-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12 border border-dashed border-border rounded-lg bg-muted/20", children: [
|
|
528
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "Unable to load products" }),
|
|
529
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground/70 mt-1", children: state.error })
|
|
530
|
+
] }) }) });
|
|
531
|
+
}
|
|
532
|
+
const products = (state.data || []).slice(0, limit);
|
|
533
|
+
if (products.length === 0) {
|
|
534
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-6xl mx-auto px-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12 border border-dashed border-border rounded-lg bg-muted/10", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No products available" }) }) }) });
|
|
535
|
+
}
|
|
536
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-6xl mx-auto px-4", children: [
|
|
537
|
+
(title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-8", children: [
|
|
538
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl md:text-3xl font-semibold tracking-tight", children: title }),
|
|
539
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-2", children: subtitle })
|
|
540
|
+
] }),
|
|
541
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg overflow-hidden group hover:shadow-md transition-shadow", children: [
|
|
542
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aspect-square relative bg-muted overflow-hidden", children: [
|
|
543
|
+
product.image ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: product.image, alt: product.name, className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-muted-foreground/30", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-12 h-12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" }) }) }),
|
|
544
|
+
product.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-3 left-3 text-xs px-2 py-1 rounded bg-primary text-primary-foreground", children: product.badge })
|
|
545
|
+
] }),
|
|
546
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-2", children: [
|
|
547
|
+
product.category && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: product.category }),
|
|
548
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-medium text-sm line-clamp-2", children: product.name }),
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pt-1", children: [
|
|
550
|
+
showPrice && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
|
|
551
|
+
currency,
|
|
552
|
+
typeof product.price === "number" ? product.price.toFixed(2) : product.price
|
|
553
|
+
] }),
|
|
554
|
+
showRating && product.rating && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
555
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5 fill-yellow-400 text-yellow-400", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }),
|
|
556
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: product.rating })
|
|
557
|
+
] })
|
|
558
|
+
] })
|
|
559
|
+
] })
|
|
560
|
+
] }, product.id)) })
|
|
561
|
+
] }) });
|
|
562
|
+
}
|
|
563
|
+
function FieldValue({ value, fieldType }) {
|
|
564
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
565
|
+
const isHtml = (v) => typeof v === "string" && /<[a-z][\s\S]*>/i.test(v);
|
|
566
|
+
if (fieldType === "richtext" || isHtml(value)) {
|
|
567
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
568
|
+
"div",
|
|
569
|
+
{
|
|
570
|
+
className: "prose prose-neutral dark:prose-invert max-w-none",
|
|
571
|
+
dangerouslySetInnerHTML: { __html: String(value) }
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
if (fieldType === "image") {
|
|
576
|
+
return /* @__PURE__ */ jsxRuntime.jsx("img", { src: String(value), alt: "", className: "rounded-lg border max-h-96 object-cover w-full" });
|
|
577
|
+
}
|
|
578
|
+
if (fieldType === "boolean") {
|
|
579
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value ? "Yes" : "No" });
|
|
580
|
+
}
|
|
581
|
+
if (fieldType === "url") {
|
|
582
|
+
return /* @__PURE__ */ jsxRuntime.jsx("a", { href: String(value), className: "text-primary underline underline-offset-2 break-all", children: String(value) });
|
|
583
|
+
}
|
|
584
|
+
if (Array.isArray(value)) {
|
|
585
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value.join(", ") });
|
|
586
|
+
}
|
|
587
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: String(value) });
|
|
588
|
+
}
|
|
589
|
+
function StructuredBlock({ block, pageType }) {
|
|
590
|
+
const nested = block.content ?? block.data ?? {};
|
|
591
|
+
if (pageType?.sections?.length) {
|
|
592
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-8", children: pageType.sections.map((section) => {
|
|
593
|
+
const sectionData = nested[section.name] ?? {};
|
|
594
|
+
const filledFields = section.fields.filter((f) => {
|
|
595
|
+
const v = sectionData[f.name];
|
|
596
|
+
return v !== void 0 && v !== null && v !== "";
|
|
597
|
+
});
|
|
598
|
+
if (filledFields.length === 0) return null;
|
|
599
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "space-y-4", children: filledFields.map((field) => {
|
|
600
|
+
const value = sectionData[field.name];
|
|
601
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
602
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(FieldValue, { value, fieldType: field.fieldType }) }, field.id);
|
|
603
|
+
}) }, section.id);
|
|
604
|
+
}) });
|
|
605
|
+
}
|
|
606
|
+
const isHtml = (v) => typeof v === "string" && /<[a-z][\s\S]*>/i.test(v);
|
|
607
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-8", children: Object.entries(nested).map(([sectionName, fields]) => {
|
|
608
|
+
if (!fields || typeof fields !== "object" || Array.isArray(fields)) return null;
|
|
609
|
+
const entries = Object.entries(fields).filter(([, v]) => v !== "" && v !== null && v !== void 0);
|
|
610
|
+
if (entries.length === 0) return null;
|
|
611
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "space-y-4", children: entries.map(([fieldName, value]) => {
|
|
612
|
+
if (typeof value === "object" && !Array.isArray(value)) return null;
|
|
613
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: isHtml(value) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none", dangerouslySetInnerHTML: { __html: String(value) } }) : Array.isArray(value) ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: value.join(", ") }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: String(value) }) }, fieldName);
|
|
614
|
+
}) }, sectionName);
|
|
615
|
+
}) });
|
|
616
|
+
}
|
|
463
617
|
function SectionBlock({ block, pageType }) {
|
|
464
618
|
const d = getData(block);
|
|
465
619
|
const section = pageType?.sections.find((s) => s.name === block.type);
|
|
466
620
|
if (section) {
|
|
467
|
-
const filledFields = section.fields.filter((f) =>
|
|
621
|
+
const filledFields = section.fields.filter((f) => {
|
|
622
|
+
const v = d[f.name];
|
|
623
|
+
return v !== void 0 && v !== null && v !== "";
|
|
624
|
+
});
|
|
468
625
|
if (filledFields.length === 0) return null;
|
|
469
|
-
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "
|
|
626
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "space-y-4", children: filledFields.map((field) => {
|
|
470
627
|
const value = d[field.name];
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
474
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-1", children: field.label }),
|
|
475
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none text-sm", dangerouslySetInnerHTML: { __html: String(value) } })
|
|
476
|
-
] }, field.id);
|
|
477
|
-
}
|
|
478
|
-
if (field.fieldType === "image") {
|
|
479
|
-
return /* @__PURE__ */ jsxRuntime.jsx("figure", { children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: String(value), alt: field.label, className: "rounded-lg border max-h-96 object-cover" }) }, field.id);
|
|
480
|
-
}
|
|
481
|
-
if (field.fieldType === "boolean") {
|
|
482
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm", children: [
|
|
483
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
484
|
-
field.label,
|
|
485
|
-
":"
|
|
486
|
-
] }),
|
|
487
|
-
" ",
|
|
488
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value ? "Yes" : "No" })
|
|
489
|
-
] }, field.id);
|
|
490
|
-
}
|
|
491
|
-
if (field.fieldType === "url") {
|
|
492
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm", children: [
|
|
493
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
494
|
-
field.label,
|
|
495
|
-
":"
|
|
496
|
-
] }),
|
|
497
|
-
" ",
|
|
498
|
-
/* @__PURE__ */ jsxRuntime.jsx("a", { href: String(value), className: "text-primary underline underline-offset-2 break-all", children: String(value) })
|
|
499
|
-
] }, field.id);
|
|
500
|
-
}
|
|
501
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm", children: [
|
|
502
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
503
|
-
field.label,
|
|
504
|
-
":"
|
|
505
|
-
] }),
|
|
506
|
-
" ",
|
|
507
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: String(value) })
|
|
508
|
-
] }, field.id);
|
|
628
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
629
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(FieldValue, { value, fieldType: field.fieldType }) }, field.id);
|
|
509
630
|
}) });
|
|
510
631
|
}
|
|
511
632
|
const isHtml = (v) => typeof v === "string" && /<[a-z][\s\S]*>/i.test(v);
|
|
@@ -513,21 +634,13 @@ function SectionBlock({ block, pageType }) {
|
|
|
513
634
|
([, v]) => v !== "" && v !== null && v !== void 0 && typeof v !== "object" && !Array.isArray(v)
|
|
514
635
|
);
|
|
515
636
|
if (entries.length === 0) return null;
|
|
516
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
([key, value]) => isHtml(value) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none text-sm", dangerouslySetInnerHTML: { __html: String(value) } }, key) : /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm", children: [
|
|
520
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium capitalize", children: [
|
|
521
|
-
key.replace(/_/g, " "),
|
|
522
|
-
":"
|
|
523
|
-
] }),
|
|
524
|
-
" ",
|
|
525
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: String(value) })
|
|
526
|
-
] }, key)
|
|
527
|
-
)
|
|
528
|
-
] });
|
|
637
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "space-y-2", children: entries.map(
|
|
638
|
+
([key, value]) => isHtml(value) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none", dangerouslySetInnerHTML: { __html: String(value) } }, key) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: String(value) }, key)
|
|
639
|
+
) });
|
|
529
640
|
}
|
|
530
641
|
var BUILT_IN = {
|
|
642
|
+
// Structured page type — content is nested { sectionName: { fieldName: value } }
|
|
643
|
+
"__structured__": (b, pt) => /* @__PURE__ */ jsxRuntime.jsx(StructuredBlock, { block: b, pageType: pt }),
|
|
531
644
|
heading: (b) => /* @__PURE__ */ jsxRuntime.jsx(HeadingBlock, { block: b }),
|
|
532
645
|
text: (b) => /* @__PURE__ */ jsxRuntime.jsx(TextBlock, { block: b }),
|
|
533
646
|
richtext: (b) => /* @__PURE__ */ jsxRuntime.jsx(RichTextBlock, { block: b }),
|
|
@@ -542,7 +655,8 @@ var BUILT_IN = {
|
|
|
542
655
|
alert: (b) => /* @__PURE__ */ jsxRuntime.jsx(AlertBlock, { block: b }),
|
|
543
656
|
divider: () => /* @__PURE__ */ jsxRuntime.jsx(DividerBlock, {}),
|
|
544
657
|
spacer: (b) => /* @__PURE__ */ jsxRuntime.jsx(SpacerBlock, { block: b }),
|
|
545
|
-
video: (b) => /* @__PURE__ */ jsxRuntime.jsx(VideoBlock, { block: b })
|
|
658
|
+
video: (b) => /* @__PURE__ */ jsxRuntime.jsx(VideoBlock, { block: b }),
|
|
659
|
+
"product-list": (b) => /* @__PURE__ */ jsxRuntime.jsx(ProductListBlock, { block: b })
|
|
546
660
|
};
|
|
547
661
|
function CMSBlocks({ blocks, pageType, className = "", custom = {} }) {
|
|
548
662
|
if (!blocks?.length) return null;
|