@wix/agent-skills 1.14.0 → 1.15.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 (247) hide show
  1. package/README.md +4 -1
  2. package/package.json +1 -1
  3. package/skills/README.md +23 -0
  4. package/skills/wix-app/SKILL.md +10 -2
  5. package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
  6. package/skills/wix-app/references/CODE_QUALITY.md +1 -0
  7. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
  8. package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
  9. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
  10. package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
  11. package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
  12. package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
  13. package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
  14. package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
  15. package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
  16. package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
  17. package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
  18. package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
  19. package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
  20. package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
  21. package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
  22. package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
  23. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
  24. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
  25. package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
  26. package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
  27. package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
  28. package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
  29. package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
  30. package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
  31. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
  32. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
  33. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
  34. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
  35. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
  36. package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
  37. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
  38. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
  39. package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
  40. package/skills/wix-auth/SKILL.md +12 -0
  41. package/skills/wix-auth/references/device-flow.md +140 -0
  42. package/skills/wix-docs/SKILL.md +188 -0
  43. package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
  44. package/skills/wix-docs/references/EXTRACTING.md +120 -0
  45. package/skills/wix-headless/SKILL.md +84 -130
  46. package/skills/wix-headless/entry/bootstrap.mjs +93 -0
  47. package/skills/wix-headless/entry/skill.md +78 -0
  48. package/skills/wix-headless/references/AI_FEATURES.md +178 -0
  49. package/skills/wix-headless/references/CAPABILITIES.md +84 -0
  50. package/skills/wix-headless/references/DISCOVERY.md +34 -56
  51. package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
  52. package/skills/wix-headless/references/FEEDBACK.md +118 -0
  53. package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
  54. package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
  55. package/skills/wix-headless/references/SEED.md +44 -188
  56. package/skills/wix-headless/references/SETUP.md +32 -103
  57. package/skills/wix-headless/references/astro.md +98 -0
  58. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
  59. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
  60. package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
  61. package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
  62. package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
  63. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
  64. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
  65. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
  66. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
  67. package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
  68. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
  69. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
  70. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
  71. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
  72. package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
  73. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
  74. package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
  75. package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
  76. package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
  77. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
  78. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
  79. package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
  80. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
  81. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
  82. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
  83. package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
  84. package/skills/wix-headless/references/managed/CONNECT.md +74 -0
  85. package/skills/wix-headless/references/managed/CREATE.md +130 -0
  86. package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
  87. package/skills/wix-headless/references/non-astro.md +59 -0
  88. package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
  89. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
  90. package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
  91. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
  92. package/skills/wix-manage/SKILL.md +24 -1
  93. package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
  94. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
  95. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
  96. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
  97. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
  98. package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
  99. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
  100. package/skills/wix-vibe-headless/SKILL.md +136 -0
  101. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
  102. package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
  103. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
  104. package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
  105. package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
  106. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
  107. package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
  108. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
  109. package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
  110. package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
  111. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
  112. package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
  113. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
  114. package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
  115. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
  116. package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
  117. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
  118. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
  119. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
  120. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
  121. package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
  122. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
  123. package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
  124. package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
  125. package/skills/wix-headless/references/BUILD-astro.md +0 -253
  126. package/skills/wix-headless/references/BUILD-own-build.md +0 -167
  127. package/skills/wix-headless/references/BUILD.md +0 -105
  128. package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
  129. package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
  130. package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
  131. package/skills/wix-headless/references/PLAN-connect.md +0 -19
  132. package/skills/wix-headless/references/PLAN-create.md +0 -17
  133. package/skills/wix-headless/references/PLAN.md +0 -92
  134. package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
  135. package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
  136. package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
  137. package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
  138. package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
  139. package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
  140. package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
  141. package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
  142. package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
  143. package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
  144. package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
  145. package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
  146. package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
  147. package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
  148. package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
  149. package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
  150. package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
  151. package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
  152. package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
  153. package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
  154. package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
  155. package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
  156. package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
  157. package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
  158. package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
  159. package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
  160. package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
  161. package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
  162. package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
  163. package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
  164. package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
  165. package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
  166. package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
  167. package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
  168. package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
  169. package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
  170. package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
  171. package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
  172. package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
  173. package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
  174. package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
  175. package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
  176. package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
  177. package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
  178. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
  179. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
  180. package/skills/wix-headless/references/astro/templates/global.css +0 -288
  181. package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
  182. package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
  183. package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
  184. package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
  185. package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
  186. package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
  187. package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
  188. package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
  189. package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
  190. package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
  191. package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
  192. package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
  193. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
  194. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
  195. package/skills/wix-headless/references/bookings/FLOW.md +0 -246
  196. package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
  197. package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
  198. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
  199. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
  200. package/skills/wix-headless/references/commands/known-apps.json +0 -6
  201. package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
  202. package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
  203. package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
  204. package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
  205. package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
  206. package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
  207. package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
  208. package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
  209. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
  210. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
  211. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
  212. package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
  213. package/skills/wix-headless/references/seed-recipes.md +0 -49
  214. package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
  215. package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
  216. package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
  217. package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
  218. package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
  219. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
  220. package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
  221. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
  222. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
  223. package/skills/wix-headless/references/shared/STYLING.md +0 -140
  224. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
  225. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
  226. package/skills/wix-headless/references/verticals/_schema.json +0 -74
  227. package/skills/wix-headless/references/verticals/_schema.md +0 -95
  228. package/skills/wix-headless/references/verticals/blog.md +0 -31
  229. package/skills/wix-headless/references/verticals/bookings.md +0 -41
  230. package/skills/wix-headless/references/verticals/cms.md +0 -30
  231. package/skills/wix-headless/references/verticals/ecom.md +0 -25
  232. package/skills/wix-headless/references/verticals/forms.md +0 -26
  233. package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
  234. package/skills/wix-headless/references/verticals/stores.md +0 -33
  235. package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
  236. package/skills/wix-headless/scripts/compose.mjs +0 -520
  237. package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
  238. package/skills/wix-headless/scripts/flatten.sh +0 -61
  239. package/skills/wix-headless/scripts/generate-images.mjs +0 -242
  240. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -154
  241. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
  242. package/skills/wix-headless/scripts/scaffold.sh +0 -139
  243. package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
  244. package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
  245. package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
  246. package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
  247. package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
