@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,13 @@
1
+ ---
2
+ name: rentals
3
+ description: Rentals — renting out an item for a length the customer picks. Runs on the Bookings vertical.
4
+ ---
5
+
6
+ # Rentals
7
+
8
+ Rentals is **the Bookings vertical** — Wix Rentals runs on the Bookings APIs. There is nothing
9
+ separate to build here.
10
+
11
+ Read and follow `.agents/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md` (its
12
+ **Rentals** section), and use the bookings scaffolds under `references/bookings/app/`. The install
13
+ already deploys those for you when `rentals` is selected.
@@ -1,10 +1,15 @@
1
1
  # Wix Storefront — ready-made client
2
2
 
3
- The storefront client is **shipped as real files**, not snippets to regenerate. It's a complete
4
- catalog + PDP + server-cart + checkout, styled with your app's design tokens (base44's
5
- `src/index.css` — the shadcn palette the design phase already set). Copy it into the app and wire
6
- the routes — you generate almost none of the commerce code (variant resolution, modifiers, stock
7
- gating, the server cart all ship and are correct).
3
+ The storefront **commerce engine ships as real files** — the hooks, the server cart, the REST
4
+ transport, the image helpers, and the `Shop` listing page, all correct (variant resolution,
5
+ modifiers, stock gating, checkout). It reads from your app's design tokens (base44's `src/index.css`
6
+ — the shadcn palette the design phase already set).
7
+
8
+ **The presentation doesn't ship — you build it** (STEP 3): the product **card**, **grid**, **variant
9
+ controls**, and the whole **product (PDP) page**, plus **Home** and the **header/footer**. Each is
10
+ built on a shipped hook whose return type + field shapes are documented in the outline right next to
11
+ it — the data is handed to you done, the layout and look are yours. `Shop` renders once your
12
+ `ProductGrid` exists; the PDP renders once you build its page — that's the point.
8
13
 
9
14
  Talks to Wix directly over the public `WIX_CLIENT_ID` (anonymous visitor tokens). Never mock
10
15
  products; never hand-build a `/checkout` URL — the shipped cart goes through the eCom
@@ -22,40 +27,38 @@ so you don't need to open them:**
22
27
  | file | what it is |
23
28
  |---|---|
24
29
  | `context/CartContext.jsx` | `useCart()` provider: server cart, add/update/remove, checkout |
25
- | `hooks/useProductDetail.js` | PDP data — product + variant resolution for a slug, plus load/add state |
30
+ | `hooks/useProductDetail.js` | PDP data — product + variant resolution for a slug, plus load/add state; **your product page (STEP 3) is built on it** |
26
31
  | `hooks/useShop.js` | catalog listing — category menu, cursor paging, sort, failure state |
27
- | `hooks/useProductCard.js` | headless data layer for a grid tile — returns `leftBadges`, `promoBadge`, `priceDisplay`, `compareAtDisplay`, `colors`, `optionLabel`, `isQuickAddable`, `image`, `hoverImage`; **always use this to build your own product card UI on the grid** |
28
- | `components/ProductCard.jsx` | reference implementation of a grid tile built on `useProductCard` — read it for inspiration, build your own component rather than using it directly |
29
- | `components/ProductGrid.jsx` | reference grid layout (2-col mobile → auto-fill desktop) with skeleton + empty state — read it for the skeleton/empty-state patterns, build your own layout rather than using it directly |
30
- | `components/ProductGallery.jsx` | PDP main image + thumbnails |
31
- | `lib/storeImage.js` | `productImage()` / `productGallery()` / `storeImage()` — normalise Wix image urls |
32
+ | `hooks/useProductCard.js` | headless data layer for a grid tile — returns `leftBadges`, `promoBadge`, `priceDisplay`, `compareAtDisplay`, `colors`, `optionLabel`, `isQuickAddable`, `image`, `hoverImage`; **your `ProductCard` (STEP 3) is built on it** |
33
+ | `lib/storeImage.js` | `productImage()` / `productGallery()` / `storeImage()` / `choiceImage()` — normalise Wix image urls; `productGallery(product)` → `[{ url, altText }]` (your PDP gallery); `choiceImage(choice)` resolves an option choice's photo (V3 read shape: `media.items[].mediaId`, not `linkedMedia`) |
32
34
  | `components/CartButton.jsx` | header cart **icon** button with a live-count badge |
33
35
  | `components/CartDrawer.jsx` | slide-over cart (mount once; opens from `useCart`) |
34
- | `hooks/useVariantOptions.js` | headless data layer for options/modifiers — returns `optionGroups` + `modifierGroups` (normalised, render-agnostic); **always use this to build your own variant UI on the PDP** |
35
- | `components/VariantPicker.jsx` | reference implementation of a variant selector built on `useVariantOptions` (pills + colour swatches) — read it for inspiration, but build your own component rather than using it directly |
36
+ | `hooks/useVariantOptions.js` | headless data layer for options/modifiers — returns `optionGroups` + `modifierGroups` (normalised, render-agnostic); **your PDP's variant controls (STEP 3) render from it** |
36
37
  | `components/WixManageBanner.jsx` | preview-only manage banner — drop it into your Layout (STEP 3) |
37
- | `pages/Shop.jsx`, `pages/ProductDetail.jsx` | the two shipped routes (`/shop`, `/product/:slug`) |
38
+ | `pages/Shop.jsx` | the shipped `/shop` listing page — renders your `ProductGrid` (you build `/product/:slug` and `/`) |
38
39
  | `rest/wix-config.js` | the two ids, written by the install step |
