@wix/agent-skills 1.16.3 → 1.18.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 (283) 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 +145 -127
  9. package/skills/wix-app/references/SITE_PLUGIN.md +14 -2
  10. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
  11. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
  12. package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
  13. package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
  14. package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
  15. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
  16. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
  17. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +94 -49
  18. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +16 -6
  19. package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
  20. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
  21. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +35 -40
  22. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +167 -445
  23. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +56 -29
  24. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
  25. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
  26. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
  27. package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +11 -3
  28. package/skills/wix-app/references/editor-react-component/PARTS.md +46 -24
  29. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
  30. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
  31. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
  32. package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
  33. package/skills/wix-base44-connector/SKILL.md +156 -50
  34. package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
  35. package/skills/wix-base44-connector/scripts/utils.js +239 -45
  36. package/skills/wix-headless/entry/bootstrap.mjs +9 -2
  37. package/skills/wix-headless/entry/skill.md +1 -1
  38. package/skills/wix-headless/references/CAPABILITIES.md +9 -1
  39. package/skills/wix-headless/references/DESIGN.md +1 -0
  40. package/skills/wix-headless/references/DISCOVERY.md +2 -1
  41. package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
  42. package/skills/wix-headless/references/SDK_HANDOFF.md +5 -2
  43. package/skills/wix-headless/references/SEED.md +2 -1
  44. package/skills/wix-headless/references/SETUP.md +1 -0
  45. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
  46. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +68 -31
  47. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
  48. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
  49. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
  50. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
  51. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
  52. package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
  53. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
  54. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
  55. package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
  56. package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
  57. package/skills/wix-headless/references/non-astro.md +1 -1
  58. package/skills/wix-headless-fast/SKILL.md +166 -0
  59. package/skills/wix-headless-fast/entry/skill.md +99 -0
  60. package/skills/wix-headless-fast/install/deploy.mjs +433 -0
  61. package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
  62. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
  63. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
  64. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
  65. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
  66. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
  67. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
  68. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
  69. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
  70. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
  71. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
  72. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
  73. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
  74. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
  75. package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
  76. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
  77. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
  78. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
  79. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
  80. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
  81. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
  82. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
  83. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
  84. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
  85. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
  86. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
  87. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
  88. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
  89. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
  90. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
  91. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
  92. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
  93. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
  94. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
  95. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
  96. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
  97. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
  98. package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
  99. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
  100. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
  101. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
  102. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
  103. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
  104. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
  105. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
  106. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
  107. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
  108. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
  109. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
  110. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
  111. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
  112. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
  113. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
  114. package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
  115. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
  116. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
  117. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
  118. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
  119. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
  120. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
  121. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
  122. package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
  123. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
  124. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
  125. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
  126. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
  127. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
  128. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
  129. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
  130. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
  131. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
  132. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
  133. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
  134. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
  135. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
  136. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
  137. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
  138. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
  139. package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
  140. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
  141. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
  142. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
  143. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
  144. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
  145. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
  146. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
  147. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
  148. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
  149. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
  150. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
  151. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
  152. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
  153. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
  154. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
  155. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
  156. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
  157. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
  158. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
  159. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
  160. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
  161. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
  162. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
  163. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
  164. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
  165. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
  166. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
  167. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
  168. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
  169. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
  170. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
  171. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
  172. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
  173. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
  174. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
  175. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
  176. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
  177. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
  178. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
  179. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
  180. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
  181. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
  182. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
  183. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
  184. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
  185. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
  186. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
  187. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
  188. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
  189. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
  190. package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
  191. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
  192. package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
  193. package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
  194. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
  195. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
  196. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
  197. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
  198. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
  199. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
  200. package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
  201. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
  202. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
  203. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
  204. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
  205. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
  206. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
  207. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
  208. package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
  209. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
  210. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
  211. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
  212. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
  213. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
  214. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
  215. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
  216. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
  217. package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
  218. package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
  219. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
  220. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
  221. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
  222. package/skills/wix-manage/SKILL.md +28 -2
  223. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
  224. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
  225. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
  226. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
  227. package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
  228. package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
  229. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
  230. package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
  231. package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
  232. package/skills/wix-manage/references/sites/query-sites.md +72 -161
  233. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +21 -6
  234. package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
  235. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
  236. package/skills/wix-vibe-headless/SKILL.md +18 -4
  237. package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
  238. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
  239. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +16 -10
  240. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +13 -8
  241. package/skills/wix-vibe-headless/platforms/base44.md +27 -62
  242. package/skills/wix-vibe-headless/platforms/generic.md +6 -3
  243. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +45 -0
  244. package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
  245. package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
  246. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
  247. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
  248. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
  249. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
  250. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
  251. package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
  252. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
  253. package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +470 -0
  254. package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
  255. package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
  256. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
  257. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
  258. package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1762 -0
  259. package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
  260. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
  261. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
  262. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
  263. package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
  264. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +152 -92
  265. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
  266. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
  267. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
  268. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
  269. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
  270. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
  271. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
  272. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
  273. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
  274. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
  275. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -516
  276. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
  277. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
  278. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
  279. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
  280. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
  281. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
  282. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
  283. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
