@xiwebdesign/xicms-core 5.3.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/XiCMSProvider.d.ts +11 -2
- package/dist/XiCMSProvider.js +10 -5
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/blockEditors/GenericEditor.js +18 -8
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/customBlocks/CustomBlocksPanel.js +12 -2
- package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
- package/dist/admin/lib/pagesClient.js +4 -1
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/upload.js +14 -7
- package/dist/admin/lib/upload.js.map +1 -1
- package/dist/admin/media/MediaManager.js +60 -28
- package/dist/admin/media/MediaManager.js.map +1 -1
- package/dist/admin/media/MediaPicker.js +25 -15
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/pages/PageEditor.d.ts +2 -1
- package/dist/admin/pages/PageEditor.js +16 -2
- package/dist/admin/pages/PageEditor.js.map +1 -1
- package/dist/admin/pages/PagesPanel.js +9 -5
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/panelRegistry.js +3 -0
- package/dist/admin/panelRegistry.js.map +1 -1
- package/dist/admin/shop/CategoriesTab.d.ts +3 -0
- package/dist/admin/shop/CategoriesTab.js +140 -0
- package/dist/admin/shop/CategoriesTab.js.map +1 -0
- package/dist/admin/shop/ConnectionsTab.d.ts +9 -0
- package/dist/admin/shop/ConnectionsTab.js +158 -0
- package/dist/admin/shop/ConnectionsTab.js.map +1 -0
- package/dist/admin/shop/OrdersTab.d.ts +3 -0
- package/dist/admin/shop/OrdersTab.js +236 -0
- package/dist/admin/shop/OrdersTab.js.map +1 -0
- package/dist/admin/shop/ProductsTab.d.ts +3 -0
- package/dist/admin/shop/ProductsTab.js +397 -0
- package/dist/admin/shop/ProductsTab.js.map +1 -0
- package/dist/admin/shop/ShopPanel.d.ts +4 -0
- package/dist/admin/shop/ShopPanel.js +25 -0
- package/dist/admin/shop/ShopPanel.js.map +1 -0
- package/dist/admin/shop/lib.d.ts +16 -0
- package/dist/admin/shop/lib.js +46 -0
- package/dist/admin/shop/lib.js.map +1 -0
- package/dist/admin/visual/VisualEditor.js +11 -2
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/agentFiles/files.d.ts +15 -3
- package/dist/agentFiles/files.js +57 -0
- package/dist/agentFiles/files.js.map +1 -1
- package/dist/auth/AuthProvider.js +3 -3
- package/dist/auth/AuthProvider.js.map +1 -1
- package/dist/blocks/builtins/Columns.js +1 -1
- package/dist/blocks/builtins/Columns.js.map +1 -1
- package/dist/blocks/builtins/Gallery.js +2 -2
- package/dist/blocks/builtins/Gallery.js.map +1 -1
- package/dist/blocks/builtins/Hero.js +1 -1
- package/dist/blocks/builtins/Hero.js.map +1 -1
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/components/PageView.js +4 -3
- package/dist/components/PageView.js.map +1 -1
- package/dist/demo/index.d.ts +7 -0
- package/dist/demo/index.js +23 -0
- package/dist/demo/index.js.map +1 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +0 -20
- package/dist/index.js.map +1 -1
- package/dist/modules/builtins.d.ts +1 -0
- package/dist/modules/builtins.js +4 -0
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/index.d.ts +4 -0
- package/dist/modules/index.js +12 -0
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/registry.d.ts +3 -4
- package/dist/modules/registry.js +2 -3
- package/dist/modules/registry.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.d.ts +2 -0
- package/dist/modules/shop/blocks/Cart.js +91 -0
- package/dist/modules/shop/blocks/Cart.js.map +1 -0
- package/dist/modules/shop/blocks/Checkout.d.ts +2 -0
- package/dist/modules/shop/blocks/Checkout.js +126 -0
- package/dist/modules/shop/blocks/Checkout.js.map +1 -0
- package/dist/modules/shop/blocks/Donation.d.ts +2 -0
- package/dist/modules/shop/blocks/Donation.js +145 -0
- package/dist/modules/shop/blocks/Donation.js.map +1 -0
- package/dist/modules/shop/blocks/OrderStatus.d.ts +2 -0
- package/dist/modules/shop/blocks/OrderStatus.js +40 -0
- package/dist/modules/shop/blocks/OrderStatus.js.map +1 -0
- package/dist/modules/shop/blocks/ProductDetail.d.ts +2 -0
- package/dist/modules/shop/blocks/ProductDetail.js +168 -0
- package/dist/modules/shop/blocks/ProductDetail.js.map +1 -0
- package/dist/modules/shop/blocks/ProductGrid.d.ts +8 -0
- package/dist/modules/shop/blocks/ProductGrid.js +136 -0
- package/dist/modules/shop/blocks/ProductGrid.js.map +1 -0
- package/dist/modules/shop/blocks/ShopCategories.d.ts +2 -0
- package/dist/modules/shop/blocks/ShopCategories.js +69 -0
- package/dist/modules/shop/blocks/ShopCategories.js.map +1 -0
- package/dist/modules/shop/cartStore.d.ts +22 -0
- package/dist/modules/shop/cartStore.js +85 -0
- package/dist/modules/shop/cartStore.js.map +1 -0
- package/dist/modules/shop/lib.d.ts +25 -0
- package/dist/modules/shop/lib.js +61 -0
- package/dist/modules/shop/lib.js.map +1 -0
- package/dist/modules/shop/module.d.ts +1 -0
- package/dist/modules/shop/module.js +39 -0
- package/dist/modules/shop/module.js.map +1 -0
- package/dist/modules/shop/settings.d.ts +41 -0
- package/dist/modules/shop/settings.js +18 -0
- package/dist/modules/shop/settings.js.map +1 -0
- package/dist/schema/blocks.d.ts +27 -12
- package/dist/schema/blocks.js +3 -0
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/settings.d.ts +1 -34
- package/dist/schema/settings.js +2 -8
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +939 -0
- package/dist/schema/shop.js +209 -0
- package/dist/schema/shop.js.map +1 -0
- package/dist/schema/siteConfig.d.ts +3 -71
- package/dist/schema/siteConfig.js +3 -8
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/schema/symbols.d.ts +2 -2
- package/dist/schema/symbols.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/pages.d.ts +23 -3
- package/dist/server/pages.js +37 -3
- package/dist/server/pages.js.map +1 -1
- package/dist/server/seo.js +5 -3
- package/dist/server/seo.js.map +1 -1
- package/dist/settings/useSiteSettings.d.ts +15 -3
- package/dist/settings/useSiteSettings.js +26 -5
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/styles.css +14 -0
- package/package.json +6 -2
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { ShopCategoriesBlockSchema } from "../../../schema/shop";
|
|
5
|
+
import { defineBlock } from "../../../blocks/registry";
|
|
6
|
+
import { Card, Heading, Text } from "../../../blocks/ui";
|
|
7
|
+
import { fetchShopCategories, useShopSettings } from "../lib";
|
|
8
|
+
function ShopCategoriesRender({ block, siteId }) {
|
|
9
|
+
const settings = useShopSettings();
|
|
10
|
+
const [cats, setCats] = useState(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
void fetchShopCategories(siteId).then(setCats).catch(() => setCats([]));
|
|
13
|
+
}, [siteId]);
|
|
14
|
+
if (cats === null) return null;
|
|
15
|
+
if (cats.length === 0) {
|
|
16
|
+
return /* @__PURE__ */ jsx(Card, { padding: 4, variant: "muted", children: /* @__PURE__ */ jsx(Text, { children: "Nog geen categorie\xEBn." }) });
|
|
17
|
+
}
|
|
18
|
+
return /* @__PURE__ */ jsxs("div", { className: "xicms-shop-categories", children: [
|
|
19
|
+
block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, "data-xicms-edit": "heading", children: block.heading }),
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
"div",
|
|
22
|
+
{
|
|
23
|
+
className: "xicms-shop-categories__grid",
|
|
24
|
+
style: {
|
|
25
|
+
display: "grid",
|
|
26
|
+
gridTemplateColumns: `repeat(auto-fill, minmax(min(260px, calc(100%/${block.columns} - 1rem)), 1fr))`,
|
|
27
|
+
gap: "1rem",
|
|
28
|
+
marginTop: block.heading ? "1rem" : 0
|
|
29
|
+
},
|
|
30
|
+
children: cats.map((c) => /* @__PURE__ */ jsx(
|
|
31
|
+
"a",
|
|
32
|
+
{
|
|
33
|
+
className: "xicms-shop-categories__item",
|
|
34
|
+
href: `${settings.shopPath}?cat=${encodeURIComponent(c.slug)}`,
|
|
35
|
+
style: { textDecoration: "none", color: "inherit" },
|
|
36
|
+
children: /* @__PURE__ */ jsxs(Card, { padding: 0, children: [
|
|
37
|
+
c.imageUrl && /* @__PURE__ */ jsx(
|
|
38
|
+
"img",
|
|
39
|
+
{
|
|
40
|
+
src: c.imageUrl,
|
|
41
|
+
alt: c.name,
|
|
42
|
+
loading: "lazy",
|
|
43
|
+
style: { width: "100%", aspectRatio: "4/3", objectFit: "cover", display: "block", borderRadius: "inherit" }
|
|
44
|
+
}
|
|
45
|
+
),
|
|
46
|
+
/* @__PURE__ */ jsxs("div", { style: { padding: "0.9rem 1rem" }, children: [
|
|
47
|
+
/* @__PURE__ */ jsx(Text, { weight: "bold", children: c.name }),
|
|
48
|
+
c.description && /* @__PURE__ */ jsx(Text, { size: "sm", style: { opacity: 0.75, marginTop: 4 }, children: c.description })
|
|
49
|
+
] })
|
|
50
|
+
] })
|
|
51
|
+
},
|
|
52
|
+
c.id
|
|
53
|
+
))
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
] });
|
|
57
|
+
}
|
|
58
|
+
const shopCategoriesBlock = defineBlock({
|
|
59
|
+
type: "shopCategories",
|
|
60
|
+
schema: ShopCategoriesBlockSchema,
|
|
61
|
+
Render: ShopCategoriesRender,
|
|
62
|
+
label: "Winkel-categorie\xEBn",
|
|
63
|
+
icon: "\u{1F5C2}\uFE0F",
|
|
64
|
+
defaults: () => ({ columns: 3 })
|
|
65
|
+
});
|
|
66
|
+
export {
|
|
67
|
+
shopCategoriesBlock
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=ShopCategories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/shop/blocks/ShopCategories.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport { ShopCategoriesBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { fetchShopCategories, useShopSettings, type StoredShopCategory } from \"../lib\";\n\ntype Blk = z.infer<typeof ShopCategoriesBlockSchema>;\n\n/** Categorie-tegels — linkt naar de winkelpagina met `?cat=<slug>` (productGrid filtert daarop). */\nfunction ShopCategoriesRender({ block, siteId }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const [cats, setCats] = useState<StoredShopCategory[] | null>(null);\n\n useEffect(() => {\n void fetchShopCategories(siteId).then(setCats).catch(() => setCats([]));\n }, [siteId]);\n\n if (cats === null) return null;\n if (cats.length === 0) {\n return (\n <Card padding={4} variant=\"muted\">\n <Text>Nog geen categorieën.</Text>\n </Card>\n );\n }\n\n return (\n <div className=\"xicms-shop-categories\">\n {block.heading && (\n <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>\n )}\n <div\n className=\"xicms-shop-categories__grid\"\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(auto-fill, minmax(min(260px, calc(100%/${block.columns} - 1rem)), 1fr))`,\n gap: \"1rem\",\n marginTop: block.heading ? \"1rem\" : 0,\n }}\n >\n {cats.map((c) => (\n <a\n key={c.id}\n className=\"xicms-shop-categories__item\"\n href={`${settings.shopPath}?cat=${encodeURIComponent(c.slug)}`}\n style={{ textDecoration: \"none\", color: \"inherit\" }}\n >\n <Card padding={0}>\n {c.imageUrl && (\n <img\n src={c.imageUrl}\n alt={c.name}\n loading=\"lazy\"\n style={{ width: \"100%\", aspectRatio: \"4/3\", objectFit: \"cover\", display: \"block\", borderRadius: \"inherit\" }}\n />\n )}\n <div style={{ padding: \"0.9rem 1rem\" }}>\n <Text weight=\"bold\">{c.name}</Text>\n {c.description && (\n <Text size=\"sm\" style={{ opacity: 0.75, marginTop: 4 }}>{c.description}</Text>\n )}\n </div>\n </Card>\n </a>\n ))}\n </div>\n </div>\n );\n}\n\nexport const shopCategoriesBlock = defineBlock({\n type: \"shopCategories\",\n schema: ShopCategoriesBlockSchema,\n Render: ShopCategoriesRender,\n label: \"Winkel-categorieën\",\n icon: \"🗂️\",\n defaults: () => ({ columns: 3 }),\n});\n"],"mappings":";AAwBQ,cAmCM,YAnCN;AAtBR,SAAS,WAAW,gBAAgB;AAEpC,SAAS,iCAAiC;AAC1C,SAAS,mBAA0C;AACnD,SAAS,MAAM,SAAS,YAAY;AACpC,SAAS,qBAAqB,uBAAgD;AAK9E,SAAS,qBAAqB,EAAE,OAAO,OAAO,GAA0B;AACtE,QAAM,WAAW,gBAAgB;AACjC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAsC,IAAI;AAElE,YAAU,MAAM;AACd,SAAK,oBAAoB,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACxE,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,oBAAC,QAAK,SAAS,GAAG,SAAQ,SACxB,8BAAC,QAAK,sCAAqB,GAC7B;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,yBACZ;AAAA,UAAM,WACL,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAE9D;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,SAAS;AAAA,UACT,qBAAqB,iDAAiD,MAAM,OAAO;AAAA,UACnF,KAAK;AAAA,UACL,WAAW,MAAM,UAAU,SAAS;AAAA,QACtC;AAAA,QAEC,eAAK,IAAI,CAAC,MACT;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YACV,MAAM,GAAG,SAAS,QAAQ,QAAQ,mBAAmB,EAAE,IAAI,CAAC;AAAA,YAC5D,OAAO,EAAE,gBAAgB,QAAQ,OAAO,UAAU;AAAA,YAElD,+BAAC,QAAK,SAAS,GACZ;AAAA,gBAAE,YACD;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK,EAAE;AAAA,kBACP,KAAK,EAAE;AAAA,kBACP,SAAQ;AAAA,kBACR,OAAO,EAAE,OAAO,QAAQ,aAAa,OAAO,WAAW,SAAS,SAAS,SAAS,cAAc,UAAU;AAAA;AAAA,cAC5G;AAAA,cAEF,qBAAC,SAAI,OAAO,EAAE,SAAS,cAAc,GACnC;AAAA,oCAAC,QAAK,QAAO,QAAQ,YAAE,MAAK;AAAA,gBAC3B,EAAE,eACD,oBAAC,QAAK,MAAK,MAAK,OAAO,EAAE,SAAS,MAAM,WAAW,EAAE,GAAI,YAAE,aAAY;AAAA,iBAE3E;AAAA,eACF;AAAA;AAAA,UApBK,EAAE;AAAA,QAqBT,CACD;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEO,MAAM,sBAAsB,YAAY;AAAA,EAC7C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,SAAS,EAAE;AAChC,CAAC;","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface CartLine {
|
|
2
|
+
productId: string;
|
|
3
|
+
slug: string;
|
|
4
|
+
name: string;
|
|
5
|
+
/** Variant-key ("68|Roze") + leesbaar label ("Maat 68, Roze"). */
|
|
6
|
+
variantKey?: string;
|
|
7
|
+
variantLabel?: string;
|
|
8
|
+
unitPriceCents: number;
|
|
9
|
+
qty: number;
|
|
10
|
+
imageUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function cartAdd(siteId: string, line: Omit<CartLine, "qty">, qty?: number): void;
|
|
13
|
+
export declare function cartSetQty(siteId: string, productId: string, variantKey: string | undefined, qty: number): void;
|
|
14
|
+
export declare function cartRemove(siteId: string, productId: string, variantKey: string | undefined): void;
|
|
15
|
+
export declare function cartClear(siteId: string): void;
|
|
16
|
+
export interface CartState {
|
|
17
|
+
lines: CartLine[];
|
|
18
|
+
count: number;
|
|
19
|
+
itemsCents: number;
|
|
20
|
+
}
|
|
21
|
+
/** Reactieve cart-state voor blocks/klantcomponenten (bv. een cart-badge in de header). */
|
|
22
|
+
export declare function useCart(siteId: string): CartState;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4
|
+
const cache = /* @__PURE__ */ new Map();
|
|
5
|
+
function storageKey(siteId) {
|
|
6
|
+
return `xicms:cart:${siteId}`;
|
|
7
|
+
}
|
|
8
|
+
function readLines(siteId) {
|
|
9
|
+
if (typeof window === "undefined") return [];
|
|
10
|
+
let raw = "";
|
|
11
|
+
try {
|
|
12
|
+
raw = window.localStorage.getItem(storageKey(siteId)) ?? "[]";
|
|
13
|
+
} catch {
|
|
14
|
+
raw = "[]";
|
|
15
|
+
}
|
|
16
|
+
const cached = cache.get(siteId);
|
|
17
|
+
if (cached && cached.raw === raw) return cached.lines;
|
|
18
|
+
let lines = [];
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(raw);
|
|
21
|
+
if (Array.isArray(parsed)) lines = parsed.filter((l) => l && typeof l === "object" && typeof l.productId === "string");
|
|
22
|
+
} catch {
|
|
23
|
+
lines = [];
|
|
24
|
+
}
|
|
25
|
+
cache.set(siteId, { raw, lines });
|
|
26
|
+
return lines;
|
|
27
|
+
}
|
|
28
|
+
function writeLines(siteId, lines) {
|
|
29
|
+
try {
|
|
30
|
+
window.localStorage.setItem(storageKey(siteId), JSON.stringify(lines));
|
|
31
|
+
} catch {
|
|
32
|
+
cache.set(siteId, { raw: `mem:${Date.now()}`, lines });
|
|
33
|
+
}
|
|
34
|
+
emit();
|
|
35
|
+
}
|
|
36
|
+
function emit() {
|
|
37
|
+
for (const l of listeners) l();
|
|
38
|
+
}
|
|
39
|
+
function subscribe(cb) {
|
|
40
|
+
listeners.add(cb);
|
|
41
|
+
const onStorage = (e) => {
|
|
42
|
+
if (e.key?.startsWith("xicms:cart:")) cb();
|
|
43
|
+
};
|
|
44
|
+
window.addEventListener("storage", onStorage);
|
|
45
|
+
return () => {
|
|
46
|
+
listeners.delete(cb);
|
|
47
|
+
window.removeEventListener("storage", onStorage);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function lineId(l) {
|
|
51
|
+
return `${l.productId}::${l.variantKey ?? ""}`;
|
|
52
|
+
}
|
|
53
|
+
function cartAdd(siteId, line, qty = 1) {
|
|
54
|
+
const lines = [...readLines(siteId)];
|
|
55
|
+
const idx = lines.findIndex((l) => lineId(l) === lineId(line));
|
|
56
|
+
if (idx >= 0) lines[idx] = { ...lines[idx], qty: Math.min(999, lines[idx].qty + qty) };
|
|
57
|
+
else lines.push({ ...line, qty: Math.min(999, Math.max(1, qty)) });
|
|
58
|
+
writeLines(siteId, lines);
|
|
59
|
+
}
|
|
60
|
+
function cartSetQty(siteId, productId, variantKey, qty) {
|
|
61
|
+
const lines = readLines(siteId).map((l) => lineId(l) === lineId({ productId, variantKey }) ? { ...l, qty: Math.min(999, qty) } : l).filter((l) => l.qty > 0);
|
|
62
|
+
writeLines(siteId, lines);
|
|
63
|
+
}
|
|
64
|
+
function cartRemove(siteId, productId, variantKey) {
|
|
65
|
+
writeLines(siteId, readLines(siteId).filter((l) => lineId(l) !== lineId({ productId, variantKey })));
|
|
66
|
+
}
|
|
67
|
+
function cartClear(siteId) {
|
|
68
|
+
writeLines(siteId, []);
|
|
69
|
+
}
|
|
70
|
+
function useCart(siteId) {
|
|
71
|
+
const lines = useSyncExternalStore(subscribe, () => readLines(siteId), () => []);
|
|
72
|
+
return {
|
|
73
|
+
lines,
|
|
74
|
+
count: lines.reduce((n, l) => n + l.qty, 0),
|
|
75
|
+
itemsCents: lines.reduce((n, l) => n + l.unitPriceCents * l.qty, 0)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
cartAdd,
|
|
80
|
+
cartClear,
|
|
81
|
+
cartRemove,
|
|
82
|
+
cartSetQty,
|
|
83
|
+
useCart
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=cartStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/cartStore.ts"],"sourcesContent":["\"use client\";\n\n/**\n * Winkelwagen-store — puur client-side (localStorage), geen Firestore-writes vóór checkout.\n * Extern store + `useSyncExternalStore` zodat élk shop-block (grid, cart-badge, checkout) dezelfde\n * state ziet zonder dat er een provider gemount hoeft te worden. Cross-tab sync via `storage`.\n *\n * Prijzen in de cart zijn indicatief voor weergave; bij `createOrder` herrekent de server alles\n * tegen de opgeslagen product-docs (client wordt nooit vertrouwd).\n */\nimport { useSyncExternalStore } from \"react\";\n\nexport interface CartLine {\n productId: string;\n slug: string;\n name: string;\n /** Variant-key (\"68|Roze\") + leesbaar label (\"Maat 68, Roze\"). */\n variantKey?: string;\n variantLabel?: string;\n unitPriceCents: number;\n qty: number;\n imageUrl?: string;\n}\n\nconst listeners = new Set<() => void>();\n/** Cache per siteId zodat getSnapshot een stabiele referentie teruggeeft (useSyncExternalStore-eis). */\nconst cache = new Map<string, { raw: string; lines: CartLine[] }>();\n\nfunction storageKey(siteId: string): string {\n return `xicms:cart:${siteId}`;\n}\n\nfunction readLines(siteId: string): CartLine[] {\n if (typeof window === \"undefined\") return [];\n let raw = \"\";\n try {\n raw = window.localStorage.getItem(storageKey(siteId)) ?? \"[]\";\n } catch {\n raw = \"[]\";\n }\n const cached = cache.get(siteId);\n if (cached && cached.raw === raw) return cached.lines;\n let lines: CartLine[] = [];\n try {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) lines = parsed.filter((l) => l && typeof l === \"object\" && typeof l.productId === \"string\");\n } catch {\n lines = [];\n }\n cache.set(siteId, { raw, lines });\n return lines;\n}\n\nfunction writeLines(siteId: string, lines: CartLine[]): void {\n try {\n window.localStorage.setItem(storageKey(siteId), JSON.stringify(lines));\n } catch {\n // localStorage vol/geblokkeerd: cart werkt dan alleen in-memory via de cache.\n cache.set(siteId, { raw: `mem:${Date.now()}`, lines });\n }\n emit();\n}\n\nfunction emit(): void {\n for (const l of listeners) l();\n}\n\nfunction subscribe(cb: () => void): () => void {\n listeners.add(cb);\n // Cross-tab: een andere tab die de cart wijzigt triggert hier een re-render.\n const onStorage = (e: StorageEvent) => {\n if (e.key?.startsWith(\"xicms:cart:\")) cb();\n };\n window.addEventListener(\"storage\", onStorage);\n return () => {\n listeners.delete(cb);\n window.removeEventListener(\"storage\", onStorage);\n };\n}\n\nfunction lineId(l: Pick<CartLine, \"productId\" | \"variantKey\">): string {\n return `${l.productId}::${l.variantKey ?? \"\"}`;\n}\n\nexport function cartAdd(siteId: string, line: Omit<CartLine, \"qty\">, qty = 1): void {\n const lines = [...readLines(siteId)];\n const idx = lines.findIndex((l) => lineId(l) === lineId(line));\n if (idx >= 0) lines[idx] = { ...lines[idx], qty: Math.min(999, lines[idx].qty + qty) };\n else lines.push({ ...line, qty: Math.min(999, Math.max(1, qty)) });\n writeLines(siteId, lines);\n}\n\nexport function cartSetQty(siteId: string, productId: string, variantKey: string | undefined, qty: number): void {\n const lines = readLines(siteId)\n .map((l) => (lineId(l) === lineId({ productId, variantKey }) ? { ...l, qty: Math.min(999, qty) } : l))\n .filter((l) => l.qty > 0);\n writeLines(siteId, lines);\n}\n\nexport function cartRemove(siteId: string, productId: string, variantKey: string | undefined): void {\n writeLines(siteId, readLines(siteId).filter((l) => lineId(l) !== lineId({ productId, variantKey })));\n}\n\nexport function cartClear(siteId: string): void {\n writeLines(siteId, []);\n}\n\nexport interface CartState {\n lines: CartLine[];\n count: number;\n itemsCents: number;\n}\n\n/** Reactieve cart-state voor blocks/klantcomponenten (bv. een cart-badge in de header). */\nexport function useCart(siteId: string): CartState {\n const lines = useSyncExternalStore(subscribe, () => readLines(siteId), () => [] as CartLine[]);\n return {\n lines,\n count: lines.reduce((n, l) => n + l.qty, 0),\n itemsCents: lines.reduce((n, l) => n + l.unitPriceCents * l.qty, 0),\n };\n}\n"],"mappings":";AAUA,SAAS,4BAA4B;AAcrC,MAAM,YAAY,oBAAI,IAAgB;AAEtC,MAAM,QAAQ,oBAAI,IAAgD;AAElE,SAAS,WAAW,QAAwB;AAC1C,SAAO,cAAc,MAAM;AAC7B;AAEA,SAAS,UAAU,QAA4B;AAC7C,MAAI,OAAO,WAAW,YAAa,QAAO,CAAC;AAC3C,MAAI,MAAM;AACV,MAAI;AACF,UAAM,OAAO,aAAa,QAAQ,WAAW,MAAM,CAAC,KAAK;AAAA,EAC3D,QAAQ;AACN,UAAM;AAAA,EACR;AACA,QAAM,SAAS,MAAM,IAAI,MAAM;AAC/B,MAAI,UAAU,OAAO,QAAQ,IAAK,QAAO,OAAO;AAChD,MAAI,QAAoB,CAAC;AACzB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,MAAM,QAAQ,MAAM,EAAG,SAAQ,OAAO,OAAO,CAAC,MAAM,KAAK,OAAO,MAAM,YAAY,OAAO,EAAE,cAAc,QAAQ;AAAA,EACvH,QAAQ;AACN,YAAQ,CAAC;AAAA,EACX;AACA,QAAM,IAAI,QAAQ,EAAE,KAAK,MAAM,CAAC;AAChC,SAAO;AACT;AAEA,SAAS,WAAW,QAAgB,OAAyB;AAC3D,MAAI;AACF,WAAO,aAAa,QAAQ,WAAW,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,EACvE,QAAQ;AAEN,UAAM,IAAI,QAAQ,EAAE,KAAK,OAAO,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC;AAAA,EACvD;AACA,OAAK;AACP;AAEA,SAAS,OAAa;AACpB,aAAW,KAAK,UAAW,GAAE;AAC/B;AAEA,SAAS,UAAU,IAA4B;AAC7C,YAAU,IAAI,EAAE;AAEhB,QAAM,YAAY,CAAC,MAAoB;AACrC,QAAI,EAAE,KAAK,WAAW,aAAa,EAAG,IAAG;AAAA,EAC3C;AACA,SAAO,iBAAiB,WAAW,SAAS;AAC5C,SAAO,MAAM;AACX,cAAU,OAAO,EAAE;AACnB,WAAO,oBAAoB,WAAW,SAAS;AAAA,EACjD;AACF;AAEA,SAAS,OAAO,GAAuD;AACrE,SAAO,GAAG,EAAE,SAAS,KAAK,EAAE,cAAc,EAAE;AAC9C;AAEO,SAAS,QAAQ,QAAgB,MAA6B,MAAM,GAAS;AAClF,QAAM,QAAQ,CAAC,GAAG,UAAU,MAAM,CAAC;AACnC,QAAM,MAAM,MAAM,UAAU,CAAC,MAAM,OAAO,CAAC,MAAM,OAAO,IAAI,CAAC;AAC7D,MAAI,OAAO,EAAG,OAAM,GAAG,IAAI,EAAE,GAAG,MAAM,GAAG,GAAG,KAAK,KAAK,IAAI,KAAK,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE;AAAA,MAChF,OAAM,KAAK,EAAE,GAAG,MAAM,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;AACjE,aAAW,QAAQ,KAAK;AAC1B;AAEO,SAAS,WAAW,QAAgB,WAAmB,YAAgC,KAAmB;AAC/G,QAAM,QAAQ,UAAU,MAAM,EAC3B,IAAI,CAAC,MAAO,OAAO,CAAC,MAAM,OAAO,EAAE,WAAW,WAAW,CAAC,IAAI,EAAE,GAAG,GAAG,KAAK,KAAK,IAAI,KAAK,GAAG,EAAE,IAAI,CAAE,EACpG,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;AAC1B,aAAW,QAAQ,KAAK;AAC1B;AAEO,SAAS,WAAW,QAAgB,WAAmB,YAAsC;AAClG,aAAW,QAAQ,UAAU,MAAM,EAAE,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,OAAO,EAAE,WAAW,WAAW,CAAC,CAAC,CAAC;AACrG;AAEO,SAAS,UAAU,QAAsB;AAC9C,aAAW,QAAQ,CAAC,CAAC;AACvB;AASO,SAAS,QAAQ,QAA2B;AACjD,QAAM,QAAQ,qBAAqB,WAAW,MAAM,UAAU,MAAM,GAAG,MAAM,CAAC,CAAe;AAC7F,SAAO;AAAA,IACL;AAAA,IACA,OAAO,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,KAAK,CAAC;AAAA,IAC1C,YAAY,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,iBAAiB,EAAE,KAAK,CAAC;AAAA,EACpE;AACF;","names":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CreateOrderInput, Product, ShopCategory } from "../../schema/shop";
|
|
2
|
+
import { type ShopSettings } from "./settings";
|
|
3
|
+
/** Publieke shop-instellingen met defaults (paden, verzendkosten, valuta). */
|
|
4
|
+
export declare function useShopSettings(): ShopSettings;
|
|
5
|
+
export type StoredProduct = Product & {
|
|
6
|
+
id: string;
|
|
7
|
+
};
|
|
8
|
+
export type StoredShopCategory = ShopCategory & {
|
|
9
|
+
id: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function fetchActiveProducts(siteId: string): Promise<StoredProduct[]>;
|
|
12
|
+
export declare function fetchProductBySlug(siteId: string, slug: string): Promise<StoredProduct | null>;
|
|
13
|
+
export declare function fetchShopCategories(siteId: string): Promise<StoredShopCategory[]>;
|
|
14
|
+
/** Start de checkout: order + Stripe-sessie server-side; geeft de redirect-URL terug. */
|
|
15
|
+
export declare function createOrderCall(input: CreateOrderInput): Promise<{
|
|
16
|
+
url: string;
|
|
17
|
+
orderNumber: string;
|
|
18
|
+
}>;
|
|
19
|
+
/** Leesbaar variantlabel: opties ["Maat","Kleur"] + key "68|Roze" → "Maat 68 · Roze". */
|
|
20
|
+
export declare function variantLabelFor(options: {
|
|
21
|
+
name: string;
|
|
22
|
+
values: string[];
|
|
23
|
+
}[], key: string): string;
|
|
24
|
+
/** Querystring-parameter client-side lezen (blocks zijn client components). */
|
|
25
|
+
export declare function readQueryParam(name: string): string | null;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { collection, getDocs, limit as fsLimit, query, where } from "firebase/firestore";
|
|
3
|
+
import { getFunctions, httpsCallable } from "firebase/functions";
|
|
4
|
+
import { getDb, getFirebaseApp } from "../../firebase/client";
|
|
5
|
+
import { functionsRegion } from "../../firebase/region";
|
|
6
|
+
import { useModuleSettings } from "../context";
|
|
7
|
+
import { defaultShopSettings } from "./settings";
|
|
8
|
+
function useShopSettings() {
|
|
9
|
+
const raw = useModuleSettings("shop");
|
|
10
|
+
return { ...defaultShopSettings, ...raw };
|
|
11
|
+
}
|
|
12
|
+
async function fetchActiveProducts(siteId) {
|
|
13
|
+
const db = getDb();
|
|
14
|
+
if (!db) return [];
|
|
15
|
+
const snap = await getDocs(
|
|
16
|
+
query(collection(db, "sites", siteId, "products"), where("status", "==", "active"), fsLimit(500))
|
|
17
|
+
);
|
|
18
|
+
return snap.docs.map((d) => ({ id: d.id, ...d.data() }));
|
|
19
|
+
}
|
|
20
|
+
async function fetchProductBySlug(siteId, slug) {
|
|
21
|
+
const db = getDb();
|
|
22
|
+
if (!db || !slug) return null;
|
|
23
|
+
const snap = await getDocs(
|
|
24
|
+
query(collection(db, "sites", siteId, "products"), where("slug", "==", slug), fsLimit(1))
|
|
25
|
+
);
|
|
26
|
+
const doc = snap.docs[0];
|
|
27
|
+
if (!doc) return null;
|
|
28
|
+
const product = { id: doc.id, ...doc.data() };
|
|
29
|
+
return product.status === "active" ? product : null;
|
|
30
|
+
}
|
|
31
|
+
async function fetchShopCategories(siteId) {
|
|
32
|
+
const db = getDb();
|
|
33
|
+
if (!db) return [];
|
|
34
|
+
const snap = await getDocs(query(collection(db, "sites", siteId, "shopCategories"), fsLimit(100)));
|
|
35
|
+
return snap.docs.map((d) => ({ id: d.id, ...d.data() })).filter((c) => c.visible !== false).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
36
|
+
}
|
|
37
|
+
async function createOrderCall(input) {
|
|
38
|
+
const app = getFirebaseApp();
|
|
39
|
+
if (!app) throw new Error("Webwinkel niet beschikbaar.");
|
|
40
|
+
const fn = httpsCallable(getFunctions(app, functionsRegion()), "createOrder");
|
|
41
|
+
const res = await fn(input);
|
|
42
|
+
return res.data;
|
|
43
|
+
}
|
|
44
|
+
function variantLabelFor(options, key) {
|
|
45
|
+
const parts = key.split("|");
|
|
46
|
+
return options.map((o, i) => `${o.name} ${parts[i] ?? "?"}`).join(" \xB7 ");
|
|
47
|
+
}
|
|
48
|
+
function readQueryParam(name) {
|
|
49
|
+
if (typeof window === "undefined") return null;
|
|
50
|
+
return new URLSearchParams(window.location.search).get(name);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
createOrderCall,
|
|
54
|
+
fetchActiveProducts,
|
|
55
|
+
fetchProductBySlug,
|
|
56
|
+
fetchShopCategories,
|
|
57
|
+
readQueryParam,
|
|
58
|
+
useShopSettings,
|
|
59
|
+
variantLabelFor
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=lib.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/lib.ts"],"sourcesContent":["\"use client\";\n\n/**\n * Client-helpers voor de shop-blocks: producten/categorieën lezen (publieke rules) en de\n * `createOrder`-callable aanroepen. Queries bewust simpel gehouden (één `where` op status,\n * filteren/sorteren client-side) zodat er géén composite-indexes nodig zijn — assortimenten\n * van XiCMS-sites zijn klein (tientallen tot honderden producten).\n */\nimport { collection, getDocs, limit as fsLimit, query, where } from \"firebase/firestore\";\nimport { getFunctions, httpsCallable } from \"firebase/functions\";\nimport { getDb, getFirebaseApp } from \"../../firebase/client\";\nimport { functionsRegion } from \"../../firebase/region\";\nimport type { CreateOrderInput, Product, ShopCategory } from \"../../schema/shop\";\nimport { useModuleSettings } from \"../context\";\nimport { defaultShopSettings, type ShopSettings } from \"./settings\";\n\n/** Publieke shop-instellingen met defaults (paden, verzendkosten, valuta). */\nexport function useShopSettings(): ShopSettings {\n const raw = useModuleSettings<Partial<ShopSettings>>(\"shop\");\n return { ...defaultShopSettings, ...raw };\n}\n\nexport type StoredProduct = Product & { id: string };\nexport type StoredShopCategory = ShopCategory & { id: string };\n\nexport async function fetchActiveProducts(siteId: string): Promise<StoredProduct[]> {\n const db = getDb();\n if (!db) return [];\n const snap = await getDocs(\n query(collection(db, \"sites\", siteId, \"products\"), where(\"status\", \"==\", \"active\"), fsLimit(500)),\n );\n return snap.docs.map((d) => ({ id: d.id, ...(d.data() as Product) }));\n}\n\nexport async function fetchProductBySlug(siteId: string, slug: string): Promise<StoredProduct | null> {\n const db = getDb();\n if (!db || !slug) return null;\n const snap = await getDocs(\n query(collection(db, \"sites\", siteId, \"products\"), where(\"slug\", \"==\", slug), fsLimit(1)),\n );\n const doc = snap.docs[0];\n if (!doc) return null;\n const product = { id: doc.id, ...(doc.data() as Product) };\n return product.status === \"active\" ? product : null;\n}\n\nexport async function fetchShopCategories(siteId: string): Promise<StoredShopCategory[]> {\n const db = getDb();\n if (!db) return [];\n const snap = await getDocs(query(collection(db, \"sites\", siteId, \"shopCategories\"), fsLimit(100)));\n return snap.docs\n .map((d) => ({ id: d.id, ...(d.data() as ShopCategory) }))\n .filter((c) => c.visible !== false)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/** Start de checkout: order + Stripe-sessie server-side; geeft de redirect-URL terug. */\nexport async function createOrderCall(input: CreateOrderInput): Promise<{ url: string; orderNumber: string }> {\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n const fn = httpsCallable(getFunctions(app, functionsRegion()), \"createOrder\");\n const res = await fn(input);\n return res.data as { url: string; orderNumber: string };\n}\n\n/** Leesbaar variantlabel: opties [\"Maat\",\"Kleur\"] + key \"68|Roze\" → \"Maat 68 · Roze\". */\nexport function variantLabelFor(options: { name: string; values: string[] }[], key: string): string {\n const parts = key.split(\"|\");\n return options.map((o, i) => `${o.name} ${parts[i] ?? \"?\"}`).join(\" · \");\n}\n\n/** Querystring-parameter client-side lezen (blocks zijn client components). */\nexport function readQueryParam(name: string): string | null {\n if (typeof window === \"undefined\") return null;\n return new URLSearchParams(window.location.search).get(name);\n}\n"],"mappings":";AAQA,SAAS,YAAY,SAAS,SAAS,SAAS,OAAO,aAAa;AACpE,SAAS,cAAc,qBAAqB;AAC5C,SAAS,OAAO,sBAAsB;AACtC,SAAS,uBAAuB;AAEhC,SAAS,yBAAyB;AAClC,SAAS,2BAA8C;AAGhD,SAAS,kBAAgC;AAC9C,QAAM,MAAM,kBAAyC,MAAM;AAC3D,SAAO,EAAE,GAAG,qBAAqB,GAAG,IAAI;AAC1C;AAKA,eAAsB,oBAAoB,QAA0C;AAClF,QAAM,KAAK,MAAM;AACjB,MAAI,CAAC,GAAI,QAAO,CAAC;AACjB,QAAM,OAAO,MAAM;AAAA,IACjB,MAAM,WAAW,IAAI,SAAS,QAAQ,UAAU,GAAG,MAAM,UAAU,MAAM,QAAQ,GAAG,QAAQ,GAAG,CAAC;AAAA,EAClG;AACA,SAAO,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,KAAK,EAAc,EAAE;AACtE;AAEA,eAAsB,mBAAmB,QAAgB,MAA6C;AACpG,QAAM,KAAK,MAAM;AACjB,MAAI,CAAC,MAAM,CAAC,KAAM,QAAO;AACzB,QAAM,OAAO,MAAM;AAAA,IACjB,MAAM,WAAW,IAAI,SAAS,QAAQ,UAAU,GAAG,MAAM,QAAQ,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,EAC1F;AACA,QAAM,MAAM,KAAK,KAAK,CAAC;AACvB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,UAAU,EAAE,IAAI,IAAI,IAAI,GAAI,IAAI,KAAK,EAAc;AACzD,SAAO,QAAQ,WAAW,WAAW,UAAU;AACjD;AAEA,eAAsB,oBAAoB,QAA+C;AACvF,QAAM,KAAK,MAAM;AACjB,MAAI,CAAC,GAAI,QAAO,CAAC;AACjB,QAAM,OAAO,MAAM,QAAQ,MAAM,WAAW,IAAI,SAAS,QAAQ,gBAAgB,GAAG,QAAQ,GAAG,CAAC,CAAC;AACjG,SAAO,KAAK,KACT,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,KAAK,EAAmB,EAAE,EACxD,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK,EACjC,KAAK,CAAC,GAAG,OAAO,EAAE,SAAS,MAAM,EAAE,SAAS,EAAE;AACnD;AAGA,eAAsB,gBAAgB,OAAwE;AAC5G,QAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,6BAA6B;AACvD,QAAM,KAAK,cAAc,aAAa,KAAK,gBAAgB,CAAC,GAAG,aAAa;AAC5E,QAAM,MAAM,MAAM,GAAG,KAAK;AAC1B,SAAO,IAAI;AACb;AAGO,SAAS,gBAAgB,SAA+C,KAAqB;AAClG,QAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,SAAO,QAAQ,IAAI,CAAC,GAAG,MAAM,GAAG,EAAE,IAAI,IAAI,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,KAAK,QAAK;AACzE;AAGO,SAAS,eAAe,MAA6B;AAC1D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,IAAI,gBAAgB,OAAO,SAAS,MAAM,EAAE,IAAI,IAAI;AAC7D;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const shopModule: import("..").ModuleDefinition;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { defineModule } from "../defineModule";
|
|
2
|
+
import { ShopSettingsSchema, defaultShopSettings } from "./settings";
|
|
3
|
+
import { shopCategoriesBlock } from "./blocks/ShopCategories";
|
|
4
|
+
import { productGridBlock } from "./blocks/ProductGrid";
|
|
5
|
+
import { productDetailBlock } from "./blocks/ProductDetail";
|
|
6
|
+
import { cartBlock } from "./blocks/Cart";
|
|
7
|
+
import { checkoutBlock } from "./blocks/Checkout";
|
|
8
|
+
import { donationBlock } from "./blocks/Donation";
|
|
9
|
+
import { orderStatusBlock } from "./blocks/OrderStatus";
|
|
10
|
+
const shopModule = defineModule({
|
|
11
|
+
id: "shop",
|
|
12
|
+
version: "1.0.0",
|
|
13
|
+
label: "Webwinkel",
|
|
14
|
+
description: "Webwinkel + donaties: producten met varianten, winkelwagen, afrekenen via Stripe (eigen account van de klant) en bestelbevestiging per e-mail via de eigen SMTP-mailbox.",
|
|
15
|
+
defaultEnabled: false,
|
|
16
|
+
blocks: [
|
|
17
|
+
shopCategoriesBlock,
|
|
18
|
+
productGridBlock,
|
|
19
|
+
productDetailBlock,
|
|
20
|
+
cartBlock,
|
|
21
|
+
checkoutBlock,
|
|
22
|
+
donationBlock,
|
|
23
|
+
orderStatusBlock
|
|
24
|
+
],
|
|
25
|
+
settingsSchema: ShopSettingsSchema,
|
|
26
|
+
defaultSettings: defaultShopSettings,
|
|
27
|
+
requires: [
|
|
28
|
+
{ kind: "function", name: "createOrder" },
|
|
29
|
+
{ kind: "function", name: "shopStripeWebhook" },
|
|
30
|
+
{ kind: "function", name: "saveShopSecrets" },
|
|
31
|
+
{ kind: "firestore", collection: "products" },
|
|
32
|
+
{ kind: "firestore", collection: "shopCategories" },
|
|
33
|
+
{ kind: "firestore", collection: "orders" }
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
export {
|
|
37
|
+
shopModule
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/module.ts"],"sourcesContent":["/**\n * Shop-module (5.5) — webwinkel + donaties op het eigen Stripe-account van de klant.\n *\n * - Producten/categorieën: `sites/{siteId}/products` + `shopCategories` (editor-write, rules).\n * - Checkout: `createOrder`-callable herrekent bedragen server-side en start een hosted\n * Stripe Checkout-sessie (iDEAL/kaart); de `shopStripeWebhook` zet de order op betaald en\n * verstuurt de bevestigingsmail (eigen SMTP van de klant, bv. Gmail — zie functions/lib/mail).\n * - Donaties: het donatie-block gebruikt dezelfde order-flow (kind:\"donation\", geen verzending).\n * - Beheer: het \"Webwinkel\"-paneel (producten/categorieën/bestellingen/koppelingen) hangt via\n * de paneel-registry aan deze module-id.\n *\n * Server-safe: geen \"use client\" hier — de blocks zelf zijn client components.\n */\nimport { defineModule } from \"../defineModule\";\nimport { ShopSettingsSchema, defaultShopSettings } from \"./settings\";\nimport { shopCategoriesBlock } from \"./blocks/ShopCategories\";\nimport { productGridBlock } from \"./blocks/ProductGrid\";\nimport { productDetailBlock } from \"./blocks/ProductDetail\";\nimport { cartBlock } from \"./blocks/Cart\";\nimport { checkoutBlock } from \"./blocks/Checkout\";\nimport { donationBlock } from \"./blocks/Donation\";\nimport { orderStatusBlock } from \"./blocks/OrderStatus\";\n\nexport const shopModule = defineModule({\n id: \"shop\",\n version: \"1.0.0\",\n label: \"Webwinkel\",\n description:\n \"Webwinkel + donaties: producten met varianten, winkelwagen, afrekenen via Stripe (eigen account van de klant) en bestelbevestiging per e-mail via de eigen SMTP-mailbox.\",\n defaultEnabled: false,\n blocks: [\n shopCategoriesBlock,\n productGridBlock,\n productDetailBlock,\n cartBlock,\n checkoutBlock,\n donationBlock,\n orderStatusBlock,\n ],\n settingsSchema: ShopSettingsSchema,\n defaultSettings: defaultShopSettings,\n requires: [\n { kind: \"function\", name: \"createOrder\" },\n { kind: \"function\", name: \"shopStripeWebhook\" },\n { kind: \"function\", name: \"saveShopSecrets\" },\n { kind: \"firestore\", collection: \"products\" },\n { kind: \"firestore\", collection: \"shopCategories\" },\n { kind: \"firestore\", collection: \"orders\" },\n ],\n});\n"],"mappings":"AAaA,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB,2BAA2B;AACxD,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AAE1B,MAAM,aAAa,aAAa;AAAA,EACrC,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,OAAO;AAAA,EACP,aACE;AAAA,EACF,gBAAgB;AAAA,EAChB,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,UAAU;AAAA,IACR,EAAE,MAAM,YAAY,MAAM,cAAc;AAAA,IACxC,EAAE,MAAM,YAAY,MAAM,oBAAoB;AAAA,IAC9C,EAAE,MAAM,YAAY,MAAM,kBAAkB;AAAA,IAC5C,EAAE,MAAM,aAAa,YAAY,WAAW;AAAA,IAC5C,EAAE,MAAM,aAAa,YAAY,iBAAiB;AAAA,IAClD,EAAE,MAAM,aAAa,YAAY,SAAS;AAAA,EAC5C;AACF,CAAC;","names":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Publieke shop-instellingen (per site, via `settings/public.modules.shop.config` of
|
|
4
|
+
* `SiteConfig.modules.shop.config`). Server-safe: alleen Zod. De SettingsPanel rendert hier
|
|
5
|
+
* automatisch een formulier voor (moduleSettingsForm); de Functions lezen dezelfde config
|
|
6
|
+
* server-side. Geheimen (Stripe-key, SMTP) horen hier NIET — die staan in
|
|
7
|
+
* `sites/{siteId}/private/shop` en lopen via callables.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ShopSettingsSchema: z.ZodObject<{
|
|
10
|
+
shopPath: z.ZodDefault<z.ZodString>;
|
|
11
|
+
detailPath: z.ZodDefault<z.ZodString>;
|
|
12
|
+
cartPath: z.ZodDefault<z.ZodString>;
|
|
13
|
+
checkoutPath: z.ZodDefault<z.ZodString>;
|
|
14
|
+
successPath: z.ZodDefault<z.ZodString>;
|
|
15
|
+
currency: z.ZodDefault<z.ZodString>;
|
|
16
|
+
shippingFlatCents: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
shippingFreeFromCents: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
orderPrefix: z.ZodDefault<z.ZodString>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
currency: string;
|
|
21
|
+
shopPath: string;
|
|
22
|
+
detailPath: string;
|
|
23
|
+
cartPath: string;
|
|
24
|
+
checkoutPath: string;
|
|
25
|
+
successPath: string;
|
|
26
|
+
shippingFlatCents: number;
|
|
27
|
+
shippingFreeFromCents: number;
|
|
28
|
+
orderPrefix: string;
|
|
29
|
+
}, {
|
|
30
|
+
currency?: string | undefined;
|
|
31
|
+
shopPath?: string | undefined;
|
|
32
|
+
detailPath?: string | undefined;
|
|
33
|
+
cartPath?: string | undefined;
|
|
34
|
+
checkoutPath?: string | undefined;
|
|
35
|
+
successPath?: string | undefined;
|
|
36
|
+
shippingFlatCents?: number | undefined;
|
|
37
|
+
shippingFreeFromCents?: number | undefined;
|
|
38
|
+
orderPrefix?: string | undefined;
|
|
39
|
+
}>;
|
|
40
|
+
export type ShopSettings = z.infer<typeof ShopSettingsSchema>;
|
|
41
|
+
export declare const defaultShopSettings: ShopSettings;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const ShopSettingsSchema = z.object({
|
|
3
|
+
shopPath: z.string().max(200).default("/webwinkel").describe("Pad van de winkelpagina"),
|
|
4
|
+
detailPath: z.string().max(200).default("/product").describe("Pad van de productpagina"),
|
|
5
|
+
cartPath: z.string().max(200).default("/winkelwagen").describe("Pad van de winkelwagen"),
|
|
6
|
+
checkoutPath: z.string().max(200).default("/afrekenen").describe("Pad van de afrekenpagina"),
|
|
7
|
+
successPath: z.string().max(200).default("/bedankt").describe("Pad van de bedankt-pagina"),
|
|
8
|
+
currency: z.string().min(3).max(3).default("EUR").describe("Valuta (ISO-code)"),
|
|
9
|
+
shippingFlatCents: z.number().int().min(0).max(1e5).default(495).describe("Verzendkosten (centen)"),
|
|
10
|
+
shippingFreeFromCents: z.number().int().min(0).max(1e8).default(0).describe("Gratis verzending vanaf (centen, 0 = nooit)"),
|
|
11
|
+
orderPrefix: z.string().max(12).default("ORDER").describe("Ordernummer-prefix")
|
|
12
|
+
});
|
|
13
|
+
const defaultShopSettings = ShopSettingsSchema.parse({});
|
|
14
|
+
export {
|
|
15
|
+
ShopSettingsSchema,
|
|
16
|
+
defaultShopSettings
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/settings.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Publieke shop-instellingen (per site, via `settings/public.modules.shop.config` of\n * `SiteConfig.modules.shop.config`). Server-safe: alleen Zod. De SettingsPanel rendert hier\n * automatisch een formulier voor (moduleSettingsForm); de Functions lezen dezelfde config\n * server-side. Geheimen (Stripe-key, SMTP) horen hier NIET — die staan in\n * `sites/{siteId}/private/shop` en lopen via callables.\n */\nexport const ShopSettingsSchema = z.object({\n shopPath: z.string().max(200).default(\"/webwinkel\").describe(\"Pad van de winkelpagina\"),\n detailPath: z.string().max(200).default(\"/product\").describe(\"Pad van de productpagina\"),\n cartPath: z.string().max(200).default(\"/winkelwagen\").describe(\"Pad van de winkelwagen\"),\n checkoutPath: z.string().max(200).default(\"/afrekenen\").describe(\"Pad van de afrekenpagina\"),\n successPath: z.string().max(200).default(\"/bedankt\").describe(\"Pad van de bedankt-pagina\"),\n currency: z.string().min(3).max(3).default(\"EUR\").describe(\"Valuta (ISO-code)\"),\n shippingFlatCents: z.number().int().min(0).max(100_000).default(495).describe(\"Verzendkosten (centen)\"),\n shippingFreeFromCents: z\n .number()\n .int()\n .min(0)\n .max(1_000_000_00)\n .default(0)\n .describe(\"Gratis verzending vanaf (centen, 0 = nooit)\"),\n orderPrefix: z.string().max(12).default(\"ORDER\").describe(\"Ordernummer-prefix\"),\n});\nexport type ShopSettings = z.infer<typeof ShopSettingsSchema>;\n\nexport const defaultShopSettings: ShopSettings = ShopSettingsSchema.parse({});\n"],"mappings":"AAAA,SAAS,SAAS;AASX,MAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,UAAU,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,QAAQ,YAAY,EAAE,SAAS,yBAAyB;AAAA,EACtF,YAAY,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,QAAQ,UAAU,EAAE,SAAS,0BAA0B;AAAA,EACvF,UAAU,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,QAAQ,cAAc,EAAE,SAAS,wBAAwB;AAAA,EACvF,cAAc,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,QAAQ,YAAY,EAAE,SAAS,0BAA0B;AAAA,EAC3F,aAAa,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,QAAQ,UAAU,EAAE,SAAS,2BAA2B;AAAA,EACzF,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,KAAK,EAAE,SAAS,mBAAmB;AAAA,EAC9E,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAO,EAAE,QAAQ,GAAG,EAAE,SAAS,wBAAwB;AAAA,EACtG,uBAAuB,EACpB,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,GAAY,EAChB,QAAQ,CAAC,EACT,SAAS,6CAA6C;AAAA,EACzD,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,OAAO,EAAE,SAAS,oBAAoB;AAChF,CAAC;AAGM,MAAM,sBAAoC,mBAAmB,MAAM,CAAC,CAAC;","names":[]}
|
package/dist/schema/blocks.d.ts
CHANGED
|
@@ -156,6 +156,9 @@ export declare const HeroBlockSchema: z.ZodObject<{
|
|
|
156
156
|
imageUrl: z.ZodOptional<z.ZodString>;
|
|
157
157
|
/** Videoachtergrond (mp4/webm); overschrijft de afbeelding als gezet. */
|
|
158
158
|
videoUrl: z.ZodOptional<z.ZodString>;
|
|
159
|
+
/** Kopniveau: "1" voor dé hoofdkop; "2" voor een tweede hero op dezelfde pagina
|
|
160
|
+
* (twee h1's = slechte SEO/a11y). */
|
|
161
|
+
headingLevel: z.ZodDefault<z.ZodEnum<["1", "2"]>>;
|
|
159
162
|
align: z.ZodDefault<z.ZodEnum<["left", "center"]>>;
|
|
160
163
|
/** Verticale uitlijning van de inhoud binnen de hero. */
|
|
161
164
|
vAlign: z.ZodDefault<z.ZodEnum<["top", "center", "bottom"]>>;
|
|
@@ -210,6 +213,7 @@ export declare const HeroBlockSchema: z.ZodObject<{
|
|
|
210
213
|
_type: "hero";
|
|
211
214
|
align: "left" | "center";
|
|
212
215
|
_key: string;
|
|
216
|
+
headingLevel: "1" | "2";
|
|
213
217
|
vAlign: "center" | "top" | "bottom";
|
|
214
218
|
minHeight: "sm" | "md" | "lg" | "auto" | "full";
|
|
215
219
|
overlayOpacity: number;
|
|
@@ -249,6 +253,7 @@ export declare const HeroBlockSchema: z.ZodObject<{
|
|
|
249
253
|
subtitle?: string | undefined;
|
|
250
254
|
imageUrl?: string | undefined;
|
|
251
255
|
videoUrl?: string | undefined;
|
|
256
|
+
headingLevel?: "1" | "2" | undefined;
|
|
252
257
|
vAlign?: "center" | "top" | "bottom" | undefined;
|
|
253
258
|
minHeight?: "sm" | "md" | "lg" | "auto" | "full" | undefined;
|
|
254
259
|
overlayColor?: string | undefined;
|
|
@@ -748,16 +753,16 @@ export declare const PricingBlockSchema: z.ZodObject<{
|
|
|
748
753
|
label: string;
|
|
749
754
|
price: string;
|
|
750
755
|
highlighted: boolean;
|
|
751
|
-
features?: string[] | undefined;
|
|
752
756
|
detail?: string | undefined;
|
|
757
|
+
features?: string[] | undefined;
|
|
753
758
|
ctaLabel?: string | undefined;
|
|
754
759
|
ctaHref?: string | undefined;
|
|
755
760
|
billingPeriod?: string | undefined;
|
|
756
761
|
}, {
|
|
757
762
|
label?: string | undefined;
|
|
758
|
-
features?: string[] | undefined;
|
|
759
763
|
price?: string | undefined;
|
|
760
764
|
detail?: string | undefined;
|
|
765
|
+
features?: string[] | undefined;
|
|
761
766
|
ctaLabel?: string | undefined;
|
|
762
767
|
ctaHref?: string | undefined;
|
|
763
768
|
highlighted?: boolean | undefined;
|
|
@@ -800,8 +805,8 @@ export declare const PricingBlockSchema: z.ZodObject<{
|
|
|
800
805
|
label: string;
|
|
801
806
|
price: string;
|
|
802
807
|
highlighted: boolean;
|
|
803
|
-
features?: string[] | undefined;
|
|
804
808
|
detail?: string | undefined;
|
|
809
|
+
features?: string[] | undefined;
|
|
805
810
|
ctaLabel?: string | undefined;
|
|
806
811
|
ctaHref?: string | undefined;
|
|
807
812
|
billingPeriod?: string | undefined;
|
|
@@ -832,9 +837,9 @@ export declare const PricingBlockSchema: z.ZodObject<{
|
|
|
832
837
|
} | undefined;
|
|
833
838
|
items?: {
|
|
834
839
|
label?: string | undefined;
|
|
835
|
-
features?: string[] | undefined;
|
|
836
840
|
price?: string | undefined;
|
|
837
841
|
detail?: string | undefined;
|
|
842
|
+
features?: string[] | undefined;
|
|
838
843
|
ctaLabel?: string | undefined;
|
|
839
844
|
ctaHref?: string | undefined;
|
|
840
845
|
highlighted?: boolean | undefined;
|
|
@@ -5191,6 +5196,9 @@ export declare const BuiltinBlockSchema: z.ZodDiscriminatedUnion<"_type", [z.Zod
|
|
|
5191
5196
|
imageUrl: z.ZodOptional<z.ZodString>;
|
|
5192
5197
|
/** Videoachtergrond (mp4/webm); overschrijft de afbeelding als gezet. */
|
|
5193
5198
|
videoUrl: z.ZodOptional<z.ZodString>;
|
|
5199
|
+
/** Kopniveau: "1" voor dé hoofdkop; "2" voor een tweede hero op dezelfde pagina
|
|
5200
|
+
* (twee h1's = slechte SEO/a11y). */
|
|
5201
|
+
headingLevel: z.ZodDefault<z.ZodEnum<["1", "2"]>>;
|
|
5194
5202
|
align: z.ZodDefault<z.ZodEnum<["left", "center"]>>;
|
|
5195
5203
|
/** Verticale uitlijning van de inhoud binnen de hero. */
|
|
5196
5204
|
vAlign: z.ZodDefault<z.ZodEnum<["top", "center", "bottom"]>>;
|
|
@@ -5245,6 +5253,7 @@ export declare const BuiltinBlockSchema: z.ZodDiscriminatedUnion<"_type", [z.Zod
|
|
|
5245
5253
|
_type: "hero";
|
|
5246
5254
|
align: "left" | "center";
|
|
5247
5255
|
_key: string;
|
|
5256
|
+
headingLevel: "1" | "2";
|
|
5248
5257
|
vAlign: "center" | "top" | "bottom";
|
|
5249
5258
|
minHeight: "sm" | "md" | "lg" | "auto" | "full";
|
|
5250
5259
|
overlayOpacity: number;
|
|
@@ -5284,6 +5293,7 @@ export declare const BuiltinBlockSchema: z.ZodDiscriminatedUnion<"_type", [z.Zod
|
|
|
5284
5293
|
subtitle?: string | undefined;
|
|
5285
5294
|
imageUrl?: string | undefined;
|
|
5286
5295
|
videoUrl?: string | undefined;
|
|
5296
|
+
headingLevel?: "1" | "2" | undefined;
|
|
5287
5297
|
vAlign?: "center" | "top" | "bottom" | undefined;
|
|
5288
5298
|
minHeight?: "sm" | "md" | "lg" | "auto" | "full" | undefined;
|
|
5289
5299
|
overlayColor?: string | undefined;
|
|
@@ -5776,16 +5786,16 @@ export declare const BuiltinBlockSchema: z.ZodDiscriminatedUnion<"_type", [z.Zod
|
|
|
5776
5786
|
label: string;
|
|
5777
5787
|
price: string;
|
|
5778
5788
|
highlighted: boolean;
|
|
5779
|
-
features?: string[] | undefined;
|
|
5780
5789
|
detail?: string | undefined;
|
|
5790
|
+
features?: string[] | undefined;
|
|
5781
5791
|
ctaLabel?: string | undefined;
|
|
5782
5792
|
ctaHref?: string | undefined;
|
|
5783
5793
|
billingPeriod?: string | undefined;
|
|
5784
5794
|
}, {
|
|
5785
5795
|
label?: string | undefined;
|
|
5786
|
-
features?: string[] | undefined;
|
|
5787
5796
|
price?: string | undefined;
|
|
5788
5797
|
detail?: string | undefined;
|
|
5798
|
+
features?: string[] | undefined;
|
|
5789
5799
|
ctaLabel?: string | undefined;
|
|
5790
5800
|
ctaHref?: string | undefined;
|
|
5791
5801
|
highlighted?: boolean | undefined;
|
|
@@ -5828,8 +5838,8 @@ export declare const BuiltinBlockSchema: z.ZodDiscriminatedUnion<"_type", [z.Zod
|
|
|
5828
5838
|
label: string;
|
|
5829
5839
|
price: string;
|
|
5830
5840
|
highlighted: boolean;
|
|
5831
|
-
features?: string[] | undefined;
|
|
5832
5841
|
detail?: string | undefined;
|
|
5842
|
+
features?: string[] | undefined;
|
|
5833
5843
|
ctaLabel?: string | undefined;
|
|
5834
5844
|
ctaHref?: string | undefined;
|
|
5835
5845
|
billingPeriod?: string | undefined;
|
|
@@ -5860,9 +5870,9 @@ export declare const BuiltinBlockSchema: z.ZodDiscriminatedUnion<"_type", [z.Zod
|
|
|
5860
5870
|
} | undefined;
|
|
5861
5871
|
items?: {
|
|
5862
5872
|
label?: string | undefined;
|
|
5863
|
-
features?: string[] | undefined;
|
|
5864
5873
|
price?: string | undefined;
|
|
5865
5874
|
detail?: string | undefined;
|
|
5875
|
+
features?: string[] | undefined;
|
|
5866
5876
|
ctaLabel?: string | undefined;
|
|
5867
5877
|
ctaHref?: string | undefined;
|
|
5868
5878
|
highlighted?: boolean | undefined;
|
|
@@ -10136,6 +10146,9 @@ export declare const AnyBlockSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"_type"
|
|
|
10136
10146
|
imageUrl: z.ZodOptional<z.ZodString>;
|
|
10137
10147
|
/** Videoachtergrond (mp4/webm); overschrijft de afbeelding als gezet. */
|
|
10138
10148
|
videoUrl: z.ZodOptional<z.ZodString>;
|
|
10149
|
+
/** Kopniveau: "1" voor dé hoofdkop; "2" voor een tweede hero op dezelfde pagina
|
|
10150
|
+
* (twee h1's = slechte SEO/a11y). */
|
|
10151
|
+
headingLevel: z.ZodDefault<z.ZodEnum<["1", "2"]>>;
|
|
10139
10152
|
align: z.ZodDefault<z.ZodEnum<["left", "center"]>>;
|
|
10140
10153
|
/** Verticale uitlijning van de inhoud binnen de hero. */
|
|
10141
10154
|
vAlign: z.ZodDefault<z.ZodEnum<["top", "center", "bottom"]>>;
|
|
@@ -10190,6 +10203,7 @@ export declare const AnyBlockSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"_type"
|
|
|
10190
10203
|
_type: "hero";
|
|
10191
10204
|
align: "left" | "center";
|
|
10192
10205
|
_key: string;
|
|
10206
|
+
headingLevel: "1" | "2";
|
|
10193
10207
|
vAlign: "center" | "top" | "bottom";
|
|
10194
10208
|
minHeight: "sm" | "md" | "lg" | "auto" | "full";
|
|
10195
10209
|
overlayOpacity: number;
|
|
@@ -10229,6 +10243,7 @@ export declare const AnyBlockSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"_type"
|
|
|
10229
10243
|
subtitle?: string | undefined;
|
|
10230
10244
|
imageUrl?: string | undefined;
|
|
10231
10245
|
videoUrl?: string | undefined;
|
|
10246
|
+
headingLevel?: "1" | "2" | undefined;
|
|
10232
10247
|
vAlign?: "center" | "top" | "bottom" | undefined;
|
|
10233
10248
|
minHeight?: "sm" | "md" | "lg" | "auto" | "full" | undefined;
|
|
10234
10249
|
overlayColor?: string | undefined;
|
|
@@ -10721,16 +10736,16 @@ export declare const AnyBlockSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"_type"
|
|
|
10721
10736
|
label: string;
|
|
10722
10737
|
price: string;
|
|
10723
10738
|
highlighted: boolean;
|
|
10724
|
-
features?: string[] | undefined;
|
|
10725
10739
|
detail?: string | undefined;
|
|
10740
|
+
features?: string[] | undefined;
|
|
10726
10741
|
ctaLabel?: string | undefined;
|
|
10727
10742
|
ctaHref?: string | undefined;
|
|
10728
10743
|
billingPeriod?: string | undefined;
|
|
10729
10744
|
}, {
|
|
10730
10745
|
label?: string | undefined;
|
|
10731
|
-
features?: string[] | undefined;
|
|
10732
10746
|
price?: string | undefined;
|
|
10733
10747
|
detail?: string | undefined;
|
|
10748
|
+
features?: string[] | undefined;
|
|
10734
10749
|
ctaLabel?: string | undefined;
|
|
10735
10750
|
ctaHref?: string | undefined;
|
|
10736
10751
|
highlighted?: boolean | undefined;
|
|
@@ -10773,8 +10788,8 @@ export declare const AnyBlockSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"_type"
|
|
|
10773
10788
|
label: string;
|
|
10774
10789
|
price: string;
|
|
10775
10790
|
highlighted: boolean;
|
|
10776
|
-
features?: string[] | undefined;
|
|
10777
10791
|
detail?: string | undefined;
|
|
10792
|
+
features?: string[] | undefined;
|
|
10778
10793
|
ctaLabel?: string | undefined;
|
|
10779
10794
|
ctaHref?: string | undefined;
|
|
10780
10795
|
billingPeriod?: string | undefined;
|
|
@@ -10805,9 +10820,9 @@ export declare const AnyBlockSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"_type"
|
|
|
10805
10820
|
} | undefined;
|
|
10806
10821
|
items?: {
|
|
10807
10822
|
label?: string | undefined;
|
|
10808
|
-
features?: string[] | undefined;
|
|
10809
10823
|
price?: string | undefined;
|
|
10810
10824
|
detail?: string | undefined;
|
|
10825
|
+
features?: string[] | undefined;
|
|
10811
10826
|
ctaLabel?: string | undefined;
|
|
10812
10827
|
ctaHref?: string | undefined;
|
|
10813
10828
|
highlighted?: boolean | undefined;
|
package/dist/schema/blocks.js
CHANGED
|
@@ -32,6 +32,9 @@ const HeroBlockSchema = z.object({
|
|
|
32
32
|
imageUrl: z.string().max(2e3).optional(),
|
|
33
33
|
/** Videoachtergrond (mp4/webm); overschrijft de afbeelding als gezet. */
|
|
34
34
|
videoUrl: z.string().max(2e3).optional(),
|
|
35
|
+
/** Kopniveau: "1" voor dé hoofdkop; "2" voor een tweede hero op dezelfde pagina
|
|
36
|
+
* (twee h1's = slechte SEO/a11y). */
|
|
37
|
+
headingLevel: z.enum(["1", "2"]).default("1").describe("Kopniveau (h1/h2)"),
|
|
35
38
|
align: z.enum(["left", "center"]).default("left"),
|
|
36
39
|
/** Verticale uitlijning van de inhoud binnen de hero. */
|
|
37
40
|
vAlign: z.enum(["top", "center", "bottom"]).default("center"),
|