@wix/agent-skills 1.17.0 → 1.18.1

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.
Files changed (253) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +115 -12
  3. package/skills/wix-app/references/APP_MARKET_REVIEW.md +1 -1
  4. package/skills/wix-app/references/BACKEND_API.md +18 -0
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +6 -0
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +10 -2
  7. package/skills/wix-app/references/DASHBOARD_PAGE.md +32 -70
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +74 -83
  9. package/skills/wix-app/references/SITE_PLUGIN.md +12 -0
  10. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
  11. package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
  12. package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
  13. package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
  14. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
  15. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +12 -11
  16. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +1 -0
  17. package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
  18. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +16 -8
  19. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +47 -14
  20. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +3 -0
  21. package/skills/wix-base44-connector/SKILL.md +133 -44
  22. package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
  23. package/skills/wix-base44-connector/scripts/utils.js +216 -30
  24. package/skills/wix-headless/entry/skill.md +1 -1
  25. package/skills/wix-headless/references/CAPABILITIES.md +9 -1
  26. package/skills/wix-headless/references/DESIGN.md +1 -0
  27. package/skills/wix-headless/references/DISCOVERY.md +2 -1
  28. package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
  29. package/skills/wix-headless/references/SDK_HANDOFF.md +4 -1
  30. package/skills/wix-headless/references/SEED.md +2 -1
  31. package/skills/wix-headless/references/SETUP.md +1 -0
  32. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
  33. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +26 -8
  34. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
  35. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
  36. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
  37. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
  38. package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
  39. package/skills/wix-headless/references/inline-recipes/setup-forms.md +57 -10
  40. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
  41. package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
  42. package/skills/wix-headless/references/non-astro.md +1 -1
  43. package/skills/wix-headless-fast/SKILL.md +166 -0
  44. package/skills/wix-headless-fast/entry/skill.md +99 -0
  45. package/skills/wix-headless-fast/install/deploy.mjs +433 -0
  46. package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
  47. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
  48. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
  49. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
  50. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
  51. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
  52. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
  53. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
  54. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
  55. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
  56. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
  57. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
  58. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
  59. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
  60. package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
  61. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
  62. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
  63. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
  64. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
  65. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
  66. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
  67. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
  68. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
  69. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
  70. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
  71. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
  72. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
  73. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
  74. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
  75. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
  76. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
  77. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
  78. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
  79. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
  80. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
  81. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
  82. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
  83. package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
  84. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
  85. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
  86. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
  87. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
  88. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
  89. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
  90. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
  91. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
  92. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
  93. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
  94. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
  95. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
  96. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
  97. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
  98. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
  99. package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
  100. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
  101. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
  102. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
  103. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
  104. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
  105. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
  106. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
  107. package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
  108. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
  109. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
  110. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
  111. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
  112. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
  113. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
  114. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
  115. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
  116. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
  117. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
  118. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
  119. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
  120. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
  121. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
  122. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
  123. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
  124. package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
  125. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
  126. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
  127. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
  128. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
  129. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
  130. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
  131. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
  132. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
  133. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
  134. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
  135. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
  136. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
  137. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
  138. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
  139. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
  140. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
  141. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
  142. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
  143. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
  144. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
  145. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
  146. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
  147. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
  148. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
  149. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
  150. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
  151. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
  152. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
  153. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
  154. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
  155. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
  156. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
  157. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
  158. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
  159. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
  160. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
  161. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
  162. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
  163. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
  164. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
  165. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
  166. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
  167. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
  168. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
  169. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
  170. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
  171. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
  172. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
  173. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
  174. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
  175. package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
  176. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
  177. package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
  178. package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
  179. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
  180. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
  181. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
  182. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
  183. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
  184. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
  185. package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
  186. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
  187. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
  188. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
  189. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
  190. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
  191. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
  192. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
  193. package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
  194. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
  195. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
  196. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
  197. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
  198. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
  199. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
  200. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
  201. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
  202. package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
  203. package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
  204. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
  205. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
  206. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
  207. package/skills/wix-manage/SKILL.md +113 -89
  208. package/skills/wix-manage/references/dashboard-navigation/routes.json +12 -52
  209. package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-api.md +0 -2
  210. package/skills/wix-manage/references/forms/create-form.md +272 -184
  211. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +13 -10
  212. package/skills/wix-manage/references/forms/update-form.md +122 -0
  213. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
  214. package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
  215. package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
  216. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
  217. package/skills/wix-manage/references/media/generate-image-with-ai.md +86 -0
  218. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +37 -7
  219. package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
  220. package/skills/wix-vibe-headless/SKILL.md +18 -4
  221. package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
  222. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
  223. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +3 -1
  224. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +3 -1
  225. package/skills/wix-vibe-headless/platforms/base44.md +27 -61
  226. package/skills/wix-vibe-headless/platforms/generic.md +6 -3
  227. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +43 -0
  228. package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
  229. package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
  230. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
  231. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
  232. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
  233. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
  234. package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
  235. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
  236. package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +486 -0
  237. package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
  238. package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
  239. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
  240. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
  241. package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1836 -0
  242. package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
  243. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +137 -84
  244. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
  245. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
  246. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
  247. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
  248. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
  249. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
  250. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
  251. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
  252. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
  253. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