@@ -1,132 +0,0 @@
1
- ---
2
- // ── Composer skeleton: src/layouts/Layout.astro ──────────────────────────────
3
- // Fully replaces the scaffold's bare stub. The <script> below and the View
4
- // Transitions wiring are LITERAL fixed bulk — do not re-author. Composer's only
5
- // substitutions (see compose.mjs):
6
- // {{components-css-imports}} — one `import '../styles/components-<pack>.css';`
7
- // per pack in "Packs with components" (omit entirely when none).
8
- // {{fonts.googleHref}} — the Google Fonts <link> href built from designTokens
9
- // .fonts (display + body families). Omit the <link> if fonts are system.
10
- // {{brand.name}} — default <title>.
11
- import '../styles/global.css';
12
- {{components-css-imports}}
13
- import { ClientRouter } from 'astro:transitions';
14
- import Navigation from '../components/Navigation.astro';
15
- import Footer from '../components/Footer.astro';
16
-
17
- interface Props {
18
- title?: string;
19
- description?: string;
20
- hasSeoTags?: boolean;
21
- }
22
- const { title, description, hasSeoTags = false } = Astro.props;
23
- ---
24
- <!doctype html>
25
- <html lang="en">
26
- <head>
27
- <meta charset="utf-8" />
28
- <meta name="viewport" content="width=device-width, initial-scale=1" />
29
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'/%3E" />
30
- <link rel="preconnect" href="https://fonts.googleapis.com" />
31
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
32
- <link rel="stylesheet" href="{{fonts.googleHref}}" />
33
- {!hasSeoTags && (
34
- <>
35
- <title>{title ? `${title} · {{brand.name}}` : "{{brand.name}}"}</title>
36
- {description && <meta name="description" content={description} />}
37
- </>
38
- )}
39
- <slot name="head" />
40
- <ClientRouter />
41
- </head>
42
- <body>
43
- <div class="nav-progress" data-nav-progress aria-hidden="true"></div>
44
- <Navigation />
45
- <main><slot /></main>
46
- <Footer />
47
- <script>
48
- // Persisted rail aria-current sync + top loading bar + rail-anchored
49
- // scroll across listing-to-listing navigation. Stores pack relies on
50
- // all three; do not split into separate scripts.
51
- function syncCategoryRail() {
52
- const path = window.location.pathname;
53
- const activeSlug = path.startsWith("/category/")
54
- ? path.slice("/category/".length).replace(/\/$/, "")
55
- : path === "/products" || path === "/products/"
56
- ? ""
57
- : null;
58
- if (activeSlug === null) return;
59
- const pills = document.querySelectorAll<HTMLAnchorElement>(
60
- "[data-category-rail] .category-pill",
61
- );
62
- for (const pill of pills) {
63
- const slug = pill.dataset.categorySlug ?? "";
64
- if (slug === activeSlug) pill.setAttribute("aria-current", "page");
65
- else pill.removeAttribute("aria-current");
66
- }
67
- }
68
- // Eager click feedback — flip aria-current before the network call.
69
- document.addEventListener("click", (event) => {
70
- const target = event.target as HTMLElement | null;
71
- const pill = target?.closest<HTMLAnchorElement>(
72
- "[data-category-rail] .category-pill",
73
- );
74
- if (!pill) return;
75
- if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
76
- const pills = document.querySelectorAll<HTMLAnchorElement>(
77
- "[data-category-rail] .category-pill",
78
- );
79
- for (const p of pills) p.removeAttribute("aria-current");
80
- pill.setAttribute("aria-current", "page");
81
- }, true);
82
- const progress = document.querySelector<HTMLElement>("[data-nav-progress]");
83
- function startProgress() {
84
- if (!progress) return;
85
- progress.dataset.state = "loading";
86
- document.body.dataset.navigating = "true";
87
- }
88
- function endProgress() {
89
- if (!progress) return;
90
- progress.dataset.state = "done";
91
- delete document.body.dataset.navigating;
92
- window.setTimeout(() => {
93
- if (progress.dataset.state === "done") delete progress.dataset.state;
94
- }, 320);
95
- }
96
- // Anchor the persisted rail across listing-to-listing navigation. The
97
- // page-header above the rail differs between /products and /category/[slug]
98
- // (breadcrumbs, lede, optional image), so naive scroll preservation reads
99
- // as a jump. Capture rail.getBoundingClientRect().top before the swap and
100
- // re-equalize after.
101
- const isListing = (p: string) =>
102
- p === "/products" || p === "/products/" || p.startsWith("/category/");
103
- let railAnchorTop: number | null = null;
104
- document.addEventListener("astro:before-preparation", (event: any) => {
105
- const from = window.location.pathname;
106
- const to = event?.to?.pathname ?? from;
107
- const rail = document.querySelector<HTMLElement>("[data-category-rail]");
108
- railAnchorTop =
109
- rail && isListing(from) && isListing(to)
110
- ? rail.getBoundingClientRect().top
111
- : null;
112
- startProgress();
113
- });
114
- document.addEventListener("astro:after-swap", () => {
115
- syncCategoryRail();
116
- if (railAnchorTop !== null) {
117
- const rail = document.querySelector<HTMLElement>("[data-category-rail]");
118
- if (rail) {
119
- const delta = rail.getBoundingClientRect().top - railAnchorTop;
120
- if (Math.abs(delta) > 0.5) {
121
- window.scrollBy({ top: delta, left: 0, behavior: "instant" as ScrollBehavior });
122
- }
123
- }
124
- }
125
- railAnchorTop = null;
126
- endProgress();
127
- });
128
- document.addEventListener("astro:page-load", endProgress);
129
- syncCategoryRail();
130
- </script>
131
- </body>
132
- </html>
@@ -1,41 +0,0 @@
1
- // ── Composer skeleton: astro.config.mjs ───────────────────────────────────────
2
- // UNLIKE the other skeletons, this one is a MERGE TARGET, not a clobber. The
3
- // scaffold's generated astro.config.mjs varies (integrations args, image.domains,
4
- // vite.server settings differ run to run). Composer must NOT overwrite it with
5
- // this file — it applies exactly two mutations to the scaffold's own config and
6
- // preserves everything else (see compose.mjs):
7
- //
8
- // (1) register the Tailwind v4 Vite plugin → vite.plugins: [tailwindcss()]
9
- // (2) fix the bare `process.env` reference → globalThis guard (TS-safe)
10
- //
11
- // The shape below is the canonical post-mutation result for a typical scaffold —
12
- // use it as the reference for what those two edits should produce.
13
- // @ts-check
14
- import { defineConfig } from "astro/config";
15
- import wix from "@wix/astro";
16
- import wixPages from "@wix/astro-pages";
17
- import react from "@astrojs/react";
18
- import cloudProviderFetchAdapter from "@wix/cloud-provider-fetch-adapter";
19
- import tailwindcss from "@tailwindcss/vite"; // (1) added by Composer
20
-
21
- // (2) `process.env` guarded so strict `tsc --noEmit` does not fail with
22
- // "Cannot find name 'process'" without an @types/node dependency.
23
- const isBuild =
24
- (/** @type {any} */ (globalThis)).process?.env?.NODE_ENV === "production";
25
-
26
- // https://astro.build/config
27
- export default defineConfig({
28
- integrations: [wix(), wixPages(), react()],
29
- security: { checkOrigin: false },
30
- ...(isBuild && { adapter: cloudProviderFetchAdapter({}) }),
31
-
32
- image: {
33
- domains: ["static.wixstatic.com"],
34
- },
35
-
36
- vite: {
37
- plugins: [tailwindcss()], // (1) merge into any existing vite config
38
- },
39
-
40
- output: "server",
41
- });
@@ -1,374 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react";
2
- import { availabilityTimeSlots, eventTimeSlots } from "@wix/bookings";
3
- import type { SelectedSlot } from "./bookingDriver";
4
- import { STAFF_MEMBER_RESOURCE_TYPE_ID } from "./bookingDriver";
5
-
6
- // AvailabilityCalendar.tsx — client:only="react" island. A week calendar: a
7
- // 7-day strip with week navigation, then the picked day's time slots. This is
8
- // the usable shape — a flat list of every slot with time-only labels leaves the
9
- // visitor unable to tell which day a slot is on.
10
- //
11
- // SDK calls run ambiently (the @wix/astro visitor client), like the ecom
12
- // CartView island — no createClient/OAuthStrategy here. On an own/own-build SPA
13
- // acquire a visitor client (OAuthStrategy) and call the same functions on it.
14
- //
15
- // Branches on serviceType:
16
- // APPOINTMENT → availabilityTimeSlots.listAvailabilityTimeSlots() (serviceId is
17
- // a single GUID string; slots carry scheduleId).
18
- // CLASS → eventTimeSlots.listEventTimeSlots() (serviceIds is an array;
19
- // slots carry eventInfo.eventId and NO scheduleId).
20
- //
21
- // LOCATION SCOPING (multi-location): listAvailabilityTimeSlots returns one slot
22
- // PER LOCATION per time — "if locations is not specified, returns time slots for
23
- // all locations where the service is available". A service offered at >1 location
24
- // therefore yields DUPLICATE same-time rows unless the call is scoped to a single
25
- // location. So availability is ALWAYS scoped to one business location: the picker
26
- // below defaults to the carried/first location and the call always passes a
27
- // single-element `locations` filter. (One location per availability call — the
28
- // same single-location guarantee the location-first SoT gets from its selector.)
29
- //
30
- // STAFF: a single slot carries multiple staff in availableResources, so staff is
31
- // a per-slot dropdown — it never multiplies rows. Only location multiplies rows.
32
- // Re-export SelectedSlot from bookingDriver so the form/driver share one shape.
33
- export type { SelectedSlot } from "./bookingDriver";
34
-
35
- // A staff member as carried on the service (service.staffMemberDetails.staffMembers[]),
36
- // fetched via conditionalFields:["STAFF_MEMBER_DETAILS"]. NOTE: the id field is
37
- // `staffMemberId` which — despite the name — IS the resource id (it matches the
38
- // service's staffMemberIds and the Staff Members API resourceId). That id is what
39
- // filters availability and books the resource.
40
- export interface StaffMemberOption {
41
- staffMemberId?: string;
42
- name?: string;
43
- }
44
-
45
- // A business location the service is offered at (derived from service.locations[]).
46
- export interface LocationOption {
47
- _id: string;
48
- name?: string;
49
- }
50
-
51
- interface Props {
52
- serviceId: string;
53
- serviceName: string;
54
- serviceType: "APPOINTMENT" | "CLASS";
55
- staffMembers?: StaffMemberOption[];
56
- locations?: LocationOption[]; // business locations the service offers
57
- locationId?: string; // the location chosen on the catalog (the default scope), if any
58
- onSlotSelected: (slot: SelectedSlot) => void;
59
- }
60
-
61
- interface FetchOpts {
62
- resourceId?: string; // a staff resource id to filter by (omit for "any staff")
63
- locationId?: string; // a business location id to scope to (omit only when the service has none)
64
- }
65
-
66
- const DAY_MS = 86_400_000;
67
- const HORIZON_WEEKS = 13; // how far "check next availability" probes forward
68
- const ANY_STAFF = ""; // the "any staff member" sentinel for the select value
69
-
70
- const pad = (n: number) => String(n).padStart(2, "0");
71
- // Local date string YYYY-MM-DDThh:mm:ss (no Z) — availability expects local time.
72
- const localDateString = (d: Date) =>
73
- `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
74
- const tz = () => Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
75
- const dateKey = (iso: string) => iso.slice(0, 10); // group slots by calendar day
76
- const timeLabel = (iso: string) =>
77
- new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
78
-
79
- const startOfDay = (d: Date) => { const n = new Date(d); n.setHours(0, 0, 0, 0); return n; };
80
- // Monday-start week containing `d`.
81
- const mondayOf = (d: Date) => {
82
- const n = startOfDay(d);
83
- const day = (n.getDay() + 6) % 7; // 0 = Monday
84
- n.setDate(n.getDate() - day);
85
- return n;
86
- };
87
-
88
- // Fetch one week of availability and group the slots by calendar day.
89
- const fetchWeek = async (
90
- serviceId: string,
91
- serviceType: "APPOINTMENT" | "CLASS",
92
- weekStart: Date,
93
- opts: FetchOpts = {},
94
- ): Promise<Record<string, SelectedSlot[]>> => {
95
- const from = startOfDay(weekStart);
96
- const to = new Date(from.getTime() + 7 * DAY_MS);
97
- const timeZone = tz();
98
- let raw: any[] = [];
99
-
100
- if (serviceType === "CLASS") {
101
- // CLASS filters via eventFilter: staff by resources.id ($hasSome), location by
102
- // location.id (a bare array, NOT a $hasSome operator).
103
- const eventFilter: Record<string, any> = {};
104
- if (opts.resourceId) eventFilter["resources.id"] = { $hasSome: [opts.resourceId] };
105
- if (opts.locationId) eventFilter["location.id"] = [opts.locationId];
106
- const result = await eventTimeSlots.listEventTimeSlots({
107
- serviceIds: [serviceId], // CLASS API takes an array
108
- fromLocalDate: localDateString(from),
109
- toLocalDate: localDateString(to),
110
- timeZone,
111
- includeNonBookable: false,
112
- cursorPaging: { limit: 100 },
113
- ...(Object.keys(eventFilter).length ? { eventFilter } : {}),
114
- });
115
- raw = (result.timeSlots ?? []).map((s: any) => ({
116
- serviceType: "CLASS" as const,
117
- serviceId,
118
- localStartDate: s.localStartDate,
119
- localEndDate: s.localEndDate,
120
- timezone: result.timeZone ?? timeZone,
121
- eventId: s.eventInfo?.eventId, // session id — no scheduleId on event slots
122
- }));
123
- } else {
124
- // APPOINTMENT filters staff via resourceTypes (resourceIds), location via locations[].
125
- // Scoping to a single location collapses the per-location duplicate rows.
126
- const result = await availabilityTimeSlots.listAvailabilityTimeSlots({
127
- serviceId, // single GUID string — NOT an array
128
- fromLocalDate: localDateString(from),
129
- toLocalDate: localDateString(to),
130
- timeZone,
131
- bookable: true,
132
- cursorPaging: { limit: 100 },
133
- ...(opts.resourceId
134
- ? {
135
- resourceTypes: [
136
- { resourceTypeId: STAFF_MEMBER_RESOURCE_TYPE_ID, resourceIds: [opts.resourceId] },
137
- ],
138
- includeResourceTypeIds: [STAFF_MEMBER_RESOURCE_TYPE_ID],
139
- }
140
- : {}),
141
- ...(opts.locationId
142
- ? { locations: [{ _id: opts.locationId, locationType: "BUSINESS" as const }] }
143
- : {}),
144
- });
145
- raw = (result.timeSlots ?? []).map((s: any) => ({
146
- serviceType: "APPOINTMENT" as const,
147
- serviceId,
148
- localStartDate: s.localStartDate,
149
- localEndDate: s.localEndDate,
150
- timezone: result.timeZone ?? timeZone,
151
- scheduleId: s.scheduleId,
152
- locationId: s.location?._id, // the id field is _id, not .id
153
- locationType: s.location?.locationType,
154
- }));
155
- }
156
-
157
- const byDay: Record<string, SelectedSlot[]> = {};
158
- for (const slot of raw) {
159
- if (!slot.localStartDate) continue;
160
- (byDay[dateKey(slot.localStartDate)] ||= []).push(slot);
161
- }
162
- return byDay;
163
- };
164
-
165
- export default function AvailabilityCalendar({
166
- serviceId,
167
- serviceName,
168
- serviceType,
169
- staffMembers,
170
- locations,
171
- locationId,
172
- onSlotSelected,
173
- }: Props) {
174
- const thisMonday = useMemo(() => mondayOf(new Date()), []);
175
- const [weekStart, setWeekStart] = useState<Date>(thisMonday);
176
- const [byDay, setByDay] = useState<Record<string, SelectedSlot[]>>({});
177
- const [selectedDay, setSelectedDay] = useState<string | null>(null);
178
- const [selectedKey, setSelectedKey] = useState<string | null>(null);
179
- const [status, setStatus] = useState<"loading" | "ready" | "error" | "searching">("loading");
180
- // The chosen staff resource id ("" = any staff member → ANY_RESOURCE fallback).
181
- const [selectedResource, setSelectedResource] = useState<string>(ANY_STAFF);
182
-
183
- // Staff options keyed by resource id; picker shown only when >1 staff.
184
- const staffOptions = useMemo(
185
- () =>
186
- (staffMembers ?? [])
187
- .map((s) => ({ id: s.staffMemberId ?? "", name: s.name ?? "Staff member" }))
188
- .filter((s) => s.id),
189
- [staffMembers],
190
- );
191
- const showStaffPicker = staffOptions.length > 1;
192
-
193
- // Business-location options. Availability is always scoped to ONE of these (the
194
- // carried location if it's one of them, else the first), so multi-location
195
- // services don't return duplicate per-location rows. Picker shown only when >1.
196
- const locationOptions = useMemo(
197
- () => (locations ?? []).filter((l) => l._id),
198
- [locations],
199
- );
200
- const [selectedLocation, setSelectedLocation] = useState<string>(() => {
201
- if (locationId && locationOptions.some((l) => l._id === locationId)) return locationId;
202
- return locationOptions[0]?._id ?? "";
203
- });
204
- const showLocationPicker = locationOptions.length > 1;
205
-
206
- const days = useMemo(
207
- () => Array.from({ length: 7 }, (_, i) => new Date(weekStart.getTime() + i * DAY_MS)),
208
- [weekStart],
209
- );
210
- const atFirstWeek = weekStart.getTime() <= thisMonday.getTime();
211
-
212
- const fetchOpts = useCallback(
213
- (): FetchOpts => ({
214
- resourceId: selectedResource || undefined,
215
- locationId: selectedLocation || undefined,
216
- }),
217
- [selectedResource, selectedLocation],
218
- );
219
-
220
- const load = useCallback(async (start: Date) => {
221
- setStatus("loading"); setSelectedKey(null);
222
- try {
223
- const grouped = await fetchWeek(serviceId, serviceType, start, fetchOpts());
224
- setByDay(grouped);
225
- const firstDayWithSlots = Object.keys(grouped).sort()[0] ?? null;
226
- setSelectedDay(firstDayWithSlots);
227
- setStatus("ready");
228
- } catch (err) {
229
- console.error("[availability] list failed:", err);
230
- setStatus("error");
231
- }
232
- }, [serviceId, serviceType, fetchOpts]);
233
-
234
- // Reload whenever the week OR the staff/location filter changes.
235
- useEffect(() => { void load(weekStart); }, [weekStart, load]);
236
-
237
- const shiftWeek = (deltaWeeks: number) =>
238
- setWeekStart((prev) => startOfDay(new Date(prev.getTime() + deltaWeeks * 7 * DAY_MS)));
239
-
240
- // Probe forward week-by-week for the next week that has any slots.
241
- const checkNextAvailability = useCallback(async () => {
242
- setStatus("searching");
243
- let cursor = new Date(weekStart.getTime() + 7 * DAY_MS);
244
- for (let i = 0; i < HORIZON_WEEKS; i++) {
245
- try {
246
- const grouped = await fetchWeek(serviceId, serviceType, cursor, fetchOpts());
247
- if (Object.keys(grouped).length > 0) {
248
- setWeekStart(cursor); // triggers load() via the effect
249
- return;
250
- }
251
- } catch { /* keep probing */ }
252
- cursor = new Date(cursor.getTime() + 7 * DAY_MS);
253
- }
254
- setStatus("ready"); // nothing found within the horizon
255
- }, [serviceId, serviceType, weekStart, fetchOpts]);
256
-
257
- const handleSelect = (s: SelectedSlot) => {
258
- const id = s.serviceType === "CLASS" ? s.eventId : s.scheduleId;
259
- if (!s.localStartDate || !id) return;
260
- setSelectedKey(`${s.localStartDate}|${id}`);
261
- // When a specific staff was chosen, record it on the slot so the booking books
262
- // that resource; otherwise the driver emits the ANY_RESOURCE fallback.
263
- const chosen = selectedResource
264
- ? staffOptions.find((o) => o.id === selectedResource)
265
- : null;
266
- onSlotSelected(chosen ? { ...s, resource: { _id: chosen.id, name: chosen.name } } : s);
267
- };
268
-
269
- const weekLabel = `${days[0].toLocaleDateString([], { month: "short", day: "numeric" })} – ${days[6].toLocaleDateString([], { month: "short", day: "numeric" })}`;
270
- const daySlots = selectedDay ? byDay[selectedDay] ?? [] : [];
271
- const weekIsEmpty = status === "ready" && Object.keys(byDay).length === 0;
272
-
273
- return (
274
- <div className="availability-calendar">
275
- {(showLocationPicker || showStaffPicker) && (
276
- <div className="availability-filters">
277
- {showLocationPicker && (
278
- <div className="availability-staff">
279
- <label className="availability-staff-label" htmlFor="location-select">Location</label>
280
- <select
281
- id="location-select"
282
- className="availability-staff-select"
283
- value={selectedLocation}
284
- onChange={(e) => { setSelectedLocation(e.target.value); setSelectedKey(null); }}
285
- >
286
- {locationOptions.map((o) => (
287
- <option key={o._id} value={o._id}>{o.name ?? "Location"}</option>
288
- ))}
289
- </select>
290
- </div>
291
- )}
292
- {showStaffPicker && (
293
- <div className="availability-staff">
294
- <label className="availability-staff-label" htmlFor="staff-select">Staff member</label>
295
- <select
296
- id="staff-select"
297
- className="availability-staff-select"
298
- value={selectedResource}
299
- onChange={(e) => { setSelectedResource(e.target.value); setSelectedKey(null); }}
300
- >
301
- <option value={ANY_STAFF}>Any staff member</option>
302
- {staffOptions.map((o) => (
303
- <option key={o.id} value={o.id}>{o.name}</option>
304
- ))}
305
- </select>
306
- </div>
307
- )}
308
- </div>
309
- )}
310
-
311
- <div className="availability-week-nav">
312
- <button type="button" className="availability-nav-btn" onClick={() => shiftWeek(-1)} disabled={atFirstWeek} aria-label="Previous week">← Prev week</button>
313
- <span className="availability-week-label">{weekLabel}</span>
314
- <button type="button" className="availability-nav-btn" onClick={() => shiftWeek(1)} aria-label="Next week">Next week →</button>
315
- </div>
316
-
317
- <div className="availability-day-strip" role="group" aria-label="Pick a day">
318
- {days.map((d) => {
319
- const key = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
320
- const has = (byDay[key]?.length ?? 0) > 0;
321
- const isSelected = key === selectedDay;
322
- return (
323
- <button
324
- key={key}
325
- type="button"
326
- className={["availability-day", isSelected ? "availability-day--selected" : "", has ? "availability-day--has-slots" : "availability-day--empty"].filter(Boolean).join(" ")}
327
- disabled={!has}
328
- aria-pressed={isSelected}
329
- onClick={() => { setSelectedDay(key); setSelectedKey(null); }}
330
- >
331
- <span className="availability-day-name">{d.toLocaleDateString([], { weekday: "short" })}</span>
332
- <span className="availability-day-num">{d.getDate()}</span>
333
- </button>
334
- );
335
- })}
336
- </div>
337
-
338
- {status === "loading" && <p className="availability-loading">Checking availability…</p>}
339
- {status === "searching" && <p className="availability-loading">Searching for the next available time…</p>}
340
- {status === "error" && (
341
- <>
342
- <p className="availability-error">Could not load availability — please try again.</p>
343
- <button type="button" className="availability-nav-btn" onClick={() => void load(weekStart)}>Retry</button>
344
- </>
345
- )}
346
- {weekIsEmpty && (
347
- <div className="availability-empty">
348
- <p>No availability this week.</p>
349
- <button type="button" className="availability-nav-btn" onClick={() => void checkNextAvailability()}>Check next availability</button>
350
- </div>
351
- )}
352
- {status === "ready" && daySlots.length > 0 && (
353
- <div className="availability-slots" role="group" aria-label={`Available times for ${serviceName}`}>
354
- {daySlots.map((s) => {
355
- const id = s.serviceType === "CLASS" ? s.eventId : s.scheduleId;
356
- const key = `${s.localStartDate}|${id}`;
357
- const isSelected = key === selectedKey;
358
- return (
359
- <button
360
- key={key}
361
- type="button"
362
- className={["time-slot", isSelected ? "time-slot--selected" : "time-slot--available"].join(" ")}
363
- aria-pressed={isSelected}
364
- onClick={() => handleSelect(s)}
365
- >
366
- <span className="time-slot-time">{timeLabel(s.localStartDate)}</span>
367
- </button>
368
- );
369
- })}
370
- </div>
371
- )}
372
- </div>
373
- );
374
- }