@wix/agent-skills 1.0.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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/package.json +29 -0
  4. package/skills/wix-app/SKILL.md +344 -0
  5. package/skills/wix-app/references/APP_IDENTIFIERS.md +35 -0
  6. package/skills/wix-app/references/APP_MARKET_REVIEW.md +311 -0
  7. package/skills/wix-app/references/APP_VALIDATION.md +171 -0
  8. package/skills/wix-app/references/BACKEND_API.md +233 -0
  9. package/skills/wix-app/references/BACKEND_EVENT.md +116 -0
  10. package/skills/wix-app/references/CODE_QUALITY.md +33 -0
  11. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +587 -0
  12. package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +157 -0
  13. package/skills/wix-app/references/DASHBOARD_MODAL.md +283 -0
  14. package/skills/wix-app/references/DASHBOARD_PAGE.md +403 -0
  15. package/skills/wix-app/references/DASHBOARD_PLUGIN.md +205 -0
  16. package/skills/wix-app/references/DATA_COLLECTION.md +451 -0
  17. package/skills/wix-app/references/DOCUMENTATION.md +42 -0
  18. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +65 -0
  19. package/skills/wix-app/references/EMBEDDED_SCRIPT.md +468 -0
  20. package/skills/wix-app/references/EXTENSION_REGISTRATION.md +96 -0
  21. package/skills/wix-app/references/SERVICE_PLUGIN.md +235 -0
  22. package/skills/wix-app/references/SITE_PLUGIN.md +436 -0
  23. package/skills/wix-app/references/STORES_VERSIONING.md +334 -0
  24. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +84 -0
  25. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +345 -0
  26. package/skills/wix-app/references/dashboard-menu-plugin/blog-slots.md +71 -0
  27. package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +58 -0
  28. package/skills/wix-app/references/dashboard-menu-plugin/crm-slots.md +8 -0
  29. package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +17 -0
  30. package/skills/wix-app/references/dashboard-menu-plugin/events-slots.md +29 -0
  31. package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +27 -0
  32. package/skills/wix-app/references/dashboard-menu-plugin/stores-slots.md +35 -0
  33. package/skills/wix-app/references/dashboard-page/API_SPEC.md +138 -0
  34. package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +573 -0
  35. package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +269 -0
  36. package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +164 -0
  37. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +294 -0
  38. package/skills/wix-app/references/data-collection/WIX_DATA.md +270 -0
  39. package/skills/wix-app/references/data-collection/extension-template.ts +107 -0
  40. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +138 -0
  41. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +454 -0
  42. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +165 -0
  43. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +576 -0
  44. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +170 -0
  45. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +6 -0
  46. package/skills/wix-app/references/editor-react-component/PARTS.md +25 -0
  47. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +203 -0
  48. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +167 -0
  49. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +137 -0
  50. package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +112 -0
  51. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +118 -0
  52. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +87 -0
  53. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +86 -0
  54. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +135 -0
  55. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +79 -0
  56. package/skills/wix-app/references/service-plugin/VALIDATIONS.md +68 -0
  57. package/skills/wix-app/references/site-plugin/EXAMPLES.md +311 -0
  58. package/skills/wix-app/references/site-plugin/SLOTS.md +263 -0
  59. package/skills/wix-design-system/SKILL.md +129 -0
  60. package/skills/wix-design-system/references/file-structure.md +56 -0
  61. package/skills/wix-design-system/scripts/wds.cjs +531 -0
  62. package/skills/wix-headless/SKILL.md +418 -0
  63. package/skills/wix-headless/references/DISCOVERY.md +332 -0
  64. package/skills/wix-headless/references/ORCHESTRATION.md +269 -0
  65. package/skills/wix-headless/references/SETUP.md +154 -0
  66. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +152 -0
  67. package/skills/wix-headless/references/blog/BLOG_PAGES.md +299 -0
  68. package/skills/wix-headless/references/blog/BLOG_SETUP.md +218 -0
  69. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +32 -0
  70. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +373 -0
  71. package/skills/wix-headless/references/cms/FAQ_KNOWLEDGE_BASE.md +229 -0
  72. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +40 -0
  73. package/skills/wix-headless/references/cms/PORTFOLIO.md +454 -0
  74. package/skills/wix-headless/references/cms/RESOURCE_LIBRARY.md +356 -0
  75. package/skills/wix-headless/references/cms/TEAM_DIRECTORY.md +299 -0
  76. package/skills/wix-headless/references/commands/install-app.md +42 -0
  77. package/skills/wix-headless/references/commands/known-apps.json +5 -0
  78. package/skills/wix-headless/references/commands/mcp-bootstrap.md +28 -0
  79. package/skills/wix-headless/references/designer/INSTRUCTIONS.md +828 -0
  80. package/skills/wix-headless/references/ecom/CART_PAGES.md +120 -0
  81. package/skills/wix-headless/references/ecom/CART_WIRING.md +103 -0
  82. package/skills/wix-headless/references/ecom/COMPONENTS_CSS.md +132 -0
  83. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +59 -0
  84. package/skills/wix-headless/references/forms/CONTACT_FORM.md +477 -0
  85. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +43 -0
  86. package/skills/wix-headless/references/gift-cards/COMPONENTS.md +119 -0
  87. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +51 -0
  88. package/skills/wix-headless/references/gift-cards/PAGES.md +129 -0
  89. package/skills/wix-headless/references/images/INSTRUCTIONS.md +359 -0
  90. package/skills/wix-headless/references/shared/BUILD_NOISE.md +8 -0
  91. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +185 -0
  92. package/skills/wix-headless/references/shared/IMPLEMENTER.md +155 -0
  93. package/skills/wix-headless/references/shared/MCP_PREFIX.md +105 -0
  94. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +97 -0
  95. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +423 -0
  96. package/skills/wix-headless/references/shared/STYLING.md +117 -0
  97. package/skills/wix-headless/references/stores/BACK_IN_STOCK.md +178 -0
  98. package/skills/wix-headless/references/stores/CATEGORY_PAGES.md +86 -0
  99. package/skills/wix-headless/references/stores/COMPONENTS_CSS.md +129 -0
  100. package/skills/wix-headless/references/stores/HOME_AND_NAV.md +227 -0
  101. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +96 -0
  102. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +249 -0
  103. package/skills/wix-headless/references/stores/PRODUCT_PAGES.md +213 -0
  104. package/skills/wix-headless/references/stores/SHARED_WIRING.md +164 -0
  105. package/skills/wix-headless/references/verticals/_schema.json +160 -0
  106. package/skills/wix-headless/references/verticals/_schema.md +185 -0
  107. package/skills/wix-headless/references/verticals/blog.md +125 -0
  108. package/skills/wix-headless/references/verticals/cms.md +121 -0
  109. package/skills/wix-headless/references/verticals/ecom.md +96 -0
  110. package/skills/wix-headless/references/verticals/forms.md +106 -0
  111. package/skills/wix-headless/references/verticals/gift-cards.md +121 -0
  112. package/skills/wix-headless/references/verticals/stores.md +167 -0
  113. package/skills/wix-headless/scripts/check-manifest.mjs +198 -0
  114. package/skills/wix-headless/scripts/copy-utility-templates.mjs +153 -0
  115. package/skills/wix-headless/scripts/emit-design-tokens.mjs +77 -0
  116. package/skills/wix-headless/scripts/finalize-run-json.mjs +141 -0
  117. package/skills/wix-headless/scripts/init-site-json.mjs +63 -0
  118. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +124 -0
  119. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +190 -0
  120. package/skills/wix-headless/scripts/preview.sh +45 -0
  121. package/skills/wix-headless/scripts/release.sh +73 -0
  122. package/skills/wix-headless/scripts/scaffold.sh +53 -0
  123. package/skills/wix-headless/scripts/seed-utilities.sh +55 -0
  124. package/skills/wix-headless/shared-utilities/analytics.ts +40 -0
  125. package/skills/wix-headless/shared-utilities/ricos.ts +179 -0
  126. package/skills/wix-headless/shared-utilities/wix-image.ts +72 -0
  127. package/skills/wix-headless/templates/ecom/CartBadge.tsx +84 -0
  128. package/skills/wix-headless/templates/ecom/CartView.tsx +543 -0
  129. package/skills/wix-headless/templates/ecom/cart.astro +13 -0
  130. package/skills/wix-headless/templates/ecom/components-ecom.css +215 -0
  131. package/skills/wix-headless/templates/ecom/discounts.ts +71 -0
  132. package/skills/wix-headless/templates/ecom/thank-you.astro +24 -0
  133. package/skills/wix-headless/templates/gift-cards/GiftCardPurchase.tsx +172 -0
  134. package/skills/wix-headless/templates/gift-cards/_home-teaser-snippet.astro +42 -0
  135. package/skills/wix-headless/templates/gift-cards/_nav-snippet.astro +11 -0
  136. package/skills/wix-headless/templates/gift-cards/components-gift-cards.css +219 -0
  137. package/skills/wix-headless/templates/gift-cards/gift-cards.astro +51 -0
  138. package/skills/wix-headless/templates/gift-cards/gift-cards.ts +75 -0
  139. package/skills/wix-headless/templates/stores/AddToCartButton.tsx +77 -0
  140. package/skills/wix-headless/templates/stores/BackInStockForm.tsx +176 -0
  141. package/skills/wix-headless/templates/stores/CategoryRail.astro +69 -0
  142. package/skills/wix-headless/templates/stores/ProductCard.astro +79 -0
  143. package/skills/wix-headless/templates/stores/ProductPurchase.tsx +397 -0
  144. package/skills/wix-headless/templates/stores/SeoTags.astro +21 -0
  145. package/skills/wix-headless/templates/stores/back-in-stock.ts +67 -0
  146. package/skills/wix-headless/templates/stores/categories.ts +155 -0
  147. package/skills/wix-headless/templates/stores/category/[slug].astro +130 -0
  148. package/skills/wix-headless/templates/stores/components-stores.css +295 -0
  149. package/skills/wix-headless/templates/stores/products/[slug].astro +128 -0
  150. package/skills/wix-headless/templates/stores/products/index.astro +101 -0
  151. package/skills/wix-manage/SKILL.md +280 -0
  152. package/skills/wix-manage/references/app-installation/install-wix-apps.md +155 -0
  153. package/skills/wix-manage/references/app-installation/list-installed-apps.md +124 -0
  154. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +226 -0
  155. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +95 -0
  156. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +416 -0
  157. package/skills/wix-manage/references/bookings/bookings-staff-setup.md +255 -0
  158. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +462 -0
  159. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +278 -0
  160. package/skills/wix-manage/references/bookings/external-calendar-integration.md +258 -0
  161. package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +231 -0
  162. package/skills/wix-manage/references/calendar/configure-default-business-hours.md +226 -0
  163. package/skills/wix-manage/references/cms/cms-data-items-crud.md +422 -0
  164. package/skills/wix-manage/references/cms/cms-data-operations-extended.md +263 -0
  165. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +136 -0
  166. package/skills/wix-manage/references/cms/cms-references-and-relationships.md +160 -0
  167. package/skills/wix-manage/references/cms/cms-schema-management.md +143 -0
  168. package/skills/wix-manage/references/contacts/bulk-delete-contacts.md +73 -0
  169. package/skills/wix-manage/references/contacts/bulk-label-and-unlabel-contacts.md +67 -0
  170. package/skills/wix-manage/references/domains/domain-search-and-purchase.md +434 -0
  171. package/skills/wix-manage/references/ecommerce/api-recommendation-tracking.md +420 -0
  172. package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +267 -0
  173. package/skills/wix-manage/references/ecommerce/flow-bundle-and-save.md +290 -0
  174. package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +300 -0
  175. package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +364 -0
  176. package/skills/wix-manage/references/ecommerce/flow-seasonal-promotion.md +315 -0
  177. package/skills/wix-manage/references/ecommerce/flow-stock-mover.md +308 -0
  178. package/skills/wix-manage/references/ecommerce/flow-upsell-boost.md +271 -0
  179. package/skills/wix-manage/references/ecommerce/goal-clear-inventory.md +118 -0
  180. package/skills/wix-manage/references/ecommerce/goal-drive-cross-sells.md +122 -0
  181. package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +132 -0
  182. package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +148 -0
  183. package/skills/wix-manage/references/ecommerce/goal-seasonal-revenue.md +146 -0
  184. package/skills/wix-manage/references/ecommerce/guardrail-discount-conflicts.md +118 -0
  185. package/skills/wix-manage/references/ecommerce/guardrail-margin-protection.md +88 -0
  186. package/skills/wix-manage/references/ecommerce/guardrail-rate-pricing-sanity.md +108 -0
  187. package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +124 -0
  188. package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +299 -0
  189. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +582 -0
  190. package/skills/wix-manage/references/ecommerce/setup-coupons.md +338 -0
  191. package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +444 -0
  192. package/skills/wix-manage/references/ecommerce/setup-shipping-rates.md +86 -0
  193. package/skills/wix-manage/references/ecommerce/setup-shipping-regions.md +56 -0
  194. package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +209 -0
  195. package/skills/wix-manage/references/ecommerce/skill-graph.md +139 -0
  196. package/skills/wix-manage/references/ecommerce/troubleshoot-checkout-delivery-dropoff.md +124 -0
  197. package/skills/wix-manage/references/ecommerce/troubleshoot-discount-not-applying.md +95 -0
  198. package/skills/wix-manage/references/events/list-events.md +203 -0
  199. package/skills/wix-manage/references/forms/create-form.md +260 -0
  200. package/skills/wix-manage/references/get-paid/create-payment-links.md +212 -0
  201. package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +57 -0
  202. package/skills/wix-manage/references/get-paid/payment-links-for-bookings.md +101 -0
  203. package/skills/wix-manage/references/media/upload-media-to-wix.md +216 -0
  204. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +77 -0
  205. package/skills/wix-manage/references/pricing-plans/pricing-plans-bookings-integration.md +166 -0
  206. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +336 -0
  207. package/skills/wix-manage/references/rich-content/ricos-converter-service.md +295 -0
  208. package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +59 -0
  209. package/skills/wix-manage/references/sites/create-site-from-template.md +183 -0
  210. package/skills/wix-manage/references/sites/query-sites.md +125 -0
  211. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +57 -0
  212. package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1041 -0
  213. package/skills/wix-manage/references/stores/create-product-catalog-v1.md +125 -0
  214. package/skills/wix-manage/references/stores/create-product-from-image.md +824 -0
  215. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +566 -0
  216. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +194 -0
  217. package/skills/wix-manage/references/stores/query-products-catalog-v1.md +80 -0
  218. package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +99 -0
  219. package/skills/wix-manage/references/stores/update-product-pre-order.md +213 -0
  220. package/skills/wix-manage/references/stores/update-product-with-options.md +318 -0
