@wix/agent-skills 1.15.0 → 1.16.0

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 (355) hide show
  1. package/README.md +5 -1
  2. package/package.json +1 -1
  3. package/skills/wix-app/SKILL.md +4 -1
  4. package/skills/wix-app/references/APP_TOOLS.md +134 -0
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +1 -1
  6. package/skills/wix-app/references/DASHBOARD_PAGE.md +0 -10
  7. package/skills/wix-app/references/DATA_COLLECTION.md +6 -4
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +28 -7
  9. package/skills/wix-app/references/SERVICE_PLUGIN.md +12 -10
  10. package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
  11. package/skills/wix-app/references/app-tools/TOOLS.md +75 -0
  12. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +5 -0
  13. package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +2 -2
  14. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +172 -0
  15. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +138 -0
  16. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +172 -0
  17. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +29 -0
  18. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +1 -1
  19. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +57 -0
  20. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +33 -2
  21. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +5 -3
  22. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +18 -1
  23. package/skills/wix-app/references/editor-react-component/PARTS.md +15 -2
  24. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +4 -3
  25. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +13 -9
  26. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +4 -0
  27. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +4 -0
  28. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +3 -1
  29. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +4 -0
  30. package/skills/wix-app/references/service-plugin/TOOLS_PROVIDER.md +54 -0
  31. package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
  32. package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
  33. package/skills/wix-app/references/stores/INVENTORY.md +37 -0
  34. package/skills/wix-app/references/stores/QUERY.md +119 -0
  35. package/skills/wix-app/references/stores/WRITE.md +55 -0
  36. package/skills/wix-docs/SKILL.md +35 -3
  37. package/skills/wix-headless/SKILL.md +9 -2
  38. package/skills/wix-headless/entry/bootstrap.mjs +2 -2
  39. package/skills/wix-headless/entry/skill.md +0 -2
  40. package/skills/wix-headless/references/CAPABILITIES.md +6 -4
  41. package/skills/wix-headless/references/CONTENT.md +36 -0
  42. package/skills/wix-headless/references/DESIGN.md +54 -0
  43. package/skills/wix-headless/references/DISCOVERY.md +25 -1
  44. package/skills/wix-headless/references/FEEDBACK.md +16 -5
  45. package/skills/wix-headless/references/IMAGE_GENERATION.md +10 -0
  46. package/skills/wix-headless/references/SDK_HANDOFF.md +2 -0
  47. package/skills/wix-headless/references/SEED.md +3 -1
  48. package/skills/wix-headless/references/SETUP.md +1 -1
  49. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +3 -2
  50. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +42 -2
  51. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +5 -1
  52. package/skills/wix-headless/references/inline-recipes/setup-forms.md +1 -1
  53. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +33 -8
  54. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +3 -1
  55. package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
  56. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +38 -2
  57. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +20 -1
  58. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +1 -1
  59. package/skills/wix-headless/references/managed/CONNECT.md +2 -2
  60. package/skills/wix-headless/references/managed/CREATE.md +15 -1
  61. package/skills/wix-headless/references/managed/DEPLOYMENT.md +47 -0
  62. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +8 -0
  63. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +8 -0
  64. package/skills/wix-manage/SKILL.md +131 -12
  65. package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +41 -0
  66. package/skills/wix-manage/references/analytics/query-site-analytics.md +66 -9
  67. package/skills/wix-manage/references/app-installation/app-installation-dashboard-navigation.md +28 -0
  68. package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
  69. package/skills/wix-manage/references/blog/blog-dashboard-navigation.md +56 -0
  70. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +31 -6
  71. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -1
  72. package/skills/wix-manage/references/bookings/bookings-dashboard-navigation.md +63 -0
  73. package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
  74. package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
  75. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +85 -42
  76. package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +44 -0
  77. package/skills/wix-manage/references/cms/cms-data-items-crud.md +31 -3
  78. package/skills/wix-manage/references/cms/cms-publishing-flow.md +287 -0
  79. package/skills/wix-manage/references/cms/cms-schema-management.md +33 -1
  80. package/skills/wix-manage/references/contacts/contacts-dashboard-navigation.md +46 -0
  81. package/skills/wix-manage/references/contacts/create-a-contact.md +82 -0
  82. package/skills/wix-manage/references/contacts/update-a-contact.md +119 -0
  83. package/skills/wix-manage/references/dashboard-navigation/dashboard-navigation.md +82 -0
  84. package/skills/wix-manage/references/dashboard-navigation/routes.json +1733 -0
  85. package/skills/wix-manage/references/domains/domains-dashboard-navigation.md +32 -0
  86. package/skills/wix-manage/references/ecommerce/ecom-pricing.md +4 -4
  87. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  88. package/skills/wix-manage/references/ecommerce/gift-cards/ecom-gift-cards-goal-sell-gift-cards.md +338 -0
  89. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +42 -78
  90. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
  91. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +1 -1
  92. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +1 -1
  93. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +90 -92
  94. package/skills/wix-manage/references/events/create-wix-event.md +176 -0
  95. package/skills/wix-manage/references/events/manage-wix-events.md +174 -0
  96. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +44 -0
  97. package/skills/wix-manage/references/get-paid/get-paid-dashboard-navigation.md +52 -0
  98. package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
  99. package/skills/wix-manage/references/google-ads/billing-and-payment.md +80 -0
  100. package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +212 -0
  101. package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +110 -0
  102. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +25 -0
  103. package/skills/wix-manage/references/google-ads/install-and-create-account.md +155 -0
  104. package/skills/wix-manage/references/google-ads/manage-campaign-lifecycle.md +63 -0
  105. package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +155 -0
  106. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +225 -144
  107. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +19 -10
  108. package/skills/wix-manage/references/marketing/marketing-dashboard-navigation.md +52 -0
  109. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +99 -1
  110. package/skills/wix-manage/references/pricing-plans/pricing-plans-dashboard-navigation.md +45 -0
  111. package/skills/wix-manage/references/restaurants/restaurants-dashboard-navigation.md +68 -0
  112. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +94 -125
  113. package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +48 -9
  114. package/skills/wix-manage/references/site-properties/site-properties-dashboard-navigation.md +31 -0
  115. package/skills/wix-manage/references/sites/create-headless-site.md +52 -0
  116. package/skills/wix-manage/references/sites/create-site-from-template.md +2 -25
  117. package/skills/wix-manage/references/sites/site-import.md +243 -0
  118. package/skills/wix-manage/references/sites/sites-dashboard-navigation.md +29 -0
  119. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +17 -1
  120. package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
  121. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +16 -10
  122. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +26 -8
  123. package/skills/wix-manage/references/stores/stores-dashboard-navigation.md +65 -0
  124. package/skills/wix-manage/references/stores/update-product-with-options.md +39 -7
  125. package/skills/wix-replatform/.publish-manifest.json +8 -0
  126. package/skills/wix-replatform/SKILL.md +693 -0
  127. package/skills/wix-replatform/lib/artifact-freshness.js +215 -0
  128. package/skills/wix-replatform/lib/completion-report.js +200 -0
  129. package/skills/wix-replatform/lib/config-env.js +59 -0
  130. package/skills/wix-replatform/lib/execution-manifest.js +185 -0
  131. package/skills/wix-replatform/lib/execution-state.js +173 -0
  132. package/skills/wix-replatform/lib/import-recovery.js +313 -0
  133. package/skills/wix-replatform/lib/local-state.js +642 -0
  134. package/skills/wix-replatform/lib/orchestration-preflight.js +143 -0
  135. package/skills/wix-replatform/lib/orchestration-router.js +122 -0
  136. package/skills/wix-replatform/lib/orchestration-state.js +455 -0
  137. package/skills/wix-replatform/lib/progress-log.js +224 -0
  138. package/skills/wix-replatform/lib/progress-log.sh +140 -0
  139. package/skills/wix-replatform/lib/url-preservation-state.js +391 -0
  140. package/skills/wix-replatform/resources/rp-discovery/SKILL.md +184 -0
  141. package/skills/wix-replatform/resources/rp-execute-import/SKILL.md +529 -0
  142. package/skills/wix-replatform/resources/rp-execute-setup/SKILL.md +316 -0
  143. package/skills/wix-replatform/resources/rp-execute-setup/scripts/mint-token.sh +64 -0
  144. package/skills/wix-replatform/resources/rp-import-codegen/SKILL.md +1114 -0
  145. package/skills/wix-replatform/resources/rp-mapper/SKILL.md +430 -0
  146. package/skills/wix-replatform/resources/rp-mapper/lib/mapping-resolve.js +217 -0
  147. package/skills/wix-replatform/resources/rp-mapper/scripts/resolve-mapping.js +148 -0
  148. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +378 -0
  149. package/skills/wix-replatform/resources/rp-setup-discovery/SKILL.md +183 -0
  150. package/skills/wix-replatform/resources/rp-source-csv/SKILL.md +478 -0
  151. package/skills/wix-replatform/resources/rp-source-csv/lib/canonical-record.js +136 -0
  152. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fileset.js +0 -0
  153. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fingerprint.js +310 -0
  154. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-layout.js +1081 -0
  155. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-parse.js +618 -0
  156. package/skills/wix-replatform/resources/rp-source-csv/scripts/csv-discovery.js +949 -0
  157. package/skills/wix-replatform/resources/rp-source-csv/source-schema.example.json +196 -0
  158. package/skills/wix-replatform/resources/rp-source-csv/vendors/bigcommerce.json +66 -0
  159. package/skills/wix-replatform/resources/rp-source-csv/vendors/magento.json +60 -0
  160. package/skills/wix-replatform/resources/rp-source-csv/vendors/shopify.json +95 -0
  161. package/skills/wix-replatform/resources/rp-source-csv/vendors/woocommerce.json +82 -0
  162. package/skills/wix-replatform/resources/rp-source-wordpress/SKILL.md +256 -0
  163. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-http.js +249 -0
  164. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-route-classifier.js +444 -0
  165. package/skills/wix-replatform/resources/rp-source-wordpress/scripts/wp-discovery.js +774 -0
  166. package/skills/wix-replatform/resources/rp-source-wordpress/source-schema.example.json +71 -0
  167. package/skills/wix-replatform/resources/rp-target-wix/SKILL.md +632 -0
  168. package/skills/wix-replatform/resources/rp-target-wix/SPEC-product-reviews-and-blog-authorship.md +330 -0
  169. package/skills/wix-replatform/resources/rp-target-wix/domains/README.md +21 -0
  170. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/domain.json +19 -0
  171. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/category.json +37 -0
  172. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/comment.json +37 -0
  173. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/post.json +39 -0
  174. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/tag.json +35 -0
  175. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/domain.json +14 -0
  176. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/collection.json +35 -0
  177. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/data-item.json +36 -0
  178. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/reference.json +35 -0
  179. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/domain.json +14 -0
  180. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/contact.json +131 -0
  181. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/email-subscription.json +37 -0
  182. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/label.json +37 -0
  183. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/domain.json +21 -0
  184. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-line-item.json +37 -0
  185. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-refund.json +37 -0
  186. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order.json +97 -0
  187. package/skills/wix-replatform/resources/rp-target-wix/domains/index.json +528 -0
  188. package/skills/wix-replatform/resources/rp-target-wix/domains/media/domain.json +14 -0
  189. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-file.json +38 -0
  190. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-folder.json +37 -0
  191. package/skills/wix-replatform/resources/rp-target-wix/domains/members/domain.json +13 -0
  192. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/badge.json +37 -0
  193. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/member.json +53 -0
  194. package/skills/wix-replatform/resources/rp-target-wix/domains/schema.json +84 -0
  195. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/domain.json +25 -0
  196. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/category.json +37 -0
  197. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/coupon.json +37 -0
  198. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/inventory-item.json +38 -0
  199. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product-tag.json +37 -0
  200. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product.json +90 -0
  201. package/skills/wix-replatform/resources/rp-target-wix/lib/audit-summary.js +64 -0
  202. package/skills/wix-replatform/resources/rp-target-wix/lib/contract-ledger.js +141 -0
  203. package/skills/wix-replatform/resources/rp-target-wix/lib/domain-knowledge.js +384 -0
  204. package/skills/wix-replatform/resources/rp-target-wix/lib/ndjson.js +260 -0
  205. package/skills/wix-replatform/resources/rp-target-wix/lib/stores-verification.js +238 -0
  206. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-build.js +237 -0
  207. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-target-spec.js +238 -0
  208. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +2219 -0
  209. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge-validate.js +31 -0
  210. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge.js +100 -0
  211. package/skills/wix-replatform/resources/rp-target-wix/scripts/verify-stores.js +107 -0
  212. package/skills/wix-replatform/resources/rp-telemetry/SKILL.md +344 -0
  213. package/skills/wix-replatform/resources/rp-telemetry/lib/bi-sink.js +250 -0
  214. package/skills/wix-replatform/resources/rp-telemetry/lib/telemetry-recorder.js +1927 -0
  215. package/skills/wix-replatform/resources/rp-telemetry/scripts/meter-from-audit.js +83 -0
  216. package/skills/wix-replatform/resources/rp-telemetry/scripts/rp-telemetry.js +141 -0
  217. package/skills/wix-replatform/scripts/artifact-freshness.js +76 -0
  218. package/skills/wix-replatform/scripts/execution-manifest-validate.js +43 -0
  219. package/skills/wix-replatform/scripts/execution-state-prepare.js +128 -0
  220. package/skills/wix-replatform/scripts/orchestration-preflight.js +48 -0
  221. package/skills/wix-replatform/scripts/orchestration-route.js +46 -0
  222. package/skills/wix-replatform/scripts/orchestration-state.js +245 -0
  223. package/skills/wix-vibe-headless/SKILL.md +54 -25
  224. package/skills/wix-vibe-headless/install/deploy.cjs +95 -0
  225. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +34 -0
  226. package/skills/wix-vibe-headless/platforms/README.md +26 -0
  227. package/skills/wix-vibe-headless/platforms/base44.md +177 -0
  228. package/skills/wix-vibe-headless/platforms/generic.md +122 -0
  229. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +230 -119
  230. package/skills/wix-vibe-headless/references/blog/app/components/PostCard.jsx +43 -0
  231. package/skills/wix-vibe-headless/references/blog/app/components/PostChips.jsx +25 -0
  232. package/skills/wix-vibe-headless/references/blog/app/components/PostGrid.jsx +15 -0
  233. package/skills/wix-vibe-headless/references/blog/app/context/TaxonomyContext.jsx +35 -0
  234. package/skills/wix-vibe-headless/references/blog/app/hooks/usePostDetail.js +38 -0
  235. package/skills/wix-vibe-headless/references/blog/app/pages/Blog.jsx +40 -0
  236. package/skills/wix-vibe-headless/references/blog/app/pages/CategoryPage.jsx +54 -0
  237. package/skills/wix-vibe-headless/references/blog/app/pages/PostDetail.jsx +65 -0
  238. package/skills/wix-vibe-headless/references/blog/app/pages/TagPage.jsx +50 -0
  239. package/skills/wix-vibe-headless/references/blog/seed/SEED.md +103 -0
  240. package/skills/wix-vibe-headless/references/blog/seed/seed-blog.js +270 -0
  241. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +260 -145
  242. package/skills/wix-vibe-headless/references/bookings/app/components/BookingForm.jsx +65 -0
  243. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceCard.jsx +47 -0
  244. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceGrid.jsx +13 -0
  245. package/skills/wix-vibe-headless/references/bookings/app/components/SlotPicker.jsx +126 -0
  246. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +108 -0
  247. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServices.js +58 -0
  248. package/skills/wix-vibe-headless/references/bookings/app/lib/serviceFacts.js +95 -0
  249. package/skills/wix-vibe-headless/references/bookings/app/pages/ServiceDetail.jsx +94 -0
  250. package/skills/wix-vibe-headless/references/bookings/app/pages/Services.jsx +89 -0
  251. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-checkout.js → app/rest/wix-bookings-checkout.js} +1 -1
  252. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-services.js → app/rest/wix-bookings-services.js} +90 -12
  253. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +117 -0
  254. package/skills/wix-vibe-headless/references/bookings/seed/seed-bookings.js +333 -0
  255. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +169 -147
  256. package/skills/wix-vibe-headless/references/cms/app/collection.config.js +31 -0
  257. package/skills/wix-vibe-headless/references/cms/app/lib/wixImage.js +18 -0
  258. package/skills/wix-vibe-headless/references/cms/{wix-cms.js → app/rest/wix-cms.js} +47 -2
  259. package/skills/wix-vibe-headless/references/cms/seed/SEED.md +145 -0
  260. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +228 -131
  261. package/skills/wix-vibe-headless/references/events/app/components/CategoryFilter.jsx +23 -0
  262. package/skills/wix-vibe-headless/references/events/app/components/EventCard.jsx +43 -0
  263. package/skills/wix-vibe-headless/references/events/app/components/EventGrid.jsx +13 -0
  264. package/skills/wix-vibe-headless/references/events/app/components/EventRegistration.jsx +29 -0
  265. package/skills/wix-vibe-headless/references/events/app/components/RsvpForm.jsx +57 -0
  266. package/skills/wix-vibe-headless/references/events/app/components/TicketPicker.jsx +78 -0
  267. package/skills/wix-vibe-headless/references/events/app/hooks/useEventDetail.js +27 -0
  268. package/skills/wix-vibe-headless/references/events/app/hooks/useEventsList.js +54 -0
  269. package/skills/wix-vibe-headless/references/events/app/hooks/useRsvpForm.js +40 -0
  270. package/skills/wix-vibe-headless/references/events/app/hooks/useTicketing.js +81 -0
  271. package/skills/wix-vibe-headless/references/events/app/pages/EventDetail.jsx +48 -0
  272. package/skills/wix-vibe-headless/references/events/app/pages/Events.jsx +36 -0
  273. package/skills/wix-vibe-headless/references/events/{wix-events-browse.js → app/rest/wix-events-browse.js} +3 -2
  274. package/skills/wix-vibe-headless/references/events/seed/SEED.md +107 -0
  275. package/skills/wix-vibe-headless/references/events/seed/seed-events.js +251 -0
  276. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +276 -188
  277. package/skills/wix-vibe-headless/references/members/app/components/LoginForm.jsx +101 -0
  278. package/skills/wix-vibe-headless/references/members/app/components/MemberMenu.jsx +33 -0
  279. package/skills/wix-vibe-headless/references/members/app/components/RequireAuth.jsx +21 -0
  280. package/skills/wix-vibe-headless/references/members/app/components/SocialButtons.jsx +29 -0
  281. package/skills/wix-vibe-headless/references/members/app/context/MemberContext.jsx +54 -0
  282. package/skills/wix-vibe-headless/references/members/app/hooks/useLoginForm.js +77 -0
  283. package/skills/wix-vibe-headless/references/members/app/pages/Account.jsx +36 -0
  284. package/skills/wix-vibe-headless/references/members/app/pages/Callback.jsx +32 -0
  285. package/skills/wix-vibe-headless/references/members/app/pages/Login.jsx +35 -0
  286. package/skills/wix-vibe-headless/references/members/{wix-members-auth.js → app/rest/wix-members-auth.js} +6 -3
  287. package/skills/wix-vibe-headless/references/members/install/Register.jsx +22 -0
  288. package/skills/wix-vibe-headless/references/members/seed/SEED.md +22 -0
  289. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +233 -104
  290. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionCard.jsx +31 -0
  291. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionGrid.jsx +15 -0
  292. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectCard.jsx +39 -0
  293. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectGrid.jsx +15 -0
  294. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectMedia.jsx +29 -0
  295. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useCollectionProjects.js +35 -0
  296. package/skills/wix-vibe-headless/references/portfolio/app/hooks/usePortfolioGallery.js +27 -0
  297. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useProjectDetail.js +25 -0
  298. package/skills/wix-vibe-headless/references/portfolio/app/pages/CollectionPage.jsx +39 -0
  299. package/skills/wix-vibe-headless/references/portfolio/app/pages/Portfolio.jsx +27 -0
  300. package/skills/wix-vibe-headless/references/portfolio/app/pages/ProjectDetail.jsx +60 -0
  301. package/skills/wix-vibe-headless/references/portfolio/{wix-portfolio.js → app/rest/wix-portfolio.js} +84 -55
  302. package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +94 -0
  303. package/skills/wix-vibe-headless/references/portfolio/seed/seed-portfolio.js +236 -0
  304. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +240 -117
  305. package/skills/wix-vibe-headless/references/pricing-plans/app/components/OrderCard.jsx +35 -0
  306. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanCard.jsx +48 -0
  307. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanGrid.jsx +16 -0
  308. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanPrice.jsx +35 -0
  309. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/useMyPlans.js +25 -0
  310. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlanDetail.js +28 -0
  311. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlans.js +30 -0
  312. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/MyPlans.jsx +30 -0
  313. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/PlanDetail.jsx +53 -0
  314. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/Plans.jsx +28 -0
  315. package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +86 -0
  316. package/skills/wix-vibe-headless/references/pricing-plans/seed/seed-pricing-plans.js +251 -0
  317. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +248 -124
  318. package/skills/wix-vibe-headless/references/restaurants/app/components/ItemDialog.jsx +81 -0
  319. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuItemCard.jsx +71 -0
  320. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuList.jsx +43 -0
  321. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartButton.jsx +21 -0
  322. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +60 -0
  323. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +63 -0
  324. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useItemOrder.js +32 -0
  325. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useReservation.js +73 -0
  326. package/skills/wix-vibe-headless/references/restaurants/app/pages/Menu.jsx +28 -0
  327. package/skills/wix-vibe-headless/references/restaurants/app/pages/Reservations.jsx +102 -0
  328. package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +180 -0
  329. package/skills/wix-vibe-headless/references/restaurants/seed/seed-restaurants.js +452 -0
  330. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +56 -0
  331. package/skills/wix-vibe-headless/references/shared/{wix-client.js → app/rest/wix-client.js} +6 -8
  332. package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +6 -0
  333. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +263 -148
  334. package/skills/wix-vibe-headless/references/storefront/app/components/CartButton.jsx +20 -0
  335. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +150 -0
  336. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +167 -0
  337. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +51 -0
  338. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +54 -0
  339. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +119 -0
  340. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +71 -0
  341. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +109 -0
  342. package/skills/wix-vibe-headless/references/storefront/app/hooks/useShop.js +98 -0
  343. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +27 -0
  344. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +139 -0
  345. package/skills/wix-vibe-headless/references/storefront/app/pages/Shop.jsx +75 -0
  346. package/skills/wix-vibe-headless/references/storefront/{wix-store-cart.js → app/rest/wix-store-cart.js} +1 -1
  347. package/skills/wix-vibe-headless/references/storefront/{wix-store-catalog.js → app/rest/wix-store-catalog.js} +25 -2
  348. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +111 -0
  349. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +299 -0
  350. /package/skills/wix-vibe-headless/references/blog/{wix-blog.js → app/rest/wix-blog.js} +0 -0
  351. /package/skills/wix-vibe-headless/references/events/{wix-events-registration.js → app/rest/wix-events-registration.js} +0 -0
  352. /package/skills/wix-vibe-headless/references/pricing-plans/{wix-pricing-plans.js → app/rest/wix-pricing-plans.js} +0 -0
  353. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-menu.js → app/rest/wix-restaurants-menu.js} +0 -0
  354. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-ordering.js → app/rest/wix-restaurants-ordering.js} +0 -0
  355. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-reservations.js → app/rest/wix-restaurants-reservations.js} +0 -0