@@ -0,0 +1,39 @@
1
+ # Members — seeding
2
+
3
+ **Members self-register — there is no member content to seed.** The Wix login page registers
4
+ or logs in members at runtime; creating members at build time is intentionally out of scope
5
+ (a headless run must never stall on an interactive login, and Create Member needs an
6
+ elevated credential).
7
+
8
+ What `seed-members.mjs` does is the one build-time setup the vertical needs: **install the
9
+ Wix Members Area app** — the *profile* layer. Identity (log in / log out / "logged-in vs
10
+ not" gating) needs no install; profile data does: without the app, `getCurrentMember()`
11
+ returns nothing for a logged-in member and the account page can't render who they are.
12
+
13
+ ```bash
14
+ # from the project root (where wix.config.json lives) — the plan file is optional:
15
+ node <SKILL_ROOT>/references/members/seed/seed-members.mjs
16
+ ```
17
+
18
+ ```json
19
+ { "installMembersArea": true }
20
+ ```
21
+
22
+ - `installMembersArea` — default `true`; set `false` only when the run needs pure
23
+ "logged-in vs not" gating and will never display member data.
24
+ - Re-running is safe: an already-installed app is recorded in the result JSON
25
+ (`membersAreaInstall.note`), never thrown.
26
+
27
+ **Seeding is additive — never delete or overwrite existing content**; ask first if a cleanup
28
+ seems needed.
29
+
30
+ ## Escape hatch — individual functions
31
+ `setupMembers` composes the exported steps — `installMembersAreaApp`, plus `makeCtx()` —
32
+ import them for a partial re-run.
33
+
34
+ ## Reference
35
+ The appDefId and the identity/profile split come from
36
+ `wix-headless/references/SETUP.md` (§ members). Signup security (email verification, owner
37
+ approval, reCAPTCHA) is dashboard-governed — never seeded. If a run's prompt explicitly needs
38
+ a pre-created member (rare), the admin Create Member shape is in the live Wix API reference —
39
+ read it via the `wix-docs` skill; don't guess it here.
@@ -0,0 +1,94 @@
1
+ // Members seed — a BUILD-TIME script, never shipped in the app. Run from the project root
2
+ // (where wix.config.json lives); the plan file is optional:
3
+ //
4
+ // node <SKILL_ROOT>/references/members/seed/seed-members.mjs [plan.json]
5
+ //
6
+ // Members SELF-REGISTER — there is no member content to create (see SEED.md). The one
7
+ // build-time setup this vertical needs is installing the Wix Members Area app, which serves
8
+ // member PROFILE data: without it getCurrentMember() returns nothing for a logged-in member,
9
+ // so the account page can't render who they are. Identity alone (log in / log out / gating)
10
+ // needs no install. Prints a JSON result to stdout.
11
+ //
12
+ // Plan shape (see SEED.md): { "installMembersArea": true } // default true
13
+ //
14
+ // Seeding is ADDITIVE — never deletes or overwrites existing content. Authoritative source:
15
+ // wix-headless/references/SETUP.md § members (the appDefId and the identity/profile split).
16
+ import { execFileSync } from "node:child_process";
17
+ import { readFileSync } from "node:fs";
18
+
19
+ const API = "https://www.wixapis.com";
20
+ // The Wix Members Area app (the profile layer). Not in the "Apps Created by Wix" table —
21
+ // the GUID comes from the App Market listing; recorded in wix-headless/references/SETUP.md.
22
+ // Installing it pulls in its Site-Members dependency automatically.
23
+ const MEMBERS_AREA_APP_ID = "14cc59bc-f0b7-15b8-e1c7-89ce41d0e0c9";
24
+
25
+ export function makeCtx({ cwd = process.cwd() } = {}) {
26
+ const config = JSON.parse(readFileSync(`${cwd}/wix.config.json`, "utf8"));
27
+ const siteId = config.siteId ?? config.projectId;
28
+ if (!siteId) throw new Error("wix.config.json has no siteId — is this a Wix CLI project?");
29
+ const token = execFileSync("npx", ["@wix/cli@latest", "token", "--site", siteId], {
30
+ encoding: "utf8",
31
+ cwd,
32
+ }).trim();
33
+ if (!token) throw new Error("The Wix CLI returned no token — run `npx @wix/cli@latest login` first.");
34
+ return { token, siteId };
35
+ }
36
+
37
+ async function req(ctx, path, { method = "POST", body } = {}) {
38
+ const res = await fetch(API + path, {
39
+ method,
40
+ headers: {
41
+ Authorization: `Bearer ${ctx.token}`,
42
+ "wix-site-id": ctx.siteId,
43
+ "Content-Type": "application/json",
44
+ },
45
+ body: body ? JSON.stringify(body) : undefined,
46
+ });
47
+ const json = await res.json().catch(() => ({}));
48
+ if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 400)}`);
49
+ return json;
50
+ }
51
+
52
+ // ---- operations ----------------------------------------------------------------------------------
53
+
54
+ /**
55
+ * Install the Wix Members Area app (idempotent in effect: re-running against a site that
56
+ * already has it errors — recorded in the result, not thrown, since "already installed" and
57
+ * a real failure aren't distinguishable from the response).
58
+ * docs: https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/platform/about-apps-created-by-wix.md
59
+ */
60
+ export async function installMembersAreaApp(ctx) {
61
+ try {
62
+ await req(ctx, "/apps-installer-service/v1/app-instance/install", { body: {
63
+ tenant: { tenantType: "SITE", id: ctx.siteId },
64
+ appInstance: { appDefId: MEMBERS_AREA_APP_ID, enabled: true },
65
+ } });
66
+ return { requested: true, note: null };
67
+ } catch (e) {
68
+ return { requested: false, note: String(e.message).slice(0, 300) };
69
+ }
70
+ }
71
+
72
+ /** ONE-CALL seed: install the Members Area app (the profile layer). The default path. */
73
+ export async function setupMembers(ctx, { installMembersArea = true } = {}) {
74
+ return {
75
+ membersAreaAppId: MEMBERS_AREA_APP_ID,
76
+ membersAreaInstall: installMembersArea ? await installMembersAreaApp(ctx) : { skipped: true },
77
+ membersCreated: 0, // members self-register — never created at build time
78
+ };
79
+ }
80
+
81
+ // ---- CLI entry ----------------------------------------------------------------------------------
82
+
83
+ const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
84
+ if (invokedDirectly) {
85
+ const planPath = process.argv[2];
86
+ const plan = planPath ? JSON.parse(readFileSync(planPath, "utf8")) : {};
87
+ const ctx = makeCtx();
88
+ setupMembers(ctx, plan)
89
+ .then((result) => console.log(JSON.stringify(result, null, 2)))
90
+ .catch((e) => {
91
+ console.error(e.message);
92
+ process.exit(1);
93
+ });
94
+ }
@@ -0,0 +1,134 @@
1
+ # Portfolio — playbook
2
+
3
+ The portfolio machinery ships as files — collections, projects, the per-project media gallery
4
+ (image AND video items), typed end-to-end. Portfolio is **read-only**: no cart, no checkout,
5
+ no `@wix/ecom`. **The presentation is yours**: you design and implement the collection card,
6
+ the project card + grid, the project-detail gallery, and the home page on the shipped
7
+ hooks/DTOs, plus the brand. You never write read logic; you never skip designing.
8
+
9
+ ## The file map (deployed into `src/`)
10
+
11
+ **Don't read the shipped files** — this table and the contracts below are everything you
12
+ need. Open a shipped file's source only on a real fallback (runtime error / uncovered field),
13
+ or to read a reference component's pattern.
14
+
15
+ | file | what it is |
16
+ |---|---|
17
+ | `wix/config.ts` · `wix/sdk.ts` · `wix/media.ts` · `wix/money.ts` | shared auth seam + helpers (deploy configures; nothing to set) |
18
+ | `wix/portfolio/types.ts` | the DTOs (`CollectionSummary`, `ProjectSummary`, `ProjectDetail`, `ProjectDetailRow`, `GalleryItem`) — contracts below |
19
+ | `wix/portfolio/portfolio.ts` | `fetchCollections`, `fetchCollectionBySlug`, `fetchProjects`, `fetchProjectBySlug`, `fetchProjectGallery` |
20
+ | `hooks/portfolio/useCollections.ts` | collections gallery — contract below |
21
+ | `hooks/portfolio/useCollectionProjects.ts` | one collection + its projects, by slug — contract below |
22
+ | `hooks/portfolio/useProjectDetail.ts` | one project + its media gallery, by slug — contract below |
23
+ | `components/portfolio/CollectionsView.tsx` (+ `CollectionCard`) · `CollectionProjectsView.tsx` (+ `ProjectCard`) · `ProjectDetailView.tsx` (+ `GalleryMedia`) | **REFERENCE implementations** — correct, plain; build your own instead of shipping them |
24
+ | `styles/global.css` | the design system: Tailwind v4 + the `@theme` token block (shared across verticals) |
25
+
26
+ Astro stack additionally gets:
27
+
28
+ | file | what it is |
29
+ |---|---|
30
+ | `layouts/SiteLayout.astro` | site chrome — **yours to brand** (keep the `seo-tags` slot + global.css import). If another vertical is also deployed, its layout won — add a Portfolio nav link there |
31
+ | `pages/portfolio.astro` | SSR collections gallery — **keep the frontmatter**, swap the island import to YOUR component |
32
+ | `pages/portfolio/[slug].astro` | SSR collection page (header + projects) — **keep the frontmatter**, swap the island import |
33
+ | `pages/projects/[slug].astro` | SSR project detail + gallery — **keep the frontmatter**, swap the island import. Portfolio has no documented Wix SEO item type, so these pages carry plain `<title>`/`<meta>` from the DTO (no `wixMetadata`/`<SEO.Tags>`) |
34
+
35
+ ## What you build — the design job
36
+
37
+ 1. **The collection card + gallery surface** — your tile (cover, title, description) and
38
+ rhythm, with skeletons while loading and an honest empty state — on `useCollections`.
39
+ 2. **The project card + collection page** — the collection header and your project grid — on
40
+ `useCollectionProjects` (route a not-found state off `notFound`, never off a transient
41
+ null).
42
+ 3. **The project-detail surface** — title/description, the `details` rows (text or link, as
43
+ given), and the media gallery: `kind: "image"` → `<img>`; `kind: "video"` → `<video>` with
44
+ `videoUrl` + `imageUrl` as poster; wrap in a link when `linkUrl` is set; empty gallery →
45
+ the project cover when it exists, else an honest empty note — on `useProjectDetail`.
46
+ 4. **The home page** — hero, featured collections or projects (fetch in frontmatter → your
47
+ components), brand story.
48
+
49
+ Plus the **theme** (`@theme` block, one edit) and the **chrome** (`SiteLayout`, one pass).
50
+ Style everything with Tailwind utilities on the tokens.
51
+
52
+ ### The contracts your components consume
53
+
54
+ ```ts
55
+ // CollectionSummary (tiles): { id, slug, title, description, imageUrl /* "" when none */ }
56
+ // ProjectSummary (tiles): { id, slug, title, description, imageUrl /* cover or video poster */,
57
+ // collectionIds: string[] }
58
+ // ProjectDetail adds: details: [{ label, text, url|null, target|null /* url set → link row */ }]
59
+ // GalleryItem: { id, kind: "image"|"video", title, description,
60
+ // imageUrl /* image, or the video's poster; may be "" */,
61
+ // videoUrl /* video only, else null */, linkUrl|null, linkTarget|null }
62
+
63
+ // useCollections({ initialCollections? }) →
64
+ // { collections: CollectionSummary[]|null /* null = loading → skeletons */, error }
65
+
66
+ // useCollectionProjects(slug, { initialCollection?, initialProjects? }) →
67
+ // { collection: CollectionSummary|null, // null while loading AND when notFound
68
+ // notFound, // the real 404 signal
69
+ // projects: ProjectSummary[]|null, // null = loading → skeletons
70
+ // error }
71
+
72
+ // useProjectDetail(slug, { initialProject?, initialItems? }) →
73
+ // { project: ProjectDetail|null, notFound,
74
+ // items: GalleryItem[]|null, // dashboard order; null = loading
75
+ // error }
76
+ ```
77
+
78
+ ### Wiring — Astro (default)
79
+
80
+ 1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass — merge into the
81
+ existing layout instead if another vertical is deployed).
82
+ 2. Write your components under `src/components/portfolio/` (new names — don't overwrite the
83
+ references), swap the island imports in `pages/portfolio.astro`,
84
+ `pages/portfolio/[slug].astro`, and `pages/projects/[slug].astro`. Islands are
85
+ `client:load` with the SSR props. **Author your surfaces in as few messages as possible** —
86
+ batch multiple Writes per message.
87
+ 3. Write `pages/index.astro` (home) — it exists from the scaffold; Read it before overwriting.
88
+
89
+ ### Wiring — React SPA (Vite etc.)
90
+
91
+ Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
92
+ plugins — deploy added the dep). Routes: `/portfolio` → your gallery; `/portfolio/:slug` →
93
+ your collection page on `useCollectionProjects(slug)`; `/projects/:slug` → your detail
94
+ surface on `useProjectDetail(slug)`.
95
+
96
+ ## Hard rules
97
+
98
+ - **Reads only through the shipped exports** — they filter `hidden`, sort collections by the
99
+ owner's `sortOrder` (projects have none — list order), and resolve every `wix:image://` /
100
+ `wix:video://` value. Never hand-build a `wixstatic.com` URL, never render a raw media
101
+ string into `src`.
102
+ - **This vertical sells nothing** — no cart, no checkout, no `@wix/ecom`/`@wix/redirects`
103
+ imports. A "contact about this project" CTA is a link, not a purchase flow.
104
+ - **Route not-found off `notFound`**, and surface `error` — a transient `null` is loading,
105
+ not a 404.
106
+ - **Render `details` rows as given** (text or link per row); don't invent metadata.
107
+ - **Gallery items branch on `kind`** — an image never gets a `<video>` tag and vice versa;
108
+ nothing renderable → skip the item, never a broken tag.
109
+ - Theme via the `@theme` tokens; no parallel theme files, no hardcoded palettes.
110
+ - Live data or an honest empty state — never mock collections, projects, or media.
111
+
112
+ ## Point the user to their dashboard
113
+
114
+ Give the owner the dashboard link — the deploy step's JSON printed `dashboardUrl`; append
115
+ `/wix-portfolio/projects` for Portfolio management (Projects and Collections are tabs on that
116
+ one page: Projects adds projects and their media galleries; Collections groups them).
117
+
118
+ ## Seeding
119
+
120
+ Per `seed/SEED.md` — plain-data `plan.json` into `seed-portfolio.mjs` from the project root.
121
+ Seed collections + projects that exercise the UI (covers on everything, 2–3 gallery images
122
+ per project, `details` rows on a couple of projects). A fresh install ships sample content —
123
+ seeding never deletes it; ask the owner before any cleanup.
124
+
125
+ ## Verify (before declaring done)
126
+
127
+ - [ ] `/portfolio` renders live collections SSR (view-source shows titles) through YOUR
128
+ components; empty portfolio shows your honest empty state.
129
+ - [ ] A collection page lists its projects (and only its); an unknown slug 404s.
130
+ - [ ] A project page renders the gallery in order, the `details` rows, and — if any project
131
+ has a video item — a playing `<video>` with poster.
132
+ - [ ] Card/grid/detail/home are YOUR designs on the tokens; data-layer/hook files unedited.
133
+ - [ ] No `@wix/ecom` import anywhere; no mocked content.
134
+ - [ ] Dashboard link handed to the owner.
@@ -0,0 +1,110 @@
1
+ // REFERENCE collection page: collection header + its projects grid on the @theme tokens.
2
+ // Correct and complete; per the skill's model you design and build your own on
3
+ // useCollectionProjects (ProjectCard is reusable for an all-work grid or a home strip).
4
+ import type { ComponentType, ReactNode } from "react";
5
+ import { useCollectionProjects } from "../../hooks/portfolio/useCollectionProjects";
6
+ import type { CollectionSummary, ProjectSummary } from "../../wix/portfolio/types";
7
+
8
+ export interface LinkLikeProps {
9
+ href: string;
10
+ className?: string;
11
+ children?: ReactNode;
12
+ }
13
+
14
+ const PlainLink = ({ href, className, children }: LinkLikeProps) => (
15
+ <a href={href} className={className}>
16
+ {children}
17
+ </a>
18
+ );
19
+
20
+ export interface ProjectCardProps {
21
+ project: ProjectSummary;
22
+ projectHref?: (slug: string) => string;
23
+ LinkComponent?: ComponentType<LinkLikeProps>;
24
+ }
25
+
26
+ export function ProjectCard({
27
+ project,
28
+ projectHref = (slug) => `/projects/${slug}`,
29
+ LinkComponent = PlainLink,
30
+ }: ProjectCardProps) {
31
+ return (
32
+ <LinkComponent href={projectHref(project.slug)} className="group block no-underline">
33
+ <div className="relative aspect-[4/3] overflow-hidden rounded-lg bg-secondary">
34
+ {project.imageUrl && (
35
+ <img
36
+ src={project.imageUrl}
37
+ alt={project.title}
38
+ loading="lazy"
39
+ className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]"
40
+ />
41
+ )}
42
+ </div>
43
+ <p className="mt-3 text-sm font-medium text-foreground">{project.title}</p>
44
+ {project.description && (
45
+ <p className="mt-0.5 text-xs text-muted-foreground">{project.description}</p>
46
+ )}
47
+ </LinkComponent>
48
+ );
49
+ }
50
+
51
+ export interface CollectionProjectsViewProps {
52
+ slug: string;
53
+ initialCollection?: CollectionSummary;
54
+ initialProjects?: ProjectSummary[];
55
+ emptyMessage?: string;
56
+ projectHref?: ProjectCardProps["projectHref"];
57
+ LinkComponent?: ComponentType<LinkLikeProps>;
58
+ CardComponent?: ComponentType<ProjectCardProps>;
59
+ }
60
+
61
+ export default function CollectionProjectsView({
62
+ slug,
63
+ initialCollection,
64
+ initialProjects,
65
+ emptyMessage = "No projects in this collection yet.",
66
+ projectHref,
67
+ LinkComponent,
68
+ CardComponent = ProjectCard,
69
+ }: CollectionProjectsViewProps) {
70
+ const { collection, notFound, projects, error } = useCollectionProjects(slug, {
71
+ initialCollection,
72
+ initialProjects,
73
+ });
74
+
75
+ if (notFound) {
76
+ return <p className="py-16 text-center text-muted-foreground">Collection not found.</p>;
77
+ }
78
+
79
+ return (
80
+ <div>
81
+ <header className="mb-8">
82
+ <h1 className="text-2xl font-semibold tracking-tight">
83
+ {collection ? collection.title : <span className="inline-block h-7 w-48 animate-pulse rounded bg-secondary" />}
84
+ </h1>
85
+ {collection?.description && (
86
+ <p className="mt-2 max-w-2xl text-muted-foreground">{collection.description}</p>
87
+ )}
88
+ </header>
89
+ {error && <p className="mb-4 text-sm text-red-600">{error}</p>}
90
+ {projects === null ? (
91
+ <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3" aria-busy="true">
92
+ {Array.from({ length: 6 }, (_, i) => (
93
+ <div key={i}>
94
+ <div className="aspect-[4/3] animate-pulse rounded-lg bg-secondary" />
95
+ <div className="mt-3 h-3.5 w-2/3 animate-pulse rounded bg-secondary" />
96
+ </div>
97
+ ))}
98
+ </div>
99
+ ) : projects.length === 0 ? (
100
+ <p className="py-16 text-center text-muted-foreground">{emptyMessage}</p>
101
+ ) : (
102
+ <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
103
+ {projects.map((p) => (
104
+ <CardComponent key={p.id} project={p} projectHref={projectHref} LinkComponent={LinkComponent} />
105
+ ))}
106
+ </div>
107
+ )}
108
+ </div>
109
+ );
110
+ }
@@ -0,0 +1,90 @@
1
+ // REFERENCE gallery surface: collections grid on the @theme tokens.
2
+ // Correct and complete; per the skill's model you design and build your own on useCollections.
3
+ import type { ComponentType, ReactNode } from "react";
4
+ import { useCollections } from "../../hooks/portfolio/useCollections";
5
+ import type { CollectionSummary } from "../../wix/portfolio/types";
6
+
7
+ export interface LinkLikeProps {
8
+ href: string;
9
+ className?: string;
10
+ children?: ReactNode;
11
+ }
12
+
13
+ const PlainLink = ({ href, className, children }: LinkLikeProps) => (
14
+ <a href={href} className={className}>
15
+ {children}
16
+ </a>
17
+ );
18
+
19
+ export interface CollectionCardProps {
20
+ collection: CollectionSummary;
21
+ collectionHref?: (slug: string) => string;
22
+ LinkComponent?: ComponentType<LinkLikeProps>;
23
+ }
24
+
25
+ export function CollectionCard({
26
+ collection,
27
+ collectionHref = (slug) => `/portfolio/${slug}`,
28
+ LinkComponent = PlainLink,
29
+ }: CollectionCardProps) {
30
+ return (
31
+ <LinkComponent href={collectionHref(collection.slug)} className="group block no-underline">
32
+ <div className="relative aspect-[4/3] overflow-hidden rounded-lg bg-secondary">
33
+ {collection.imageUrl && (
34
+ <img
35
+ src={collection.imageUrl}
36
+ alt={collection.title}
37
+ loading="lazy"
38
+ className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]"
39
+ />
40
+ )}
41
+ </div>
42
+ <p className="mt-3 text-sm font-medium text-foreground">{collection.title}</p>
43
+ {collection.description && (
44
+ <p className="mt-0.5 text-xs text-muted-foreground">{collection.description}</p>
45
+ )}
46
+ </LinkComponent>
47
+ );
48
+ }
49
+
50
+ export interface CollectionsViewProps {
51
+ initialCollections?: CollectionSummary[];
52
+ emptyMessage?: string;
53
+ collectionHref?: CollectionCardProps["collectionHref"];
54
+ LinkComponent?: ComponentType<LinkLikeProps>;
55
+ CardComponent?: ComponentType<CollectionCardProps>;
56
+ }
57
+
58
+ export default function CollectionsView({
59
+ initialCollections,
60
+ emptyMessage = "No collections yet — check back soon.",
61
+ collectionHref,
62
+ LinkComponent,
63
+ CardComponent = CollectionCard,
64
+ }: CollectionsViewProps) {
65
+ const { collections, error } = useCollections({ initialCollections });
66
+
67
+ return (
68
+ <div>
69
+ {error && <p className="mb-4 text-sm text-red-600">{error}</p>}
70
+ {collections === null ? (
71
+ <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3" aria-busy="true">
72
+ {Array.from({ length: 6 }, (_, i) => (
73
+ <div key={i}>
74
+ <div className="aspect-[4/3] animate-pulse rounded-lg bg-secondary" />
75
+ <div className="mt-3 h-3.5 w-2/3 animate-pulse rounded bg-secondary" />
76
+ </div>
77
+ ))}
78
+ </div>
79
+ ) : collections.length === 0 ? (
80
+ <p className="py-16 text-center text-muted-foreground">{emptyMessage}</p>
81
+ ) : (
82
+ <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
83
+ {collections.map((c) => (
84
+ <CardComponent key={c.id} collection={c} collectionHref={collectionHref} LinkComponent={LinkComponent} />
85
+ ))}
86
+ </div>
87
+ )}
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,115 @@
1
+ // REFERENCE project detail: header, details[] rows (text or link), media gallery (image AND
2
+ // video items) on the @theme tokens. Correct and complete; per the skill's model you design
3
+ // and build your own on useProjectDetail. GalleryMedia's kind branching is the load-bearing
4
+ // part — keep it (or its logic) in whatever you build.
5
+ import type { ReactNode } from "react";
6
+ import { useProjectDetail } from "../../hooks/portfolio/useProjectDetail";
7
+ import type { GalleryItem, ProjectDetail } from "../../wix/portfolio/types";
8
+
9
+ /** One gallery item: image, or video with poster. Nothing renderable → null (never a broken tag). */
10
+ export function GalleryMedia({ item }: { item: GalleryItem }) {
11
+ if (item.kind === "video" && item.videoUrl) {
12
+ return (
13
+ <video
14
+ src={item.videoUrl}
15
+ poster={item.imageUrl || undefined}
16
+ controls
17
+ playsInline
18
+ className="block w-full rounded-lg bg-secondary"
19
+ />
20
+ );
21
+ }
22
+ if (item.imageUrl) {
23
+ return (
24
+ <img src={item.imageUrl} alt={item.title} loading="lazy" className="block w-full rounded-lg" />
25
+ );
26
+ }
27
+ return null;
28
+ }
29
+
30
+ function MaybeLink({ item, children }: { item: GalleryItem; children: ReactNode }) {
31
+ return item.linkUrl ? (
32
+ <a href={item.linkUrl} target={item.linkTarget ?? undefined} rel="noopener">
33
+ {children}
34
+ </a>
35
+ ) : (
36
+ <>{children}</>
37
+ );
38
+ }
39
+
40
+ export interface ProjectDetailViewProps {
41
+ slug: string;
42
+ initialProject?: ProjectDetail;
43
+ initialItems?: GalleryItem[];
44
+ }
45
+
46
+ export default function ProjectDetailView({ slug, initialProject, initialItems }: ProjectDetailViewProps) {
47
+ const { project, notFound, items, error } = useProjectDetail(slug, { initialProject, initialItems });
48
+
49
+ if (notFound) {
50
+ return <p className="py-16 text-center text-muted-foreground">Project not found.</p>;
51
+ }
52
+ if (!project) {
53
+ return (
54
+ <div aria-busy="true">
55
+ <div className="h-7 w-64 animate-pulse rounded bg-secondary" />
56
+ <div className="mt-6 aspect-[4/3] animate-pulse rounded-lg bg-secondary" />
57
+ </div>
58
+ );
59
+ }
60
+
61
+ return (
62
+ <article>
63
+ <header className="mb-8 max-w-2xl">
64
+ <h1 className="text-2xl font-semibold tracking-tight">{project.title}</h1>
65
+ {project.description && (
66
+ <p className="mt-2 leading-relaxed text-muted-foreground">{project.description}</p>
67
+ )}
68
+ {project.details.length > 0 && (
69
+ <dl className="mt-5 grid grid-cols-[auto_1fr] items-baseline gap-x-6 gap-y-1.5">
70
+ {project.details.map((d, i) => (
71
+ <div key={i} className="contents">
72
+ <dt className="text-sm text-muted-foreground">{d.label}</dt>
73
+ <dd className="m-0 text-sm text-foreground">
74
+ {d.url ? (
75
+ <a href={d.url} target={d.target ?? undefined} rel="noopener" className="underline">
76
+ {d.text}
77
+ </a>
78
+ ) : (
79
+ d.text
80
+ )}
81
+ </dd>
82
+ </div>
83
+ ))}
84
+ </dl>
85
+ )}
86
+ </header>
87
+ {error && <p className="mb-4 text-sm text-red-600">{error}</p>}
88
+ {items === null ? (
89
+ <div className="flex flex-col gap-6" aria-busy="true">
90
+ <div className="aspect-[4/3] animate-pulse rounded-lg bg-secondary" />
91
+ </div>
92
+ ) : items.length === 0 ? (
93
+ // No gallery items — the cover is the project's only real media; text-only otherwise.
94
+ project.imageUrl ? (
95
+ <img src={project.imageUrl} alt={project.title} className="block w-full rounded-lg" />
96
+ ) : (
97
+ <p className="py-16 text-center text-muted-foreground">No media in this project yet.</p>
98
+ )
99
+ ) : (
100
+ <div className="flex flex-col gap-6">
101
+ {items.map((item) => (
102
+ <figure key={item.id} className="m-0">
103
+ <MaybeLink item={item}>
104
+ <GalleryMedia item={item} />
105
+ </MaybeLink>
106
+ {item.title && (
107
+ <figcaption className="mt-1.5 text-sm text-muted-foreground">{item.title}</figcaption>
108
+ )}
109
+ </figure>
110
+ ))}
111
+ </div>
112
+ )}
113
+ </article>
114
+ );
115
+ }
@@ -0,0 +1,59 @@
1
+ // One collection's header + its projects, by slug. SSR-friendly: pass both `initial*` and no
2
+ // client fetch happens. `notFound` is the real not-found signal (collection stays null while
3
+ // loading too) — route a 404 off it, never off a transient null.
4
+ import { useEffect, useState } from "react";
5
+ import { fetchCollectionBySlug, fetchProjects } from "../../wix/portfolio/portfolio";
6
+ import type { CollectionSummary, ProjectSummary } from "../../wix/portfolio/types";
7
+
8
+ export interface UseCollectionProjectsOptions {
9
+ initialCollection?: CollectionSummary;
10
+ initialProjects?: ProjectSummary[];
11
+ }
12
+
13
+ export interface UseCollectionProjects {
14
+ /** null while loading AND when not found — check `notFound` to tell them apart. */
15
+ collection: CollectionSummary | null;
16
+ notFound: boolean;
17
+ /** null while the first load is in flight — render skeletons, not an empty state. */
18
+ projects: ProjectSummary[] | null;
19
+ error: string | null;
20
+ }
21
+
22
+ export function useCollectionProjects(
23
+ slug: string,
24
+ { initialCollection, initialProjects }: UseCollectionProjectsOptions = {},
25
+ ): UseCollectionProjects {
26
+ const [collection, setCollection] = useState<CollectionSummary | null>(initialCollection ?? null);
27
+ const [notFound, setNotFound] = useState(false);
28
+ const [projects, setProjects] = useState<ProjectSummary[] | null>(initialProjects ?? null);
29
+ const [error, setError] = useState<string | null>(null);
30
+
31
+ useEffect(() => {
32
+ if (initialCollection && initialProjects) return;
33
+ let alive = true;
34
+ (async () => {
35
+ try {
36
+ const col = initialCollection ?? (await fetchCollectionBySlug(slug));
37
+ if (!alive) return;
38
+ if (!col) {
39
+ setNotFound(true);
40
+ setProjects([]);
41
+ return;
42
+ }
43
+ setCollection(col);
44
+ const projs = await fetchProjects({ collectionId: col.id });
45
+ if (alive) setProjects(projs);
46
+ } catch (e) {
47
+ if (!alive) return;
48
+ setProjects([]);
49
+ setError(e instanceof Error ? e.message : String(e));
50
+ }
51
+ })();
52
+ return () => {
53
+ alive = false;
54
+ };
55
+ // eslint-disable-next-line react-hooks/exhaustive-deps
56
+ }, [slug]);
57
+
58
+ return { collection, notFound, projects, error };
59
+ }