39
40
  | `rest/wix-client.js` + `rest/wix-store-*.js` | REST transport + catalog/cart helpers |
40
41
 
41
- They're already in place — go **straight to theming + wiring**, nothing to verify first. **Don't
42
- `read_file` the shipped page/component/hook source to inspect it** — the table above says what each is
43
- and every field shape you need is in the snippets below. Read a shipped file's source **only** on a
44
- real fallback — a runtime error, or a field the snippets don't cover (see "Fallback only" at the
45
- end). (Files missing? the install's `deploy` result lists what it wrote; re-run install, or copy
42
+ Everything in the table is already in place — go **straight to wiring + building your presentation**
43
+ (card, grid, variant controls, the product page, Home — STEP 3), nothing to verify first.
44
+ **Don't `read_file` the shipped page/hook source to inspect it** — the table says what each is and
45
+ every field shape you need is in the outlines below. Read a shipped file's source **only** on a real
46
+ fallback — a runtime error, or a field the outlines don't cover (see "Fallback only" at the end).
47
+ (Shipped files missing? the install's `deploy` result lists what it wrote; re-run install, or copy
46
48
  `references/storefront/app/` → `src/`.)
47
49
 
48
50
 
49
- ## STEP 2 — Theme (nothing to style on the shipped components)
50
- The shipped components carry **no palette of their own** — they render from base44's design tokens
51
+ ## STEP 2 — Theme
52
+ The shipped pages carry **no palette of their own** — they render from base44's design tokens
51
53
  in `src/index.css` (`:root`/`.dark`: `--background`, `--foreground`, `--card`, `--primary`,
52
54
  `--muted`, `--border`, `--radius`, `--font-*`) via shadcn Tailwind classes (`bg-card`,
53
55
  `text-foreground`, `bg-primary`, `text-muted-foreground`, `border-border`, `rounded-lg`,
54
56
  `font-display`). Those tokens are **already set to the brand by the design phase**, so the shipped
55
57
  pages are themed with zero work here. To adjust the palette, edit `index.css` (`:root` **and**
56
58
  `.dark`) — the base44 way; **never add a parallel theme file (e.g. a `theme.css`) or restyle the
57
- shipped JSX.** Build the Home/Header you add (STEP 3) from the **same** base44 tokens/classes so it
58
- matches automatically. A dark brand is just base44's dark palette in `index.css` — no per-component work.
59
+ shipped pages.** Style the components you build (STEP 3) and the Home/Header you add from the
60
+ **same** base44 tokens/classes so everything matches automatically. A dark brand is just base44's
61
+ dark palette in `index.css` — no per-component work.
59
62
 
60
63
  ## STEP 3 — Wire routes + provider (surgical `find_replace` on `src/App.jsx`, never a rewrite)
61
64
  **No file reads needed to wire this.** Every shipped page and `WixManageBanner` is a default export that takes **no props** — wire them exactly as the snippet shows; nothing in those files needs looking up.
@@ -64,77 +67,126 @@ replace it.
64
67
  - Wrap the routed tree in `<CartProvider>` (from `@/context/CartContext`).
65
68
  - Put your **header + footer in a `Layout`** that renders `<Outlet/>` between them, and nest every
66
69
  route under one pathless `<Route element={<Layout/>}>`. Your brand chrome then wraps **every** page
67
- — including the shipped `Shop` / `ProductDetail` — so you **never edit the shipped pages to add a
68
- header/footer** (they render inside `<Outlet/>` as-is). Mount `<CartDrawer/>` once in the Layout.
70
+ — including the shipped `Shop` and your own pages — so you **never edit the shipped `Shop` to add a
71
+ header/footer** (it renders inside `<Outlet/>` as-is). Mount `<CartDrawer/>` once in the Layout.
69
72
  - **Pin the top chrome as one fixed block.** Put `<WixManageBanner/>` (shipped, preview-only) **above**
70
73
  your `<Header/>` inside a single `position:fixed` top region — the header itself is plain in-flow
71
74
  markup, the region owns the fixing — so banner + header ride together (no scroll drift/gap). Pad
72
75
  the content by the region's measured height so it clears the chrome and self-corrects when the
73
76
  banner is dismissed.
74
- - Routes under the Layout: `/shop` → `Shop`, `/product/:slug` → `ProductDetail` (both shipped, as-is).
75
- **You add `/` → your own Home** page.
76
- - **Build your own variant selector on the PDP — this is required, not optional, and it's your chance to be creative.** `ProductDetail.jsx` ships with a `VariantPicker` import — remove it and replace with your own component built on `useVariantOptions`. Design the controls to fit the brief: the business type, the tone, the audience. A fashion brand might want large colour swatches and a size chart link; a tech store might want a compact dropdown. `VariantPicker.jsx` is in `src/` for reference — read it, don't use it:
77
- - **Build your own product card for the grid — this is required, not optional, and it's your chance to be creative.** `ProductGrid.jsx` ships with a `ProductCard` import — replace it with your own component built on `useProductCard`. The hook hands you everything the tile needs (badges, price display, colour dots, quick-add flag, images) — you decide the layout, shape, hover behaviour, and CTA style. A lifestyle brand might want full-bleed images with an overlay gradient; a tech store might want a compact horizontal list item. `ProductCard.jsx` is in `src/` for reference — read it, don't use it:
78
- - **Build your own grid layout — this is required, not optional, and it's your chance to be creative.** `ProductGrid.jsx` ships as a reference (2-col mobile → auto-fill desktop, 220px min) — replace it with an arrangement that fits the brief. A curated boutique might want a 3-col asymmetric editorial layout; a high-volume store might want a dense 4-col grid; a featured strip on the home page might want horizontal scroll. Keep the skeleton and empty-state patterns from `ProductGrid.jsx` (copy them into your own component) — the states themselves are correct, just the layout is yours to choose.
77
+ - Routes under the Layout: `/shop` → `Shop` (shipped, renders your grid); `/product/:slug` → **your
78
+ `ProductDetail`**; `/` → **your `Home`**.
79
+
80
+ **Build the presentation — it's all yours.** Each piece below is built on a shipped hook whose return
81
+ type + field shapes are in the outline right after this list — the data is done, the render is yours.
82
+ `Shop` won't show products until `ProductGrid` exists, and `/product/:slug` won't render until you
83
+ build the product page, so these aren't optional:
84
+
85
+ - **`components/ProductGrid.jsx`** — `Shop` and your Home render it. It receives `products`, `loading`,
86
+ `empty`, `emptyHint` and owns three states (loading, empty, list) plus the layout. A boutique might
87
+ want a 3-col editorial layout; a high-volume store a dense 4-col grid; a home strip a horizontal scroll.
88
+ - **`components/ProductCard.jsx`** — your grid maps each product to it. Built on `useProductCard`
89
+ (badges, price display, colour dots, quick-add flag, images) — you decide layout, shape, hover, CTA.
90
+ A lifestyle brand might want full-bleed images with an overlay gradient; a tech store a compact item.
91
+ - **`pages/ProductDetail.jsx`** — the **whole product page**, built on `useProductDetail`; route
92
+ `/product/:slug` to it. Gallery, price, description, the variant controls (options/modifiers via
93
+ `useVariantOptions`), the buy box — you arrange and style all of it (nothing PDP ships). This is the
94
+ surface that usually looks most generic, so make the layout the brand's: an editorial split, a sticky
95
+ buy column, a full-bleed gallery, large swatches vs a compact dropdown — your call.
79
96
 
80
97
  ```jsx
98
+ // components/ProductCard.jsx — your grid maps each product to it.
81
99
  import { Link } from "react-router-dom";
82
- import { useCart } from "@/context/CartContext";
100
+ import { useCart } from "@/context/CartContext"; // addToCart(product.id) for quick-add
83
101
  import { useProductCard } from "@/hooks/useProductCard";
84
102
 
85
- export default function MyProductCard({ product }) {
103
+ export default function ProductCard({ product }) {
86
104
  const { addToCart } = useCart();
87
105
  const {
88
106
  isSoldOut, isPreorder,
89
- leftBadges, // [{ type: 'pre-order'|'sold-out'|'limited-stock', label }] — render left side of image
90
- promoBadge, // { type: 'discount'|'ribbon', label } | null — render right side
91
- priceDisplay, // "€10" or "€10 – €20" (range when variants differ)
92
- compareAtDisplay, // original price string | null
93
- colors, // hex strings → render as dots (slice to how many you want)
94
- optionLabel, // "3 sizes · 2 materials" or empty string
95
- isQuickAddable, // true for single-variant, in-stock products
96
- image, // primary image URL | null
97
- hoverImage, // second image URL | null
107
+ leftBadges, // [{ type: 'pre-order'|'sold-out'|'limited-stock', label }] — image top-left
108
+ promoBadge, // { type: 'discount'|'ribbon', label } | null — image top-right
109
+ priceDisplay, // "€10" | "€10 – €20" (range when variants differ)
110
+ compareAtDisplay, // original price string | null — strike-through
111
+ colors, // hex strings → colour dots
112
+ optionLabel, // "3 sizes · 2 materials" | ""
113
+ isQuickAddable, // true → addToCart(product.id); else <Link to={`/product/${product.slug}`}>
114
+ image, hoverImage,// URLs | null
98
115
  } = useProductCard(product);
99
-
100
- // Then render however you want:
101
- return (
102
- <div>
103
- {/* image, badges, price, colour dots, quick-add or "Choose options" CTA */}
104
- {isQuickAddable && <button onClick={() => addToCart(product.id)}>Quick add</button>}
105
- {!isQuickAddable && !isSoldOut && <Link to={`/product/${product.slug}`}>Choose options</Link>}
106
- {isSoldOut && isPreorder && <Link to={`/product/${product.slug}`}>Pre-order</Link>}
107
- </div>
108
- );
116
+ // …you implement the tile.
109
117
  }
110
118
  ```
111
119
 
112
120
  ```jsx
121
+ // Variant controls — render the product's options/modifiers from useVariantOptions.
122
+ // The inputs (options, modifiers, selectedOptions, modifierValues) come from useProductDetail (below).
113
123
  import { useVariantOptions } from "@/hooks/useVariantOptions";
114
124
 
115
- // options/modifiers/selectedOptions/modifierValues come from useProductDetail:
116
125
  const { optionGroups, modifierGroups } = useVariantOptions(options, modifiers, selectedOptions, modifierValues);
117
-
118
- // optionGroups: [{ id, name, isColor, choices: [{ choiceId, name, colorCode, isColorSwatch, inStock, selected }] }]
126
+ // optionGroups: [{ id, name, isColor, choices: [{ choiceId, name, colorCode, isColorSwatch, inStock, selected }] }]
119
127
  // modifierGroups: [{ key, name, mandatory, type: 'choices'|'text', choices?: [{ key, name, selected }], value?: string }]
128
+ // pick a choice: selectOption(group.id, choice.choiceId)
129
+ // set a modifier: setModifier(m.key, choice.key) · text type: setModifier(m.key, e.target.value)
130
+ ```
120
131
 
121
- // Then render however you want:
122
- optionGroups.map((group) =>
123
- group.choices.map((c) =>
124
- c.isColorSwatch
125
- ? <MySwatch key={c.choiceId} color={c.colorCode} active={c.selected} disabled={!c.inStock}
126
- onClick={() => selectOption(group.id, c.choiceId)} />
127
- : <MyPill key={c.choiceId} active={c.selected} disabled={!c.inStock}
128
- onClick={() => selectOption(group.id, c.choiceId)}>{c.name}</MyPill>
129
- )
130
- );
131
- modifierGroups.map((m) =>
132
- m.type === "text"
133
- ? <MyInput key={m.key} label={m.name} value={m.value} onChange={(v) => setModifier(m.key, v)} />
134
- : m.choices.map((c) =>
135
- <MyPill key={c.key} active={c.selected} onClick={() => setModifier(m.key, c.key)}>{c.name}</MyPill>
136
- )
137
- );
132
+ ```jsx
133
+ // components/ProductGrid.jsx — Shop and your Home render it.
134
+ import ProductCard from "./ProductCard"; // your card, above
135
+
136
+ export default function ProductGrid({ products, loading, empty, emptyHint }) {
137
+ // products — array | null (null while loading)
138
+ // loading — boolean
139
+ // empty — heading string for the no-products state
140
+ // emptyHint — sub-text string for the no-products state
141
+ // …you implement: the loading state, the empty state (empty + emptyHint), and the layout
142
+ // mapping products → <ProductCard product={p} />.
143
+ }
144
+ ```
145
+
146
+ ```jsx
147
+ // pages/ProductDetail.jsx — YOU build the whole product page. Route `/product/:slug` to it.
148
+ // A thin view over useProductDetail: keep the data logic in the hook, render however fits the brand.
149
+ import { useMemo } from "react";
150
+ import { useParams, Link } from "react-router-dom";
151
+ import { useProductDetail } from "@/hooks/useProductDetail";
152
+ import { productGallery } from "@/lib/storeImage";
153
+
154
+ export default function ProductDetail() {
155
+ const { slug } = useParams();
156
+ const d = useProductDetail(slug);
157
+ // useProductDetail(slug) returns:
158
+ // product Wix product | null (loading) — has .name, .plainDescription (HTML), .slug
159
+ // notFound bool — dead link (distinct from error)
160
+ // error string | null — failed load; call retry() to reload
161
+ // retry () => void
162
+ // price formatted string, follows the selection ("€24.00")
163
+ // compareAtPrice formatted string — a "was" price; strike it only when it differs from price
164
+ // options, modifiers → feed useVariantOptions for the variant controls (block above)
165
+ // selectedOptions, selectOption, modifierValues, setModifier → also for the variant controls
166
+ // variant resolved variant | null (null until every option is picked)
167
+ // focusMediaUrl image url for the selected choice — make the gallery show it
168
+ // quantity, setQuantity(n) number (may be "" mid-edit) — keep min 1
169
+ // inStock, canAdd, adding booleans that gate the buy button
170
+ // submit async () => adds the resolved variant + quantity + modifiers to the cart
171
+ const images = useMemo(() => productGallery(d.product), [d.product]); // [{ url, altText }], main first, de-duped
172
+
173
+ // …you implement the page. Handle in order:
174
+ // error → show d.error + a retry button (onClick={d.retry})
175
+ // notFound → a "not found" message + a <Link to="/shop">
176
+ // !product → a loading placeholder
177
+ // else the product view, laid out to fit the brand:
178
+ // • gallery from `images` — main + thumbnails, a carousel, a full-bleed hero (your call);
179
+ // make the shown image follow d.focusMediaUrl when a choice is selected
180
+ // • d.product.name · d.price (strike d.compareAtPrice when it differs) ·
181
+ // d.product.plainDescription (HTML → dangerouslySetInnerHTML)
182
+ // • variant controls — render d.options/d.modifiers via useVariantOptions (block above);
183
+ // d.selectOption / d.setModifier update the selection
184
+ // • a "pick an option to continue" hint when d.options.length && !d.variant
185
+ // • a quantity control (d.quantity / d.setQuantity, min 1 — a −/+ stepper reads better than a
186
+ // native number input) + the buy button:
187
+ // <button disabled={!d.canAdd || d.adding} onClick={d.submit}>
188
+ // {d.adding ? "Adding…" : d.inStock ? "Add to cart" : "Out of stock"}</button>
189
+ }
138
190
  ```
139
191
 
140
192
  ```jsx
@@ -144,7 +196,7 @@ import { CartProvider } from "@/context/CartContext";
144
196
  import CartDrawer from "@/components/CartDrawer";
145
197
  import WixManageBanner from "@/components/WixManageBanner"; // shipped, preview-only · default export, no props
146
198
  import Shop from "@/pages/Shop"; // shipped · default export, no props
147
- import ProductDetail from "@/pages/ProductDetail"; // shipped · default export, no props
199
+ import ProductDetail from "@/pages/ProductDetail"; // YOU build
148
200
  import Home from "@/pages/Home"; // YOU build
149
201
  import Header from "@/components/Header"; // YOU build — plain in-flow markup, NOT position:fixed
150
202
  import Footer from "@/components/Footer"; // YOU build
@@ -163,7 +215,7 @@ function Layout() {
163
215
  <Header /> {/* your brand header, in-flow inside this fixed block */}
164
216
  </div>
165
217
  <div style={{ paddingTop: offset }}> {/* clears the chrome; shrinks when the banner is dismissed */}
166
- <Outlet /> {/* shipped Shop/ProductDetail render here, untouched */}
218
+ <Outlet /> {/* shipped Shop + your pages render here */}
167
219
  <Footer />
168
220
  </div>
169
221
  <CartDrawer /> {/* overlays every page */}
@@ -175,7 +227,7 @@ function Layout() {
175
227
  <Route element={<Layout />}> {/* chrome wraps all */}
176
228
  <Route path="/" element={<Home />} /> {/* yours */}
177
229
  <Route path="/shop" element={<Shop />} /> {/* shipped, as-is */}
178
- <Route path="/product/:slug" element={<ProductDetail />} /> {/* shipped, as-is */}
230
+ <Route path="/product/:slug" element={<ProductDetail />} /> {/* yours */}
179
231
  </Route>
180
232
  </Routes>
181
233
  </CartProvider>
@@ -184,8 +236,8 @@ function Layout() {
184
236
  ## What you build (not shipped)
185
237
  The **home / landing page**, the **`Header`** (mount `<CartButton/>` in it) and a **`Footer`** — the
186
238
  two you drop into the `Layout` (STEP 3) so they wrap every route — plus the overall brand story,
187
- styled from the same base44 tokens/classes. **Compose the shipped pieces** — a
188
- featured strip is just `queryProducts` + the shipped `ProductGrid`; the nav is a `<CartButton/>`
239
+ styled from the same base44 tokens/classes. **Reuse your own `ProductGrid`** (STEP 3) and the shipped
240
+ cart pieces — a featured strip is just `queryProducts` + your `ProductGrid`; the nav is a `<CartButton/>`
189
241
  (a clean cart-**icon** button with a live-count badge — render it as-is, don't wrap it in your own
190
242
  text button) + a link to `/shop`:
191
243
 
@@ -193,8 +245,8 @@ text button) + a link to `/shop`:
193
245
  import { useState, useEffect } from "react";
194
246
  import { Link } from "react-router-dom";
195
247
  import { queryProducts } from "@/rest/wix-store-catalog";
196
- import ProductGrid from "@/components/ProductGrid";
197
- import CartButton from "@/components/CartButton";
248
+ import ProductGrid from "@/components/ProductGrid"; // yours (STEP 3)
249
+ import CartButton from "@/components/CartButton"; // shipped
198
250
 
199
251
  // Responsive header: choose ONE branch with a state flag, so <CartButton/> mounts once.
200
252
  // Do NOT render a desktop nav AND a mobile nav toggled by `hidden md:flex` / `md:hidden`:
@@ -268,7 +320,7 @@ function CartCount() { // header badge
268
320
  return <button onClick={() => setIsOpen(true)}>Cart ({itemCount})</button>;
269
321
  }
270
322
 
271
- // Buy from a card → link to the PDP; the shipped ProductDetail owns options/variants + add-to-cart.
323
+ // Buy from a card → link to the PDP; your ProductDetail (on useProductDetail) owns options/variants + add-to-cart.
272
324
  // (Listing helpers return no variants — only getProductBySlug does — so buying happens on the PDP.)
273
325
  const CardBuy = ({ product }) => <Link to={`/product/${product.slug}`}>View</Link>;
274
326
 
@@ -313,8 +365,8 @@ reference page inline; these are the areas they sit in:
313
365
  - Headless redirect session (hosted checkout): https://dev.wix.com/docs/api-reference/business-management/headless/redirects.md
314
366
 
315
367
  ## Hard rules
316
- - Style via base44 design tokens (`index.css` / shadcn Tailwind classes), never by rewriting the shipped components or adding a parallel theme file.
317
- - Header/footer live in a `Layout` around `<Outlet/>` (STEP 3) — never edit the shipped `Shop`/`ProductDetail` to add chrome.
368
+ - Style via base44 design tokens (`index.css` / shadcn Tailwind classes), never by rewriting the shipped pages or adding a parallel theme file. Everything you build (card, grid, PDP, variant controls, Home) draws from the same tokens.
369
+ - Header/footer live in a `Layout` around `<Outlet/>` (STEP 3) — never edit the shipped `Shop` to add chrome.
318
370
  - The Layout's fixed top region owns positioning: `<WixManageBanner/>` above `<Header/>`; your `Header` is plain in-flow markup (not `position:fixed`).
319
371
  - Checkout goes through the shipped cart (redirect-session) — never a hand-built `/checkout` URL.
320
372
  - Render live Wix data or the shipped empty state — never mock products.
@@ -330,9 +382,10 @@ client build; run in parallel.
330
382
 
331
383
  ## Verify (before declaring done)
332
384
  - [ ] Client files copied into `src/`; `WIX_CLIENT_ID` set (not the placeholder).
333
- - [ ] Brand palette lives in `index.css` (`:root`/`.dark`); no parallel theme file; shipped components/pages not restyled or rewritten.
334
- - [ ] **Opened `/shop` and a product detail page** (not just the home page) and confirmed the shipped cards render themed (surface, text, brand color) with images.
335
- - [ ] `Layout` (fixed `<WixManageBanner/>` + `<Header/>` region, then `<Outlet/>` + Footer) wraps all routes; shipped `Shop`/`ProductDetail` untouched; content clears the fixed chrome; `<CartProvider>` wraps the tree; `<CartDrawer/>` mounted; `<CartButton/>` in the header.
385
+ - [ ] **The pieces you own exist and are wired:** `components/ProductCard.jsx`, `components/ProductGrid.jsx` (imported by `Shop` + your Home), and `pages/ProductDetail.jsx` (routed at `/product/:slug`, with working variant controls). `/shop` and a PDP compile and render (they won't until these exist).
386
+ - [ ] Brand palette lives in `index.css` (`:root`/`.dark`); no parallel theme file; the shipped `Shop` page not restyled or rewritten.
387
+ - [ ] **Opened `/shop` and a product detail page** (not just the home page) and confirmed your cards render themed (surface, text, brand color) with images; the grid shows its loading + empty states; the PDP shows the gallery, price, variant controls, and add-to-cart, and its error/not-found/loading states hold.
388
+ - [ ] `Layout` (fixed `<WixManageBanner/>` + `<Header/>` region, then `<Outlet/>` + Footer) wraps all routes; the shipped `Shop` untouched; content clears the fixed chrome; `<CartProvider>` wraps the tree; `<CartDrawer/>` mounted; `<CartButton/>` in the header.
336
389
  - [ ] Cart survives reload (same visitor); add / update-qty / remove work; checkout redirects; the drawer shows a **subtotal**.
337
390
  - [ ] Empty catalog shows the shipped empty state; no mock products anywhere.
338
391
  - [ ] A product with several images shows **thumbnails** on the PDP, and one with per-variant prices shows a **range** on its card.
@@ -5,7 +5,7 @@
5
5
  // renders what this returns.
6
6
  import { useState, useEffect, useMemo } from "react";
7
7
  import { getProductBySlug } from "@/rest/wix-store-catalog";
8
- import { storeImage } from "@/lib/storeImage";
8
+ import { choiceImage, variantImage } from "@/lib/storeImage";
9
9
  import { useCart } from "@/context/CartContext";
10
10
 
11
11
  export function useProductDetail(slug) {
@@ -61,19 +61,26 @@ export function useProductDetail(slug) {
61
61
  m.modifierRenderType === "FREE_TEXT" ? !!modifierValues[m.freeTextSettings?.key] : !!modifierValues[m.key]);
62
62
  }, [options, variant, inStock, modifiers, modifierValues]);
63
63
 
64
+ // Everything the buyer sees follows the resolved `variant` (also returned below, so an agent can
65
+ // surface more from it — sku, barcode, subscriptionPricesInfo — without new plumbing). Price and
66
+ // its struck-through "was" price come off the variant, falling back to the product's range before
67
+ // every option is picked.
64
68
  const price = variant?.price?.actualPrice?.formattedAmount || product?.actualPriceRange?.minValue?.formattedAmount || "";
69
+ const compareAtPrice = variant?.price?.compareAtPrice?.formattedAmount || product?.compareAtPriceRange?.minValue?.formattedAmount || "";
65
70
 
66
- // A colour choice carries `linkedMedia` — the shots of the product in that colour. Picking "Dark
67
- // Green" should move the gallery to the green photo, so resolve the selection to a URL here; only
68
- // colour-style choices have linked media, so the first hit across the options is the right one.
71
+ // The gallery follows the selection. Prefer the selected choice's own image (the per-swatch photo,
72
+ // choice.media.items[].mediaId) — Wix's per-variant media is often NOT differentiated (it defaults to
73
+ // the product's main image), so preferring the variant would override the correct choice image for
74
+ // every colour. Fall back to the resolved variant's image only when no chosen option carries one.
75
+ // See lib/storeImage: choiceImage() / variantImage().
69
76
  const focusMediaUrl = useMemo(() => {
70
77
  for (const o of options) {
71
78
  const choice = (o.choicesSettings?.choices || []).find((c) => c.choiceId === selectedOptions[o.id]);
72
- const url = storeImage(choice?.linkedMedia?.[0]);
79
+ const url = choiceImage(choice);
73
80
  if (url) return url;
74
81
  }
75
- return null;
76
- }, [options, selectedOptions]);
82
+ return variantImage(variant);
83
+ }, [variant, options, selectedOptions]);
77
84
 
78
85
  const selectOption = (optionId, choiceId) => setSelectedOptions((s) => ({ ...s, [optionId]: choiceId }));
79
86
  const setModifier = (key, value) => setModifierValues((s) => ({ ...s, [key]: value }));
@@ -104,6 +111,6 @@ export function useProductDetail(slug) {
104
111
  product, notFound, error, retry: () => setReloadKey((k) => k + 1),
105
112
  options, modifiers,
106
113
  selectedOptions, selectOption, modifierValues, setModifier,
107
- quantity, setQuantity, variant, inStock, canAdd, adding, price, submit, focusMediaUrl,
114
+ quantity, setQuantity, variant, inStock, canAdd, adding, price, compareAtPrice, submit, focusMediaUrl,
108
115
  };
109
116
  }
@@ -10,6 +10,43 @@ export function storeImage(value) {
10
10
  return url;
11
11
  }
12
12
 
13
+ // A Wix media id (e.g. "abc123~mv2.jpg") is NOT a URL — build the static CDN url for it.
14
+ export function wixMediaUrl(mediaId) {
15
+ if (!mediaId || typeof mediaId !== "string") return null;
16
+ if (mediaId.startsWith("http") || mediaId.startsWith("//")) return storeImage(mediaId);
17
+ return `https://static.wixstatic.com/media/${mediaId}`;
18
+ }
19
+
20
+ // The media id inside a Wix image url (…/media/<id>/v1/… or a bare …/media/<id>). Compare two urls of
21
+ // the SAME image that differ only in sizing/format params by their id, not full-string equality.
22
+ export function wixMediaId(url) {
23
+ const m = typeof url === "string" && url.match(/\/media\/([^/?]+)/);
24
+ return m ? m[1] : url;
25
+ }
26
+
27
+ // The image assigned to a product OPTION CHOICE (e.g. a colour swatch). The storefront fetches with the
28
+ // PRODUCT_CHOICES_MEDIA_REFERENCES field, so Wix returns the choice image at choice.media.items[].mediaId
29
+ // and returns choice.linkedMedia EMPTY. Read media.items — do NOT switch this to choice.linkedMedia even
30
+ // if a direct admin/API probe shows linkedMedia populated: a probe made WITHOUT that field mask returns
31
+ // linkedMedia, but the storefront requests the mask, which blanks linkedMedia and returns media.items.
32
+ export function choiceImage(choice) {
33
+ const mediaId = choice?.media?.items?.[0]?.mediaId;
34
+ return mediaId ? wixMediaUrl(mediaId) : null;
35
+ }
36
+
37
+ // The image for a resolved VARIANT (a full choice combination). Wix computes variant.media from the
38
+ // picked choices' media, so this is the exact image for the current selection — prefer it over a
39
+ // single choice's image once all options are chosen.
40
+ // ⚠️ Read `media.image.url` (the URL the API already returns), or build from `media.id` — the
41
+ // `~mv2` file id. NOT `media.uploadId`: that's a dashed GUID (the id the file was uploaded with),
42
+ // and https://static.wixstatic.com/media/<uploadId> is a 403. Variants without media (a fresh
43
+ // template's demo products) return null, and the caller falls back to the choice's own image.
44
+ export function variantImage(variant) {
45
+ const m = variant?.media;
46
+ if (!m) return null;
47
+ return storeImage(m.image?.url) || wixMediaUrl(m.id) || storeImage(m.thumbnail?.url);
48
+ }
49
+
13
50
  // The main catalog image for a product (grid tiles, cart fallbacks).