@@ -0,0 +1,109 @@
1
+ // useProductDetail — all PDP logic, no markup: load product by slug, pre-select first in-stock
2
+ // choice per option, resolve the buyer's selections to a Wix variant, gate add-to-cart on stock +
3
+ // mandatory modifiers, and build the addToCart payload. The data paths here (variant resolution,
4
+ // modifier keys, stock gating) are the bug-prone part — keep them verbatim; the PDP page only
5
+ // renders what this returns.
6
+ import { useState, useEffect, useMemo } from "react";
7
+ import { getProductBySlug } from "@/rest/wix-store-catalog";
8
+ import { storeImage } from "@/lib/storeImage";
9
+ import { useCart } from "@/context/CartContext";
10
+
11
+ export function useProductDetail(slug) {
12
+ const { addToCart } = useCart();
13
+ const [product, setProduct] = useState(null);
14
+ const [notFound, setNotFound] = useState(false);
15
+ // A missing product (notFound) and a failed request (error) need different pages: one is a dead
16
+ // link, the other is worth retrying. Without the split, a network blip reads as "product deleted".
17
+ const [error, setError] = useState(null);
18
+ const [adding, setAdding] = useState(false);
19
+ const [selectedOptions, setSelectedOptions] = useState({});
20
+ const [modifierValues, setModifierValues] = useState({});
21
+ const [quantity, setQuantity] = useState(1);
22
+ const [reloadKey, setReloadKey] = useState(0);
23
+
24
+ useEffect(() => {
25
+ let cancelled = false;
26
+ setProduct(null);
27
+ setNotFound(false);
28
+ setError(null);
29
+ getProductBySlug(slug)
30
+ .then((p) => {
31
+ if (cancelled) return;
32
+ if (!p) return setNotFound(true);
33
+ setProduct(p);
34
+ const initial = {};
35
+ (p.options || []).forEach((o) => {
36
+ const first = o.choicesSettings?.choices?.find((c) => c.inStock !== false);
37
+ if (first) initial[o.id] = first.choiceId;
38
+ });
39
+ setSelectedOptions(initial);
40
+ })
41
+ .catch((e) => { if (!cancelled) setError(e?.message || "Couldn't load this product."); });
42
+ return () => { cancelled = true; };
43
+ }, [slug, reloadKey]);
44
+
45
+ const options = product?.options || [];
46
+ const modifiers = product?.modifiers || [];
47
+ const variants = product?.variantsInfo?.variants || [];
48
+
49
+ const variant = useMemo(() => {
50
+ if (options.length === 0) return variants[0] || null;
51
+ if (!options.every((o) => selectedOptions[o.id])) return null;
52
+ return variants.find((v) => (v.choices || []).every((c) =>
53
+ selectedOptions[c.optionChoiceIds?.optionId] === c.optionChoiceIds?.choiceId)) || null;
54
+ }, [options, variants, selectedOptions]);
55
+
56
+ const inStock = variant ? variant.inventoryStatus?.inStock !== false : true;
57
+ const canAdd = useMemo(() => {
58
+ if (options.length > 0 && !variant) return false;
59
+ if (variant && !inStock) return false;
60
+ return modifiers.filter((m) => m.mandatory).every((m) =>
61
+ m.modifierRenderType === "FREE_TEXT" ? !!modifierValues[m.freeTextSettings?.key] : !!modifierValues[m.key]);
62
+ }, [options, variant, inStock, modifiers, modifierValues]);
63
+
64
+ const price = variant?.price?.actualPrice?.formattedAmount || product?.actualPriceRange?.minValue?.formattedAmount || "";
65
+
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.
69
+ const focusMediaUrl = useMemo(() => {
70
+ for (const o of options) {
71
+ const choice = (o.choicesSettings?.choices || []).find((c) => c.choiceId === selectedOptions[o.id]);
72
+ const url = storeImage(choice?.linkedMedia?.[0]);
73
+ if (url) return url;
74
+ }
75
+ return null;
76
+ }, [options, selectedOptions]);
77
+
78
+ const selectOption = (optionId, choiceId) => setSelectedOptions((s) => ({ ...s, [optionId]: choiceId }));
79
+ const setModifier = (key, value) => setModifierValues((s) => ({ ...s, [key]: value }));
80
+
81
+ async function submit() {
82
+ const modifierChoices = {}, customTextFields = {};
83
+ modifiers.forEach((m) => {
84
+ const k = m.modifierRenderType === "FREE_TEXT" ? m.freeTextSettings?.key : m.key;
85
+ if (!k || !modifierValues[k]) return;
86
+ (m.modifierRenderType === "FREE_TEXT" ? customTextFields : modifierChoices)[k] = modifierValues[k];
87
+ });
88
+ setAdding(true);
89
+ try {
90
+ // addToCart reports its own failures through the cart context (it opens the drawer with the
91
+ // reason), so nothing is swallowed by leaving this unguarded beyond resetting the button.
92
+ // Coerce the quantity: the shipped stepper lets the field sit empty mid-edit, and a keyboard
93
+ // submit from that state would otherwise post "" as the quantity.
94
+ await addToCart(product.id, variant?.id, Math.max(1, Number(quantity) || 1), {
95
+ modifierChoices: Object.keys(modifierChoices).length ? modifierChoices : undefined,
96
+ customTextFields: Object.keys(customTextFields).length ? customTextFields : undefined,
97
+ });
98
+ } finally {
99
+ setAdding(false);
100
+ }
101
+ }
102
+
103
+ return {
104
+ product, notFound, error, retry: () => setReloadKey((k) => k + 1),
105
+ options, modifiers,
106
+ selectedOptions, selectOption, modifierValues, setModifier,
107
+ quantity, setQuantity, variant, inStock, canAdd, adding, price, submit, focusMediaUrl,
108
+ };
109
+ }
@@ -0,0 +1,98 @@
1
+ // useShop — all catalog-listing logic, no markup: load the category menu, load a page of products for
2
+ // the active category, append the next page on demand, sort client-side, and surface a failure instead
3
+ // of leaving the page on a spinner. The Shop page only renders what this returns.
4
+ //
5
+ // Load-bearing:
6
+ // • paging is CURSOR-based. Keep the cursor from the previous response and pass it back; a cursor
7
+ // follow-up reuses the original filter, so the category is fixed for the life of that cursor.
8
+ // Changing category starts a fresh query, never a cursor continuation.
9
+ // • queryCategories returns the auto-created "all-products" system category alongside real ones, and
10
+ // `visible` does not flag it — filter it by slug or the menu shows a duplicate of everything.
11
+ // • sorting is done here on the loaded page, not by the API: with cursor paging the server would
12
+ // re-sort per page, so a sort applied across pages already fetched is the honest option. Say so in
13
+ // the UI if the catalog is larger than one page.
14
+ import { useCallback, useEffect, useMemo, useState } from "react";
15
+ import { queryProducts, queryProductsByCategory, queryCategories } from "@/rest/wix-store-catalog";
16
+
17
+ const SYSTEM_CATEGORY_SLUG = "all-products";
18
+ export const SORTS = {
19
+ featured: { label: "Featured" },
20
+ priceAsc: { label: "Price: low to high" },
21
+ priceHigh: { label: "Price: high to low" },
22
+ name: { label: "Name: A–Z" },
23
+ };
24
+
25
+ // Prices arrive formatted for display ("$12.00"), so read the numeric value for sorting from the
26
+ // amount when it's there and fall back to digits in the formatted string.
27
+ function priceOf(product) {
28
+ const min = product?.actualPriceRange?.minValue;
29
+ const n = Number(min?.amount ?? String(min?.formattedAmount || "").replace(/[^\d.]/g, ""));
30
+ return Number.isFinite(n) ? n : 0;
31
+ }
32
+
33
+ export function useShop({ pageSize = 24 } = {}) {
34
+ const [categories, setCategories] = useState([]);
35
+ const [activeCategory, setActiveCategory] = useState(null); // null = everything
36
+ const [products, setProducts] = useState(null); // null = first load
37
+ const [cursor, setCursor] = useState(null);
38
+ const [loadingMore, setLoadingMore] = useState(false);
39
+ const [error, setError] = useState(null);
40
+ const [sort, setSort] = useState("featured");
41
+
42
+ useEffect(() => {
43
+ queryCategories({ limit: 100 })
44
+ .then(({ categories: list }) =>
45
+ setCategories((list || []).filter((c) => c.visible !== false && c.slug !== SYSTEM_CATEGORY_SLUG)))
46
+ .catch(() => setCategories([])); // a store without categories is normal, not an error
47
+ }, []);
48
+
49
+ const load = useCallback(async (categoryId) => {
50
+ setProducts(null);
51
+ setCursor(null);
52
+ setError(null);
53
+ try {
54
+ const res = categoryId
55
+ ? await queryProductsByCategory(categoryId, { limit: pageSize })
56
+ : await queryProducts({ limit: pageSize });
57
+ setProducts(res.products);
58
+ setCursor(res.nextCursor);
59
+ } catch (e) {
60
+ setError(e?.message || "Couldn't load products.");
61
+ setProducts([]);
62
+ }
63
+ }, [pageSize]);
64
+
65
+ useEffect(() => { load(activeCategory?.id ?? null); }, [activeCategory, load]);
66
+
67
+ const loadMore = async () => {
68
+ if (!cursor || loadingMore) return;
69
+ setLoadingMore(true);
70
+ try {
71
+ const res = activeCategory
72
+ ? await queryProductsByCategory(activeCategory.id, { limit: pageSize, cursor })
73
+ : await queryProducts({ limit: pageSize, cursor });
74
+ setProducts((prev) => [...(prev || []), ...res.products]);
75
+ setCursor(res.nextCursor);
76
+ } catch (e) {
77
+ setError(e?.message || "Couldn't load more products.");
78
+ } finally {
79
+ setLoadingMore(false);
80
+ }
81
+ };
82
+
83
+ const sorted = useMemo(() => {
84
+ if (!products) return null;
85
+ const copy = [...products];
86
+ if (sort === "priceAsc") copy.sort((a, b) => priceOf(a) - priceOf(b));
87
+ else if (sort === "priceHigh") copy.sort((a, b) => priceOf(b) - priceOf(a));
88
+ else if (sort === "name") copy.sort((a, b) => (a.name || "").localeCompare(b.name || ""));
89
+ return copy;
90
+ }, [products, sort]);
91
+
92
+ return {
93
+ categories, activeCategory, setActiveCategory,
94
+ products: sorted, loading: products === null, error,
95
+ hasMore: !!cursor, loadMore, loadingMore,
96
+ sort, setSort, retry: () => load(activeCategory?.id ?? null),
97
+ };
98
+ }
@@ -0,0 +1,27 @@
1
+ // storeImage — turn a Wix Stores image value into a URL the browser can load.
2
+ // Wix returns these protocol-relative (`//static.wixstatic.com/...`), which resolves against the
3
+ // current page. That works on https pages and breaks on anything else, so normalise it once here
4
+ // instead of at each call site — product media, PDP gallery items, and cart line items all carry the
5
+ // same shape. Returns null for a missing value so callers can render a placeholder.
6
+ export function storeImage(value) {
7
+ const url = typeof value === "string" ? value : value?.image?.url || value?.url;
8
+ if (!url) return null;
9
+ if (url.startsWith("//")) return `https:${url}`;
10
+ return url;
11
+ }
12
+
13
+ // The main catalog image for a product (grid tiles, cart fallbacks).
14
+ export function productImage(product) {
15
+ return storeImage(product?.media?.main?.image?.url);
16
+ }
17
+
18
+ // Every gallery image for a product, main first, de-duplicated — `media.itemsInfo.items` repeats the
19
+ // main image, and video items carry no `image.url`. Returns [{ url, altText }].
20
+ export function productGallery(product) {
21
+ const items = product?.media?.itemsInfo?.items || [];
22
+ const urls = [productImage(product), ...items.map((i) => storeImage(i))];
23
+ const seen = new Set();
24
+ return urls
25
+ .map((url, i) => ({ url, altText: items[i - 1]?.altText || product?.name || "" }))
26
+ .filter(({ url }) => url && !seen.has(url) && seen.add(url));
27
+ }
@@ -0,0 +1,139 @@
1
+ // PDP — thin view over useProductDetail (all logic lives in the hook). plainDescription is HTML
2
+ // despite the name; render via dangerouslySetInnerHTML. Styled with base44 design tokens (shadcn Tailwind classes).
3
+ //
4
+ // The price shown follows the selection: once options resolve to a variant the hook returns that
5
+ // variant's price, so a picked size can cost more than the "from" figure the grid tile showed.
6
+ import { useMemo } from "react";
7
+ import { Link, useParams } from "react-router-dom";
8
+ import { useProductDetail } from "@/hooks/useProductDetail";
9
+ import { productGallery } from "@/lib/storeImage";
10
+ import ProductGallery from "@/components/ProductGallery";
11
+ import VariantPicker from "@/components/VariantPicker";
12
+
13
+ export default function ProductDetail() {
14
+ const { slug } = useParams();
15
+ const d = useProductDetail(slug);
16
+ // Memoised so the gallery keeps its selected image across re-renders (see ProductGallery).
17
+ const images = useMemo(() => productGallery(d.product), [d.product]);
18
+
19
+ if (d.error) {
20
+ return (
21
+ <Centered>
22
+ <p className="m-0">{d.error}</p>
23
+ <button onClick={d.retry} className="border border-border bg-card text-foreground rounded-sm py-2 px-4 cursor-pointer text-sm">Try again</button>
24
+ </Centered>
25
+ );
26
+ }
27
+ if (d.notFound) {
28
+ return (
29
+ <Centered>
30
+ <p className="m-0">We couldn't find that product.</p>
31
+ <Link to="/shop" className="text-primary">Back to shop</Link>
32
+ </Centered>
33
+ );
34
+ }
35
+ if (!d.product) return <ProductDetailSkeleton />;
36
+
37
+ const compareAt = d.product?.compareAtPriceRange?.minValue?.formattedAmount;
38
+
39
+ return (
40
+ <main className="max-w-[1200px] mx-auto p-4">
41
+ <nav aria-label="Breadcrumb" className="mb-4 text-sm text-muted-foreground">
42
+ <Link to="/shop" className="text-muted-foreground hover:text-foreground">Shop</Link>
43
+ <span aria-hidden="true"> / </span>
44
+ <span className="text-foreground">{d.product.name}</span>
45
+ </nav>
46
+
47
+ <div className="grid gap-8 [grid-template-columns:repeat(auto-fit,minmax(320px,1fr))]">
48
+ <ProductGallery images={images} name={d.product.name} focusUrl={d.focusMediaUrl} />
49
+
50
+ <div>
51
+ <h1 className="font-display m-0 mb-2">{d.product.name}</h1>
52
+
53
+ <div className="flex items-baseline gap-2 mb-4">
54
+ <p className="text-[22px] font-semibold m-0">{d.price}</p>
55
+ {compareAt && compareAt !== d.price && (
56
+ <span className="text-muted-foreground line-through">{compareAt}</span>
57
+ )}
58
+ </div>
59
+
60
+ {d.product.plainDescription && (
61
+ <div className="text-muted-foreground leading-relaxed mb-6"
62
+ dangerouslySetInnerHTML={{ __html: d.product.plainDescription }} />
63
+ )}
64
+
65
+ <VariantPicker
66
+ options={d.options} modifiers={d.modifiers}
67
+ selectedOptions={d.selectedOptions} selectOption={d.selectOption}
68
+ modifierValues={d.modifierValues} setModifier={d.setModifier}
69
+ />
70
+
71
+ {/* Tell the buyer WHY the button is dead: an unresolvable combination reads as a broken page. */}
72
+ {d.options.length > 0 && !d.variant && (
73
+ <p className="text-[13px] text-muted-foreground m-0 mt-1">Pick an option from each list to continue.</p>
74
+ )}
75
+
76
+ <div className="flex items-stretch gap-3 mt-4">
77
+ <QuantityStepper value={d.quantity} onChange={d.setQuantity} disabled={!d.inStock} />
78
+ <button disabled={!d.canAdd || d.adding} onClick={d.submit}
79
+ className="flex-1 h-12 px-6 bg-primary text-primary-foreground border-none rounded-md text-[15px] font-semibold cursor-pointer transition-opacity hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed">
80
+ {d.adding ? "Adding…" : d.inStock ? "Add to cart" : "Out of stock"}
81
+ </button>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </main>
86
+ );
87
+ }
88
+
89
+ // Segmented −/+ stepper, height-matched to the Add-to-cart button so the row reads as one control.
90
+ // A native number input is avoided on purpose: its spinners are ~10px, OS-rendered (so they ignore
91
+ // the app's tokens), effectively untappable, and they accept "e"/"+"/"1e5" plus scroll-wheel edits.
92
+ // The value stays typeable — inputMode="numeric" brings up a keypad — but only digits survive, and
93
+ // blur restores 1 when the field is left empty. `tabular-nums` keeps the width steady across digits.
94
+ function QuantityStepper({ value, onChange, disabled }) {
95
+ const set = (n) => onChange(Math.max(1, n));
96
+ return (
97
+ <div data-disabled={disabled || undefined}
98
+ className="inline-flex items-stretch h-12 rounded-md border border-input bg-background overflow-hidden data-[disabled]:opacity-50">
99
+ <StepButton label="Decrease quantity" disabled={disabled || value <= 1} onClick={() => set(value - 1)}>−</StepButton>
100
+ <label className="sr-only" htmlFor="pdp-qty">Quantity</label>
101
+ <input id="pdp-qty" type="text" inputMode="numeric" autoComplete="off" disabled={disabled}
102
+ value={value} aria-live="polite"
103
+ onChange={(e) => { const n = e.target.value.replace(/\D/g, ""); onChange(n === "" ? "" : Math.max(1, Number(n))); }}
104
+ onBlur={(e) => { if (!e.target.value) set(1); }}
105
+ className="w-12 text-center bg-transparent text-foreground font-semibold tabular-nums border-x border-input outline-none focus-visible:ring-2 focus-visible:ring-primary/40 disabled:cursor-not-allowed" />
106
+ <StepButton label="Increase quantity" disabled={disabled} onClick={() => set(Number(value || 0) + 1)}>+</StepButton>
107
+ </div>
108
+ );
109
+ }
110
+
111
+ function StepButton({ children, label, onClick, disabled }) {
112
+ return (
113
+ <button type="button" onClick={onClick} disabled={disabled} aria-label={label}
114
+ className="w-11 grid place-items-center text-lg leading-none text-muted-foreground bg-transparent border-none cursor-pointer transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent">
115
+ {children}
116
+ </button>
117
+ );
118
+ }
119
+
120
+ function ProductDetailSkeleton() {
121
+ return (
122
+ <main className="max-w-[1200px] mx-auto p-4" aria-busy="true">
123
+ <div className="grid gap-8 [grid-template-columns:repeat(auto-fit,minmax(320px,1fr))]">
124
+ <div className="aspect-square bg-muted rounded-lg animate-pulse" />
125
+ <div className="flex flex-col gap-3">
126
+ <div className="h-7 w-2/3 bg-muted rounded-sm animate-pulse" />
127
+ <div className="h-6 w-24 bg-muted rounded-sm animate-pulse" />
128
+ <div className="h-4 w-full bg-muted rounded-sm animate-pulse mt-3" />
129
+ <div className="h-4 w-5/6 bg-muted rounded-sm animate-pulse" />
130
+ <div className="h-11 w-full bg-muted rounded-sm animate-pulse mt-6" />
131
+ </div>
132
+ </div>
133
+ </main>
134
+ );
135
+ }
136
+
137
+ function Centered({ children }) {
138
+ return <div className="p-12 flex flex-col items-center gap-3 text-center text-muted-foreground">{children}</div>;
139
+ }
@@ -0,0 +1,75 @@
1
+ // Shop / catalog page — thin view over useShop (all logic lives in the hook). Category menu, sort,
2
+ // cursor paging, plus the loading / empty / failed states a seeded-separately catalog needs.
3
+ // Styled with base44 design tokens (shadcn Tailwind classes).
4
+ import { useShop, SORTS } from "@/hooks/useShop";
5
+ import ProductGrid from "@/components/ProductGrid";
6
+
7
+ export default function Shop() {
8
+ const s = useShop();
9
+ const showCategories = s.categories.length > 0;
10
+
11
+ return (
12
+ <main className="max-w-[1200px] mx-auto p-4">
13
+ <div className="flex flex-wrap items-end justify-between gap-3 mb-4">
14
+ <h1 className="font-display m-0">{s.activeCategory?.name || "Shop"}</h1>
15
+ {s.products?.length > 0 && (
16
+ <label className="flex items-center gap-2 text-sm text-muted-foreground">
17
+ Sort
18
+ <select value={s.sort} onChange={(e) => s.setSort(e.target.value)}
19
+ className="py-1.5 px-2 border border-input rounded-sm bg-background text-foreground text-sm">
20
+ {Object.entries(SORTS).map(([key, { label }]) => <option key={key} value={key}>{label}</option>)}
21
+ </select>
22
+ </label>
23
+ )}
24
+ </div>
25
+
26
+ {showCategories && (
27
+ <nav aria-label="Categories" className="flex flex-wrap gap-2 mb-6">
28
+ <CategoryChip active={!s.activeCategory} onClick={() => s.setActiveCategory(null)}>All</CategoryChip>
29
+ {s.categories.map((c) => (
30
+ <CategoryChip key={c.id} active={s.activeCategory?.id === c.id} onClick={() => s.setActiveCategory(c)}>
31
+ {c.name}
32
+ </CategoryChip>
33
+ ))}
34
+ </nav>
35
+ )}
36
+
37
+ {s.error ? (
38
+ <div role="alert" className="flex flex-col items-center gap-3 py-16 text-center">
39
+ <p className="m-0 text-muted-foreground">{s.error}</p>
40
+ <button onClick={s.retry}
41
+ className="border border-border bg-card text-foreground rounded-sm py-2 px-4 cursor-pointer text-sm">Try again</button>
42
+ </div>
43
+ ) : (
44
+ <>
45
+ <ProductGrid
46
+ products={s.products}
47
+ loading={s.loading}
48
+ empty={s.activeCategory ? `Nothing in ${s.activeCategory.name} yet.` : "No products yet."}
49
+ emptyHint={s.activeCategory
50
+ ? "Pick another category, or add products to this one from your Wix dashboard."
51
+ : "Add products in your Wix dashboard and they'll appear here — no redeploy needed."}
52
+ />
53
+
54
+ {s.hasMore && (
55
+ <div className="flex justify-center mt-8">
56
+ <button onClick={s.loadMore} disabled={s.loadingMore}
57
+ className="border border-border bg-card text-foreground rounded-sm py-2.5 px-6 cursor-pointer text-sm font-semibold disabled:opacity-60 disabled:cursor-wait">
58
+ {s.loadingMore ? "Loading…" : "Load more"}
59
+ </button>
60
+ </div>
61
+ )}
62
+ </>
63
+ )}
64
+ </main>
65
+ );
66
+ }
67
+
68
+ function CategoryChip({ active, onClick, children }) {
69
+ return (
70
+ <button onClick={onClick} aria-pressed={active}
71
+ className={`py-1.5 px-3 cursor-pointer text-sm rounded-sm border ${
72
+ active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-foreground"
73
+ }`}>{children}</button>
74
+ );
75
+ }
@@ -8,7 +8,7 @@ const STORES_APP_ID = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
8
8
 