@@ -0,0 +1,26 @@
1
+ # Design floor — every vertical, every surface you author
2
+
3
+ **A fallback, not an override.** These rules fill the gap when the user gave no design
4
+ direction. The moment the brief specifies a palette, a mood, a reference — their intent wins.
5
+ Two exceptions that hold regardless: the contrast floor (in `styles/global.css`, where you
6
+ choose the tokens), and the anti-genericism intent — derive the look from *this* brand even
7
+ when the user supplied the inputs.
8
+
9
+ Token judgment (polarity, palette, contrast, type floors) lives in the `@theme` header in
10
+ `styles/global.css` — you'll meet it when you set the tokens. This file governs the surfaces:
11
+
12
+ - **Full-bleed, not boxed.** Don't wrap pages in a narrow centered shell (`max-w-4xl mx-auto`
13
+ around everything). Design for the viewport; use peripheral space intentionally.
14
+ - **One primary CTA per page**, worded to the page's actual action — "Add to Cart",
15
+ "Book a Table", "Reserve Your Spot" — never "Submit" / "Click here" / "Learn more" as the
16
+ hero action.
17
+ - **Icons render bare on the surface** — no circle/square/pill shell behind nav or card
18
+ glyphs.
19
+ - **No emojis** in UI copy, headings, or empty states (unless the brief itself asks for
20
+ them).
21
+ - **Vary the look across projects.** Repeating the same palette/layout on unrelated brands is
22
+ a failure mode, not a shortcut — two sites with the same vertical and different briefs
23
+ should look nothing alike.
24
+
25
+ This constrains the *how*, not the *what* — the brief and the vertical decide what the pages
26
+ are; INSTRUCTIONS decides which surfaces exist.
@@ -0,0 +1,52 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Wix+Madefor+Text:wght@400;500;600;700;800&display=swap');
2
+ @import 'tailwindcss';
3
+
4
+ /* ─── THE design system ─────────────────────────────────────────────────────────────────
5
+ Theme the entire store by editing THIS @theme block (same token family as the official
6
+ Wix headless templates). Every shipped component styles itself from these via Tailwind
7
+ utilities (bg-primary, text-muted-foreground, rounded-lg, …) — change a token, everything
8
+ follows. A dark theme is just flipped values (dark background/foreground, adjusted
9
+ secondary/border). Don't restyle shipped component markup; restyle the tokens.
10
+
11
+ Choosing values: argue polarity from the business — light is not "cheap" (wellness/food
12
+ usually read better light); never dark-by-default for "premium". Palette: one dominant +
13
+ accents from ADJACENT hues (~30° arc), 2-4 colors total. Every background/foreground pair
14
+ you set must hit WCAG 4.5:1 (3:1 for text ≥24px); body copy never below 16px/1.5. Derive
15
+ from THIS brand — a look repeated across projects is a failure, not a shortcut. The user's
16
+ explicit direction beats all of this except the contrast floor. */
17
+ @theme {
18
+ --color-background: hsl(0 0% 100%);
19
+ --color-foreground: hsl(230 24% 14%);
20
+ --color-primary: hsl(230 24% 14%);
21
+ --color-primary-foreground: hsl(0 0% 100%);
22
+ --color-secondary: hsl(228 24% 96%);
23
+ --color-secondary-foreground: hsl(230 24% 14%);
24
+ --color-muted-foreground: hsl(228 8% 46%);
25
+ --color-border: hsl(220 14% 90%);
26
+
27
+ --radius-lg: 12px;
28
+ --radius-md: 8px;
29
+ --radius-sm: 6px;
30
+
31
+ --font-sans: 'Wix Madefor Text', system-ui, sans-serif;
32
+ }
33
+
34
+ @layer base {
35
+ body {
36
+ background-color: var(--color-background);
37
+ color: var(--color-foreground);
38
+ font-family: var(--font-sans);
39
+ -webkit-font-smoothing: antialiased;
40
+ font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
41
+ }
42
+ }
43
+
44
+ @layer utilities {
45
+ .eyebrow {
46
+ font-size: 0.8125rem;
47
+ font-weight: 600;
48
+ letter-spacing: 0.1em;
49
+ text-transform: uppercase;
50
+ color: var(--color-muted-foreground);
51
+ }
52
+ }
@@ -0,0 +1,15 @@
1
+ // Wix connection config — written by the skill's deploy step (install/deploy.mjs).
2
+ //
3
+ // WIX_CLIENT_ID = null → ambient auth (a Wix-managed Astro project: `@wix/astro` authenticates
4
+ // every SDK call automatically; there is no client and nothing to set).
5
+ // WIX_CLIENT_ID = "..." → manual visitor client (any other React setup): the public OAuth client id.
6
+ // It is NOT a secret — it only mints anonymous visitor tokens — so
7
+ // hardcoding and committing it is fine. On a Wix-managed non-Astro project
8
+ // it equals the `appId` in wix.config.json.
9
+ export const WIX_CLIENT_ID: string | null = null;
10
+
11
+ // The Members vertical uses an explicit OAuthStrategy client only to drive the
12
+ // custom credential form. In managed Astro it writes the resulting member
13
+ // tokens into Astro's wixSession cookie, so subsequent ambient SDK calls use
14
+ // that same member identity.
15
+ export const WIX_MEMBERS_CLIENT_ID: string | null = null;
@@ -0,0 +1,27 @@
1
+ // Wix media resolution — define once, use on EVERY image render path. Copy as-is.
2
+ //
3
+ // SDK media fields come back either as an already-absolute https URL, or as a
4
+ // `wix:image://v1/<hash>/<file>#originWidth=…` identifier that a browser cannot load
5
+ // (ERR_UNKNOWN_URL_SCHEME). The wix:image:// form must go through the SDK media module;
6
+ // never hand-build a static.wixstatic.com URL (wrong format → 403).
7
+ // docs: https://dev.wix.com/docs/sdk/core-modules/sdk/media.md
8
+ import { media } from "@wix/sdk";
9
+
10
+ type MediaLike =
11
+ | string
12
+ | null
13
+ | undefined
14
+ | { image?: string | null; url?: string | null };
15
+
16
+ /** Resolve any Wix media value to a browser-loadable URL ("" when absent). */
17
+ export function imgSrc(value: MediaLike, width = 600, height = 600): string {
18
+ const v =
19
+ typeof value === "object" && value !== null
20
+ ? (value.image ?? value.url ?? "")
21
+ : (value ?? "");
22
+ if (!v) return "";
23
+ if (typeof v === "string" && v.startsWith("wix:image://")) {
24
+ return media.getScaledToFillImageUrl(v, width, height, {});
25
+ }
26
+ return typeof v === "string" ? v : "";
27
+ }
@@ -0,0 +1,24 @@
1
+ // Money formatting for API amounts that carry no formatted string. Copy as-is.
2
+ //
3
+ // Catalog prices come with a ready `formattedAmount` — use that directly. But eCom Cart V2
4
+ // amounts are ConvertedMoney `{ amount, convertedAmount }` with NO formatted string, and the
5
+ // currency lives on the cart, not on the money object. Never hardcode "$" or assume USD.
6
+ export interface ConvertedMoneyLike {
7
+ amount?: string | null;
8
+ convertedAmount?: string | null;
9
+ }
10
+
11
+ /** Format a ConvertedMoney in the given currency, using the visitor's locale. */
12
+ export function formatMoney(
13
+ money: ConvertedMoneyLike | null | undefined,
14
+ currencyCode: string | null | undefined,
15
+ ): string {
16
+ const value = money?.convertedAmount ?? money?.amount;
17
+ if (value == null || value === "") return "";
18
+ const currency = currencyCode || "USD";
19
+ try {
20
+ return new Intl.NumberFormat(undefined, { style: "currency", currency }).format(Number(value));
21
+ } catch {
22
+ return `${value} ${currency}`;
23
+ }
24
+ }
@@ -0,0 +1,76 @@
1
+ // The one auth seam for every Wix SDK call in this app. Copy as-is; do not rewrite.
2
+ //
3
+ // Two modes, switched by WIX_CLIENT_ID in ./config:
4
+ // null (ambient) — a Wix-managed Astro project: `@wix/astro` authenticates raw SDK module
5
+ // calls automatically, server-side AND in client islands. `wixModule()`
6
+ // returns the module untouched.
7
+ // string (manual) — any other React setup (Vite SPA, non-Astro): one shared client is built
8
+ // with OAuthStrategy, and `wixModule()` returns the module bound to it.
9
+ // The strategy self-manages visitor tokens on every call (mints on first
10
+ // use, renews on expiry) and persists them through the storage below.
11
+ //
12
+ // The visitor token IS the identity of the current cart / member session, so in manual mode
13
+ // tokens persist to localStorage — never re-minted per load (a fresh anonymous mint is a NEW
14
+ // visitor and silently empties the cart).
15
+ // docs: https://dev.wix.com/docs/sdk/core-modules/sdk/oauth-strategy.md
16
+ // docs: https://dev.wix.com/docs/go-headless/wix-managed-headless/authentication/about-the-astro-integration.md
17
+ import { createClient, OAuthStrategy, EMPTY_TOKENS } from "@wix/sdk";
18
+ import type { IOAuthStrategy, TokenStorage, Tokens } from "@wix/sdk";
19
+ import { WIX_CLIENT_ID } from "./config";
20
+
21
+ const STORAGE_KEY = `wix-session-${WIX_CLIENT_ID ?? "ambient"}`;
22
+
23
+ function browserTokenStorage(): TokenStorage {
24
+ return {
25
+ getTokens(): Tokens {
26
+ if (typeof window !== "undefined") {
27
+ try {
28
+ const raw = window.localStorage.getItem(STORAGE_KEY);
29
+ if (raw) return JSON.parse(raw) as Tokens;
30
+ } catch {
31
+ /* disabled/corrupt storage — fall through to empty */
32
+ }
33
+ }
34
+ return EMPTY_TOKENS;
35
+ },
36
+ setTokens(tokens: Tokens): void {
37
+ if (typeof window === "undefined") return;
38
+ try {
39
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(tokens));
40
+ } catch {
41
+ /* storage full/disabled — the session just won't survive a reload */
42
+ }
43
+ },
44
+ };
45
+ }
46
+
47
+ const client = WIX_CLIENT_ID
48
+ ? createClient({
49
+ auth: OAuthStrategy({
50
+ clientId: WIX_CLIENT_ID,
51
+ tokenStorage: browserTokenStorage(),
52
+ }),
53
+ })
54
+ : null;
55
+
56
+ /**
57
+ * Bind an SDK module to this app's auth. Usage (identical in both modes):
58
+ * import { productsV3 } from "@wix/stores";
59
+ * const products = wixModule(productsV3);
60
+ * await products.queryProducts(...)
61
+ */
62
+ export function wixModule<T>(module: T): T {
63
+ // The cast bridges the SDK's internal Descriptors constraint; the in/out type is identical.
64
+ return client
65
+ ? (client.use(module as unknown as Record<string, unknown>) as unknown as T)
66
+ : module;
67
+ }
68
+
69
+ /**
70
+ * The shared data client's manual-mode auth strategy, or null under ambient auth. The
71
+ * Members vertical deliberately owns a separate explicit client for its custom in-app login;
72
+ * app code reads that session through the members hooks instead.
73
+ */
74
+ export function wixAuth(): IOAuthStrategy | null {
75
+ return client ? client.auth : null;
76
+ }
@@ -0,0 +1,46 @@
1
+ // Safe browser half of the optional Media Upload capability.
2
+ // The browser supplies bytes only. It cannot choose a destination or elevate a Wix call:
3
+ // the named policy is enforced by /api/wix/media-upload on the server.
4
+
5
+ export type UploadedMedia = {
6
+ id: string;
7
+ url?: string;
8
+ uploadUrl: string;
9
+ };
10
+
11
+ type UploadPolicyRequest = {
12
+ policyId: string;
13
+ fileName: string;
14
+ mimeType: string;
15
+ sizeInBytes: number;
16
+ };
17
+
18
+ export async function uploadMedia(policyId: string, file: File | Blob, fileName?: string): Promise<UploadedMedia> {
19
+ const mimeType = file.type;
20
+ const request: UploadPolicyRequest = {
21
+ policyId,
22
+ fileName: fileName ?? (file instanceof File ? file.name : "upload"),
23
+ mimeType,
24
+ sizeInBytes: file.size,
25
+ };
26
+ const ticket = await fetch("/api/wix/media-upload", {
27
+ method: "POST",
28
+ headers: { "Content-Type": "application/json" },
29
+ body: JSON.stringify(request),
30
+ });
31
+ if (!ticket.ok) throw new Error(`Upload could not be authorized (${ticket.status})`);
32
+ const { uploadUrl } = (await ticket.json()) as UploadedMedia;
33
+
34
+ const uploaded = await fetch(uploadUrl, {
35
+ method: "PUT",
36
+ headers: { "Content-Type": mimeType },
37
+ body: file,
38
+ });
39
+ const payload = (await uploaded.json().catch(() => null)) as
40
+ | { file?: { id?: string; url?: string }; id?: string; url?: string }
41
+ | null;
42
+ const media = payload?.file ?? payload;
43
+ if (!uploaded.ok || !media?.id) throw new Error(`Upload failed (${uploaded.status})`);
44
+
45
+ return { id: media.id, url: media.url, uploadUrl };
46
+ }
@@ -0,0 +1,46 @@
1
+ import type { APIRoute } from "astro";
2
+ import { auth } from "@wix/essentials";
3
+ import { files } from "@wix/media";
4
+ import { mediaUploadPolicies } from "../../../wix/media-upload/policies.generated";
5
+
6
+ const elevatedGenerateUploadUrl = auth.elevate(files.generateFileUploadUrl);
7
+
8
+ type UploadRequest = {
9
+ policyId?: unknown;
10
+ fileName?: unknown;
11
+ mimeType?: unknown;
12
+ sizeInBytes?: unknown;
13
+ };
14
+
15
+ const json = (body: unknown, status = 200) =>
16
+ new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json" } });
17
+
18
+ export const POST: APIRoute = async ({ request }) => {
19
+ let body: UploadRequest;
20
+ try {
21
+ body = (await request.json()) as UploadRequest;
22
+ } catch {
23
+ return json({ error: "Expected JSON" }, 400);
24
+ }
25
+
26
+ if (
27
+ typeof body.policyId !== "string" ||
28
+ typeof body.fileName !== "string" ||
29
+ typeof body.mimeType !== "string" ||
30
+ typeof body.sizeInBytes !== "number" ||
31
+ !Number.isSafeInteger(body.sizeInBytes)
32
+ ) {
33
+ return json({ error: "Invalid upload request" }, 400);
34
+ }
35
+ const policy = mediaUploadPolicies.find((candidate) => candidate.id === body.policyId);
36
+ if (!policy) return json({ error: "Unknown upload policy" }, 404);
37
+ if (!policy.accept.includes(body.mimeType as never)) return json({ error: "File type is not allowed" }, 415);
38
+ if (body.sizeInBytes < 1 || body.sizeInBytes > policy.maxBytes) return json({ error: "File exceeds this policy's size limit" }, 413);
39
+
40
+ // Do not accept a folder id, labels, privacy setting, or any other destination choice from
41
+ // the browser. Add those as fixed policy fields only after the product actually needs them.
42
+ const result = await elevatedGenerateUploadUrl(body.mimeType, {
43
+ fileName: body.fileName.slice(0, 255),
44
+ });
45
+ return json({ uploadUrl: result.uploadUrl });
46
+ };
@@ -0,0 +1,145 @@
1
+ // Shared seed util: entity images by URL or by AI GENERATION (Wix AI / Runware via the
2
+ // wixapis proxy). BUILD-TIME only — imported by the vertical seed scripts, never shipped.
3
+ //
4
+ // The contract every seed relies on:
5
+ // - RESILIENT: nothing here ever throws out of resolveItemImages — a failed image resolves
6
+ // to null and the entity stays text-only; the seed's exit code never depends on images.
7
+ // - PARALLEL: all images resolve in one concurrent wave (each generation is its own
8
+ // single-task request — the google model 504s when one body bundles ≥3 tasks).
9
+ // - PASS-2: seeds create entities first, then attach what this returns — an image is never
10
+ // a precondition for an entity.
11
+ //
12
+ // Generation costs 1 Wix AI credit per image, billed to the account behind the site.
13
+ // Authoritative reference: wix-headless/references/IMAGE_GENERATION.md.
14
+ import { randomUUID } from "node:crypto";
15
+ import { readFileSync } from "node:fs";
16
+ import { basename, extname } from "node:path";
17
+
18
+ const API = "https://www.wixapis.com";
19
+ // Order = cheap-and-permissive first (runware ~0.009 credits/img, ~5s, loosest content
20
+ // filter), then google (best fidelity, ~0.14, ~25s; rejects steps/CFGScale and free-form
21
+ // sizes), then bfl (strictest filter — refuses trademark-ish prompts). A refusal or failure
22
+ // falls through to the next model.
23
+ const MODELS = ["runware:400@1", "google:4@2", "bfl:5@1"];
24
+ /** Allowed dimensions: 1024×1024 (square — entities), 1376×768 (16:9 hero), 1200×896 (4:3). */
25
+ export const IMAGE_SIZES = { square: [1024, 1024], hero: [1376, 768], editorial: [1200, 896] };
26
+
27
+ async function req(ctx, path, body, timeoutMs = 45_000) {
28
+ const res = await fetch(API + path, {
29
+ method: "POST",
30
+ headers: {
31
+ Authorization: `Bearer ${ctx.token}`,
32
+ "wix-site-id": ctx.siteId,
33
+ "Content-Type": "application/json",
34
+ },
35
+ body: JSON.stringify(body),
36
+ signal: AbortSignal.timeout(timeoutMs),
37
+ });
38
+ const json = await res.json().catch(() => ({}));
39
+ if (!res.ok) throw new Error(`POST ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 300)}`);
40
+ return json;
41
+ }
42
+
43
+ /**
44
+ * Generate one image; returns its short-lived URL (import it immediately). Tries each model
45
+ * once — a per-model failure (bad params, 5xx, credit exhaustion, timeout) falls through to
46
+ * the next; throws only after all models failed.
47
+ * docs: no public reference for /runwareschemaless/v1/request — see wix-headless/references/IMAGE_GENERATION.md
48
+ */
49
+ export async function generateImage(ctx, prompt, { width = 1024, height = 1024 } = {}) {
50
+ let lastErr;
51
+ for (const model of MODELS) {
52
+ try {
53
+ const r = await req(ctx, "/runwareschemaless/v1/request", [
54
+ {
55
+ taskType: "imageInference",
56
+ taskUUID: randomUUID(), // must be a real UUIDv4 — slugs 400
57
+ outputType: "URL",
58
+ outputFormat: "PNG",
59
+ positivePrompt: prompt,
60
+ width,
61
+ height,
62
+ model,
63
+ numberResults: 1,
64
+ },
65
+ ]);
66
+ const url = r?.data?.[0]?.imageURL;
67
+ if (url) return url;
68
+ lastErr = new Error(`no imageURL in response: ${JSON.stringify(r).slice(0, 200)}`);
69
+ } catch (e) {
70
+ lastErr = e;
71
+ }
72
+ }
73
+ throw lastErr;
74
+ }
75
+
76
+ const MIME = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".webp": "image/webp", ".gif": "image/gif", ".avif": "image/avif" };
77
+
78
+ /**
79
+ * Upload a LOCAL file (a path on this machine — the user's own asset) into Wix Media;
80
+ * returns { id, url } (permanent). Two steps per the Upload API: generate-upload-url, then
81
+ * PUT the bytes to it — the PUT response carries the file descriptor.
82
+ * docs: https://dev.wix.com/docs/api-reference/assets/media/media-manager/files/generate-file-upload-url.md
83
+ */
84
+ export async function uploadImage(ctx, path, displayName) {
85
+ const ext = extname(path).toLowerCase();
86
+ const mimeType = MIME[ext];
87
+ if (!mimeType) throw new Error(`unsupported image extension: ${path}`);
88
+ const bytes = readFileSync(path); // throws loud on a wrong path (caught per-item by resolveItemImages)
89
+ // fileName's extension MUST match the real file type — a mismatch (slug.png for a .jpg) is
90
+ // rejected; keep the caller's display name, swap in the file's own extension.
91
+ const fileName = (displayName ?? basename(path)).replace(/\.[a-z0-9]+$/i, "") + ext;
92
+ const { uploadUrl } = await req(ctx, "/site-media/v1/files/generate-upload-url", {
93
+ mimeType,
94
+ fileName,
95
+ });
96
+ const res = await fetch(uploadUrl, {
97
+ method: "PUT",
98
+ headers: { "Content-Type": mimeType },
99
+ body: bytes,
100
+ signal: AbortSignal.timeout(120_000),
101
+ });
102
+ const json = await res.json().catch(() => ({}));
103
+ const f = json.file || json;
104
+ if (!res.ok || !f?.id) throw new Error(`upload failed (${res.status}): ${JSON.stringify(json).slice(0, 200)}`);
105
+ return { id: f.id, url: f.url };
106
+ }
107
+
108
+ /** Import an external/generated URL into Wix Media; returns { id, url } (permanent). */
109
+ // docs: https://dev.wix.com/docs/api-reference/assets/media/media-manager/files/import-file.md
110
+ export async function importImage(ctx, url, displayName = "image.png") {
111
+ const r = await req(ctx, "/site-media/v1/files/import", { url, mimeType: "image/png", displayName });
112
+ const f = r.file || r;
113
+ if (!f?.id) throw new Error(`import-file returned no file id: ${JSON.stringify(r).slice(0, 200)}`);
114
+ return { id: f.id, url: f.url };
115
+ }
116
+
117
+ /**
118
+ * THE seed entry point. Resolves a batch of image specs to Wix Media files in ONE parallel
119
+ * wave. Each spec: { path } (LOCAL file — the user's own asset, uploaded) OR { url }
120
+ * (verified external URL — imported) OR { prompt } (generated, ~1 credit) — plus optional
121
+ * displayName, width, height. Returns an array aligned with the input: { id, url } per
122
+ * success, null per failure or empty spec. Never throws.
123
+ */
124
+ export async function resolveItemImages(ctx, specs, { perImageBudgetMs = 120_000 } = {}) {
125
+ // unref: the budget timer must never keep the seed process alive after the work is done —
126
+ // a lingering timer delays the seed's exit (and the run's .seed-exit marker) by the budget.
127
+ const deadline = new Promise((r) => {
128
+ const t = setTimeout(() => r(null), perImageBudgetMs);
129
+ t.unref?.();
130
+ });
131
+ const results = await Promise.allSettled(
132
+ (specs ?? []).map(async (s) => {
133
+ if (!s || (!s.path && !s.url && !s.prompt)) return null;
134
+ const resolve = (async () => {
135
+ if (s.path) return uploadImage(ctx, s.path, s.displayName);
136
+ const source = s.url ?? (await generateImage(ctx, s.prompt, { width: s.width, height: s.height }));
137
+ return importImage(ctx, source, s.displayName ?? "image.png");
138
+ })();
139
+ // Hard per-image budget: even a pathological multi-model hang costs the seed at most
140
+ // perImageBudgetMs of wall clock (the wave is parallel, so it's paid once, not per item).
141
+ return Promise.race([resolve, deadline]);
142
+ }),
143
+ );
144
+ return results.map((r) => (r.status === "fulfilled" ? r.value : null));
145
+ }
@@ -0,0 +1,149 @@
1
+ # Storefront — playbook
2
+
3
+ The commerce machinery ships as files — data layer, hooks, cart, checkout, SEO plumbing,
4
+ typed end-to-end. **The presentation is yours**: you design and implement the product card,
5
+ the grid, and the PDP surface on the shipped hooks/DTOs, plus the home page and the brand.
6
+ You never write commerce code; you never skip designing the store.
7
+
8
+ ## The file map (deployed into `src/`)
9
+
10
+ **Don't read the shipped files** — this table and the contracts below are everything you
11
+ need. Open a shipped file's source **only** on a real fallback: a runtime error, a field this
12
+ playbook doesn't cover, or when a *reference* component's pattern is explicitly worth reading
13
+ (marked below). Files you edit: `SiteLayout.astro`, `styles/global.css`, and the two page
14
+ imports you swap to your own components.
15
+
16
+ | file | what it is |
17
+ |---|---|
18
+ | `wix/config.ts` · `wix/sdk.ts` | shared auth seam (deploy configures it — nothing to set by hand) |
19
+ | `wix/media.ts` · `wix/money.ts` | `imgSrc()` / `formatMoney()` — already used by everything shipped |
20
+ | `wix/storefront/types.ts` | the DTOs (`ProductSummary`, `ProductDetail`, `Cart`, `Category`) — contracts inlined below |
21
+ | `wix/storefront/catalog.ts` | `fetchProducts`, `fetchProductsByCategory`, `fetchProductBySlug`, `fetchCategories`, `resolveVariant` |
22
+ | `wix/storefront/cart.ts` · `cart-store.ts` | Cart V2 + shared cart state (module store — spans Astro islands) |
23
+ | `hooks/storefront/useCart.ts` | cart state + actions — contract below |
24
+ | `hooks/storefront/useShop.ts` | listing + live category filter — contract below |
25
+ | `hooks/storefront/useProductDetail.ts` | option selection → variant resolution → add-to-cart — contract below |
26
+ | `components/storefront/CartButton.tsx` · `CartDrawer.tsx` | header badge + slide-over cart — **wire as-is** (drawer once per page) |
27
+ | `components/storefront/ShopView.tsx` · `ProductCard.tsx` · `ProductGrid.tsx` · `ProductDetailView.tsx` · `VariantPicker.tsx` | **REFERENCE implementations** — correct, plain, deliberately generic. Read for patterns if useful; **build your own instead of shipping them** (below) |
28
+ | `styles/global.css` | **the design system**: Tailwind v4 + the `@theme` token block (colors, radii, fonts — same token family as the official Wix templates). Everything, shipped and yours, styles from these tokens |
29
+
30
+ Astro stack additionally gets:
31
+
32
+ | file | what it is |
33
+ |---|---|
34
+ | `layouts/SiteLayout.astro` | the site chrome — **yours to brand**: header, footer, nav. Keep the `<slot name="seo-tags" />`, the global.css import, and the CartButton/CartDrawer mounts |
35
+ | `pages/shop.astro` | SSR listing page — **keep its frontmatter** (the data fetching), swap the island import to YOUR shop component |
36
+ | `pages/products/[slug].astro` | SSR PDP with owner-editable SEO — **keep its frontmatter and the SEO pieces** (`wixMetadata`, `loadSEOTagsServiceConfig`, `<SEO.Tags>`) exactly, swap the island import to YOUR detail component |
37
+
38
+ ## What you build — this is the design job, not optional polish
39
+
40
+ You implement **four surfaces yourself**, styled with Tailwind utilities on the `@theme`
41
+ tokens, designed to fit the brief (the business, the tone, the audience — a toy brand and a
42
+ jewelry house should not get the same store):
43
+
44
+ 1. **The product card + grid** — your tile design (image treatment, badges, price/sale
45
+ presentation, hover behavior) and your grid rhythm (columns, density, maybe an editorial
46
+ featured tile). Keep skeleton-while-loading and an honest empty state (the reference
47
+ `ProductGrid` shows the pattern — `products === null` → skeletons, `[]` → empty message).
48
+ 2. **The shop surface** — category filter + your grid, on `useShop`.
49
+ 3. **The PDP surface** — gallery, price/sale, description, your option-selection UI (color
50
+ options = real swatches), quantity, add-to-cart — on `useProductDetail`, which owns ALL
51
+ selection/variant logic; you own how it looks.
52
+ 4. **The home page** — hero, featured products (fetch in frontmatter → your grid), brand story.
53
+
54
+ Plus the **theme** (edit the `@theme` block in `styles/global.css` — one edit; a dark brand is
55
+ flipped token values; add brand fonts as extra tokens) and the **chrome** (header/footer in
56
+ `SiteLayout.astro`, one edit pass; mount the shipped `CartButton` in your header).
57
+
58
+ ### The contracts your components consume (everything you need — don't read the source)
59
+
60
+ ```ts
61
+ // ProductSummary (grid tiles) — all display-ready: prices formatted, images https URLs:
62
+ // { id, slug, name, price, maxPrice, compareAtPrice|null, ribbon|null,
63
+ // availability: "IN_STOCK"|"OUT_OF_STOCK"|"PARTIALLY_OUT_OF_STOCK", preorder: boolean,
64
+ // imageUrl, hoverImageUrl, optionsSummary /* "2 colors · 3 sizes" */, quickAddable: boolean }
65
+ // price vs maxPrice differ → show a range. quickAddable → useCart().addToCart(product.id).
66
+
67
+ // useShop({ initialProducts?, initialCategories? }) →
68
+ // { products: ProductSummary[]|null /* null = loading → skeletons */, categories: Category[],
69
+ // activeCategoryId: string|null, setActiveCategoryId(id|null), loading, error }
70
+ // Category = { id, slug, name }. Render the filter bar only when categories.length > 1.
71
+
72
+ // useProductDetail({ initial? /* SSR */, slug? /* SPA */ }) →
73
+ // { product: ProductDetail|null, notFound,
74
+ // optionGroups: [{ id, name, isColor, choices: [{ choiceId, name, colorCode|null, inStock, selected }] }],
75
+ // selectOption(optionName, choiceName),
76
+ // modifierValues, setModifier(key, value), // product.modifiers: pills or text input; "*" = mandatory
77
+ // price, compareAtPrice, // live: variant price once resolved
78
+ // canAdd, // gate the button; false until every option picked & in stock
79
+ // quantity, setQuantity, add(), adding, error }
80
+ // ProductDetail adds: descriptionHtml (render as HTML), gallery: string[] (urls, main first),
81
+ // options, modifiers, variants — but selection ALWAYS goes through the hook above.
82
+
83
+ // useCart() →
84
+ // { cart: { lines, itemCount, subtotal, currency }|null, busy, error, open,
85
+ // addToCart(productId, variantId?, qty?, extras?), updateQuantity(lineItemId, qty),
86
+ // removeLine(lineItemId), checkout(), openCart(), closeCart(), refresh() }
87
+ ```
88
+
89
+ ### Wiring — Astro (default)
90
+
91
+ 1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass).
92
+ 2. Write your components under `src/components/storefront/` (new file names — don't overwrite
93
+ the references), then **swap the island import** in `pages/shop.astro` and
94
+ `pages/products/[slug].astro` to yours — keep each page's frontmatter (data fetching, SEO
95
+ pieces) exactly as shipped. Primary-content islands mount `client:load` with the SSR props;
96
+ browser-state widgets (cart) are `client:only="react"` — the shipped mounts show this.
97
+ 3. Write `pages/index.astro` (home) on `SiteLayout`.
98
+
99
+ ### Wiring — React SPA (Vite etc.)
100
+
101
+ Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
102
+ config plugins — deploy already added the dep). Write route wrappers in the project's router:
103
+ `/shop` → your shop component; `/products/:slug` → your detail component
104
+ (`useProductDetail({ slug })` — components fetch client-side when no `initial` is passed).
105
+ Mount the shipped `CartButton` in the header and `CartDrawer` once. Deploy wrote the public
106
+ client id into `wix/config.ts`; nothing else to configure.
107
+
108
+ ## Hard rules
109
+
110
+ - **Data and commerce logic only through the shipped exports** — never rewrite their
111
+ internals or re-derive a request shape. Extend by calling the exports or adding a new
112
+ function in `wix/storefront/` for a genuine gap (API contracts: the `wix-docs` skill).
113
+ - **Selection→cart goes through `useProductDetail`** — never add a product with options by
114
+ picking `variants[0]`, and never gate `canAdd` yourself.
115
+ - Don't wrap shipped calls in your own API routes — they run client-side by design.
116
+ - Theme via the `@theme` tokens; your markup uses Tailwind utilities on the same tokens. No
117
+ parallel theme files, no hardcoded palette values in components.
118
+ - Checkout only through the shipped cart (`checkout()`) — never a hand-built checkout URL.
119
+ - Live data or an honest empty state — never mock products, prices, reviews, or counts.
120
+ - Keep the PDP page's SEO pieces (`wixMetadata` + `loadSEOTagsServiceConfig` + `<SEO.Tags>`)
121
+ exactly as shipped — owners edit those tags in their dashboard.
122
+
123
+ ## Point the user to their dashboard
124
+
125
+ Give the owner the dashboard, products, and categories links — **the deploy step's JSON
126
+ output already printed them ready-made** (`dashboardUrl`, `productsUrl`, `categoriesUrl`);
127
+ copy, don't re-derive. Real payments additionally need a premium plan + a connected payment
128
+ method (dashboard) — mention it, don't treat it as a code failure.
129
+
130
+ ## Seeding
131
+
132
+ Per `seed/SEED.md` — a plain-data `plan.json` into `seed-store.mjs`, run from the project
133
+ root. Independent of the frontend work; seed a catalog that exercises the UI (≥1 product with
134
+ a color option, ≥1 on sale, an image per product) unless the brief says otherwise.
135
+
136
+ ## Verify (before declaring done)
137
+
138
+ - [ ] `/shop` renders live products SSR (view-source shows product names) through **your**
139
+ grid/card; category bar filters when categories exist; empty catalog shows your honest
140
+ empty state.
141
+ - [ ] Your PDP: color options render as swatches, add is disabled until every option is
142
+ picked (`canAdd`), the resolved variant's price shows, a sale shows the strikethrough.
143
+ - [ ] Cart: add / quantity ± / remove work; badge count is live; subtotal shows; cart survives
144
+ a reload (same visitor token).
145
+ - [ ] Checkout button redirects to Wix-hosted checkout.
146
+ - [ ] PDP view-source carries the SEO tags (Astro).
147
+ - [ ] Card/grid/PDP/home are YOUR designs on the tokens — not the shipped references; the
148
+ data-layer/hook/cart files are unedited.
149
+ - [ ] Dashboard links handed to the owner.
@@ -0,0 +1,26 @@
1
+ // Header cart icon with a live count badge — mount once in your header, as-is.
2
+ // Opens the CartDrawer (mount that once too, anywhere in the page).
3
+ import { useCart } from "../../hooks/storefront/useCart";
4
+
5
+ export default function CartButton() {
6
+ const { itemCount, openCart } = useCart();
7
+ return (
8
+ <button
9
+ type="button"
10
+ aria-label={`Cart, ${itemCount} items`}
11
+ onClick={openCart}
12
+ className="relative inline-flex items-center p-1.5 text-foreground transition-opacity hover:opacity-70"
13
+ >
14
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
15
+ <path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z" />
16
+ <line x1="3" y1="6" x2="21" y2="6" />
17
+ <path d="M16 10a4 4 0 01-8 0" />
18
+ </svg>
19
+ {itemCount > 0 && (
20
+ <span className="absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1 text-[10px] font-bold text-primary-foreground">
21
+ {itemCount}
22
+ </span>
23
+ )}
24
+ </button>
25
+ );
26
+ }