14
51
  export function productImage(product) {
15
52
  return storeImage(product?.media?.main?.image?.url);
@@ -30,12 +30,13 @@ import { wixApiRequest } from "./wix-client.js";
30
30
  * options {array} — product options e.g. Size, Color:
31
31
  * [{ id, name, optionRenderType "TEXT_CHOICES"|"COLOR_CHOICES"|"SWATCH_CHOICES",
32
32
  * choicesSettings.choices [{ choiceId, key, name, inStock, visible, choiceType, colorCode,
33
- * linkedMedia }] }],
33
+ * media }] }],
34
34
  * A COLOR/SWATCH option's choices carry choiceType "ONE_COLOR" and colorCode "#395E55" — render
35
- * those as real colour swatches, not text pills. linkedMedia [{ image.url }] holds that colour's
36
- * photos, so selecting a swatch can move the gallery to the matching shot. visible false is a
37
- * retired choice the merchant no longer sells: filter it out. (TEXT_CHOICES choices are
38
- * choiceType "CHOICE_TEXT" with no colorCode.)
35
+ * those as real colour swatches, not text pills. A choice's photo is at media.items[].mediaId (a
36
+ * bare Wix media id — build https://static.wixstatic.com/media/<id>); use choiceImage() from
37
+ * lib/storeImage to resolve it. Needs the PRODUCT_CHOICES_MEDIA_REFERENCES field (requested by
38
+ * getProductBySlug below). visible false is a retired choice the merchant no longer sells: filter
39
+ * it out. (TEXT_CHOICES choices are choiceType "CHOICE_TEXT" with no colorCode.)
39
40
  * modifiers {array} — non-variant customizations (engraving, gift wrap):