@@ -0,0 +1,219 @@
1
+ /* Gift Cards pack — scoped CSS.
2
+ *
3
+ * Imported by Layout.astro alongside other components-*.css files. Covers:
4
+ * 1. Buy form (`.gift-card-form` + fields)
5
+ * 2. /gift-cards landing page sections
6
+ * 3. Home teaser block
7
+ *
8
+ * Reuses tokens declared by the designer foundation: --color-cream,
9
+ * --color-cream-deep, --color-ink, --color-ink-soft, --color-muted,
10
+ * --color-rule, --color-paper, --color-bark/espresso/gold-deep,
11
+ * --spacing-{sm,md,lg,xl,2xl,3xl,4xl}, --radius-sm, --font-body,
12
+ * --font-display. If a token isn't in your design system, fall back to a
13
+ * sibling token; do NOT invent new ones.
14
+ */
15
+
16
+ /* -------------------------------------------------------------------------- */
17
+ /* Buy form */
18
+ /* -------------------------------------------------------------------------- */
19
+
20
+ .gift-card-form {
21
+ display: flex;
22
+ flex-direction: column;
23
+ gap: var(--spacing-lg);
24
+ margin-top: var(--spacing-lg);
25
+ }
26
+
27
+ .gift-card-fieldset {
28
+ border: none;
29
+ padding: 0;
30
+ margin: 0;
31
+ }
32
+
33
+ .gift-card-amounts {
34
+ display: flex;
35
+ flex-wrap: wrap;
36
+ gap: var(--spacing-sm);
37
+ margin-top: var(--spacing-sm);
38
+ }
39
+
40
+ .gift-card-grid {
41
+ display: grid;
42
+ grid-template-columns: 1fr 1fr;
43
+ gap: var(--spacing-md);
44
+ }
45
+
46
+ .gift-card-field {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: 0.4rem;
50
+ position: relative;
51
+ }
52
+
53
+ .gift-card-field-wide {
54
+ grid-column: 1 / -1;
55
+ }
56
+
57
+ .gift-card-field input,
58
+ .gift-card-field textarea {
59
+ font-family: var(--font-body);
60
+ font-size: 0.9375rem;
61
+ line-height: 1.5;
62
+ color: var(--color-ink);
63
+ background: var(--color-cream);
64
+ border: 1px solid var(--color-rule);
65
+ border-radius: var(--radius-sm);
66
+ padding: 0.65rem 0.8rem;
67
+ transition: border-color 0.2s ease;
68
+ }
69
+
70
+ .gift-card-field input:focus,
71
+ .gift-card-field textarea:focus {
72
+ outline: none;
73
+ border-color: var(--color-ink);
74
+ }
75
+
76
+ .gift-card-field textarea {
77
+ resize: vertical;
78
+ min-height: 5rem;
79
+ }
80
+
81
+ .gift-card-counter {
82
+ position: absolute;
83
+ right: 0;
84
+ bottom: -1.2rem;
85
+ font-family: var(--font-body);
86
+ font-size: 0.6875rem;
87
+ color: var(--color-muted);
88
+ }
89
+
90
+ .gift-card-error {
91
+ font-family: var(--font-body);
92
+ font-size: 0.875rem;
93
+ color: var(--color-gold-deep, #a04a3c);
94
+ margin: 0;
95
+ }
96
+
97
+ /* -------------------------------------------------------------------------- */
98
+ /* /gift-cards landing page */
99
+ /* -------------------------------------------------------------------------- */
100
+
101
+ .gift-card-page {
102
+ max-width: 80rem;
103
+ margin: 0 auto;
104
+ padding: var(--spacing-3xl) var(--spacing-lg) var(--spacing-4xl);
105
+ }
106
+
107
+ .gift-card-grid-wrap {
108
+ display: grid;
109
+ grid-template-columns: 1fr;
110
+ gap: var(--spacing-2xl);
111
+ align-items: start;
112
+ }
113
+
114
+ @media (min-width: 768px) {
115
+ .gift-card-grid-wrap {
116
+ grid-template-columns: 1fr 1fr;
117
+ gap: var(--spacing-4xl);
118
+ }
119
+ }
120
+
121
+ .gift-card-hero-image {
122
+ background: var(--color-cream-deep, var(--color-paper, var(--color-cream)));
123
+ border-radius: var(--radius-sm);
124
+ overflow: hidden;
125
+ aspect-ratio: 1 / 1;
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ }
130
+
131
+ .gift-card-hero-image img {
132
+ width: 100%;
133
+ height: 100%;
134
+ object-fit: cover;
135
+ }
136
+
137
+ .gift-card-body {
138
+ max-width: 36rem;
139
+ }
140
+
141
+ .gift-card-body h1 {
142
+ margin: var(--spacing-md) 0 var(--spacing-md);
143
+ }
144
+
145
+ .gift-card-lede {
146
+ font-family: var(--font-body);
147
+ font-size: 1.0625rem;
148
+ line-height: 1.7;
149
+ color: var(--color-ink-soft);
150
+ max-width: 48ch;
151
+ margin: 0 0 var(--spacing-xl);
152
+ }
153
+
154
+ .gift-card-fineprint {
155
+ margin-top: var(--spacing-lg);
156
+ font-family: var(--font-body);
157
+ font-size: 0.8125rem;
158
+ line-height: 1.6;
159
+ color: var(--color-muted);
160
+ max-width: 44ch;
161
+ }
162
+
163
+ /* -------------------------------------------------------------------------- */
164
+ /* Home teaser */
165
+ /* -------------------------------------------------------------------------- */
166
+
167
+ .gift-card-teaser {
168
+ padding: var(--spacing-4xl) var(--spacing-lg);
169
+ background: var(--color-cream-deep, var(--color-paper, var(--color-cream)));
170
+ }
171
+
172
+ .gift-card-teaser-link {
173
+ display: grid;
174
+ grid-template-columns: 1fr;
175
+ gap: var(--spacing-2xl);
176
+ max-width: 80rem;
177
+ margin: 0 auto;
178
+ align-items: center;
179
+ text-decoration: none;
180
+ color: var(--color-ink);
181
+ }
182
+
183
+ @media (min-width: 768px) {
184
+ .gift-card-teaser-link {
185
+ grid-template-columns: 1fr 1fr;
186
+ gap: var(--spacing-4xl);
187
+ }
188
+ }
189
+
190
+ .gift-card-teaser-image {
191
+ aspect-ratio: 4 / 3;
192
+ overflow: hidden;
193
+ border-radius: var(--radius-sm);
194
+ background: var(--color-cream);
195
+ }
196
+
197
+ .gift-card-teaser-image img {
198
+ width: 100%;
199
+ height: 100%;
200
+ object-fit: cover;
201
+ transition: transform 0.6s ease;
202
+ }
203
+
204
+ .gift-card-teaser-link:hover .gift-card-teaser-image img {
205
+ transform: scale(1.02);
206
+ }
207
+
208
+ .gift-card-teaser-body h2 {
209
+ margin: var(--spacing-md) 0 var(--spacing-md);
210
+ }
211
+
212
+ .gift-card-teaser-lede {
213
+ font-family: var(--font-body);
214
+ font-size: 1.0625rem;
215
+ line-height: 1.7;
216
+ color: var(--color-ink-soft);
217
+ max-width: 44ch;
218
+ margin: 0 0 var(--spacing-lg);
219
+ }
@@ -0,0 +1,51 @@
1
+ ---
2
+ import Layout from "../layouts/Layout.astro";
3
+ import GiftCardPurchase from "../components/GiftCardPurchase.tsx";
4
+ import { getGiftCardProduct } from "../utils/gift-cards";
5
+ import { resolveWixImageUrl } from "../utils/wix-image";
6
+
7
+ // The probe returns null if the Wix Gift Card app is uninstalled, revoked,
8
+ // or the dashboard's eGift Card template hasn't been configured. Redirect
9
+ // rather than rendering an empty page — keeps stale links from showing a
10
+ // broken UI.
11
+ const product = await getGiftCardProduct();
12
+ if (!product) return Astro.redirect("/", 302);
13
+
14
+ const heroImage = resolveWixImageUrl(product.image, 800, 800);
15
+ ---
16
+
17
+ <Layout
18
+ title={product.name}
19
+ description={product.description}
20
+ >
21
+ <section class="py-3xl md:py-4xl">
22
+ <div class="max-w-wide mx-auto px-xl grid grid-cols-1 md:grid-cols-2 gap-2xl md:gap-4xl items-center">
23
+ <div class="aspect-square bg-cream rounded-sm overflow-hidden">
24
+ {heroImage && (
25
+ <img
26
+ src={heroImage}
27
+ alt={product.image?.altText || product.name}
28
+ loading="lazy"
29
+ decoding="async"
30
+ width={product.image?.width ?? 800}
31
+ height={product.image?.height ?? 800}
32
+ class="w-full h-full object-cover"
33
+ />
34
+ )}
35
+ </div>
36
+
37
+ <div class="flex flex-col gap-lg">
38
+ <p class="eyebrow">A gift, considered</p>
39
+ <h1 class="font-display text-5xl leading-tight">{product.name}</h1>
40
+ <p class="text-ink-soft leading-relaxed">{product.description}</p>
41
+
42
+ <GiftCardPurchase product={product} client:load />
43
+
44
+ <p class="text-mute text-sm leading-relaxed">
45
+ Sent by email to your recipient with a redeemable code. Redeemed at
46
+ checkout against any product on the site.
47
+ </p>
48
+ </div>
49
+ </div>
50
+ </section>
51
+ </Layout>
@@ -0,0 +1,75 @@
1
+ // Wix Gift Card app — eGift Card template fetch.
2
+ //
3
+ // The dashboard's Catalog → Gift Cards screen configures a single eGift Card
4
+ // "product" with preset denominations. That product is queryable via a public
5
+ // REST endpoint (POST /gift-cards/v1/gift-card-products/query). The JS SDK
6
+ // auto-package @wix/auto_sdk_ecom_gift-vouchers only exposes redemption
7
+ // methods (getGiftCard / redeemGiftCard / voidTransaction), so we hit REST
8
+ // directly using @wix/essentials httpClient.fetchWithAuth.
9
+ //
10
+ // The buy flow uses the standard cart: currentCart.addToCurrentCart with a
11
+ // catalogReference whose appId is WIX_GIFT_CARDS_APP_ID below. After payment,
12
+ // Wix's gift-card backend automatically issues a redeemable gift card with
13
+ // source: "ORDER" and emails the recipient — no follow-up API call needed.
14
+ //
15
+ // The appId is observable on installed sites and stable across sites. If Wix
16
+ // ever rotates it, update this constant; both the runtime probe and the buy
17
+ // flow will fail together (and the page hides gracefully — same as "app
18
+ // uninstalled").
19
+
20
+ import { httpClient } from "@wix/essentials";
21
+
22
+ export const WIX_GIFT_CARDS_APP_ID = "d80111c5-a0f4-47a8-b63a-65b54d774a27";
23
+
24
+ export interface GiftCardImage {
25
+ id?: string;
26
+ url?: string;
27
+ height?: number;
28
+ width?: number;
29
+ altText?: string;
30
+ }
31
+
32
+ export interface GiftCardPresetVariant {
33
+ id: string;
34
+ price: { amount: string; formattedAmount: string; convertedAmount?: string; formattedConvertedAmount?: string };
35
+ value: { amount: string; formattedAmount: string; convertedAmount?: string; formattedConvertedAmount?: string };
36
+ }
37
+
38
+ export interface GiftCardProduct {
39
+ id: string;
40
+ revision?: string;
41
+ name: string;
42
+ description: string;
43
+ image?: GiftCardImage;
44
+ expirationType?: string;
45
+ presetVariants: GiftCardPresetVariant[];
46
+ }
47
+
48
+ const ENDPOINT = "https://www.wixapis.com/gift-cards/v1/gift-card-products/query";
49
+
50
+ // Module-level memoization. Navigation, the home teaser, and /gift-cards all
51
+ // call getGiftCardProduct() in the same request — coalesce them into one
52
+ // fetch by holding the in-flight promise at module scope.
53
+ let cached: Promise<GiftCardProduct | null> | null = null;
54
+
55
+ export async function getGiftCardProduct(): Promise<GiftCardProduct | null> {
56
+ if (cached) return cached;
57
+ cached = (async () => {
58
+ try {
59
+ const res = await httpClient.fetchWithAuth(ENDPOINT, {
60
+ method: "POST",
61
+ headers: { "Content-Type": "application/json" },
62
+ body: JSON.stringify({ query: { paging: { limit: 1 } } }),
63
+ });
64
+ if (!res.ok) return null;
65
+ const data = await res.json();
66
+ const products = data?.giftCardProducts;
67
+ if (!Array.isArray(products) || products.length === 0) return null;
68
+ return products[0] as GiftCardProduct;
69
+ } catch (err) {
70
+ console.error("[gift-cards] queryGiftCardProducts failed:", err);
71
+ return null;
72
+ }
73
+ })();
74
+ return cached;
75
+ }
@@ -0,0 +1,77 @@
1
+ import { useState } from "react";
2
+ import { currentCart } from "@wix/ecom";
3
+ import { trackEvent } from "../utils/analytics";
4
+
5
+ const WIX_STORES_APP_ID = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
6
+
7
+ interface AddToCartButtonProps {
8
+ productId: string;
9
+ productName: string;
10
+ price?: number;
11
+ currency?: string;
12
+ variantId?: string;
13
+ variantName?: string;
14
+ quantity?: number;
15
+ disabled?: boolean;
16
+ // Modifier selections, already flattened by ProductPurchase. Shapes:
17
+ // modifierChoices: { [modifier.key]: choice.key }
18
+ // customTextFields: { [modifier.freeTextSettings.key]: "<user input>" }
19
+ modifierChoices?: Record<string, string>;
20
+ customTextFields?: Record<string, string>;
21
+ }
22
+
23
+ export default function AddToCartButton({
24
+ productId, productName, price, currency,
25
+ variantId, variantName, quantity = 1, disabled,
26
+ modifierChoices, customTextFields,
27
+ }: AddToCartButtonProps) {
28
+ const [status, setStatus] = useState<"idle" | "added">("idle");
29
+
30
+ const handleAddToCart = async () => {
31
+ // Optimistic: show success immediately, fire API in background
32
+ setStatus("added");
33
+ setTimeout(() => setStatus("idle"), 2000);
34
+ window.dispatchEvent(new CustomEvent("cart-updated", { detail: { delta: quantity } }));
35
+
36
+ try {
37
+ // Build catalogReference.options per Wix Stores Catalog V3 contract:
38
+ // { variantId, options: { [modifier.key]: choice.key }, customTextFields: { … } }
39
+ const catalogOptions: Record<string, unknown> = {};
40
+ if (variantId) catalogOptions.variantId = variantId;
41
+ if (modifierChoices && Object.keys(modifierChoices).length > 0) {
42
+ catalogOptions.options = modifierChoices;
43
+ }
44
+ if (customTextFields && Object.keys(customTextFields).length > 0) {
45
+ catalogOptions.customTextFields = customTextFields;
46
+ }
47
+ const { cart } = await currentCart.addToCurrentCart({
48
+ lineItems: [{
49
+ catalogReference: {
50
+ appId: WIX_STORES_APP_ID,
51
+ catalogItemId: productId,
52
+ options: Object.keys(catalogOptions).length > 0 ? catalogOptions : undefined,
53
+ },
54
+ quantity,
55
+ }],
56
+ });
57
+ window.dispatchEvent(new CustomEvent("cart-updated", { detail: { cart } }));
58
+ trackEvent("AddToCart", {
59
+ id: productId, name: productName, price, currency,
60
+ quantity, variant: variantName, origin: "Product Page",
61
+ });
62
+ } catch {
63
+ setStatus("idle");
64
+ window.dispatchEvent(new CustomEvent("cart-updated", { detail: {} }));
65
+ }
66
+ };
67
+
68
+ return (
69
+ <button
70
+ onClick={handleAddToCart}
71
+ disabled={disabled || status === "added"}
72
+ className="add-to-cart-btn"
73
+ >
74
+ {disabled ? "Select Options" : status === "added" ? "Added \u2713" : "Add to Cart"}
75
+ </button>
76
+ );
77
+ }
@@ -0,0 +1,176 @@
1
+ import { useState } from "react";
2
+ import { backInStockNotifications } from "@wix/ecom";
3
+ import { WIX_STORES_BACK_IN_STOCK_APP_ID } from "../utils/back-in-stock";
4
+
5
+ interface BackInStockFormProps {
6
+ productId: string;
7
+ variantId?: string;
8
+ productName: string;
9
+ // Numeric price (number or numeric string). The Wix backend validates
10
+ // `itemDetails.price >= 0` against the parsed decimal, so currency-
11
+ // formatted strings ("$695") are stripped here before submission.
12
+ productPrice: number | string;
13
+ variantLabel?: string;
14
+ }
15
+
16
+ type Status =
17
+ | { kind: "idle" }
18
+ | { kind: "submitting" }
19
+ | { kind: "success"; alreadySubscribed?: boolean }
20
+ | { kind: "error"; message: string };
21
+
22
+ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
23
+
24
+ function normalizePrice(raw: number | string): string {
25
+ const s =
26
+ typeof raw === "number" ? String(raw) : String(raw).replace(/[^0-9.]/g, "");
27
+ const n = Number(s);
28
+ return Number.isFinite(n) && n >= 0 ? s : "0";
29
+ }
30
+
31
+ function readErrorCode(err: unknown): string | undefined {
32
+ if (!err || typeof err !== "object") return undefined;
33
+ // Wix SDK errors expose details.applicationError.code; some shapes also
34
+ // surface a top-level details.code or http status. Try the common ones.
35
+ const e = err as Record<string, any>;
36
+ return (
37
+ e?.details?.applicationError?.code ??
38
+ e?.details?.code ??
39
+ e?.applicationError?.code ??
40
+ undefined
41
+ );
42
+ }
43
+
44
+ export default function BackInStockForm({
45
+ productId,
46
+ variantId,
47
+ productName,
48
+ productPrice,
49
+ variantLabel,
50
+ }: BackInStockFormProps) {
51
+ const [email, setEmail] = useState("");
52
+ const [status, setStatus] = useState<Status>({ kind: "idle" });
53
+
54
+ const submitting = status.kind === "submitting";
55
+ const success = status.kind === "success";
56
+
57
+ async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
58
+ e.preventDefault();
59
+ if (submitting) return;
60
+ if (!EMAIL_RE.test(email)) {
61
+ setStatus({ kind: "error", message: "Enter a valid email." });
62
+ return;
63
+ }
64
+ setStatus({ kind: "submitting" });
65
+
66
+ // Bare-fields rule: the SDK throws an opaque
67
+ // "TypeError: Failed to construct 'URL': Invalid URL" when the optional
68
+ // request.itemUrl or itemDetails.image fields are present, even with
69
+ // browser-valid URLs. Send only the four required fields:
70
+ // catalogReference, email, name, price. The dashboard's Back-in-Stock
71
+ // Requests view + the customer notification email both work without
72
+ // them; the email just won't have a thumbnail and the dashboard uses
73
+ // its default item URL.
74
+ const request = {
75
+ catalogReference: {
76
+ appId: WIX_STORES_BACK_IN_STOCK_APP_ID,
77
+ catalogItemId: productId,
78
+ ...(variantId ? { options: { variantId } } : {}),
79
+ },
80
+ email,
81
+ };
82
+ const itemDetails = {
83
+ name: productName,
84
+ price: normalizePrice(productPrice),
85
+ };
86
+
87
+ try {
88
+ await backInStockNotifications.createBackInStockNotificationRequest(
89
+ request,
90
+ itemDetails,
91
+ );
92
+ setStatus({ kind: "success" });
93
+ } catch (err) {
94
+ const code = readErrorCode(err);
95
+ if (code === "BACK_IN_STOCK_NOTIFICATION_REQUEST_ALREADY_EXISTS") {
96
+ setStatus({ kind: "success", alreadySubscribed: true });
97
+ return;
98
+ }
99
+ if (code === "REQUEST_COLLECTION_DISABLED") {
100
+ setStatus({
101
+ kind: "error",
102
+ message: "Notifications aren't being collected right now.",
103
+ });
104
+ return;
105
+ }
106
+ console.error("[back-in-stock] subscribe failed:", err);
107
+ setStatus({
108
+ kind: "error",
109
+ message: "Something went wrong. Please try again.",
110
+ });
111
+ }
112
+ }
113
+
114
+ if (success) {
115
+ return (
116
+ <div className="back-in-stock-success" role="status" aria-live="polite">
117
+ <p className="back-in-stock-success-headline">
118
+ {status.alreadySubscribed
119
+ ? "You're already on the list."
120
+ : "We'll let you know."}
121
+ </p>
122
+ <p className="back-in-stock-success-detail">
123
+ {status.alreadySubscribed
124
+ ? `We had your note for ${productName}${variantLabel ? ` (${variantLabel})` : ""}. We'll email ${email} the moment it's back.`
125
+ : `We'll email ${email} the moment ${productName}${variantLabel ? ` (${variantLabel})` : ""} is back in stock.`}
126
+ </p>
127
+ </div>
128
+ );
129
+ }
130
+
131
+ return (
132
+ <form className="back-in-stock-form" onSubmit={handleSubmit} noValidate>
133
+ <div className="back-in-stock-headline">
134
+ <span className="back-in-stock-eyebrow">Currently sold out</span>
135
+ <p className="back-in-stock-lede">
136
+ Leave your email and we'll notify you the moment
137
+ {variantLabel ? ` ${variantLabel.toLowerCase()}` : ""} is back in
138
+ stock.
139
+ </p>
140
+ </div>
141
+ <label className="back-in-stock-label" htmlFor="back-in-stock-email">
142
+ Email
143
+ </label>
144
+ <div className="back-in-stock-row">
145
+ <input
146
+ id="back-in-stock-email"
147
+ type="email"
148
+ inputMode="email"
149
+ autoComplete="email"
150
+ required
151
+ placeholder="you@example.com"
152
+ value={email}
153
+ onChange={(e) => {
154
+ setEmail(e.target.value);
155
+ if (status.kind === "error") setStatus({ kind: "idle" });
156
+ }}
157
+ className="back-in-stock-input"
158
+ aria-invalid={status.kind === "error"}
159
+ disabled={submitting}
160
+ />
161
+ <button
162
+ type="submit"
163
+ className="back-in-stock-submit"
164
+ disabled={submitting || email.trim().length === 0}
165
+ >
166
+ {submitting ? "Sending…" : "Notify me"}
167
+ </button>
168
+ </div>
169
+ {status.kind === "error" && (
170
+ <p className="back-in-stock-error" role="alert">
171
+ {status.message}
172
+ </p>
173
+ )}
174
+ </form>
175
+ );
176
+ }
@@ -0,0 +1,69 @@
1
+ ---
2
+ // Shared category-rail + Prev/Next pagination for /products and
3
+ // /category/[slug]. Persists across <ClientRouter /> swaps so pill clicks
4
+ // feel like an in-place filter, not a navigation. The active pill is
5
+ // recomputed from the URL by an astro:after-swap hook in Layout.astro.
6
+ //
7
+ // Owned by the stores pack. Ecom/blog/etc. do NOT write to this file.
8
+ import type { StoreCategory } from "../utils/categories";
9
+
10
+ interface Props {
11
+ categories: StoreCategory[];
12
+ // null = "All" view; otherwise the slug of the active category.
13
+ activeSlug: string | null;
14
+ prevHref: string | null;
15
+ nextHref: string | null;
16
+ }
17
+
18
+ const { categories, activeSlug, prevHref, nextHref } = Astro.props;
19
+ ---
20
+
21
+ {categories.length > 0 && (
22
+ <nav
23
+ class="category-rail"
24
+ aria-label="Browse by category"
25
+ data-category-rail
26
+ transition:persist="category-rail"
27
+ transition:name="category-rail"
28
+ >
29
+ <div class="container-page category-rail-inner">
30
+ <a
31
+ href="/products"
32
+ class="category-pill"
33
+ data-category-slug=""
34
+ data-astro-prefetch="hover"
35
+ aria-current={activeSlug ? undefined : "page"}
36
+ >All</a>
37
+ {categories.map((cat) => (
38
+ <a
39
+ href={`/category/${cat.slug}`}
40
+ class="category-pill"
41
+ data-category-slug={cat.slug}
42
+ data-astro-prefetch="hover"
43
+ aria-current={activeSlug === cat.slug ? "page" : undefined}
44
+ >{cat.name}</a>
45
+ ))}
46
+ </div>
47
+ </nav>
48
+ )}
49
+
50
+ {(prevHref || nextHref) && (
51
+ <nav class="pagination" aria-label="Listing pagination">
52
+ <div class="container-page pagination-inner">
53
+ {prevHref ? (
54
+ <a href={prevHref} class="pagination-link" data-astro-prefetch="hover" rel="prev">
55
+ &larr; Previous
56
+ </a>
57
+ ) : (
58
+ <span class="pagination-link is-disabled" aria-disabled="true">&larr; Previous</span>
59
+ )}
60
+ {nextHref ? (
61
+ <a href={nextHref} class="pagination-link" data-astro-prefetch="hover" rel="next">
62
+ Next &rarr;
63
+ </a>
64
+ ) : (
65
+ <span class="pagination-link is-disabled" aria-disabled="true">Next &rarr;</span>
66
+ )}
67
+ </div>
68
+ </nav>
69
+ )}