@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/dist/next/index.js
CHANGED
|
@@ -454,52 +454,173 @@ function VideoBlock({ block }) {
|
|
|
454
454
|
const embedUrl = url.replace("youtube.com/watch?v=", "youtube.com/embed/").replace("youtu.be/", "youtube.com/embed/").replace("vimeo.com/", "player.vimeo.com/video/");
|
|
455
455
|
return /* @__PURE__ */ jsx("div", { className: "aspect-video rounded-lg overflow-hidden border bg-muted", children: /* @__PURE__ */ jsx("iframe", { src: embedUrl, allow: "autoplay; fullscreen", allowFullScreen: true, className: "w-full h-full", title: d.title || "Video" }) });
|
|
456
456
|
}
|
|
457
|
+
function normaliseProduct(raw) {
|
|
458
|
+
if (raw.id !== void 0 && raw.price !== void 0) return raw;
|
|
459
|
+
const firstPlan = Array.isArray(raw.plans) && raw.plans.length > 0 ? raw.plans[0] : null;
|
|
460
|
+
return {
|
|
461
|
+
id: raw._id ?? raw.id ?? String(Math.random()),
|
|
462
|
+
name: raw.name ?? "Unnamed",
|
|
463
|
+
description: raw.description,
|
|
464
|
+
price: firstPlan?.price ?? 0,
|
|
465
|
+
image: raw.image ?? raw.thumbnail ?? void 0,
|
|
466
|
+
rating: raw.rating ?? void 0,
|
|
467
|
+
category: raw.type ? raw.type.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) : void 0,
|
|
468
|
+
badge: raw.duration ? `${raw.duration} months` : void 0
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function ProductListBlock({ block }) {
|
|
472
|
+
const d = getData(block);
|
|
473
|
+
const { title, subtitle, endpoint, columns = 3, showPrice = true, showRating = true, limit = 6, currency = "$" } = d;
|
|
474
|
+
const cols = parseInt(String(columns), 10);
|
|
475
|
+
const [state, setState] = React.useState({
|
|
476
|
+
data: null,
|
|
477
|
+
loading: true,
|
|
478
|
+
error: null
|
|
479
|
+
});
|
|
480
|
+
React.useEffect(() => {
|
|
481
|
+
if (!endpoint) {
|
|
482
|
+
setState({ data: [], loading: false, error: null });
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
let cancelled = false;
|
|
486
|
+
async function fetchData() {
|
|
487
|
+
try {
|
|
488
|
+
const res = await fetch(endpoint);
|
|
489
|
+
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
|
490
|
+
const json = await res.json();
|
|
491
|
+
if (cancelled) return;
|
|
492
|
+
const items = Array.isArray(json) ? json : json.data ?? json.products ?? [];
|
|
493
|
+
setState({ data: items.map(normaliseProduct), loading: false, error: null });
|
|
494
|
+
} catch (err) {
|
|
495
|
+
if (!cancelled) setState({ data: null, loading: false, error: err.message });
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
fetchData();
|
|
499
|
+
return () => {
|
|
500
|
+
cancelled = true;
|
|
501
|
+
};
|
|
502
|
+
}, [endpoint]);
|
|
503
|
+
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";
|
|
504
|
+
if (state.loading) {
|
|
505
|
+
return /* @__PURE__ */ jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxs("div", { className: "max-w-6xl mx-auto px-4", children: [
|
|
506
|
+
(title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "text-center mb-8", children: [
|
|
507
|
+
title && /* @__PURE__ */ jsx("div", { className: "h-8 w-64 bg-muted animate-pulse rounded mx-auto" }),
|
|
508
|
+
subtitle && /* @__PURE__ */ jsx("div", { className: "h-4 w-96 max-w-full bg-muted/60 animate-pulse rounded mx-auto mt-2" })
|
|
509
|
+
] }),
|
|
510
|
+
/* @__PURE__ */ jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: Array.from({ length: Math.min(limit, 6) }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "border rounded-lg overflow-hidden", children: [
|
|
511
|
+
/* @__PURE__ */ jsx("div", { className: "aspect-square bg-muted animate-pulse" }),
|
|
512
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 space-y-3", children: [
|
|
513
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-20 bg-muted/60 animate-pulse rounded" }),
|
|
514
|
+
/* @__PURE__ */ jsx("div", { className: "h-5 w-full bg-muted animate-pulse rounded" }),
|
|
515
|
+
/* @__PURE__ */ jsx("div", { className: "h-6 w-16 bg-muted animate-pulse rounded" })
|
|
516
|
+
] })
|
|
517
|
+
] }, i)) })
|
|
518
|
+
] }) });
|
|
519
|
+
}
|
|
520
|
+
if (state.error) {
|
|
521
|
+
return /* @__PURE__ */ jsx("section", { className: "py-12", children: /* @__PURE__ */ jsx("div", { className: "max-w-6xl mx-auto px-4", children: /* @__PURE__ */ jsxs("div", { className: "text-center py-12 border border-dashed border-border rounded-lg bg-muted/20", children: [
|
|
522
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "Unable to load products" }),
|
|
523
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground/70 mt-1", children: state.error })
|
|
524
|
+
] }) }) });
|
|
525
|
+
}
|
|
526
|
+
const products = (state.data || []).slice(0, limit);
|
|
527
|
+
if (products.length === 0) {
|
|
528
|
+
return /* @__PURE__ */ jsx("section", { className: "py-12", children: /* @__PURE__ */ jsx("div", { className: "max-w-6xl mx-auto px-4", children: /* @__PURE__ */ jsx("div", { className: "text-center py-12 border border-dashed border-border rounded-lg bg-muted/10", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No products available" }) }) }) });
|
|
529
|
+
}
|
|
530
|
+
return /* @__PURE__ */ jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxs("div", { className: "max-w-6xl mx-auto px-4", children: [
|
|
531
|
+
(title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "text-center mb-8", children: [
|
|
532
|
+
title && /* @__PURE__ */ jsx("h2", { className: "text-2xl md:text-3xl font-semibold tracking-tight", children: title }),
|
|
533
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-2", children: subtitle })
|
|
534
|
+
] }),
|
|
535
|
+
/* @__PURE__ */ jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: products.map((product) => /* @__PURE__ */ jsxs("div", { className: "border rounded-lg overflow-hidden group hover:shadow-md transition-shadow", children: [
|
|
536
|
+
/* @__PURE__ */ jsxs("div", { className: "aspect-square relative bg-muted overflow-hidden", children: [
|
|
537
|
+
product.image ? /* @__PURE__ */ jsx("img", { src: product.image, alt: product.name, className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center text-muted-foreground/30", children: /* @__PURE__ */ jsx("svg", { className: "w-12 h-12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" }) }) }),
|
|
538
|
+
product.badge && /* @__PURE__ */ jsx("span", { className: "absolute top-3 left-3 text-xs px-2 py-1 rounded bg-primary text-primary-foreground", children: product.badge })
|
|
539
|
+
] }),
|
|
540
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 space-y-2", children: [
|
|
541
|
+
product.category && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: product.category }),
|
|
542
|
+
/* @__PURE__ */ jsx("h3", { className: "font-medium text-sm line-clamp-2", children: product.name }),
|
|
543
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-1", children: [
|
|
544
|
+
showPrice && /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
|
|
545
|
+
currency,
|
|
546
|
+
typeof product.price === "number" ? product.price.toFixed(2) : product.price
|
|
547
|
+
] }),
|
|
548
|
+
showRating && product.rating && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
549
|
+
/* @__PURE__ */ jsx("svg", { className: "w-3.5 h-3.5 fill-yellow-400 text-yellow-400", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) }),
|
|
550
|
+
/* @__PURE__ */ jsx("span", { children: product.rating })
|
|
551
|
+
] })
|
|
552
|
+
] })
|
|
553
|
+
] })
|
|
554
|
+
] }, product.id)) })
|
|
555
|
+
] }) });
|
|
556
|
+
}
|
|
557
|
+
function FieldValue({ value, fieldType }) {
|
|
558
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
559
|
+
const isHtml = (v) => typeof v === "string" && /<[a-z][\s\S]*>/i.test(v);
|
|
560
|
+
if (fieldType === "richtext" || isHtml(value)) {
|
|
561
|
+
return /* @__PURE__ */ jsx(
|
|
562
|
+
"div",
|
|
563
|
+
{
|
|
564
|
+
className: "prose prose-neutral dark:prose-invert max-w-none",
|
|
565
|
+
dangerouslySetInnerHTML: { __html: String(value) }
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
if (fieldType === "image") {
|
|
570
|
+
return /* @__PURE__ */ jsx("img", { src: String(value), alt: "", className: "rounded-lg border max-h-96 object-cover w-full" });
|
|
571
|
+
}
|
|
572
|
+
if (fieldType === "boolean") {
|
|
573
|
+
return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: value ? "Yes" : "No" });
|
|
574
|
+
}
|
|
575
|
+
if (fieldType === "url") {
|
|
576
|
+
return /* @__PURE__ */ jsx("a", { href: String(value), className: "text-primary underline underline-offset-2 break-all", children: String(value) });
|
|
577
|
+
}
|
|
578
|
+
if (Array.isArray(value)) {
|
|
579
|
+
return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: value.join(", ") });
|
|
580
|
+
}
|
|
581
|
+
return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: String(value) });
|
|
582
|
+
}
|
|
583
|
+
function StructuredBlock({ block, pageType }) {
|
|
584
|
+
const nested = block.content ?? block.data ?? {};
|
|
585
|
+
if (pageType?.sections?.length) {
|
|
586
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-8", children: pageType.sections.map((section) => {
|
|
587
|
+
const sectionData = nested[section.name] ?? {};
|
|
588
|
+
const filledFields = section.fields.filter((f) => {
|
|
589
|
+
const v = sectionData[f.name];
|
|
590
|
+
return v !== void 0 && v !== null && v !== "";
|
|
591
|
+
});
|
|
592
|
+
if (filledFields.length === 0) return null;
|
|
593
|
+
return /* @__PURE__ */ jsx("section", { className: "space-y-4", children: filledFields.map((field) => {
|
|
594
|
+
const value = sectionData[field.name];
|
|
595
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
596
|
+
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(FieldValue, { value, fieldType: field.fieldType }) }, field.id);
|
|
597
|
+
}) }, section.id);
|
|
598
|
+
}) });
|
|
599
|
+
}
|
|
600
|
+
const isHtml = (v) => typeof v === "string" && /<[a-z][\s\S]*>/i.test(v);
|
|
601
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-8", children: Object.entries(nested).map(([sectionName, fields]) => {
|
|
602
|
+
if (!fields || typeof fields !== "object" || Array.isArray(fields)) return null;
|
|
603
|
+
const entries = Object.entries(fields).filter(([, v]) => v !== "" && v !== null && v !== void 0);
|
|
604
|
+
if (entries.length === 0) return null;
|
|
605
|
+
return /* @__PURE__ */ jsx("section", { className: "space-y-4", children: entries.map(([fieldName, value]) => {
|
|
606
|
+
if (typeof value === "object" && !Array.isArray(value)) return null;
|
|
607
|
+
return /* @__PURE__ */ jsx("div", { children: isHtml(value) ? /* @__PURE__ */ jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none", dangerouslySetInnerHTML: { __html: String(value) } }) : Array.isArray(value) ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: value.join(", ") }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: String(value) }) }, fieldName);
|
|
608
|
+
}) }, sectionName);
|
|
609
|
+
}) });
|
|
610
|
+
}
|
|
457
611
|
function SectionBlock({ block, pageType }) {
|
|
458
612
|
const d = getData(block);
|
|
459
613
|
const section = pageType?.sections.find((s) => s.name === block.type);
|
|
460
614
|
if (section) {
|
|
461
|
-
const filledFields = section.fields.filter((f) =>
|
|
615
|
+
const filledFields = section.fields.filter((f) => {
|
|
616
|
+
const v = d[f.name];
|
|
617
|
+
return v !== void 0 && v !== null && v !== "";
|
|
618
|
+
});
|
|
462
619
|
if (filledFields.length === 0) return null;
|
|
463
|
-
return /* @__PURE__ */ jsx("section", { className: "
|
|
620
|
+
return /* @__PURE__ */ jsx("section", { className: "space-y-4", children: filledFields.map((field) => {
|
|
464
621
|
const value = d[field.name];
|
|
465
|
-
if (
|
|
466
|
-
|
|
467
|
-
return /* @__PURE__ */ jsxs("div", { children: [
|
|
468
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-1", children: field.label }),
|
|
469
|
-
/* @__PURE__ */ jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none text-sm", dangerouslySetInnerHTML: { __html: String(value) } })
|
|
470
|
-
] }, field.id);
|
|
471
|
-
}
|
|
472
|
-
if (field.fieldType === "image") {
|
|
473
|
-
return /* @__PURE__ */ jsx("figure", { children: /* @__PURE__ */ jsx("img", { src: String(value), alt: field.label, className: "rounded-lg border max-h-96 object-cover" }) }, field.id);
|
|
474
|
-
}
|
|
475
|
-
if (field.fieldType === "boolean") {
|
|
476
|
-
return /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
477
|
-
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
478
|
-
field.label,
|
|
479
|
-
":"
|
|
480
|
-
] }),
|
|
481
|
-
" ",
|
|
482
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: value ? "Yes" : "No" })
|
|
483
|
-
] }, field.id);
|
|
484
|
-
}
|
|
485
|
-
if (field.fieldType === "url") {
|
|
486
|
-
return /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
487
|
-
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
488
|
-
field.label,
|
|
489
|
-
":"
|
|
490
|
-
] }),
|
|
491
|
-
" ",
|
|
492
|
-
/* @__PURE__ */ jsx("a", { href: String(value), className: "text-primary underline underline-offset-2 break-all", children: String(value) })
|
|
493
|
-
] }, field.id);
|
|
494
|
-
}
|
|
495
|
-
return /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
496
|
-
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
497
|
-
field.label,
|
|
498
|
-
":"
|
|
499
|
-
] }),
|
|
500
|
-
" ",
|
|
501
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: String(value) })
|
|
502
|
-
] }, field.id);
|
|
622
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
623
|
+
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(FieldValue, { value, fieldType: field.fieldType }) }, field.id);
|
|
503
624
|
}) });
|
|
504
625
|
}
|
|
505
626
|
const isHtml = (v) => typeof v === "string" && /<[a-z][\s\S]*>/i.test(v);
|
|
@@ -507,21 +628,13 @@ function SectionBlock({ block, pageType }) {
|
|
|
507
628
|
([, v]) => v !== "" && v !== null && v !== void 0 && typeof v !== "object" && !Array.isArray(v)
|
|
508
629
|
);
|
|
509
630
|
if (entries.length === 0) return null;
|
|
510
|
-
return /* @__PURE__ */
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
([key, value]) => isHtml(value) ? /* @__PURE__ */ jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none text-sm", dangerouslySetInnerHTML: { __html: String(value) } }, key) : /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
514
|
-
/* @__PURE__ */ jsxs("span", { className: "font-medium capitalize", children: [
|
|
515
|
-
key.replace(/_/g, " "),
|
|
516
|
-
":"
|
|
517
|
-
] }),
|
|
518
|
-
" ",
|
|
519
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: String(value) })
|
|
520
|
-
] }, key)
|
|
521
|
-
)
|
|
522
|
-
] });
|
|
631
|
+
return /* @__PURE__ */ jsx("section", { className: "space-y-2", children: entries.map(
|
|
632
|
+
([key, value]) => isHtml(value) ? /* @__PURE__ */ jsx("div", { className: "prose prose-neutral dark:prose-invert max-w-none", dangerouslySetInnerHTML: { __html: String(value) } }, key) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: String(value) }, key)
|
|
633
|
+
) });
|
|
523
634
|
}
|
|
524
635
|
var BUILT_IN = {
|
|
636
|
+
// Structured page type — content is nested { sectionName: { fieldName: value } }
|
|
637
|
+
"__structured__": (b, pt) => /* @__PURE__ */ jsx(StructuredBlock, { block: b, pageType: pt }),
|
|
525
638
|
heading: (b) => /* @__PURE__ */ jsx(HeadingBlock, { block: b }),
|
|
526
639
|
text: (b) => /* @__PURE__ */ jsx(TextBlock, { block: b }),
|
|
527
640
|
richtext: (b) => /* @__PURE__ */ jsx(RichTextBlock, { block: b }),
|
|
@@ -536,7 +649,8 @@ var BUILT_IN = {
|
|
|
536
649
|
alert: (b) => /* @__PURE__ */ jsx(AlertBlock, { block: b }),
|
|
537
650
|
divider: () => /* @__PURE__ */ jsx(DividerBlock, {}),
|
|
538
651
|
spacer: (b) => /* @__PURE__ */ jsx(SpacerBlock, { block: b }),
|
|
539
|
-
video: (b) => /* @__PURE__ */ jsx(VideoBlock, { block: b })
|
|
652
|
+
video: (b) => /* @__PURE__ */ jsx(VideoBlock, { block: b }),
|
|
653
|
+
"product-list": (b) => /* @__PURE__ */ jsx(ProductListBlock, { block: b })
|
|
540
654
|
};
|
|
541
655
|
function CMSBlocks({ blocks, pageType, className = "", custom = {} }) {
|
|
542
656
|
if (!blocks?.length) return null;
|