40
41
  * [{ id, name, mandatory, modifierRenderType "TEXT_CHOICES"|"FREE_TEXT",
41
42
  * key, choicesSettings.choices, freeTextSettings.key }],
@@ -85,7 +86,18 @@ export async function queryProducts({ limit = 100, cursor } = {}) {
85
86
  export async function getProductBySlug(slug) {
86
87
  const res = await wixApiRequest(`/stores/v3/products/slug/${encodeURIComponent(slug)}`, {
87
88
  method: "GET",
88
- query: { fields: ["CURRENCY", "PLAIN_DESCRIPTION", "MEDIA_ITEMS_INFO"] },
89
+ // PRODUCT_CHOICES_MEDIA_REFERENCES → choice.media.items[].mediaId (the per-colour photos, needed
90
+ // for the swatch→gallery swap); VARIANT_OPTION_CHOICE_NAMES → variant choice names. Without these
91
+ // the choice media / variant data come back null.
92
+ query: {
93
+ fields: [
94
+ "CURRENCY",
95
+ "PLAIN_DESCRIPTION",
96
+ "MEDIA_ITEMS_INFO",
97
+ "PRODUCT_CHOICES_MEDIA_REFERENCES",
98
+ "VARIANT_OPTION_CHOICE_NAMES",
99
+ ],
100
+ },
89
101
  });
90
102
  return res?.product ?? null;
91
103
  }
@@ -4,6 +4,10 @@ Seed a Wix Stores catalog by **calling `seed-store.js`** — don't hand-write th
4
4
  a build-time module (run via `exec_tool`, not shipped in the app) that abstracts every Wix Stores
5
5
  seed operation. Load it and call **`setupStore` — the one-call path** — with plain data.
6
6
 
7
+ **Match each product's type to what the buyer receives** (the example shows both). *Access* — a
8
+ membership, or an online course/program the buyer enrolls in — isn't a store product at all; that's
9
+ the `pricing-plans` vertical, not here.
10
+
7
11
  ```js
8
12
  // build-time exec_tool
9
13
  const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix");
@@ -22,12 +26,15 @@ const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
22
26
  // generate_image runs in the background while you build, so the urls are ready by seed time.
23
27
  const result = await seed.setupStore(ctx, {
24
28
  products: [
29
+ // physical — a shipped item: carries `quantity` (the default type)
25
30
  { name: "The Glam Rocker", description: "Sequin-studded velvet legend…", price: 49.99, quantity: 12, imageUrl: imageUrls[0] },
26
31
  // a product with buyer choices — see "Options, variants and sale prices" below
27
32
  { name: "The Understudy", description: "…", price: 245, quantity: 8, imageUrl: imageUrls[1],
28
33
  options: [{ name: "Color", type: "color", choices: [{ name: "Ink", colorCode: "#1B1B2F" }, { name: "Bone", colorCode: "#EDE6D6" }] }] },
29
34
  // a product on sale — compareAtPrice drives the strikethrough + the tile's percent-off badge
30
35
  { name: "Encore Jacket", description: "…", price: 68, compareAtPrice: 129, quantity: 5, imageUrl: imageUrls[2] },
36
+ // digital — a file the buyer downloads & keeps (ebook, PDF, video): `digitalFileUrl`, NO `quantity`
37
+ { name: "Backstage Guide", description: "…", price: 12, digitalFileUrl: "https://…/guide.pdf" },
31
38
  ],
32
39
  categories: { "Legends": ["The Glam Rocker"], "Rising Stars": [] }, // omit if the brief names none
33
40
  });
@@ -37,13 +44,15 @@ const result = await seed.setupStore(ctx, {
37
44
  **Seeding is additive — never delete or overwrite existing content.** Don't clean up, don't remove
38
45
  "sample" data, don't reset. Just add.
39
46
 
40
- ## Options, variants and sale prices
47
+ ## How many, and exercising the UI
48
+
49
+ **Default to 3 products** unless the brief asks for a specific catalog — the seed shows the shape,
50
+ not a full inventory; the owner adds the rest later, from the Wix dashboard or by asking you for more.
41
51
 
42
52
  The shipped storefront renders colour options as real swatches, shows a size/colour summary on each
43
53
  tile, and puts a percent-off badge on a discounted product. A catalog of plain single-price products
44
- leaves all of that invisible, so **seed a catalog that exercises it**: unless the brief says
45
- otherwise, give at least one product a colour option and put one product on sale. Keep it truthful
46
- to the business — a ceramics studio has glaze colours, a bakery does not.
54
+ leaves all of that invisible, so **make those 3 exercise it**: unless the brief says otherwise, give
55
+ at least one product a colour option and put one product on sale. Keep it truthful to the business.
47
56
 
48
57
  ```js
49
58
  options: [
@@ -60,13 +69,27 @@ options: [
60
69
  - `compareAtPrice` (> `price`) is the "was" price: strikethrough on the PDP and a `−N%` badge on the
61
70
  tile, computed from the two amounts. It works with or without options.
62
71
 
72
+ ## Digital downloads
73
+
74
+ **Pick the product type from what the buyer receives.** A shipped physical item is the default. A
75
+ **downloadable file the buyer keeps** — ebook, PDF guide, template, preset pack, printable, music
76
+ track, downloadable video — is a **digital** product: pass its file as `digitalFileUrl`. Selling
77
+ *access* rather than a file — a membership, subscription, or an online course/program the buyer
78
+ enrolls in — is **Pricing Plans**, not a Stores product, so it isn't seeded here.
79
+
80
+ `digitalFileUrl` (plus `digitalFileName` when the url carries no filename) makes a product a digital
81
+ download — uploaded and created with both the file and stock, which is what the cart requires
82
+ (`quantity` is ignored). It's also the only way in: a file-less digital product is created
83
+ successfully, reads back healthy, and is then rejected at add-to-cart as `ITEM_NOT_FOUND_IN_CATALOG`.
84
+
63
85
  Two things this module does **not** seed, so don't try:
64
86
 
65
87
  - **Ribbons** ("New", "Best Seller"). The tile renders `product.ribbon` when it's there, but ribbons
66
88
  are set in the Wix dashboard — tell the merchant that's where to add them.
67
- - **Per-choice linked media** (`linkedMedia`), which is what makes picking a colour swap the gallery
68
- photo. Seeded swatches select and price correctly; the gallery just doesn't follow the colour until
69
- the merchant links photos to choices in the dashboard.
89
+ - **Per-choice media** — the photo that makes picking a choice swap the gallery image. Seeded swatches
90
+ select and price correctly; the gallery follows a choice once photos are linked to it (Wix dashboard,
91
+ or the wix-manage "Update Product with Options" recipe → Choice & variant fields). The shipped PDP then
92
+ follows automatically — `choiceImage()` reads it back at `media.items[].mediaId`.
70
93
 
71
94
  ## Escape hatch — individual functions
72
95
  Reach for the functions below only when the one-call `setupStore` doesn't fit (partial re-seed, custom