@thorprovider/storefront 0.3.1 → 0.4.0-mvp.2
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/README.md +321 -152
- package/VENDOR.md +69 -0
- package/assets/openspec/config.yaml +38 -0
- package/assets/templates/AGENTS.md +76 -0
- package/assets/templates/app/app/[[...slug]]/page.tsx +54 -2
- package/assets/templates/app/app/[[...slug]]/renderer.tsx +13 -2
- package/assets/templates/app/app/globals.css +5 -8
- package/assets/templates/app/app/layout.tsx +17 -7
- package/assets/templates/app/app/robots.ts +19 -0
- package/assets/templates/app/app/sitemap.ts +71 -0
- package/assets/templates/app/lib/__STOREFRONT__/actions.ts +612 -0
- package/assets/templates/app/lib/__STOREFRONT__/cart-state.ts +66 -0
- package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +50 -57
- package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +679 -0
- package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +197 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.ts +5 -36
- package/assets/templates/app/lib/__STOREFRONT__/icon-map.ts +27 -0
- package/assets/templates/app/lib/__STOREFRONT__/mappers.ts +13 -11
- package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +264 -51
- package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +6 -3
- package/assets/templates/app/lib/__STOREFRONT__/schema.ts +136 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-observation.ts +182 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-sources.ts +130 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.core.ts +470 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.ts +169 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/content.ts +120 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +38 -0
- package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +129 -10
- package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +5 -1
- package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +191 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.core.ts +257 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.ts +7 -31
- package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +161 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.client.tsx +25 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.tsx +16 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.client.tsx +24 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.tsx +5 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/logoCloud.tsx +26 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/pricing.tsx +36 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.client.tsx +100 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.tsx +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.cta.ts +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.faq.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.products.ts +39 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/statistics.tsx +35 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/testimonials.tsx +31 -13
- package/assets/templates/app/lib/__STOREFRONT__/views/types.ts +5 -3
- package/assets/templates/features/checkout/handlers.ts +159 -0
- package/assets/templates/features/checkout/state.ts +61 -0
- package/assets/templates/features/customer-auth/handlers.ts +59 -0
- package/assets/templates/features/customer-auth/state.ts +45 -0
- package/assets/templates/features/recommendations/state.ts +11 -0
- package/assets/templates/views/account/content.ts +35 -0
- package/assets/templates/views/account/index.tsx +114 -0
- package/assets/templates/views/account/registry.tsx +439 -0
- package/assets/templates/views/account/schema.ts +53 -0
- package/assets/templates/views/cart/content.ts +11 -0
- package/assets/templates/views/cart/data.ts +23 -0
- package/assets/templates/views/cart/index.tsx +53 -0
- package/assets/templates/views/cart/props.ts +12 -0
- package/assets/templates/views/cart/registry.tsx +81 -0
- package/assets/templates/views/cart/schema.ts +52 -0
- package/assets/templates/views/category/assembly/assembly.json +29 -0
- package/assets/templates/views/category/assembly/index.skeleton.tsx +251 -0
- package/assets/templates/views/category/assembly/registry.skeleton.tsx +34 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/binding.json +5 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/catalog.part +4 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/element.part +7 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/registry.part +18 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/catalog.part +5 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/element.part +34 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/registry.part +71 -0
- package/assets/templates/views/category/content.ts +30 -0
- package/assets/templates/views/category/data.ts +12 -0
- package/assets/templates/views/category/index.tsx +299 -0
- package/assets/templates/views/category/props.ts +23 -0
- package/assets/templates/views/category/registry.tsx +122 -0
- package/assets/templates/views/category/schema.ts +91 -0
- package/assets/templates/views/checkout/content.ts +105 -0
- package/assets/templates/views/checkout/data.ts +23 -0
- package/assets/templates/views/checkout/index.tsx +111 -0
- package/assets/templates/views/checkout/props.ts +49 -0
- package/assets/templates/views/checkout/registry.tsx +217 -0
- package/assets/templates/views/checkout/schema.ts +229 -0
- package/assets/templates/views/home/assembly/assembly.json +33 -0
- package/assets/templates/views/home/assembly/index.skeleton.tsx +90 -0
- package/assets/templates/views/home/assembly/registry.skeleton.tsx +25 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/registry.part +11 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/registry.part +10 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/registry.part +16 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +26 -0
- package/assets/templates/views/home/content.ts +70 -0
- package/assets/templates/views/home/data.ts +24 -0
- package/assets/templates/views/home/index.tsx +57 -85
- package/assets/templates/views/home/props.ts +22 -0
- package/assets/templates/views/home/registry.tsx +38 -22
- package/assets/templates/views/home/schema.ts +93 -0
- package/assets/templates/views/product/content.ts +25 -0
- package/assets/templates/views/product/data.ts +50 -0
- package/assets/templates/views/product/index.tsx +148 -0
- package/assets/templates/views/product/props.ts +27 -0
- package/assets/templates/views/product/registry.tsx +103 -0
- package/assets/templates/views/product/schema.ts +121 -0
- package/assets/templates/views/static/content.ts +99 -0
- package/assets/templates/views/static/index.tsx +60 -0
- package/assets/templates/views/static/registry.tsx +66 -0
- package/assets/templates/views/static/schema.ts +45 -0
- package/bin/storefront.js +2424 -148
- package/examples/merchandising/category-led.json +37 -0
- package/examples/merchandising/collection-led.json +37 -0
- package/package.json +15 -9
- package/recipes/archetypes.json +28 -14
- package/recipes/catalog.json +400 -0
- package/recipes/catalog.mjs +128 -0
- package/recipes/catalog.schema.json +64 -0
- package/recipes/feature.schema.json +89 -0
- package/recipes/features.json +162 -0
- package/recipes/manifest.schema.json +69 -0
- package/recipes/operations.schema.json +43 -0
- package/recipes/recipe.schema.json +11 -2
- package/recipes/recipes.json +76 -19
- package/recipes/sections.json +34 -5
- package/recipes/validate.mjs +838 -32
- package/scripts/candidate.mjs +236 -0
- package/scripts/composers.mjs +160 -0
- package/scripts/env-file.mjs +86 -0
- package/scripts/file-classes.mjs +121 -0
- package/scripts/logical-controls.mjs +61 -0
- package/scripts/manifest.mjs +298 -0
- package/scripts/migrate-english-routes.mjs +276 -0
- package/scripts/operation-registry.mjs +256 -0
- package/scripts/operations.mjs +720 -0
- package/scripts/ownership-conflict.mjs +356 -0
- package/scripts/pinning.mjs +573 -0
- package/scripts/plan-apply.mjs +987 -0
- package/scripts/preflight.mjs +51 -0
- package/scripts/reconcile.mjs +549 -0
- package/scripts/render-templates.mjs +338 -68
- package/scripts/schema-validate.mjs +132 -0
- package/scripts/section-compat.mjs +300 -0
- package/scripts/section-config.mjs +253 -0
- package/scripts/section-operations.mjs +508 -0
- package/scripts/starter.mjs +17 -0
- package/scripts/sync-assets.mjs +22 -15
- package/scripts/theme/color.mjs +185 -0
- package/scripts/theme/css-theme.mjs +233 -0
- package/scripts/theme/fonts.mjs +123 -0
- package/scripts/theme/import-export.mjs +125 -0
- package/scripts/theme/preset.mjs +93 -0
- package/scripts/theme/theme-plan.mjs +292 -0
- package/scripts/theme/tokens.mjs +137 -0
- package/scripts/view-assembly.mjs +337 -0
- package/scripts/view-selection.mjs +211 -0
- package/skills/sf-feature/SKILL.md +80 -0
- package/skills/sf-setup/SKILL.md +79 -0
- package/skills/sf-theme-gen/SKILL.md +100 -30
- package/skills/sf-theme-gen/references/shadcn-theming.md +87 -0
- package/skills/{shadcn-theming/references/templates → sf-theme-gen/references}/theme-setup.md +15 -19
- package/skills/{shadcn-theming → sf-theme-gen}/references/theming-guide.md +6 -11
- package/skills/sf-view-gen/SKILL.md +146 -93
- package/skills/sf-view-gen/assets/recipes/archetypes.json +28 -14
- package/skills/sf-view-gen/assets/recipes/catalog.json +400 -0
- package/skills/sf-view-gen/assets/recipes/catalog.schema.json +64 -0
- package/skills/sf-view-gen/assets/recipes/features.json +162 -0
- package/skills/sf-view-gen/assets/recipes/recipes.json +76 -19
- package/skills/sf-view-gen/assets/recipes/sections.json +34 -5
- package/skills/sf-view-gen/assets/templates/views/sections/cta.client.tsx +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/cta.tsx +16 -0
- package/skills/sf-view-gen/assets/templates/views/sections/faq.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/faq.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.client.tsx +12 -8
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.client.tsx +14 -10
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.tsx +2 -9
- package/skills/sf-view-gen/assets/templates/views/sections/products.client.tsx +100 -0
- package/skills/sf-view-gen/assets/templates/views/sections/products.tsx +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.cta.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.faq.ts +18 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.logoCloud.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.pricing.ts +26 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.products.ts +39 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.statistics.ts +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.testimonials.ts +23 -0
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.client.tsx +16 -8
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.tsx +2 -5
- package/skills/{json-render-core/SKILL.md → sf-view-gen/references/json-render-core.md} +4 -27
- package/skills/{json-render-next/SKILL.md → sf-view-gen/references/json-render-next.md} +5 -8
- package/skills/{json-render-react/SKILL.md → sf-view-gen/references/json-render-react.md} +3 -5
- package/skills/{json-render-shadcn/SKILL.md → sf-view-gen/references/json-render-shadcn.md} +3 -5
- package/skills/sf-view-gen/references/views.md +58 -33
- package/skills/sf-view-gen/scripts/catalog.mjs +128 -0
- package/skills/sf-view-gen/scripts/schema-validate.mjs +132 -0
- package/skills/sf-view-gen/scripts/validate.mjs +838 -32
- package/skills/storefront-workflow/SKILL.md +179 -0
- package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
- package/CHANGELOG.md +0 -61
- package/commands/sf-add-view.md +0 -26
- package/commands/sf-theme.md +0 -20
- package/commands/sf-view.md +0 -25
- package/skills/building-storefronts/SKILL.md +0 -178
- package/skills/building-storefronts/references/frontend-integration.md +0 -229
- package/skills/json-render-remotion/SKILL.md +0 -111
- package/skills/json-render-solid/SKILL.md +0 -204
- package/skills/nextjs-shadcn/SKILL.md +0 -367
- package/skills/nextjs-shadcn/references/architecture.md +0 -499
- package/skills/nextjs-shadcn/references/project-setup.md +0 -162
- package/skills/nextjs-shadcn/references/shadcn-platform.md +0 -261
- package/skills/nextjs-shadcn/references/sidebar.md +0 -274
- package/skills/nextjs-shadcn/references/styling.md +0 -555
- package/skills/sf-view-gen/assets/templates/views/category/index.tsx +0 -86
- package/skills/sf-view-gen/assets/templates/views/category/registry.tsx +0 -48
- package/skills/sf-view-gen/assets/templates/views/checkout/index.tsx +0 -192
- package/skills/sf-view-gen/assets/templates/views/checkout/registry.tsx +0 -45
- package/skills/sf-view-gen/assets/templates/views/product/index.tsx +0 -122
- package/skills/sf-view-gen/assets/templates/views/product/registry.tsx +0 -49
- package/skills/sf-view-gen/assets/templates/views/user-panel/index.tsx +0 -168
- package/skills/sf-view-gen/assets/templates/views/user-panel/registry.tsx +0 -49
- package/skills/shadcn-component-discovery/SKILL.md +0 -273
- package/skills/shadcn-component-discovery/references/registries.md +0 -226
- package/skills/shadcn-theming/SKILL.md +0 -104
- package/skills/storefront-best-practices/SKILL.md +0 -421
- package/skills/storefront-best-practices/reference/components/breadcrumbs.md +0 -123
- package/skills/storefront-best-practices/reference/components/cart-popup.md +0 -189
- package/skills/storefront-best-practices/reference/components/country-selector.md +0 -298
- package/skills/storefront-best-practices/reference/components/footer.md +0 -112
- package/skills/storefront-best-practices/reference/components/hero.md +0 -241
- package/skills/storefront-best-practices/reference/components/megamenu.md +0 -239
- package/skills/storefront-best-practices/reference/components/navbar.md +0 -397
- package/skills/storefront-best-practices/reference/components/popups.md +0 -221
- package/skills/storefront-best-practices/reference/components/product-card.md +0 -125
- package/skills/storefront-best-practices/reference/components/product-reviews.md +0 -217
- package/skills/storefront-best-practices/reference/components/product-slider.md +0 -174
- package/skills/storefront-best-practices/reference/components/search.md +0 -101
- package/skills/storefront-best-practices/reference/connecting-to-backend.md +0 -391
- package/skills/storefront-best-practices/reference/features/promotions.md +0 -307
- package/skills/storefront-best-practices/reference/features/wishlist.md +0 -230
- package/skills/storefront-best-practices/reference/layouts/account.md +0 -380
- package/skills/storefront-best-practices/reference/layouts/cart.md +0 -316
- package/skills/storefront-best-practices/reference/layouts/checkout.md +0 -486
- package/skills/storefront-best-practices/reference/layouts/home-page.md +0 -264
- package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +0 -231
- package/skills/storefront-best-practices/reference/layouts/product-details.md +0 -527
- package/skills/storefront-best-practices/reference/layouts/product-listing.md +0 -520
- package/skills/storefront-best-practices/reference/layouts/static-pages.md +0 -356
- package/skills/storefront-best-practices/reference/medusa.md +0 -307
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/mobile-responsiveness.md +0 -0
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/seo.md +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"views": [
|
|
5
5
|
{
|
|
6
6
|
"name": "home",
|
|
7
|
+
"mvp": true,
|
|
7
8
|
"description": "Storefront landing page with hero, benefits, and category highlights",
|
|
8
9
|
"route": "/",
|
|
9
10
|
"loader": "home",
|
|
@@ -19,43 +20,77 @@
|
|
|
19
20
|
"categories": ["ProductCategory1", "ProductCategory2", "ProductCategory4", "ProductCategory5"],
|
|
20
21
|
"productCard": ["ProductCard1", "ProductCard2", "ProductCard3", "ProductCard5"]
|
|
21
22
|
},
|
|
22
|
-
"optionalSections": ["testimonials", "faq", "statistics", "logoCloud", "pricing"]
|
|
23
|
+
"optionalSections": ["testimonials", "faq", "statistics", "logoCloud", "pricing"],
|
|
24
|
+
"registeredSlots": ["hero", "benefits", "categories"],
|
|
25
|
+
"allowedSections": ["faq", "cta", "products"],
|
|
26
|
+
"maxSections": 4
|
|
23
27
|
},
|
|
24
28
|
{
|
|
25
29
|
"name": "product",
|
|
30
|
+
"mvp": true,
|
|
26
31
|
"description": "Single product detail page with overview, gallery, and reviews",
|
|
27
|
-
"route": "/
|
|
32
|
+
"route": "/products/[id]",
|
|
28
33
|
"loader": "product",
|
|
29
34
|
"requiredDataKeys": ["selectedProduct"],
|
|
30
35
|
"defaultVariants": {
|
|
31
36
|
"overview": "ProductOverview1",
|
|
32
|
-
"reviews": "ReviewRating1"
|
|
37
|
+
"reviews": "ReviewRating1",
|
|
38
|
+
"breadcrumb": "Breadcrumb"
|
|
33
39
|
},
|
|
34
40
|
"allowedVariants": {
|
|
35
41
|
"overview": ["ProductOverview1", "ProductOverview2", "ProductOverview5"],
|
|
36
42
|
"reviews": ["ReviewRating1", "ReviewRating2"],
|
|
43
|
+
"breadcrumb": ["Breadcrumb"],
|
|
37
44
|
"productCard": ["ProductCard1", "ProductCard2", "ProductCard3", "ProductCard5"]
|
|
38
45
|
},
|
|
39
|
-
"optionalSections": ["testimonials", "faq", "statistics"]
|
|
46
|
+
"optionalSections": ["testimonials", "faq", "statistics"],
|
|
47
|
+
"registeredSlots": ["overview", "reviews", "breadcrumb"],
|
|
48
|
+
"allowedSections": [],
|
|
49
|
+
"maxSections": 4
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "cart",
|
|
53
|
+
"mvp": true,
|
|
54
|
+
"description": "Standalone cart review page with authoritative totals and quantity editing",
|
|
55
|
+
"route": "/cart",
|
|
56
|
+
"loader": "cart",
|
|
57
|
+
"requiredDataKeys": ["cart"],
|
|
58
|
+
"defaultVariants": {
|
|
59
|
+
"view": "ShoppingCart4"
|
|
60
|
+
},
|
|
61
|
+
"allowedVariants": {
|
|
62
|
+
"view": ["ShoppingCart4"]
|
|
63
|
+
},
|
|
64
|
+
"optionalSections": [],
|
|
65
|
+
"registeredSlots": ["view"],
|
|
66
|
+
"allowedSections": [],
|
|
67
|
+
"maxSections": 0
|
|
40
68
|
},
|
|
41
69
|
{
|
|
42
70
|
"name": "category",
|
|
71
|
+
"mvp": true,
|
|
43
72
|
"description": "Product listing filtered by category with filters and sorting",
|
|
44
|
-
"route": "/
|
|
73
|
+
"route": "/categories/[[...slug]]",
|
|
45
74
|
"loader": "category",
|
|
46
75
|
"requiredDataKeys": ["categoryProducts", "storeCategories"],
|
|
47
76
|
"defaultVariants": {
|
|
48
77
|
"filter": "CategoryFilter2",
|
|
49
|
-
"productCard": "ProductCard1"
|
|
78
|
+
"productCard": "ProductCard1",
|
|
79
|
+
"breadcrumb": "Breadcrumb"
|
|
50
80
|
},
|
|
51
81
|
"allowedVariants": {
|
|
52
82
|
"filter": ["CategoryFilter1", "CategoryFilter2", "CategoryFilter4"],
|
|
53
|
-
"productCard": ["ProductCard1", "ProductCard2", "ProductCard3", "ProductCard5"]
|
|
83
|
+
"productCard": ["ProductCard1", "ProductCard2", "ProductCard3", "ProductCard5"],
|
|
84
|
+
"breadcrumb": ["Breadcrumb"]
|
|
54
85
|
},
|
|
55
|
-
"optionalSections": ["logoCloud", "testimonials"]
|
|
86
|
+
"optionalSections": ["logoCloud", "testimonials"],
|
|
87
|
+
"registeredSlots": ["breadcrumb", "filter", "productCard"],
|
|
88
|
+
"allowedSections": ["faq", "cta"],
|
|
89
|
+
"maxSections": 4
|
|
56
90
|
},
|
|
57
91
|
{
|
|
58
92
|
"name": "checkout",
|
|
93
|
+
"mvp": true,
|
|
59
94
|
"description": "Multi-step checkout with cart summary, shipping, and payment",
|
|
60
95
|
"route": "/checkout",
|
|
61
96
|
"loader": "checkout",
|
|
@@ -68,23 +103,45 @@
|
|
|
68
103
|
"checkout": ["CheckoutForm1", "CheckoutForm2", "CheckoutForm3"],
|
|
69
104
|
"confirmation": ["CheckoutConfirmation"]
|
|
70
105
|
},
|
|
71
|
-
"optionalSections": []
|
|
106
|
+
"optionalSections": [],
|
|
107
|
+
"registeredSlots": ["checkout", "confirmation"],
|
|
108
|
+
"allowedSections": [],
|
|
109
|
+
"maxSections": 4
|
|
72
110
|
},
|
|
73
111
|
{
|
|
74
|
-
"name": "
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
112
|
+
"name": "account",
|
|
113
|
+
"mvp": true,
|
|
114
|
+
"description": "Customer account area with sign-in, registration, and a minimal signed-in state",
|
|
115
|
+
"route": "/account",
|
|
116
|
+
"loader": "account",
|
|
117
|
+
"requiredDataKeys": ["accountCustomer"],
|
|
79
118
|
"defaultVariants": {
|
|
80
|
-
"
|
|
81
|
-
"
|
|
119
|
+
"login": "LoginPage1",
|
|
120
|
+
"register": "SignUpPage1"
|
|
82
121
|
},
|
|
83
122
|
"allowedVariants": {
|
|
84
|
-
"
|
|
85
|
-
"
|
|
123
|
+
"login": ["LoginPage1", "LoginPage2"],
|
|
124
|
+
"register": ["SignUpPage1"],
|
|
125
|
+
"orders": ["OrderHistory1", "OrderHistory2"]
|
|
86
126
|
},
|
|
87
|
-
"optionalSections": []
|
|
127
|
+
"optionalSections": [],
|
|
128
|
+
"registeredSlots": ["login", "register", "orders"],
|
|
129
|
+
"allowedSections": [],
|
|
130
|
+
"maxSections": 4
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "static",
|
|
134
|
+
"mvp": true,
|
|
135
|
+
"description": "Content-driven static pages (contact, legal, about) with per-page metadata",
|
|
136
|
+
"route": "/contact",
|
|
137
|
+
"loader": "static",
|
|
138
|
+
"requiredDataKeys": [],
|
|
139
|
+
"defaultVariants": {},
|
|
140
|
+
"allowedVariants": {},
|
|
141
|
+
"optionalSections": [],
|
|
142
|
+
"registeredSlots": [],
|
|
143
|
+
"allowedSections": [],
|
|
144
|
+
"maxSections": 0
|
|
88
145
|
}
|
|
89
146
|
]
|
|
90
147
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./section.schema.json",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
+
"description": "Editorial section registry. Each entry declares a `status`: `executable` (shipped, with a verified presentation bridge/provenance and no backend data source required) or `held` (bounded curation: no verified presentation bridge/provenance in the current composition or no verified backend/data source for the MVP; not an intrinsic exclusion). A held entry declares a non-empty `reason`. The status is the single source of truth that `recipes/validate.mjs` and the CLI introspection read; there is no separate held list.",
|
|
4
5
|
"sections": [
|
|
5
6
|
{
|
|
6
7
|
"name": "testimonials",
|
|
@@ -8,7 +9,9 @@
|
|
|
8
9
|
"elementType": "Testimonials",
|
|
9
10
|
"variants": ["Testimonial1", "Testimonial2"],
|
|
10
11
|
"defaultVariant": "Testimonial1",
|
|
11
|
-
"propsHint": "title, badge, items[] (quote, author, role, avatar)"
|
|
12
|
+
"propsHint": "title, badge, items[] (quote, author, role, avatar)",
|
|
13
|
+
"status": "held",
|
|
14
|
+
"reason": "bounded curation: no verified presentation bridge/provenance in the current composition and no verified backend/data source for the MVP"
|
|
12
15
|
},
|
|
13
16
|
{
|
|
14
17
|
"name": "faq",
|
|
@@ -16,7 +19,27 @@
|
|
|
16
19
|
"elementType": "Faq",
|
|
17
20
|
"variants": ["FaqBlock1"],
|
|
18
21
|
"defaultVariant": "FaqBlock1",
|
|
19
|
-
"propsHint": "title, description, items[] (question, answer)"
|
|
22
|
+
"propsHint": "title, description, items[] (question, answer)",
|
|
23
|
+
"status": "executable"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "cta",
|
|
27
|
+
"description": "Call-to-action banner with primary and secondary links",
|
|
28
|
+
"elementType": "Cta",
|
|
29
|
+
"variants": ["CtaSection1"],
|
|
30
|
+
"defaultVariant": "CtaSection1",
|
|
31
|
+
"propsHint": "badgeText, title, description, primaryCta/secondaryCta (label, href)",
|
|
32
|
+
"status": "executable"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "products",
|
|
36
|
+
"description": "Data-bound product presentation (grid or combined grid-and-carousel) whose selection is configured independently per instance",
|
|
37
|
+
"elementType": "Products",
|
|
38
|
+
"variants": ["ProductCard1", "ProductShowcase1"],
|
|
39
|
+
"defaultVariant": "ProductCard1",
|
|
40
|
+
"dataBound": true,
|
|
41
|
+
"propsHint": "per-instance selection configured in views/<view>/data.ts sectionSources[id] (canonical category/collection/search/ordering query); heading, description, objective, ctaLabel/ctaHref are editorial content",
|
|
42
|
+
"status": "executable"
|
|
20
43
|
},
|
|
21
44
|
{
|
|
22
45
|
"name": "statistics",
|
|
@@ -24,7 +47,9 @@
|
|
|
24
47
|
"elementType": "Statistics",
|
|
25
48
|
"variants": ["Statistic1"],
|
|
26
49
|
"defaultVariant": "Statistic1",
|
|
27
|
-
"propsHint": "title, items[] (value, label)"
|
|
50
|
+
"propsHint": "title, items[] (value, label)",
|
|
51
|
+
"status": "held",
|
|
52
|
+
"reason": "bounded curation: no verified backend/data source for the metrics and no verified presentation bridge/provenance in the current composition"
|
|
28
53
|
},
|
|
29
54
|
{
|
|
30
55
|
"name": "logoCloud",
|
|
@@ -32,7 +57,9 @@
|
|
|
32
57
|
"elementType": "LogoCloud",
|
|
33
58
|
"variants": ["LogoCloud1"],
|
|
34
59
|
"defaultVariant": "LogoCloud1",
|
|
35
|
-
"propsHint": "title, platforms[]/logos[] (name, src)"
|
|
60
|
+
"propsHint": "title, platforms[]/logos[] (name, src)",
|
|
61
|
+
"status": "held",
|
|
62
|
+
"reason": "bounded curation: no verified backend/data source for partner/brand logos and no verified presentation bridge/provenance in the current composition"
|
|
36
63
|
},
|
|
37
64
|
{
|
|
38
65
|
"name": "pricing",
|
|
@@ -40,7 +67,9 @@
|
|
|
40
67
|
"elementType": "Pricing",
|
|
41
68
|
"variants": ["PricingSection1"],
|
|
42
69
|
"defaultVariant": "PricingSection1",
|
|
43
|
-
"propsHint": "title, description, tiers[] (name, price, features, cta)"
|
|
70
|
+
"propsHint": "title, description, tiers[] (name, price, features, cta)",
|
|
71
|
+
"status": "held",
|
|
72
|
+
"reason": "bounded curation: no verified backend/data source for pricing tiers and no verified presentation bridge/provenance in the current composition"
|
|
44
73
|
}
|
|
45
74
|
]
|
|
46
75
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
// Optional section fragment: cta (mirrors recipes/sections.json) — client registry.
|
|
4
|
+
// The matching server-side catalog lives in cta.tsx. @thorprovider/blocks ships a
|
|
5
|
+
// 'use client' boundary, but this fragment keeps the explicit client boundary so
|
|
6
|
+
// the section composes identically in any consumer graph.
|
|
7
|
+
|
|
8
|
+
import { CtaSection1 as CtaBlock } from '@thorprovider/blocks'
|
|
9
|
+
import { ctaSection1PropsSchema } from './schema.cta'
|
|
10
|
+
import type { ViewRegistry } from '../types'
|
|
11
|
+
|
|
12
|
+
export const ctaRegistry: ViewRegistry = {
|
|
13
|
+
Cta: ({ props }) => {
|
|
14
|
+
const parsed = ctaSection1PropsSchema.parse(props)
|
|
15
|
+
return (
|
|
16
|
+
<CtaBlock
|
|
17
|
+
badgeText={parsed.badgeText}
|
|
18
|
+
title={parsed.title}
|
|
19
|
+
description={parsed.description}
|
|
20
|
+
primaryCta={parsed.primaryCta}
|
|
21
|
+
secondaryCta={parsed.secondaryCta}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
},
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Optional section fragment: cta (mirrors recipes/sections.json)
|
|
2
|
+
// Server-side part: element type + zod catalog entry. The component mappings
|
|
3
|
+
// live in cta.client.tsx ('use client') and are composed via composeSections.
|
|
4
|
+
|
|
5
|
+
import { ctaSection1PropsSchema } from './schema.cta'
|
|
6
|
+
|
|
7
|
+
export const ctaSection = {
|
|
8
|
+
elementType: 'Cta',
|
|
9
|
+
catalog: {
|
|
10
|
+
Cta: {
|
|
11
|
+
props: ctaSection1PropsSchema,
|
|
12
|
+
description: 'Call-to-action banner with optional primary and secondary links.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
registryModule: './cta.client',
|
|
16
|
+
}
|
|
@@ -6,15 +6,19 @@
|
|
|
6
6
|
// the section composes identically in any consumer graph.
|
|
7
7
|
|
|
8
8
|
import { FaqBlock1 as FaqBlock } from '@thorprovider/blocks'
|
|
9
|
+
import { faqPropsSchema } from './schema.faq'
|
|
9
10
|
import type { ViewRegistry } from '../types'
|
|
10
11
|
|
|
11
|
-
export const
|
|
12
|
-
Faq: ({ props }) =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
export const faqRegistry: ViewRegistry = {
|
|
13
|
+
Faq: ({ props }) => {
|
|
14
|
+
const parsed = faqPropsSchema.parse(props)
|
|
15
|
+
return (
|
|
16
|
+
<FaqBlock
|
|
17
|
+
title={parsed.title ?? 'Preguntas frecuentes'}
|
|
18
|
+
description={parsed.description}
|
|
19
|
+
items={parsed.items}
|
|
20
|
+
accordionType={parsed.accordionType ?? 'single'}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
},
|
|
20
24
|
}
|
|
@@ -2,18 +2,13 @@
|
|
|
2
2
|
// Server-side part: element type + zod catalog entry. The component mappings
|
|
3
3
|
// live in faq.client.tsx ('use client') and are composed via composeSections.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { faqPropsSchema } from './schema.faq'
|
|
6
6
|
|
|
7
7
|
export const faqSection = {
|
|
8
8
|
elementType: 'Faq',
|
|
9
9
|
catalog: {
|
|
10
10
|
Faq: {
|
|
11
|
-
props:
|
|
12
|
-
title: z.string().optional(),
|
|
13
|
-
description: z.string().optional(),
|
|
14
|
-
items: z.array(z.record(z.string(), z.unknown())),
|
|
15
|
-
accordionType: z.enum(['single', 'multiple']).optional(),
|
|
16
|
-
}),
|
|
11
|
+
props: faqPropsSchema,
|
|
17
12
|
description: 'Frequently asked questions accordion.',
|
|
18
13
|
},
|
|
19
14
|
},
|
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
// The matching server-side catalog entry lives in logoCloud.tsx.
|
|
5
5
|
|
|
6
6
|
import { LogoCloud1 as LogoCloudBlock } from '@thorprovider/blocks'
|
|
7
|
+
import { logoCloudPropsSchema } from './schema.logoCloud'
|
|
7
8
|
import type { ViewRegistry } from '../types'
|
|
8
9
|
|
|
9
10
|
export const registry: ViewRegistry = {
|
|
10
|
-
LogoCloud: ({ props }) =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
LogoCloud: ({ props }) => {
|
|
12
|
+
const parsed = logoCloudPropsSchema.parse(props)
|
|
13
|
+
return (
|
|
14
|
+
<LogoCloudBlock
|
|
15
|
+
title={parsed.title ?? 'Marcas que confían en nosotros'}
|
|
16
|
+
description={parsed.description}
|
|
17
|
+
moreLabel={parsed.moreLabel}
|
|
18
|
+
platforms={parsed.platforms}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
},
|
|
18
22
|
}
|
|
@@ -2,18 +2,13 @@
|
|
|
2
2
|
// Server-side part: element type + zod catalog entry. The component mappings
|
|
3
3
|
// live in logoCloud.client.tsx ('use client').
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { logoCloudPropsSchema } from './schema.logoCloud'
|
|
6
6
|
|
|
7
7
|
export const logoCloudSection = {
|
|
8
8
|
elementType: 'LogoCloud',
|
|
9
9
|
catalog: {
|
|
10
10
|
LogoCloud: {
|
|
11
|
-
props:
|
|
12
|
-
title: z.string().optional(),
|
|
13
|
-
description: z.string().optional(),
|
|
14
|
-
moreLabel: z.string().optional(),
|
|
15
|
-
platforms: z.array(z.record(z.string(), z.unknown())),
|
|
16
|
-
}),
|
|
11
|
+
props: logoCloudPropsSchema,
|
|
17
12
|
description: 'Brand or partner logo strip.',
|
|
18
13
|
},
|
|
19
14
|
},
|
|
@@ -4,17 +4,21 @@
|
|
|
4
4
|
// The matching server-side catalog entry lives in pricing.tsx.
|
|
5
5
|
|
|
6
6
|
import { PricingSection1 as PricingBlock } from '@thorprovider/blocks'
|
|
7
|
+
import { pricingPropsSchema } from './schema.pricing'
|
|
7
8
|
import type { ViewRegistry } from '../types'
|
|
8
9
|
|
|
9
10
|
export const registry: ViewRegistry = {
|
|
10
|
-
Pricing: ({ props }) =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
Pricing: ({ props }) => {
|
|
12
|
+
const parsed = pricingPropsSchema.parse(props)
|
|
13
|
+
return (
|
|
14
|
+
<PricingBlock
|
|
15
|
+
sectionTitle={parsed.sectionTitle ?? 'Planes y precios'}
|
|
16
|
+
sectionLabel={parsed.sectionLabel}
|
|
17
|
+
currencySymbol={parsed.currencySymbol}
|
|
18
|
+
popularBadgeLabel={parsed.popularBadgeLabel ?? 'Popular'}
|
|
19
|
+
getStartedLabel={parsed.getStartedLabel ?? 'Empezar'}
|
|
20
|
+
tiers={parsed.tiers}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
},
|
|
20
24
|
}
|
|
@@ -2,20 +2,13 @@
|
|
|
2
2
|
// Server-side part: element type + zod catalog entry. The component mappings
|
|
3
3
|
// live in pricing.client.tsx ('use client').
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { pricingPropsSchema } from './schema.pricing'
|
|
6
6
|
|
|
7
7
|
export const pricingSection = {
|
|
8
8
|
elementType: 'Pricing',
|
|
9
9
|
catalog: {
|
|
10
10
|
Pricing: {
|
|
11
|
-
props:
|
|
12
|
-
sectionTitle: z.string().optional(),
|
|
13
|
-
sectionLabel: z.string().optional(),
|
|
14
|
-
currencySymbol: z.string().optional(),
|
|
15
|
-
popularBadgeLabel: z.string().optional(),
|
|
16
|
-
getStartedLabel: z.string().optional(),
|
|
17
|
-
tiers: z.array(z.record(z.string(), z.unknown())),
|
|
18
|
-
}),
|
|
11
|
+
props: pricingPropsSchema,
|
|
19
12
|
description: 'Pricing tiers or plans.',
|
|
20
13
|
},
|
|
21
14
|
},
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
// Optional section fragment: products (mirrors recipes/sections.json) — client registry.
|
|
4
|
+
// The matching server-side catalog lives in products.tsx. A data-bound section
|
|
5
|
+
// renders one of two verified presentations (ProductCard1 grid, or the combined
|
|
6
|
+
// grid-and-carousel ProductShowcase1) chosen by the resolved `variant`. The
|
|
7
|
+
// selection and resolved products arrive through the view state; this boundary
|
|
8
|
+
// only validates them and wires navigation/purchase callbacks.
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
ProductCard1 as ProductCard1Block,
|
|
12
|
+
ProductShowcase1 as ProductShowcase1Block,
|
|
13
|
+
type ProductCard1Product,
|
|
14
|
+
} from '@thorprovider/blocks'
|
|
15
|
+
import { useStateStore } from '@json-render/react'
|
|
16
|
+
import { useSectionObservation } from '../../section-observation'
|
|
17
|
+
import { productsPropsSchema, type ProductsStatus } from './schema.products'
|
|
18
|
+
import type { ViewRegistry } from '../types'
|
|
19
|
+
|
|
20
|
+
// Truthful, actionable messages for the non-`ready` states. A failed or
|
|
21
|
+
// unconfigured section never fabricates products.
|
|
22
|
+
function sectionStatusMessage(status: ProductsStatus): string {
|
|
23
|
+
switch (status) {
|
|
24
|
+
case 'unconfigured':
|
|
25
|
+
return 'Esta sección de productos aún no tiene una selección configurada.'
|
|
26
|
+
case 'empty':
|
|
27
|
+
return 'Esta selección no tiene productos disponibles por ahora.'
|
|
28
|
+
case 'invalid-query':
|
|
29
|
+
return 'La selección de productos de esta sección no es válida.'
|
|
30
|
+
case 'unsupported-query':
|
|
31
|
+
return 'Esta selección usa criterios que el catálogo no admite.'
|
|
32
|
+
case 'unmounted-capability':
|
|
33
|
+
return 'Esta selección requiere una capacidad que este catálogo no tiene montada.'
|
|
34
|
+
case 'data-error':
|
|
35
|
+
return 'No se pudieron cargar los productos de esta sección.'
|
|
36
|
+
default:
|
|
37
|
+
return ''
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const productsRegistry: ViewRegistry = {
|
|
42
|
+
Products: ({ props, emit }) => {
|
|
43
|
+
const { set } = useStateStore()
|
|
44
|
+
const parsed = productsPropsSchema.parse(props)
|
|
45
|
+
const { containerRef, noteProductClick } = useSectionObservation({
|
|
46
|
+
sectionId: parsed.sectionId ?? '',
|
|
47
|
+
sectionType: parsed.sectionType ?? 'products',
|
|
48
|
+
...(parsed.variant ? { sectionVariant: parsed.variant } : {}),
|
|
49
|
+
...(parsed.objective ? { objective: parsed.objective } : {}),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (parsed.status !== 'ready') {
|
|
53
|
+
return (
|
|
54
|
+
<section
|
|
55
|
+
aria-label={parsed.heading ?? 'Productos'}
|
|
56
|
+
className="mx-auto w-full max-w-7xl px-4 py-12"
|
|
57
|
+
>
|
|
58
|
+
{parsed.heading ? (
|
|
59
|
+
<h2 className="mb-2 text-2xl font-semibold tracking-tight">{parsed.heading}</h2>
|
|
60
|
+
) : null}
|
|
61
|
+
<p className="text-sm text-muted-foreground">{sectionStatusMessage(parsed.status)}</p>
|
|
62
|
+
</section>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// The detail affordance opens the product so a variant is chosen explicitly.
|
|
67
|
+
// It is also the section's observation origin (disabled by default).
|
|
68
|
+
const openProduct = (product: ProductCard1Product) => {
|
|
69
|
+
noteProductClick(product)
|
|
70
|
+
set('/lastClicked', product)
|
|
71
|
+
emit('openProduct')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Product-card shortcut: the add affordance adds the product's first
|
|
75
|
+
// purchasable variant (resolved server-side from the product id), then opens
|
|
76
|
+
// the mini-cart. It is not the section's observation origin.
|
|
77
|
+
const addToCart = (product: ProductCard1Product) => {
|
|
78
|
+
set('/lastClicked', product)
|
|
79
|
+
emit('addClickedToCart')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const shared = {
|
|
83
|
+
products: parsed.products,
|
|
84
|
+
heading: parsed.heading,
|
|
85
|
+
description: parsed.description,
|
|
86
|
+
onAddToCart: addToCart,
|
|
87
|
+
onProductClick: openProduct,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div ref={containerRef}>
|
|
92
|
+
{parsed.variant === 'ProductShowcase1' ? (
|
|
93
|
+
<ProductShowcase1Block {...shared} />
|
|
94
|
+
) : (
|
|
95
|
+
<ProductCard1Block {...shared} />
|
|
96
|
+
)}
|
|
97
|
+
</div>
|
|
98
|
+
)
|
|
99
|
+
},
|
|
100
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Optional section fragment: products (mirrors recipes/sections.json)
|
|
2
|
+
// Server-side part: element type + zod catalog entry. The component mappings
|
|
3
|
+
// live in products.client.tsx ('use client'). Unlike the stateless editorial
|
|
4
|
+
// fragments (faq/cta), the products section is data-bound: its per-instance
|
|
5
|
+
// selection is resolved by the host loader and delivered through the view state,
|
|
6
|
+
// so this catalog entry describes the *resolved* props shape.
|
|
7
|
+
|
|
8
|
+
import { productsPropsSchema } from './schema.products'
|
|
9
|
+
|
|
10
|
+
export const productsSection = {
|
|
11
|
+
elementType: 'Products',
|
|
12
|
+
catalog: {
|
|
13
|
+
Products: {
|
|
14
|
+
props: productsPropsSchema,
|
|
15
|
+
description: 'Data-bound product presentation (grid or combined grid-and-carousel).',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
registryModule: './products.client',
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Optional section fragment: cta (mirrors recipes/sections.json) — shared contract.
|
|
2
|
+
// Zod mirror of the Cta/CtaSection1Props block contracts, shared by the server
|
|
3
|
+
// catalog (cta.tsx) and the client registry (cta.client.tsx). The React-only
|
|
4
|
+
// callbacks (onPrimaryClick/onSecondaryClick) are intentionally excluded.
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod'
|
|
7
|
+
|
|
8
|
+
export const ctaSchema = z.object({
|
|
9
|
+
label: z.string(),
|
|
10
|
+
href: z.string().optional(),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export const ctaSection1PropsSchema = z.object({
|
|
14
|
+
badgeText: z.string().optional(),
|
|
15
|
+
title: z.string().optional(),
|
|
16
|
+
description: z.string().optional(),
|
|
17
|
+
primaryCta: ctaSchema.optional(),
|
|
18
|
+
secondaryCta: ctaSchema.optional(),
|
|
19
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Optional section fragment: faq (mirrors recipes/sections.json) — shared contract.
|
|
2
|
+
// Zod mirror of the FaqItem/FaqBlock1Props block contracts, shared by the server
|
|
3
|
+
// catalog (faq.tsx) and the client registry (faq.client.tsx).
|
|
4
|
+
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
export const faqItemSchema = z.object({
|
|
8
|
+
value: z.string(),
|
|
9
|
+
question: z.string(),
|
|
10
|
+
answer: z.string(),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export const faqPropsSchema = z.object({
|
|
14
|
+
title: z.string().optional(),
|
|
15
|
+
description: z.string().optional(),
|
|
16
|
+
items: z.array(faqItemSchema),
|
|
17
|
+
accordionType: z.enum(['single', 'multiple']).optional(),
|
|
18
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Optional section fragment: logoCloud (mirrors recipes/sections.json) — shared contract.
|
|
2
|
+
// Zod mirror of the LogoCloud1Platform/LogoCloud1Props block contracts, shared
|
|
3
|
+
// by the server catalog (logoCloud.tsx) and the client registry
|
|
4
|
+
// (logoCloud.client.tsx). `id` is a simple-icons slug resolved internally by
|
|
5
|
+
// the block.
|
|
6
|
+
|
|
7
|
+
import { z } from 'zod'
|
|
8
|
+
|
|
9
|
+
export const logoCloudPlatformSchema = z.object({
|
|
10
|
+
name: z.string(),
|
|
11
|
+
id: z.string(),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export const logoCloudPropsSchema = z.object({
|
|
15
|
+
title: z.string().optional(),
|
|
16
|
+
description: z.string().optional(),
|
|
17
|
+
moreLabel: z.string().optional(),
|
|
18
|
+
platforms: z.array(logoCloudPlatformSchema),
|
|
19
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Optional section fragment: pricing (mirrors recipes/sections.json) — shared contract.
|
|
2
|
+
// Zod mirror of the PricingTier/PricingSection1Props block contracts, shared by
|
|
3
|
+
// the server catalog (pricing.tsx) and the client registry (pricing.client.tsx).
|
|
4
|
+
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
export const pricingTierSchema = z.object({
|
|
8
|
+
id: z.string(),
|
|
9
|
+
name: z.string(),
|
|
10
|
+
description: z.string(),
|
|
11
|
+
// Precio sin símbolo de moneda; el símbolo se pasa aparte en `currencySymbol`.
|
|
12
|
+
price: z.string(),
|
|
13
|
+
// Frecuencia de facturación, p. ej. '/mes'.
|
|
14
|
+
frequency: z.string(),
|
|
15
|
+
features: z.array(z.string()),
|
|
16
|
+
popular: z.boolean().optional(),
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export const pricingPropsSchema = z.object({
|
|
20
|
+
sectionTitle: z.string().optional(),
|
|
21
|
+
sectionLabel: z.string().optional(),
|
|
22
|
+
currencySymbol: z.string().optional(),
|
|
23
|
+
popularBadgeLabel: z.string().optional(),
|
|
24
|
+
getStartedLabel: z.string().optional(),
|
|
25
|
+
tiers: z.array(pricingTierSchema),
|
|
26
|
+
})
|