@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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Thor Commerce view module: static
|
|
2
|
+
// Server Component module: elements + catalog entries + routes + loader only.
|
|
3
|
+
// The client-side component mapping lives in ./registry.tsx ('use client'); this
|
|
4
|
+
// module imports it as data so the RSC graph never evaluates @json-render/react
|
|
5
|
+
// on the server. Registered by importing it in ../index.ts. Recipe: recipes.json -> "static".
|
|
6
|
+
//
|
|
7
|
+
// The pages are declared in the user-owned ./content.ts. This module builds one
|
|
8
|
+
// fixed route per declared page (each with its own metadata); an undeclared path
|
|
9
|
+
// is never declared here, so it falls through to the storefront not-found
|
|
10
|
+
// response.
|
|
11
|
+
|
|
12
|
+
import { getDataSource } from '../../store-context'
|
|
13
|
+
import { pageRoot } from '../../spec/page-root'
|
|
14
|
+
import type { StorefrontElement } from '../../spec/types'
|
|
15
|
+
import type { ViewModule, ViewRoute } from '../types'
|
|
16
|
+
import { registry } from './registry'
|
|
17
|
+
import { staticPagesContent } from './content'
|
|
18
|
+
import { staticContentPropsSchema } from './schema'
|
|
19
|
+
|
|
20
|
+
// A single catalog/registry declaration for the local StaticContent element. The
|
|
21
|
+
// per-route props (the page's sections) are supplied in each route's entry below.
|
|
22
|
+
const elements: Record<string, StorefrontElement> = {
|
|
23
|
+
'static.content': {
|
|
24
|
+
type: 'StaticContent',
|
|
25
|
+
props: {},
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const catalog = {
|
|
30
|
+
StaticContent: {
|
|
31
|
+
props: staticContentPropsSchema,
|
|
32
|
+
description: 'Renders declared static page sections.',
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A stable, unique root id per page: `/contact` -> `static-contact`,
|
|
37
|
+
// `/` -> `static-index`.
|
|
38
|
+
const pageRootId = (path: string): string =>
|
|
39
|
+
`static-${path.replace(/^\//, '').replace(/\//g, '-') || 'index'}`
|
|
40
|
+
|
|
41
|
+
const route: ViewRoute[] = staticPagesContent.map((page) => ({
|
|
42
|
+
path: page.path,
|
|
43
|
+
loaderName: 'static',
|
|
44
|
+
layout: 'default',
|
|
45
|
+
metadata: { title: page.title, description: page.description },
|
|
46
|
+
entry: pageRoot(pageRootId(page.path), ['static.content'], {
|
|
47
|
+
'static.content': { type: 'StaticContent', props: { sections: page.sections } },
|
|
48
|
+
}),
|
|
49
|
+
}))
|
|
50
|
+
|
|
51
|
+
export const staticView: ViewModule = {
|
|
52
|
+
name: 'static',
|
|
53
|
+
elements,
|
|
54
|
+
catalog,
|
|
55
|
+
registry,
|
|
56
|
+
route,
|
|
57
|
+
loader: {
|
|
58
|
+
static: async () => ({ dataSource: getDataSource(), dataError: null }),
|
|
59
|
+
},
|
|
60
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
// Thor Commerce view registry fragment: static
|
|
4
|
+
// Client boundary for the static view. The local StaticContent component renders
|
|
5
|
+
// the declared sections with semantic HTML and storefront tokens; it reads no
|
|
6
|
+
// backend data, so it is a pure, Server-Component-safe client component.
|
|
7
|
+
|
|
8
|
+
import type { ViewRegistry } from '../types'
|
|
9
|
+
import { staticContentPropsSchema, type StaticSection } from './schema'
|
|
10
|
+
|
|
11
|
+
function Section({ section }: { section: StaticSection }) {
|
|
12
|
+
switch (section.kind) {
|
|
13
|
+
case 'heading':
|
|
14
|
+
return <h2 className="text-2xl font-semibold tracking-tight">{section.text}</h2>
|
|
15
|
+
case 'paragraph':
|
|
16
|
+
return <p className="text-muted-foreground leading-relaxed">{section.text}</p>
|
|
17
|
+
case 'list':
|
|
18
|
+
return (
|
|
19
|
+
<ul className="list-disc space-y-1 pl-6">
|
|
20
|
+
{section.items.map((item, index) => (
|
|
21
|
+
<li key={index}>{item}</li>
|
|
22
|
+
))}
|
|
23
|
+
</ul>
|
|
24
|
+
)
|
|
25
|
+
case 'links':
|
|
26
|
+
return (
|
|
27
|
+
<ul className="space-y-1">
|
|
28
|
+
{section.items.map((item, index) => (
|
|
29
|
+
<li key={index}>
|
|
30
|
+
<a className="text-primary underline-offset-4 hover:underline" href={item.href}>
|
|
31
|
+
{item.label}
|
|
32
|
+
</a>
|
|
33
|
+
</li>
|
|
34
|
+
))}
|
|
35
|
+
</ul>
|
|
36
|
+
)
|
|
37
|
+
case 'contact':
|
|
38
|
+
return (
|
|
39
|
+
<dl className="space-y-2">
|
|
40
|
+
{section.entries.map((entry, index) => (
|
|
41
|
+
<div key={index} className="flex flex-col">
|
|
42
|
+
<dt className="text-muted-foreground text-sm">{entry.label}</dt>
|
|
43
|
+
<dd>{entry.value}</dd>
|
|
44
|
+
</div>
|
|
45
|
+
))}
|
|
46
|
+
</dl>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function StaticContent({ sections }: { sections: StaticSection[] }) {
|
|
52
|
+
return (
|
|
53
|
+
<div className="mx-auto w-full max-w-3xl px-4 py-12 sm:px-6 lg:px-8 space-y-6">
|
|
54
|
+
{sections.map((section, index) => (
|
|
55
|
+
<Section key={index} section={section} />
|
|
56
|
+
))}
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const registry: ViewRegistry = {
|
|
62
|
+
StaticContent: ({ props }) => {
|
|
63
|
+
const parsed = staticContentPropsSchema.parse(props)
|
|
64
|
+
return <StaticContent sections={parsed.sections} />
|
|
65
|
+
},
|
|
66
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Thor Commerce view schema fragment: static
|
|
2
|
+
// Zod contract for content-driven static pages. The user-owned content declares
|
|
3
|
+
// each page (path, title, optional description, ordered sections); the derived
|
|
4
|
+
// index builds one fixed route per page and the client registry renders the
|
|
5
|
+
// sections. Kept free of React and server imports so the Server Component module
|
|
6
|
+
// and the 'use client' registry share one contract.
|
|
7
|
+
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
|
|
10
|
+
// One rendered block inside a static page. A discriminated union keeps each
|
|
11
|
+
// section's props explicit and lets the registry switch on `kind`.
|
|
12
|
+
export const staticSectionSchema = z.discriminatedUnion('kind', [
|
|
13
|
+
z.object({ kind: z.literal('heading'), text: z.string() }),
|
|
14
|
+
z.object({ kind: z.literal('paragraph'), text: z.string() }),
|
|
15
|
+
z.object({ kind: z.literal('list'), items: z.array(z.string()) }),
|
|
16
|
+
z.object({
|
|
17
|
+
kind: z.literal('links'),
|
|
18
|
+
items: z.array(z.object({ label: z.string(), href: z.string() })),
|
|
19
|
+
}),
|
|
20
|
+
z.object({
|
|
21
|
+
kind: z.literal('contact'),
|
|
22
|
+
entries: z.array(z.object({ label: z.string(), value: z.string() })),
|
|
23
|
+
}),
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
// A declared page: an absolute route path, its document metadata, and the
|
|
27
|
+
// ordered sections to render.
|
|
28
|
+
export const staticPageSchema = z.object({
|
|
29
|
+
path: z.string().startsWith('/'),
|
|
30
|
+
title: z.string(),
|
|
31
|
+
description: z.string().optional(),
|
|
32
|
+
sections: z.array(staticSectionSchema),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// The user-owned content is a list of pages.
|
|
36
|
+
export const staticPagesContentSchema = z.array(staticPageSchema)
|
|
37
|
+
|
|
38
|
+
// The props a single `StaticContent` element carries on a route.
|
|
39
|
+
export const staticContentPropsSchema = z.object({
|
|
40
|
+
sections: z.array(staticSectionSchema),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export type StaticSection = z.infer<typeof staticSectionSchema>
|
|
44
|
+
export type StaticPageContent = z.infer<typeof staticPageSchema>
|
|
45
|
+
export type StaticContentProps = z.infer<typeof staticContentPropsSchema>
|