9
9
  /**
10
10
  * Wix eCom Cart — key fields for building a cart UI.
11
- * Full model: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart/get-cart.md
11
+ * Full model: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/get-current-cart.md
12
12
  *
13
13
  * id {string}, currency {string},
14
14
  * lineItems[].id {string} — lineItemId for update/remove (NOT catalogItemId),
@@ -13,14 +13,35 @@ import { wixApiRequest } from "./wix-client.js";
13
13
  * actualPriceRange.minValue.formattedAmount {string} — lowest price with currency symbol,
14
14
  * actualPriceRange.maxValue.formattedAmount {string} — highest price with currency symbol,
15
15
  * compareAtPriceRange.minValue.formattedAmount {string} — strikethrough price (present when on sale),
16
+ * actualPriceRange/compareAtPriceRange .minValue.amount {string} — the same figures unformatted
17
+ * ("129.00"). Use these for arithmetic: a percent-off badge can't be computed from "€129.00",
16
18
  * inventory.availabilityStatus {string} — "IN_STOCK"|"OUT_OF_STOCK"|"PARTIALLY_OUT_OF_STOCK",
19
+ * inventory.preorderStatus {string} — "ENABLED"|"DISABLED". ENABLED + OUT_OF_STOCK is a pre-order,
20
+ * which is buyable — label it "Pre-order" rather than "Sold out",
21
+ * NB: inventory carries no stock COUNT. "Limited stock" (from PARTIALLY_OUT_OF_STOCK) is the most
22
+ * precise scarcity signal a tile can show; "Only 2 left" needs per-variant inventory, i.e. a
23
+ * getProductBySlug call per product,
24
+ * ribbon {object} — { id, name } merchant-set badge: "New", "Sale", "Best Seller". This is the
25
+ * catalogue's own label, so prefer it over anything derived — a "new" badge computed from
26
+ * createdDate flags every product at once right after seeding,
27
+ * additionalRibbons {array} — further { id, name } badges,
28
+ * createdDate / updatedDate {string} — ISO timestamps,
29
+ * variantSummary.variantCount {number} — how many variants exist, without fetching them,
17
30
  * options {array} — product options e.g. Size, Color:
18
31
  * [{ id, name, optionRenderType "TEXT_CHOICES"|"COLOR_CHOICES"|"SWATCH_CHOICES",
19
- * choicesSettings.choices [{ choiceId, key, name, inStock, visible, linkedMedia }] }],
32
+ * choicesSettings.choices [{ choiceId, key, name, inStock, visible, choiceType, colorCode,
33
+ * linkedMedia }] }],
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.)
20
39
  * modifiers {array} — non-variant customizations (engraving, gift wrap):
21
40
  * [{ id, name, mandatory, modifierRenderType "TEXT_CHOICES"|"FREE_TEXT",
22
41
  * key, choicesSettings.choices, freeTextSettings.key }],
23
- * plainDescription {string} — HTML product description,
42
+ * plainDescription {string} — product description as an HTML string (contains <p>, <br>,
43
+ * <strong>…) despite the "plain" name — NOT plain text. Render with innerHTML /
44
+ * dangerouslySetInnerHTML; strip tags only for plain-text contexts (meta description, teaser),
24
45
  * variantsInfo.variants {array} — returned only by getProductBySlug:
25
46
  * [{ id, visible, choices [{ optionChoiceIds: { optionId, choiceId } }],
26
47
  * price: { actualPrice, compareAtPrice }, media, inventoryStatus: { inStock } }]
@@ -28,6 +49,8 @@ import { wixApiRequest } from "./wix-client.js";
28
49
  * match all selected { optionId, choiceId } pairs, then pass variant.id to addToCart.
29
50
  *
30
51
  * Category: { id, name, slug, visible, description, image, itemCounter, parentCategory.id }
52
+ * NB: queryCategories includes the auto-created system category { slug: "all-products" } —
53
+ * filter it out of a category menu (see INSTRUCTIONS.md). `visible` does not flag it.
31
54
  * Full model: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories
32
55
  */
