@thorprovider/storefront 0.4.0-mvp.0 → 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 +173 -153
- 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 +42 -1
- 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 +1 -5
- package/assets/templates/app/app/robots.ts +9 -3
- package/assets/templates/app/app/sitemap.ts +64 -5
- package/assets/templates/app/lib/__STOREFRONT__/actions.ts +70 -0
- package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +15 -5
- package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +71 -0
- package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +36 -4
- package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +82 -50
- package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +3 -0
- package/assets/templates/app/lib/__STOREFRONT__/schema.ts +29 -14
- 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__/shell/content.ts +31 -7
- package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +4 -0
- package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +56 -26
- package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +165 -0
- package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +26 -7
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +2 -1
- 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.products.ts +39 -0
- package/assets/templates/features/checkout/handlers.ts +6 -0
- package/assets/templates/features/customer-auth/state.ts +10 -1
- package/assets/templates/views/account/index.tsx +1 -1
- package/assets/templates/views/account/registry.tsx +80 -19
- package/assets/templates/views/account/schema.ts +1 -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 +1 -0
- package/assets/templates/views/category/assembly/index.skeleton.tsx +64 -6
- package/assets/templates/views/category/assembly/registry.skeleton.tsx +2 -1
- 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/index.tsx +76 -7
- package/assets/templates/views/category/props.ts +7 -0
- package/assets/templates/views/category/registry.tsx +19 -0
- package/assets/templates/views/category/schema.ts +13 -0
- package/assets/templates/views/home/assembly/assembly.json +9 -0
- package/assets/templates/views/home/assembly/index.skeleton.tsx +22 -4
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +1 -1
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +2 -2
- package/assets/templates/views/home/data.ts +9 -0
- package/assets/templates/views/home/index.tsx +23 -5
- package/assets/templates/views/home/registry.tsx +2 -2
- package/assets/templates/views/product/data.ts +4 -2
- package/assets/templates/views/product/index.tsx +49 -5
- package/assets/templates/views/product/props.ts +7 -0
- package/assets/templates/views/product/registry.tsx +25 -0
- package/assets/templates/views/product/schema.ts +13 -0
- package/assets/templates/views/static/content.ts +4 -4
- package/assets/templates/views/static/index.tsx +1 -1
- package/bin/storefront.js +1231 -154
- package/examples/merchandising/category-led.json +37 -0
- package/examples/merchandising/collection-led.json +37 -0
- package/package.json +11 -7
- package/recipes/archetypes.json +9 -22
- package/recipes/catalog.json +40 -1
- package/recipes/features.json +25 -2
- package/recipes/recipe.schema.json +1 -1
- package/recipes/recipes.json +32 -30
- package/recipes/sections.json +10 -0
- package/recipes/validate.mjs +54 -0
- package/scripts/candidate.mjs +4 -4
- package/scripts/composers.mjs +25 -5
- package/scripts/env-file.mjs +86 -0
- package/scripts/file-classes.mjs +5 -0
- package/scripts/migrate-english-routes.mjs +276 -0
- package/scripts/pinning.mjs +74 -5
- package/scripts/plan-apply.mjs +149 -5
- package/scripts/reconcile.mjs +49 -11
- package/scripts/render-templates.mjs +97 -44
- package/scripts/section-config.mjs +253 -0
- package/scripts/starter.mjs +17 -0
- 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 +47 -1
- package/skills/sf-feature/SKILL.md +32 -19
- package/skills/sf-setup/SKILL.md +79 -0
- package/skills/sf-theme-gen/SKILL.md +99 -36
- 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 +63 -40
- package/skills/sf-view-gen/assets/recipes/archetypes.json +9 -22
- package/skills/sf-view-gen/assets/recipes/catalog.json +40 -1
- package/skills/sf-view-gen/assets/recipes/features.json +25 -2
- package/skills/sf-view-gen/assets/recipes/recipes.json +32 -30
- package/skills/sf-view-gen/assets/recipes/sections.json +10 -0
- 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.products.ts +39 -0
- 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 +28 -37
- package/skills/sf-view-gen/scripts/validate.mjs +54 -0
- package/skills/storefront-workflow/SKILL.md +94 -31
- package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
- package/CHANGELOG.md +0 -84
- package/assets/templates/views/user-panel/index.tsx +0 -106
- package/assets/templates/views/user-panel/registry.tsx +0 -54
- package/assets/templates/views/user-panel/schema.ts +0 -79
- package/commands/sf-add-view.md +0 -57
- package/commands/sf-feature.md +0 -28
- package/commands/sf-theme.md +0 -26
- package/commands/sf-view.md +0 -67
- 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/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
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// Thor Commerce view module: user-panel
|
|
2
|
-
// Server Component module: elements + catalog entries + route + loader only.
|
|
3
|
-
// The client-side component mappings live in ./registry.tsx ('use client'); this
|
|
4
|
-
// module imports them 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 -> "user-panel".
|
|
6
|
-
|
|
7
|
-
import { getCatalog } from '@thorprovider/runtime/commerce'
|
|
8
|
-
import { pageRoot } from '../../spec/page-root'
|
|
9
|
-
import type { StorefrontElement } from '../../spec/types'
|
|
10
|
-
import type { ViewModule } from '../types'
|
|
11
|
-
import { registry } from './registry'
|
|
12
|
-
import { appShellPropsSchema, orderHistoryPropsSchema } from './schema'
|
|
13
|
-
|
|
14
|
-
const elements: Record<string, StorefrontElement> = {
|
|
15
|
-
'userPanel.shell': {
|
|
16
|
-
type: 'AppShell',
|
|
17
|
-
props: {
|
|
18
|
-
brandName: '__SITE_NAME__',
|
|
19
|
-
navGroupLabel: 'Mi cuenta',
|
|
20
|
-
navItems: [
|
|
21
|
-
{ label: 'Mis pedidos', href: '/cuenta', icon: 'package', active: true },
|
|
22
|
-
{ label: 'Mi perfil', href: '/cuenta/perfil', icon: 'user' },
|
|
23
|
-
{ label: 'Ajustes', href: '/cuenta/ajustes', icon: 'settings' },
|
|
24
|
-
],
|
|
25
|
-
user: {
|
|
26
|
-
name: 'Cliente Demo',
|
|
27
|
-
email: 'cliente@ejemplo.com',
|
|
28
|
-
initials: 'CD',
|
|
29
|
-
},
|
|
30
|
-
breadcrumb: [
|
|
31
|
-
{ label: 'Inicio', href: '/' },
|
|
32
|
-
{ label: 'Mi cuenta' },
|
|
33
|
-
],
|
|
34
|
-
pageTitle: 'Mi cuenta',
|
|
35
|
-
pageDescription: 'Consulta tus pedidos recientes y gestiona tu cuenta.',
|
|
36
|
-
action: { label: 'Seguir comprando', href: '/' },
|
|
37
|
-
stats: [
|
|
38
|
-
{ label: 'Pedidos', value: '1' },
|
|
39
|
-
{ label: 'Estado', value: 'Confirmado' },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
children: ['userPanel.orderHistory'],
|
|
43
|
-
},
|
|
44
|
-
'userPanel.orderHistory': {
|
|
45
|
-
type: 'OrderHistory',
|
|
46
|
-
props: {
|
|
47
|
-
orders: { $state: '/lastOrderLines' },
|
|
48
|
-
title: 'Historial de pedidos',
|
|
49
|
-
description: 'Tus compras recientes y su estado.',
|
|
50
|
-
},
|
|
51
|
-
on: {
|
|
52
|
-
viewOrder: { action: 'viewOrder' },
|
|
53
|
-
downloadInvoice: { action: 'downloadInvoice' },
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const catalog = {
|
|
59
|
-
AppShell: {
|
|
60
|
-
props: appShellPropsSchema,
|
|
61
|
-
slots: ['default'],
|
|
62
|
-
description: 'Panel de cuenta con navegación lateral, cabecera y área de contenido.',
|
|
63
|
-
},
|
|
64
|
-
OrderHistory: {
|
|
65
|
-
props: orderHistoryPropsSchema,
|
|
66
|
-
description: 'Historial de pedidos del cliente.',
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const userPanel: ViewModule = {
|
|
71
|
-
name: 'user-panel',
|
|
72
|
-
elements,
|
|
73
|
-
catalog,
|
|
74
|
-
registry,
|
|
75
|
-
route: {
|
|
76
|
-
path: '/cuenta',
|
|
77
|
-
loaderName: 'userPanel',
|
|
78
|
-
layout: 'default',
|
|
79
|
-
metadata: {
|
|
80
|
-
title: 'Mi cuenta',
|
|
81
|
-
description: 'Consulta tu historial de pedidos y gestiona tu cuenta.',
|
|
82
|
-
},
|
|
83
|
-
entry: pageRoot('userPanel', ['userPanel.shell'], elements),
|
|
84
|
-
},
|
|
85
|
-
loader: {
|
|
86
|
-
userPanel: async () => {
|
|
87
|
-
const { products } = await getCatalog()
|
|
88
|
-
const placedAt = new Date()
|
|
89
|
-
const orderDate = placedAt.toISOString().slice(0, 10)
|
|
90
|
-
const lastOrderLines = products.slice(0, 3).map((product, index) => ({
|
|
91
|
-
name: product.title,
|
|
92
|
-
image: product.image,
|
|
93
|
-
color: 'Estándar',
|
|
94
|
-
size: 'Único',
|
|
95
|
-
quantity: index + 1,
|
|
96
|
-
price: product.price,
|
|
97
|
-
orderDate,
|
|
98
|
-
}))
|
|
99
|
-
// Only lastOrderLines is bound by this view's elements. lastOrder and
|
|
100
|
-
// orderPlaced belong to the checkout contract (StorefrontOrder shape and
|
|
101
|
-
// an ISO timestamp); writing demo values in a foreign shape here would
|
|
102
|
-
// leak into /checkout state and crash CheckoutConfirmation.
|
|
103
|
-
return { lastOrderLines }
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
// Thor Commerce view registry fragment: user-panel
|
|
4
|
-
// Client boundary for the user-panel view. Imports value bindings from
|
|
5
|
-
// @json-render/react and components from @thorprovider/blocks — both must stay
|
|
6
|
-
// on the client side of the RSC graph. Kept separate from index.tsx so the view
|
|
7
|
-
// spec (elements/catalog/route/loader) stays a pure Server Component module.
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
AppShell1 as AppShellBlock,
|
|
11
|
-
OrderHistory1 as OrderHistoryBlock,
|
|
12
|
-
} from '@thorprovider/blocks'
|
|
13
|
-
import { useStateStore } from '@json-render/react'
|
|
14
|
-
import { appShellPropsSchema, orderHistoryPropsSchema } from './schema'
|
|
15
|
-
import type { ViewRegistry } from '../types'
|
|
16
|
-
|
|
17
|
-
export const registry: ViewRegistry = {
|
|
18
|
-
AppShell: ({ props, children }) => {
|
|
19
|
-
const parsed = appShellPropsSchema.parse(props)
|
|
20
|
-
return (
|
|
21
|
-
<AppShellBlock
|
|
22
|
-
brandName={parsed.brandName}
|
|
23
|
-
navGroupLabel={parsed.navGroupLabel}
|
|
24
|
-
navItems={parsed.navItems}
|
|
25
|
-
user={parsed.user}
|
|
26
|
-
breadcrumb={parsed.breadcrumb}
|
|
27
|
-
pageTitle={parsed.pageTitle}
|
|
28
|
-
pageDescription={parsed.pageDescription}
|
|
29
|
-
action={parsed.action}
|
|
30
|
-
stats={parsed.stats}
|
|
31
|
-
>
|
|
32
|
-
{children}
|
|
33
|
-
</AppShellBlock>
|
|
34
|
-
)
|
|
35
|
-
},
|
|
36
|
-
OrderHistory: ({ props, emit }) => {
|
|
37
|
-
const parsed = orderHistoryPropsSchema.parse(props)
|
|
38
|
-
const { set } = useStateStore()
|
|
39
|
-
return (
|
|
40
|
-
<OrderHistoryBlock
|
|
41
|
-
orders={parsed.orders}
|
|
42
|
-
title={parsed.title}
|
|
43
|
-
description={parsed.description}
|
|
44
|
-
onViewDetails={() => {
|
|
45
|
-
set('/orderDetailsOpen', true)
|
|
46
|
-
emit('viewOrder')
|
|
47
|
-
}}
|
|
48
|
-
onDownloadInvoice={() => {
|
|
49
|
-
emit('downloadInvoice')
|
|
50
|
-
}}
|
|
51
|
-
/>
|
|
52
|
-
)
|
|
53
|
-
},
|
|
54
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// Thor Commerce view schema fragment: user-panel
|
|
2
|
-
// Zod mirrors of the block contracts for this view — the single source for the
|
|
3
|
-
// catalog entries and the client-side registry parsing (json-render does not
|
|
4
|
-
// validate props against the catalog itself, so the registry parses here).
|
|
5
|
-
// Kept free of React and server imports so the Server Component module and the
|
|
6
|
-
// 'use client' registry can share one contract.
|
|
7
|
-
|
|
8
|
-
import { z } from 'zod'
|
|
9
|
-
|
|
10
|
-
export const ctaSchema = z.object({ label: z.string(), href: z.string().optional() })
|
|
11
|
-
|
|
12
|
-
// Mirrors the AppShell1NavItem block contract: `icon` is a NAME of the
|
|
13
|
-
// AppShell1NavIcon set — the block resolves it to a component internally.
|
|
14
|
-
export const appShellNavItemSchema = z.object({
|
|
15
|
-
label: z.string(),
|
|
16
|
-
href: z.string(),
|
|
17
|
-
icon: z.enum([
|
|
18
|
-
'layout-dashboard',
|
|
19
|
-
'package',
|
|
20
|
-
'user',
|
|
21
|
-
'settings',
|
|
22
|
-
'home',
|
|
23
|
-
'shopping-cart',
|
|
24
|
-
'bar-chart-3',
|
|
25
|
-
'users',
|
|
26
|
-
'folder-kanban',
|
|
27
|
-
]),
|
|
28
|
-
active: z.boolean().optional(),
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
export const appShellUserSchema = z.object({
|
|
32
|
-
name: z.string(),
|
|
33
|
-
email: z.string(),
|
|
34
|
-
initials: z.string(),
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
export const breadcrumbItemSchema = z.object({
|
|
38
|
-
label: z.string(),
|
|
39
|
-
href: z.string().optional(),
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
export const statSchema = z.object({
|
|
43
|
-
label: z.string(),
|
|
44
|
-
value: z.string(),
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
// Mirrors the OrderHistory1Order block contract.
|
|
48
|
-
export const orderLineSchema = z.object({
|
|
49
|
-
name: z.string(),
|
|
50
|
-
image: z.string(),
|
|
51
|
-
color: z.string(),
|
|
52
|
-
size: z.string(),
|
|
53
|
-
quantity: z.number(),
|
|
54
|
-
price: z.number(),
|
|
55
|
-
orderDate: z.string(),
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
export const appShellPropsSchema = z.object({
|
|
59
|
-
brandName: z.string().optional(),
|
|
60
|
-
navGroupLabel: z.string().optional(),
|
|
61
|
-
navItems: z.array(appShellNavItemSchema).optional(),
|
|
62
|
-
user: appShellUserSchema.optional(),
|
|
63
|
-
breadcrumb: z.array(breadcrumbItemSchema).optional(),
|
|
64
|
-
pageTitle: z.string().optional(),
|
|
65
|
-
pageDescription: z.string().optional(),
|
|
66
|
-
action: ctaSchema.optional(),
|
|
67
|
-
stats: z.array(statSchema).optional(),
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
export const orderHistoryPropsSchema = z.object({
|
|
71
|
-
orders: z.array(orderLineSchema),
|
|
72
|
-
title: z.string().optional(),
|
|
73
|
-
description: z.string().optional(),
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
export type AppShellNavItem = z.infer<typeof appShellNavItemSchema>
|
|
77
|
-
export type AppShellProps = z.infer<typeof appShellPropsSchema>
|
|
78
|
-
export type OrderLine = z.infer<typeof orderLineSchema>
|
|
79
|
-
export type OrderHistoryProps = z.infer<typeof orderHistoryPropsSchema>
|
package/commands/sf-add-view.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Add a view to a Thor Commerce storefront via the storefront CLI"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Add one view to the current storefront. The CLI is the structural authority; do
|
|
6
|
-
not copy templates or edit derived files.
|
|
7
|
-
|
|
8
|
-
**Input**: view name, optionally a description of what it should contain.
|
|
9
|
-
Examples:
|
|
10
|
-
- `/sf-add-view product`
|
|
11
|
-
- `/sf-add-view category specialize in power stations, use a dense grid`
|
|
12
|
-
|
|
13
|
-
**Provided arguments**: $ARGUMENTS
|
|
14
|
-
|
|
15
|
-
Use the `sf-view-gen` skill. The agent selects the change and delegates every
|
|
16
|
-
structural write to the CLI; the user states the change in natural language and
|
|
17
|
-
never types a command.
|
|
18
|
-
|
|
19
|
-
**Flow:**
|
|
20
|
-
1. `npx @thorprovider/storefront views --json` — confirm the view is supported
|
|
21
|
-
and read its `supportedIntents`, `registeredSlots`, `allowedSections`,
|
|
22
|
-
`maxSections`, and the top-level `sectionTypes`. Held units (`user-panel`,
|
|
23
|
-
recommendations) and the feature-owned `checkout` view are rejected; sections
|
|
24
|
-
are composable (step 4).
|
|
25
|
-
2. Choose an intent per slot by meaning from the user's description.
|
|
26
|
-
3. Delegate the write:
|
|
27
|
-
`npx @thorprovider/storefront view add <name> [--intent slot=intent] [--variant slot=Variant]`
|
|
28
|
-
4. To compose **sections** on the new view, delegate to the CLI's section
|
|
29
|
-
operations (`section.add` / `section.remove` / `section.reorder`) in E1's
|
|
30
|
-
operations envelope `{ "formatVersion": 1, "operations": [ ... ] }`; `plan` is
|
|
31
|
-
read-only and `apply --plan` is the only writer:
|
|
32
|
-
- `section.add` (`view`, `type`, optional `id`, `variant`, `at`) adds an
|
|
33
|
-
editorial instance; `type` must be in the view's `allowedSections`, an
|
|
34
|
-
omitted `id` is auto-minted, and the add is rejected past `maxSections`.
|
|
35
|
-
- `section.remove` (`view`, `id`) removes an editorial instance; a registered
|
|
36
|
-
core slot (`slot:<slot>`) cannot be removed.
|
|
37
|
-
- `section.reorder` (`view`, `order`) requires `order` to be a permutation of
|
|
38
|
-
the view's current entry ids: every current id exactly once and every
|
|
39
|
-
registered slot present.
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
npx @thorprovider/storefront plan --operations operations.json --out plan.json
|
|
43
|
-
npx @thorprovider/storefront apply --plan plan.json
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Only `faq` and `cta` are executable editorial types. Held types
|
|
47
|
-
(`testimonials`, `statistics`, `logoCloud`, `pricing`) are not available and
|
|
48
|
-
are refused with the bounded reason the registry reports. These three section
|
|
49
|
-
operations are implemented and supported — there is no proposed or future
|
|
50
|
-
section command.
|
|
51
|
-
5. Report the result. If the CLI exits non-zero, show its message; never
|
|
52
|
-
hand-edit derived files to work around it.
|
|
53
|
-
|
|
54
|
-
**Constraints:**
|
|
55
|
-
- UI only `@thorprovider/blocks`; data only `@thorprovider/adapters` +
|
|
56
|
-
`@thorprovider/runtime/commerce`.
|
|
57
|
-
- No manual template copy, no derived-file edits, no manual barrel edits.
|
package/commands/sf-feature.md
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Add or remove a storefront feature bundle (e.g. checkout) via the storefront CLI"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Add or remove a feature bundle in the current storefront. A feature may own
|
|
6
|
-
views (plus its state/handlers/adapter wiring), an owned route, and instance
|
|
7
|
-
mounts into a host view's slot; the CLI writes every derived file.
|
|
8
|
-
|
|
9
|
-
**Input**: `add <name>` or `remove <name>` (e.g. `add checkout`).
|
|
10
|
-
**Provided arguments**: $ARGUMENTS
|
|
11
|
-
|
|
12
|
-
Use the `sf-feature` skill.
|
|
13
|
-
|
|
14
|
-
**Flow:**
|
|
15
|
-
1. `npx @thorprovider/storefront features --json` — confirm the feature is
|
|
16
|
-
supported. Held features are rejected before any write.
|
|
17
|
-
2. Delegate the write:
|
|
18
|
-
`npx @thorprovider/storefront feature add|remove <name>`
|
|
19
|
-
3. Report the result and any preserved user-owned file the CLI names. A
|
|
20
|
-
mount-based feature (e.g. `benefits` at `home.benefits`) leaves the host
|
|
21
|
-
view's customized content in place; the CLI reports its location.
|
|
22
|
-
|
|
23
|
-
**Constraints:**
|
|
24
|
-
- The curated MVP features are `checkout` (owns the `/checkout` route) and
|
|
25
|
-
`benefits` (mounts at `home.benefits`).
|
|
26
|
-
- No derived-file edits; the CLI reconciles state/handlers/adapter wiring.
|
|
27
|
-
- Purchase logic is owned by `single-tenant-commerce-mvp`; this installs
|
|
28
|
-
structural wiring only.
|
package/commands/sf-theme.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Customize storefront theme: OKLCH colors (light/dark), typography, and identity metadata"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Customize the theme and identity of the current storefront. The manifest
|
|
6
|
-
(`storefront.config.json`) is the theme authority; the CLI applies deterministic
|
|
7
|
-
changes.
|
|
8
|
-
|
|
9
|
-
**Input**: optional — the wizard asks what to customize (colors, typography, identity, SEO, Open Graph).
|
|
10
|
-
**Provided arguments**: $ARGUMENTS
|
|
11
|
-
|
|
12
|
-
Use the `sf-theme-gen` skill.
|
|
13
|
-
|
|
14
|
-
**Flow:**
|
|
15
|
-
1. Run from inside the project (no directory argument).
|
|
16
|
-
2. **Mode (light/dark/system)** is manifest state, not a hand edit:
|
|
17
|
-
`npx @thorprovider/storefront theme --mode light|dark|system`
|
|
18
|
-
3. Colors/typography/metadata are user-owned edits in `app/globals.css` and
|
|
19
|
-
`app/layout.tsx`, following the skill's assets.
|
|
20
|
-
4. `npx @thorprovider/storefront sync` and report.
|
|
21
|
-
|
|
22
|
-
**Constraints (do not violate without explicit user authorization):**
|
|
23
|
-
- Colors are CSS variables in OKLCH with complete background/foreground pairs
|
|
24
|
-
(light AND dark); never raw Tailwind color utilities for themed colors.
|
|
25
|
-
- Never hand-edit `app/layout.tsx` for the mode — the CLI rewrites the
|
|
26
|
-
`ThemeProvider` wiring idempotently from the manifest.
|
package/commands/sf-view.md
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Modify a storefront view's user-owned content/props/data, or compose its sections, via the storefront CLI"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Modify an existing view in the current storefront.
|
|
6
|
-
|
|
7
|
-
**Input**: view name followed by the change to make.
|
|
8
|
-
Examples:
|
|
9
|
-
- `/sf-view home add a FAQ section after the hero`
|
|
10
|
-
- `/sf-view home move the CTA above the benefits`
|
|
11
|
-
- `/sf-view category switch to a 4-column grid`
|
|
12
|
-
|
|
13
|
-
**Provided arguments**: $ARGUMENTS
|
|
14
|
-
|
|
15
|
-
Use the `sf-view-gen` skill. The agent selects the change and delegates every
|
|
16
|
-
structural write to the CLI; the user describes the change in natural language
|
|
17
|
-
and never types a command.
|
|
18
|
-
|
|
19
|
-
**Flow:**
|
|
20
|
-
1. Read the registry through the CLI
|
|
21
|
-
(`npx @thorprovider/storefront views --json`) for the view's
|
|
22
|
-
`registeredSlots`, `allowedSections`, `maxSections`, and the top-level
|
|
23
|
-
`sectionTypes`.
|
|
24
|
-
2. If the change composes **sections**, delegate to the CLI's section
|
|
25
|
-
operations — do not edit derived files. They are carried in E1's operations
|
|
26
|
-
envelope `{ "formatVersion": 1, "operations": [ ... ] }`; `plan` is read-only
|
|
27
|
-
and validates the whole intended state, `apply --plan` is the only writer:
|
|
28
|
-
- `{ "op": "section.add", "view": "home", "type": "faq" }` — optional `id`,
|
|
29
|
-
`variant`, and `at` (0-based insertion index, default append). `type` must
|
|
30
|
-
be in the view's `allowedSections`; omit `id` to auto-mint one; rejected
|
|
31
|
-
when adding would exceed `maxSections`.
|
|
32
|
-
- `{ "op": "section.remove", "view": "home", "id": "home-faq-1" }` — removes
|
|
33
|
-
an editorial instance. A registered core slot (`slot:<slot>`) cannot be
|
|
34
|
-
removed.
|
|
35
|
-
- `{ "op": "section.reorder", "view": "home", "order": ["slot:hero",
|
|
36
|
-
"home-faq-1", "slot:benefits", "slot:categories"] }` — `order` must be a
|
|
37
|
-
permutation of the view's current entry ids: every current id exactly once
|
|
38
|
-
and every registered slot present.
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npx @thorprovider/storefront plan --operations operations.json --out plan.json
|
|
42
|
-
npx @thorprovider/storefront apply --plan plan.json
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Only `faq` and `cta` are executable editorial types. Held types
|
|
46
|
-
(`testimonials`, `statistics`, `logoCloud`, `pricing`) are not available and
|
|
47
|
-
are refused with the bounded reason the registry reports; never present a
|
|
48
|
-
held type as available. A removed instance's content is preserved in the
|
|
49
|
-
view's user-owned `content.ts`; re-adding the same `id` rebinds it, while an
|
|
50
|
-
auto-minted id never does. These three section operations are implemented and
|
|
51
|
-
supported — there is no proposed or future section command; the held section
|
|
52
|
-
types are the only not-yet-available part of this surface.
|
|
53
|
-
3. If the change is a different block variant or an added/removed view, delegate
|
|
54
|
-
to the CLI: `npx @thorprovider/storefront view add|remove ...`.
|
|
55
|
-
4. If the change is content/props/data, edit only the **user-owned** files:
|
|
56
|
-
`lib/<name>/views/<view>/content.ts`, `props.ts`, `data.ts`, `schema.ts`, and
|
|
57
|
-
`lib/<name>/mappers.ts`.
|
|
58
|
-
5. Regenerate the derived wrappers around the edit:
|
|
59
|
-
`npx @thorprovider/storefront sync`.
|
|
60
|
-
6. Report the result and the files touched.
|
|
61
|
-
|
|
62
|
-
**Constraints:**
|
|
63
|
-
- Preserve exported names, element ids, and the prop/event contracts the derived
|
|
64
|
-
wrapper imports.
|
|
65
|
-
- Never edit derived files (`index.tsx`, `registry.tsx`, `views/index.ts`,
|
|
66
|
-
`views/registry.ts`, `catalog.ts`, `runtime.ts`, `spec/index.ts`).
|
|
67
|
-
- UI only `@thorprovider/blocks`.
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: building-storefronts
|
|
3
|
-
description: Load automatically when planning, researching, or implementing Medusa storefront features (calling custom API routes, SDK integration, React Query patterns, data fetching). REQUIRED for all storefront development in ALL modes (planning, implementation, exploration). Contains SDK usage patterns, frontend integration, and critical rules for calling Medusa APIs.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Medusa Storefront Development
|
|
7
|
-
|
|
8
|
-
Frontend integration guide for building storefronts with Medusa. Covers SDK usage, React Query patterns, and calling custom API routes.
|
|
9
|
-
|
|
10
|
-
## When to Apply
|
|
11
|
-
|
|
12
|
-
**Load this skill for ANY storefront development task, including:**
|
|
13
|
-
- Calling custom Medusa API routes from the storefront
|
|
14
|
-
- Integrating Medusa SDK in frontend applications
|
|
15
|
-
- Using React Query for data fetching
|
|
16
|
-
- Implementing mutations with optimistic updates
|
|
17
|
-
- Error handling and cache invalidation
|
|
18
|
-
|
|
19
|
-
**Also load building-with-medusa when:** Building the backend API routes that the storefront calls
|
|
20
|
-
|
|
21
|
-
## CRITICAL: Load Reference Files When Needed
|
|
22
|
-
|
|
23
|
-
**The quick reference below is NOT sufficient for implementation.** You MUST load the reference file before writing storefront integration code.
|
|
24
|
-
|
|
25
|
-
**Load this reference when implementing storefront features:**
|
|
26
|
-
|
|
27
|
-
- **Calling API routes?** → MUST load `references/frontend-integration.md` first
|
|
28
|
-
- **Using SDK?** → MUST load `references/frontend-integration.md` first
|
|
29
|
-
- **Implementing React Query?** → MUST load `references/frontend-integration.md` first
|
|
30
|
-
|
|
31
|
-
## Rule Categories by Priority
|
|
32
|
-
|
|
33
|
-
| Priority | Category | Impact | Prefix |
|
|
34
|
-
|----------|----------|--------|--------|
|
|
35
|
-
| 1 | SDK Usage | CRITICAL | `sdk-` |
|
|
36
|
-
| 2 | React Query Patterns | HIGH | `query-` |
|
|
37
|
-
| 3 | Data Display | HIGH (includes CRITICAL price rule) | `display-` |
|
|
38
|
-
| 4 | Error Handling | MEDIUM | `error-` |
|
|
39
|
-
|
|
40
|
-
## Quick Reference
|
|
41
|
-
|
|
42
|
-
### 1. SDK Usage (CRITICAL)
|
|
43
|
-
|
|
44
|
-
- `sdk-always-use` - **ALWAYS use the Medusa JS SDK for ALL API requests** - NEVER use regular fetch()
|
|
45
|
-
- `sdk-existing-methods` - For built-in endpoints, use existing SDK methods (`sdk.store.product.list()`, `sdk.admin.order.retrieve()`)
|
|
46
|
-
- `sdk-client-fetch` - For custom API routes, use `sdk.client.fetch()`
|
|
47
|
-
- `sdk-required-headers` - SDK automatically adds required headers (publishable API key for store, auth for admin) - regular fetch() missing these headers causes errors
|
|
48
|
-
- `sdk-no-json-stringify` - **NEVER use JSON.stringify() on body** - SDK handles serialization automatically
|
|
49
|
-
- `sdk-plain-objects` - Pass plain JavaScript objects to body, not strings
|
|
50
|
-
- `sdk-locate-first` - Always locate where SDK is instantiated in the project before using it
|
|
51
|
-
|
|
52
|
-
### 2. React Query Patterns (HIGH)
|
|
53
|
-
|
|
54
|
-
- `query-use-query` - Use `useQuery` for GET requests (data fetching)
|
|
55
|
-
- `query-use-mutation` - Use `useMutation` for POST/DELETE requests (mutations)
|
|
56
|
-
- `query-invalidate` - Invalidate queries in `onSuccess` to refresh data after mutations
|
|
57
|
-
- `query-keys-hierarchical` - Structure query keys hierarchically for effective cache management
|
|
58
|
-
- `query-loading-states` - Always handle `isLoading`, `isPending`, `isError` states
|
|
59
|
-
|
|
60
|
-
### 3. Data Display (HIGH)
|
|
61
|
-
|
|
62
|
-
- `display-price-format` - **CRITICAL**: Prices from Medusa are stored as-is ($49.99 = 49.99, NOT in cents). Display them directly - NEVER divide by 100
|
|
63
|
-
|
|
64
|
-
### 4. Error Handling (MEDIUM)
|
|
65
|
-
|
|
66
|
-
- `error-on-error` - Implement `onError` callback in mutations to handle failures
|
|
67
|
-
- `error-display` - Show error messages to users when mutations fail
|
|
68
|
-
- `error-rollback` - Use optimistic updates with rollback on error for better UX
|
|
69
|
-
|
|
70
|
-
## Critical SDK Pattern
|
|
71
|
-
|
|
72
|
-
**ALWAYS pass plain objects to the SDK - NEVER use JSON.stringify():**
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// ✅ CORRECT - Plain object
|
|
76
|
-
await sdk.client.fetch("/store/reviews", {
|
|
77
|
-
method: "POST",
|
|
78
|
-
body: {
|
|
79
|
-
product_id: "prod_123",
|
|
80
|
-
rating: 5,
|
|
81
|
-
}
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
// ❌ WRONG - JSON.stringify breaks the request
|
|
85
|
-
await sdk.client.fetch("/store/reviews", {
|
|
86
|
-
method: "POST",
|
|
87
|
-
body: JSON.stringify({ // ❌ DON'T DO THIS!
|
|
88
|
-
product_id: "prod_123",
|
|
89
|
-
rating: 5,
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Why this matters:**
|
|
95
|
-
- The SDK handles JSON serialization automatically
|
|
96
|
-
- Using JSON.stringify() will double-serialize and break the request
|
|
97
|
-
- The server won't be able to parse the body
|
|
98
|
-
|
|
99
|
-
## Common Mistakes Checklist
|
|
100
|
-
|
|
101
|
-
Before implementing, verify you're NOT doing these:
|
|
102
|
-
|
|
103
|
-
**SDK Usage:**
|
|
104
|
-
- [ ] Using regular fetch() instead of the Medusa JS SDK (causes missing header errors)
|
|
105
|
-
- [ ] Not using existing SDK methods for built-in endpoints (e.g., using sdk.client.fetch("/store/products") instead of sdk.store.product.list())
|
|
106
|
-
- [ ] Using JSON.stringify() on the body parameter
|
|
107
|
-
- [ ] Manually setting Content-Type headers (SDK adds them)
|
|
108
|
-
- [ ] Hardcoding SDK import paths (locate in project first)
|
|
109
|
-
- [ ] Not using sdk.client.fetch() for custom routes
|
|
110
|
-
|
|
111
|
-
**React Query:**
|
|
112
|
-
- [ ] Not invalidating queries after mutations
|
|
113
|
-
- [ ] Using flat query keys instead of hierarchical
|
|
114
|
-
- [ ] Not handling loading and error states
|
|
115
|
-
- [ ] Forgetting to disable buttons during mutations (isPending)
|
|
116
|
-
|
|
117
|
-
**Data Display:**
|
|
118
|
-
- [ ] **CRITICAL**: Dividing prices by 100 when displaying (prices are stored as-is: $49.99 = 49.99, NOT in cents)
|
|
119
|
-
|
|
120
|
-
**Error Handling:**
|
|
121
|
-
- [ ] Not implementing onError callbacks
|
|
122
|
-
- [ ] Not showing error messages to users
|
|
123
|
-
- [ ] Not handling network failures gracefully
|
|
124
|
-
|
|
125
|
-
## How to Use
|
|
126
|
-
|
|
127
|
-
**For detailed patterns and examples, load reference file:**
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
references/frontend-integration.md - SDK usage, React Query patterns, API integration
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
The reference file contains:
|
|
134
|
-
- Step-by-step SDK integration patterns
|
|
135
|
-
- Complete React Query examples
|
|
136
|
-
- Correct vs incorrect code examples
|
|
137
|
-
- Query key best practices
|
|
138
|
-
- Optimistic update patterns
|
|
139
|
-
- Error handling strategies
|
|
140
|
-
|
|
141
|
-
## When to Use MedusaDocs MCP Server
|
|
142
|
-
|
|
143
|
-
**Use this skill for (PRIMARY SOURCE):**
|
|
144
|
-
- How to call custom API routes from storefront
|
|
145
|
-
- SDK usage patterns (sdk.client.fetch)
|
|
146
|
-
- React Query integration patterns
|
|
147
|
-
- Common mistakes and anti-patterns
|
|
148
|
-
|
|
149
|
-
**Use MedusaDocs MCP server for (SECONDARY SOURCE):**
|
|
150
|
-
- Built-in SDK methods (sdk.admin.*, sdk.store.*)
|
|
151
|
-
- Official Medusa SDK API reference
|
|
152
|
-
- Framework-specific configuration options
|
|
153
|
-
|
|
154
|
-
**Why skills come first:**
|
|
155
|
-
- Skills contain critical patterns like "don't use JSON.stringify" that MCP doesn't emphasize
|
|
156
|
-
- Skills show correct vs incorrect patterns; MCP shows what's possible
|
|
157
|
-
- Planning requires understanding patterns, not just API reference
|
|
158
|
-
|
|
159
|
-
## Integration with Backend
|
|
160
|
-
|
|
161
|
-
**⚠️ CRITICAL: ALWAYS use the Medusa JS SDK - NEVER use regular fetch()**
|
|
162
|
-
|
|
163
|
-
When building features that span backend and frontend:
|
|
164
|
-
|
|
165
|
-
1. **Backend (building-with-medusa skill):** Module → Workflow → API Route
|
|
166
|
-
2. **Storefront (this skill):** SDK → React Query → UI Components
|
|
167
|
-
3. **Connection:**
|
|
168
|
-
- Built-in endpoints: Use existing SDK methods (`sdk.store.product.list()`)
|
|
169
|
-
- Custom API routes: Use `sdk.client.fetch("/store/my-route")`
|
|
170
|
-
- **NEVER use regular fetch()** - missing publishable API key causes errors
|
|
171
|
-
|
|
172
|
-
**Why the SDK is required:**
|
|
173
|
-
- Store routes need `x-publishable-api-key` header
|
|
174
|
-
- Admin routes need `Authorization` and session headers
|
|
175
|
-
- SDK handles all required headers automatically
|
|
176
|
-
- Regular fetch() without headers → authentication/authorization errors
|
|
177
|
-
|
|
178
|
-
See `building-with-medusa` for backend API route patterns.
|