33
56
 
@@ -0,0 +1,111 @@
1
+ # Storefront — seeding
2
+
3
+ Seed a Wix Stores catalog by **calling `seed-store.js`** — don't hand-write the REST calls. It's
4
+ a build-time module (run via `exec_tool`, not shipped in the app) that abstracts every Wix Stores
5
+ seed operation. Load it and call **`setupStore` — the one-call path** — with plain data.
6
+
7
+ ```js
8
+ // build-time exec_tool
9
+ const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix"); // Base44 (generic: use $TOKEN)
10
+ const fs = require("fs");
11
+ // exec_tool's require can return EMPTY exports for these build-time modules — load the file itself:
12
+ const seed = (() => { const m = { exports: {} };
13
+ new Function("module", "exports", "require", fs.readFileSync("/app/.agents/skills/wix-vibe-headless/references/storefront/seed/seed-store.js", "utf8"))(m, m.exports, require);
14
+ return m.exports; })();
15
+ const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
16
+
17
+ // ONE call: install (+ wait for V3) → create products → categories → attach images, ids kept
18
+ // in memory (no hand-threading). Categories map name -> product NAMES. Pass an imageUrl per product
19
+ // to attach its image; omit it to skip images.
20
+ // imageUrl must be the FINAL https://media.base44.com/... url from the COMPLETED generate_image
21
+ // result — not a still-generating /__generating__/<id>.png placeholder (Wix can't fetch that).
22
+ // generate_image runs in the background while you build, so the urls are ready by seed time.
23
+ const result = await seed.setupStore(ctx, {
24
+ products: [
25
+ { name: "The Glam Rocker", description: "Sequin-studded velvet legend…", price: 49.99, quantity: 12, imageUrl: imageUrls[0] },
26
+ // a product with buyer choices — see "Options, variants and sale prices" below
27
+ { name: "The Understudy", description: "…", price: 245, quantity: 8, imageUrl: imageUrls[1],
28
+ options: [{ name: "Color", type: "color", choices: [{ name: "Ink", colorCode: "#1B1B2F" }, { name: "Bone", colorCode: "#EDE6D6" }] }] },
29
+ // a product on sale — compareAtPrice drives the strikethrough + the tile's percent-off badge
30
+ { name: "Encore Jacket", description: "…", price: 68, compareAtPrice: 129, quantity: 5, imageUrl: imageUrls[2] },
31
+ ],
32
+ categories: { "Legends": ["The Glam Rocker"], "Rising Stars": [] }, // omit if the brief names none
33
+ });
34
+ // result: { products:[{id,slug,revision,name}], categories:[{id,name}], imagesAttached }
35
+ ```
36
+
37
+ **Seeding is additive — never delete or overwrite existing content.** Don't clean up, don't remove
38
+ "sample" data, don't reset. Just add.
39
+
40
+ ## Options, variants and sale prices
41
+
42
+ The shipped storefront renders colour options as real swatches, shows a size/colour summary on each
43
+ 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.
47
+
48
+ ```js
49
+ options: [
50
+ { name: "Color", type: "color", choices: [{ name: "Ink", colorCode: "#1B1B2F" }, { name: "Bone", colorCode: "#EDE6D6" }] },
51
+ { name: "Size", type: "text", choices: ["Small", "Medium", "Large"] }, // or [{ name: "Small" }, …]
52
+ ]
53
+ ```
54
+
55
+ - `type: "color"` → `SWATCH_CHOICES` with each choice's `colorCode`, which the PDP draws as a swatch.
56
+ Any other `type` → text pills. Give every colour choice a `colorCode`.
57
+ - Variants are expanded for you: the full cross-product of the options, each carrying the product's
58
+ `price`, `compareAtPrice` and `quantity`. Two options with 2 and 3 choices means 6 variants — keep
59
+ option counts small.
60
+ - `compareAtPrice` (> `price`) is the "was" price: strikethrough on the PDP and a `−N%` badge on the
61
+ tile, computed from the two amounts. It works with or without options.
62
+
63
+ Two things this module does **not** seed, so don't try:
64
+
65
+ - **Ribbons** ("New", "Best Seller"). The tile renders `product.ribbon` when it's there, but ribbons
66
+ 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.
70
+
71
+ ## Escape hatch — individual functions
72
+ Reach for the functions below only when the one-call `setupStore` doesn't fit (partial re-seed, custom
73
+ ordering, mid-flow checks). `setupStore` is built from them, in this order:
74
+
75
+ ```js
76
+ await seed.installStoresApp(ctx); // install + wait for the V3 catalog
77
+ const products = await seed.bulkCreateProducts(ctx, [ // → [{id,slug,revision}], in stock by `quantity`
78
+ { name: "The Glam Rocker", description: "…", price: 49.99, quantity: 12 },
79
+ ]);
80
+ const cats = await seed.createCategories(ctx, ["Legends"]); // sequential → [{id,name}]
81
+ await seed.addProductsToCategories(ctx, { [cats[0].id]: [products[0].id] });
82
+ // images: use the FINAL https://media.base44.com/... url only (never a /__generating__/ placeholder)
83
+ await seed.attachProductImages(ctx, products.map((p, i) => ({ id: p.id, url: imageUrls[i], altText: p.slug })));
84
+ ```
85
+
86
+ ## Functions
87
+ | fn | does |
88
+ |---|---|
89
+ | `setupStore(ctx, {products, categories?})` | **one-call**: install+wait → products → categories → images |
90
+ | `installStoresApp(ctx)` | install the Wix Stores app on the site (waits for the V3 catalog) |
91
+ | `bulkCreateProducts(ctx, products)` | one bulk create → `[{id,slug,revision}]`; products come out in stock with the `quantity` you pass |
92
+ | `createCategories(ctx, names)` | sequential (shared tree 409s on concurrent) → `[{id,name}]` |
93
+ | `addProductsToCategories(ctx, {catId:[pid]})` | sequential add-items |
94
+ | `attachProductImages(ctx, [{id,url,altText}])` | one bulk media attach; no revision to pass. Wix re-hosts each url server-side; the media can take a little while to appear on read-back (propagation) — normal, not a failure |
95
+
96
+ ## Reference
97
+ If a call returns a shape you didn't expect, or you need an operation this module doesn't cover,
98
+ use the **`wix-docs`** skill to search + read the live Wix API reference — never guess. The
99
+ authoritative source recipe is `wix-headless/references/inline-recipes/setup-online-store.md`.
100
+
101
+ Read a method's page before writing its call: it carries the exact body shape, the required
102
+ permission scope, and the response envelope.
103
+ - Install a Wix app onto the site: https://dev.wix.com/docs/api-reference/business-management/app-installation/app-installation/install-app.md
104
+ - Import an image into Wix Media: https://dev.wix.com/docs/api-reference/assets/media/media-manager/files/import-file.md
105
+ - Create Category: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories/create-category.md
106
+ - Bulk Update Categories: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories/bulk-update-categories.md
107
+ - Bulk Add Items To Category: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories/bulk-add-items-to-category.md
108
+ - Bulk Create Products With Inventory: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/bulk-create-products-with-inventory.md
109
+ - Bulk Update Products: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/bulk-update-products.md
110
+ - Bulk Create Inventory Items: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/inventory-items-v3/bulk-create-inventory-items.md
111
+ - Query Products: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/query-products.md