@wix/agent-skills 1.7.0 → 1.9.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.
- package/README.md +3 -7
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +2 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +2 -1
- package/skills/wix-app/references/STORES_VERSIONING.md +1 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +14 -0
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +11 -6
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +3 -17
- package/skills/wix-app/references/editor-react-component/SSR.md +119 -0
- package/skills/wix-design-system/SKILL.md +5 -1
- package/skills/wix-headless/SKILL.md +55 -32
- package/skills/wix-headless/references/BUILD-astro.md +244 -0
- package/skills/wix-headless/references/BUILD-own-build.md +167 -0
- package/skills/wix-headless/references/BUILD.md +50 -252
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +94 -34
- package/skills/wix-headless/references/DISCOVERY-connect.md +55 -0
- package/skills/wix-headless/references/DISCOVERY-create.md +238 -0
- package/skills/wix-headless/references/DISCOVERY.md +41 -422
- package/skills/wix-headless/references/PLAN-connect.md +19 -0
- package/skills/wix-headless/references/PLAN-create.md +17 -0
- package/skills/wix-headless/references/PLAN.md +37 -27
- package/skills/wix-headless/references/SEED.md +27 -18
- package/skills/wix-headless/references/SETUP.md +32 -213
- package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +5 -4
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +45 -0
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +58 -0
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +5 -5
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +10 -10
- package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +12 -13
- package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +10 -12
- package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +8 -8
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +47 -27
- package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +7 -8
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +5 -5
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +3 -3
- package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +5 -19
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +2 -2
- package/skills/wix-headless/references/astro/gift-cards/PAGES.md +1 -1
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +6 -6
- package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +4 -4
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +3 -3
- package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +3 -3
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +9 -9
- package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +5 -4
- package/skills/wix-headless/references/astro/templates/Footer.astro +1 -1
- package/skills/wix-headless/references/astro/templates/Layout.astro +1 -1
- package/skills/wix-headless/references/astro/templates/Navigation.astro +1 -1
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +1 -1
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +233 -0
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +136 -0
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +25 -0
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +54 -0
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +45 -0
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +49 -0
- package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +245 -0
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +356 -0
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +133 -0
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +73 -0
- package/skills/wix-headless/references/astro/templates/global.css +2 -2
- package/skills/wix-headless/references/astro/templates/index.astro +1 -1
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +19 -9
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +3 -3
- package/skills/wix-headless/references/bookings/FLOW.md +185 -0
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +90 -0
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +295 -0
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +4 -2
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +27 -1
- package/skills/wix-headless/references/commands/known-apps.json +2 -1
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +142 -0
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +71 -21
- package/skills/wix-headless/references/custom/blog/WIRING.md +52 -0
- package/skills/wix-headless/references/custom/bookings/WIRING.md +146 -0
- package/skills/wix-headless/references/custom/cms/WIRING.md +97 -0
- package/skills/wix-headless/references/custom/ecom/WIRING.md +67 -0
- package/skills/wix-headless/references/custom/forms/WIRING.md +101 -0
- package/skills/wix-headless/references/custom/stores/WIRING.md +80 -0
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +5 -5
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +2 -2
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +3 -3
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +16 -15
- package/skills/wix-headless/references/seed-recipes.md +2 -2
- package/skills/wix-headless/references/shared/AGENTS_MD.md +47 -0
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +3 -5
- package/skills/wix-headless/references/shared/DESIGN_MD.md +85 -0
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +29 -28
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +87 -27
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +2 -2
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +24 -313
- package/skills/wix-headless/references/shared/STYLING.md +8 -18
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +39 -9
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +17 -14
- package/skills/wix-headless/references/verticals/_schema.json +1 -1
- package/skills/wix-headless/references/verticals/_schema.md +3 -3
- package/skills/wix-headless/references/verticals/blog.md +1 -1
- package/skills/wix-headless/references/verticals/bookings.md +39 -0
- package/skills/wix-headless/references/verticals/cms.md +1 -1
- package/skills/wix-headless/references/verticals/ecom.md +2 -2
- package/skills/wix-headless/references/verticals/gift-cards.md +1 -1
- package/skills/wix-headless/references/verticals/stores.md +1 -1
- package/skills/wix-headless/scripts/check-manifest.mjs +143 -6
- package/skills/wix-headless/scripts/compose.mjs +540 -0
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +128 -51
- package/skills/wix-headless/scripts/flatten.sh +61 -0
- package/skills/wix-headless/scripts/generate-images.mjs +242 -0
- package/skills/wix-headless/scripts/scaffold.sh +47 -16
- package/skills/wix-headless/scripts/write-decorative-json.mjs +62 -0
- package/skills/wix-manage/SKILL.md +13 -1
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -27
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +1 -1
- package/skills/wix-manage/references/bookings/create-appointment-service.md +266 -0
- package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +37 -0
- package/skills/wix-manage/references/bookings/create-class-service.md +245 -0
- package/skills/wix-manage/references/bookings/create-course-service.md +249 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +3 -2
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +1 -1
- package/skills/wix-manage/references/cms/cms-schema-management.md +2 -2
- package/skills/wix-manage/references/domains/domain-search-and-purchase.md +10 -7
- package/skills/wix-manage/references/forms/create-form.md +49 -1
- package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1 -1
- package/skills/wix-manage/references/stores/create-product-from-image.md +154 -2
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +1 -1
- package/skills/wix-headless/references/astro/COMPOSE.md +0 -142
- package/skills/wix-headless/scripts/finalize-run-json.mjs +0 -141
- package/skills/wix-headless/scripts/init-site-json.mjs +0 -101
- package/skills/wix-headless/scripts/preview.sh +0 -45
- package/skills/wix-headless/scripts/release.sh +0 -73
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# Phase 3 Components — Back in Stock (Stores)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The stores `components` scope writes the TSX/util files; the CSS rules ship in the **pre-copied** `components-stores.css` template (no agent authors them). The matching page wiring lives in `PRODUCT_PAGES.md` (SSR probe import + new props on `<ProductPurchase>`). Both the components and that page wiring run inside the **same stores merged build agent** (the build wave), components first.
|
|
4
4
|
|
|
5
5
|
## Scope
|
|
6
6
|
|
|
7
7
|
Files written for back-in-stock, by scope:
|
|
8
8
|
|
|
9
9
|
**`components` scope** (see `./SHARED_WIRING.md`):
|
|
10
|
-
- `src/utils/back-in-stock.ts` — SSR-elevated probe of the Wix back-in-stock service, plus the canonical Stores app id constant
|
|
11
10
|
- `src/components/BackInStockForm.tsx` — React island that posts via `@wix/ecom`'s `backInStockNotifications.createBackInStockNotificationRequest`
|
|
12
11
|
|
|
12
|
+
**Pre-copied by the orchestrator** (do NOT author — same treatment as `categories.ts`):
|
|
13
|
+
- `src/utils/back-in-stock.ts` — SSR-elevated probe of the Wix back-in-stock service, plus the canonical Stores app id constant. Pre-copied into the project in the build-wave pre-batch (BUILD-astro.md § "Step 4.5"). **Import** `getBackInStockEnabled`/the app-id constants from `../utils/back-in-stock`; never `Write` it yourself (racing the pre-copy trips the harness staleness guard).
|
|
14
|
+
|
|
13
15
|
**`components-css` scope** (see `./COMPONENTS_CSS.md`):
|
|
14
16
|
- `src/styles/components-stores.css` — appends the back-in-stock form CSS rules at the end of the file (see § 3 below)
|
|
15
17
|
|
|
@@ -45,9 +47,9 @@ This scope uses **template files** instead of inline code. For each file below:
|
|
|
45
47
|
|
|
46
48
|
Do NOT modify logic, imports, the bare-fields request shape, or the app-id constants.
|
|
47
49
|
|
|
48
|
-
### 1. `src/utils/back-in-stock.ts`
|
|
50
|
+
### 1. `src/utils/back-in-stock.ts` — pre-copied, not owned by this scope
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
> Pre-copied by the orchestrator in the build-wave pre-batch (BUILD-astro.md § "Step 4.5") — same treatment as `categories.ts`. **Import** from `../utils/back-in-stock`; do NOT write it yourself. The exports below are documented here so callers (the form island, the `[slug].astro` probe) know the surface.
|
|
51
53
|
|
|
52
54
|
Exports:
|
|
53
55
|
- `WIX_STORES_BACK_IN_STOCK_APP_ID` — string constant. Use this for the `catalogReference.appId` in the form.
|
|
@@ -150,7 +152,6 @@ The full components scope return must mention back-in-stock:
|
|
|
150
152
|
"summary": "Wrote stores islands, scoped CSS, back-in-stock probe + form",
|
|
151
153
|
"data": {
|
|
152
154
|
"islands": ["ProductPurchase.tsx", "AddToCartButton.tsx", "BackInStockForm.tsx"],
|
|
153
|
-
"utils": ["back-in-stock.ts"],
|
|
154
155
|
"scopedCssFile": "src/styles/components-stores.css",
|
|
155
156
|
"backInStockWired": true
|
|
156
157
|
},
|
|
@@ -159,7 +160,6 @@ The full components scope return must mention back-in-stock:
|
|
|
159
160
|
"src/components/AddToCartButton.tsx",
|
|
160
161
|
"src/components/ProductPurchase.tsx",
|
|
161
162
|
"src/components/BackInStockForm.tsx",
|
|
162
|
-
"src/utils/back-in-stock.ts",
|
|
163
163
|
"src/styles/components-stores.css"
|
|
164
164
|
],
|
|
165
165
|
"errors": []
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Phase 4 Category Pages — Stores
|
|
2
2
|
|
|
3
|
-
Scope: `pages-categories
|
|
3
|
+
Scope: `pages-categories` — written by the stores **merged build agent** (the build wave) *before* its `pages-products` scope, so `<CategoryRail/>` is on disk before that scope mounts it. This scope writes the dedicated category landing route and the shared `<CategoryRail/>`. The `categories.ts` helper is **pre-copied by the orchestrator in the build-wave pre-batch** (BUILD-astro.md § "Step 4.5") — do NOT write it here.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Within-agent order:** the merged stores agent writes `components` → `pages-categories` (this scope) → `pages-products`. `pages-home-and-nav` is a *separate* serialized agent (it patches the shared shells) and resolves `<CategoryRail/>` at build time (Step 8). Each scope only needs its own declared files to exist by the time `astro build` runs.
|
|
6
6
|
|
|
7
7
|
## Scope
|
|
8
8
|
|
|
@@ -23,7 +23,7 @@ Files this agent MUST NOT touch:
|
|
|
23
23
|
## Inputs (from parent prompt)
|
|
24
24
|
|
|
25
25
|
- **Phase 1 return data** — `categories: []`. Phase 1 does not seed categories (they're merchant-driven). This scope still writes the helper + rail + route — they're harmless when no categories exist, and they light up automatically once the merchant creates visible categories with items in the dashboard. `listStoreCategories()` queries the API live at SSR time (5-min TTL cache), so no redeploy is needed when categories are added later.
|
|
26
|
-
- **Design tokens** — the
|
|
26
|
+
- **Design tokens** — read the design tokens (the DESIGN.md vocabulary) from `.wix/design-tokens.css` (on disk). Page header / breadcrumbs / pill / pagination styling should follow `references/shared/STYLING.md` (utilities derived from tokens, semantic classes only for primitives).
|
|
27
27
|
- **Designer output summary** — confirm `Layout.astro` already includes `<ClientRouter />`, `transition:persist` markers on nav/footer, and the `[data-nav-progress]` element + after-swap hook. If any of those is missing, return `status: "partial"` with `errors: [{ code: "DESIGNER_LAYOUT_MISSING_TRANSITIONS", path: "src/layouts/Layout.astro" }]`.
|
|
28
28
|
|
|
29
29
|
## Critical rules (all must be honored)
|
|
@@ -40,7 +40,7 @@ Files this agent MUST NOT touch:
|
|
|
40
40
|
|
|
41
41
|
## Writing the templates
|
|
42
42
|
|
|
43
|
-
Read each template at `templates/stores/` and write it verbatim to the corresponding `src/` path, with three small adjustments. (`categories.ts` is **not** in this list — the orchestrator pre-copies it; you only import its helpers.)
|
|
43
|
+
Read each template at `references/astro/templates/stores/` and write it verbatim to the corresponding `src/` path, with three small adjustments. (`categories.ts` is **not** in this list — the orchestrator pre-copies it; you only import its helpers.)
|
|
44
44
|
|
|
45
45
|
| Template path | Site path |
|
|
46
46
|
|---|---|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Phase 3 Components-CSS — Stores
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**This stylesheet is pre-copied from the skill template by the orchestrator** (build-wave pre-batch, BUILD-astro.md § "Step 4.5") — there is no `components-css` subagent to dispatch. This file documents the CSS for reference so the stores `components` scope (in the merged build agent) knows the class-name surface it targets.
|
|
4
4
|
|
|
5
5
|
## What this scope owns
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ You only need:
|
|
|
23
23
|
2. **`<SKILL_ROOT>/references/shared/STYLING.md`** — the styling-contract conventions (how to use `@apply`, the `@theme` token utilities, the no-default-Tailwind-colors rule, and the global-vs-scoped CSS ownership boundary).
|
|
24
24
|
3. **`<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md`** — the return JSON shape.
|
|
25
25
|
4. **`src/styles/global.css`** in the project — read to audit for stores-class leaks (see § "Global-CSS leak audit" below).
|
|
26
|
-
5. **Design tokens (
|
|
26
|
+
5. **Design tokens (on disk)** — read the design tokens (the DESIGN.md vocabulary — `colors`/`typography`/`spacing`/`rounded`/`containers`) from `.wix/design-tokens.css` (gate-verified present before the wave). They are NOT inlined in your prompt.
|
|
27
27
|
|
|
28
28
|
You do NOT need to read `INSTRUCTIONS.md`, `SHARED_WIRING.md`, `BACK_IN_STOCK.md`, the TSX templates, the back-in-stock util, or any other reference. Skipping those reads is the point of the split — they would consume tokens for context this scope doesn't use.
|
|
29
29
|
|
|
@@ -86,7 +86,7 @@ Write the adapted CSS to `src/styles/components-stores.css`. The first line must
|
|
|
86
86
|
|
|
87
87
|
## Coordination: design tokens
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
Read the design tokens from `.wix/design-tokens.css` (on disk, gate-verified present before the wave) — they are NOT inlined in your prompt.
|
|
90
90
|
|
|
91
91
|
## Return format
|
|
92
92
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Phase 4 Home Page + Nav — Stores
|
|
2
2
|
|
|
3
|
-
Scope: `pages-home-and-nav
|
|
3
|
+
Scope: `pages-home-and-nav` — dispatched as its **own serialized shell-patcher agent** in the build wave (NOT merged into the stores private-files agent, because it patches the shared shells). Imports the orchestrator-pre-copied `categories.ts` helper and the `CategoryRail`/`ProductCard` the stores private agent writes — **resolved at build time, so no write-ordering against that agent.** Patches the home page's stores-related placeholder data with live `productsV3` queries AND inserts the Shop submenu (categories list) into the persisted Navigation at the `<!-- nav:links -->` marker. (The `CartBadge` mount at `<!-- nav:actions -->` is ecom's; you own only `<!-- nav:links -->`.) Read your seeded slice from `.wix/seeded.json` (`seeded.stores`).
|
|
4
4
|
|
|
5
|
-
> **You patch the shared `Navigation.astro` + `index.astro` shells**, which other packs (
|
|
5
|
+
> **You patch the shared `Navigation.astro` + `index.astro` shells**, which other packs (ecom at `nav:actions`, gift-cards, blog) also patch at their own markers. **Touch only your markers and preserve every other scope's siblings — never rewrite either file.** (Flow is the conductor's job: it serializes the shell-patching agents so concurrent marker edits don't collide — BUILD-astro.md § "Step 4.5", the serialized shell chain.)
|
|
6
6
|
|
|
7
7
|
## Scope
|
|
8
8
|
|
|
@@ -21,7 +21,7 @@ Files this agent MUST NOT touch:
|
|
|
21
21
|
## Inputs (from parent prompt)
|
|
22
22
|
|
|
23
23
|
- **Phase 1 stores return** — `products: [{id, name, slug, ...}]`. Needed for live query on home page; also useful for deciding how many to feature.
|
|
24
|
-
- **Design tokens** — the
|
|
24
|
+
- **Design tokens** — read the design tokens (the DESIGN.md vocabulary) from `.wix/design-tokens.css` (on disk) for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens at the call site rather than inventing semantic classes. See `references/shared/STYLING.md` for the three styling categories.
|
|
25
25
|
- **Designer output summary** — path of `src/pages/index.astro` and `src/components/Navigation.astro`, with notes on what placeholder data exists.
|
|
26
26
|
- **Categories (lookup)** — if the designer used category links with hardcoded slugs, call `categoriesV3` SDK to discover real category slugs and rewrite `href`s.
|
|
27
27
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Phase 4 Product Pages — Stores
|
|
2
2
|
|
|
3
|
-
Scope: `product-pages
|
|
3
|
+
Scope: `product-pages` (the `pages-products` scope) — written by the stores **merged build agent** (the build wave) *after* its `components` and `pages-categories` scopes. This scope writes the product listing, product detail, and ProductCard component **once** — applying the designer's visual spec (`references/astro/designer/INSTRUCTIONS.md` → `store-pages`) together with live `productsV3` queries in a single pass. Read your seeded slice from `.wix/seeded.json` (`seeded.stores`).
|
|
4
4
|
|
|
5
5
|
## Scope
|
|
6
6
|
|
|
7
|
-
Files this agent OWNS (
|
|
7
|
+
Files this agent OWNS (each written once, visual structure + live queries together):
|
|
8
8
|
|
|
9
9
|
- `src/pages/products/index.astro` — product listing
|
|
10
10
|
- `src/pages/products/[slug].astro` — product detail with `wixMetadata` + SEO tags
|
|
@@ -12,17 +12,17 @@ Files this agent OWNS (rewrites from designer output):
|
|
|
12
12
|
|
|
13
13
|
Files this agent MUST NOT touch:
|
|
14
14
|
- `src/components/ProductPurchase.tsx`, `src/components/AddToCartButton.tsx` — owned by `components`
|
|
15
|
-
- `src/pages/cart.astro`, `src/pages/thank-you.astro` — owned by `
|
|
15
|
+
- `src/pages/cart.astro`, `src/pages/thank-you.astro` — owned by `cart-checkout`
|
|
16
16
|
- `src/pages/index.astro`, `src/components/Navigation.astro` — owned by `pages-home-and-nav`
|
|
17
|
-
- `src/components/CategoryRail.astro` — owned by `pages-categories
|
|
18
|
-
- `src/utils/categories.ts` — pre-copied by the orchestrator
|
|
17
|
+
- `src/components/CategoryRail.astro` — owned by the `pages-categories` scope, which your merged agent writes **before** this one. **Import** from `../../components/CategoryRail.astro`; never `Write` it here. By the time you mount it, the `pages-categories` step has already put it on disk. If it's somehow absent, you wrote your scopes out of order — return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "src/components/CategoryRail.astro" }]` (write `pages-categories` before `pages-products`; never defensively `Write` it from this scope).
|
|
18
|
+
- `src/utils/categories.ts` — pre-copied by the orchestrator in the build-wave pre-batch (BUILD-astro.md § "Step 4.5"). **Import** `listStoreCategories`/etc. from `../../utils/categories`; never `Write` it.
|
|
19
19
|
- `global.css`, any other `.astro` page, any other component — owned by designers
|
|
20
20
|
|
|
21
21
|
## Inputs (from parent prompt)
|
|
22
22
|
|
|
23
23
|
- **Phase 1 return data** — `products: [{id, name, slug, variantId, price, inventory, sku}]` — use slugs when needed (rarely; `queryProducts` returns them already).
|
|
24
|
-
- **Design tokens** — the
|
|
25
|
-
- **Designer
|
|
24
|
+
- **Design tokens** — read the design tokens (the DESIGN.md vocabulary) from `.wix/design-tokens.css` (on disk) for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens (`class="py-4xl flex flex-col gap-md font-display"`) at the call site rather than inventing semantic classes for layout/spacing/typography. Retained global semantic classes are limited to compound patterns (`offer-callout`, `cart-summary`), interactive primitives (`btn-primary`, `product-card`), and JS targets — see `references/shared/STYLING.md`.
|
|
25
|
+
- **Designer visual spec** — the layout, contract classes, and decorative-slot conventions for `products/index.astro`, `products/[slug].astro`, `ProductCard.astro` (from `references/astro/designer/INSTRUCTIONS.md` → `store-pages`), applied in the same pass as the live queries.
|
|
26
26
|
|
|
27
27
|
## Critical rules (all must be honored)
|
|
28
28
|
|
|
@@ -68,9 +68,9 @@ Do NOT modify logic, imports, SDK calls, `wixMetadata` export, or prop-passing.
|
|
|
68
68
|
|
|
69
69
|
Use template `templates/products/index.astro`.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
Applies the designer's page structure (class names, layout) and binds a guarded, **cursor-paginated** `productsV3.queryProducts({ fields: ["CURRENCY"] }).limit(24).skipTo(cursor).find()` (cursor read from `?cursor=` on the URL; Prev/Next anchors built from `result.cursors.next` / `.prev`). Mounts the shared `<CategoryRail/>` (written by `pages-categories`) above the grid, passing `activeSlug={null}` and the prev/next hrefs. Emits the `AddProductImpression` analytics event from a client-side script that reads a JSON payload serialized at SSR.
|
|
72
72
|
|
|
73
|
-
> **Imports written by `pages-categories
|
|
73
|
+
> **Imports you must NOT write.** `<CategoryRail/>` (`../../components/CategoryRail.astro`) is written by the `pages-categories` scope your merged agent runs *before* this one; `listStoreCategories` (`../../utils/categories`) is pre-copied by the orchestrator. Both are on disk by the time you mount them. If either fails to resolve, return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "<missing path>" }]` — that means your agent wrote `pages-products` before `pages-categories`, or the pre-copy was skipped.
|
|
74
74
|
|
|
75
75
|
> **Page size 24** — multiple of the 2/3/4-column grid, well under Wix's per-request cap of 100. Do not change without updating `CATEGORY_PAGES.md` to match.
|
|
76
76
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Phase 3 Components — Stores (TSX/Astro)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This is the **components** portion of the stores **merged build agent** (the build wave — `BUILD-astro.md` § "Step 4.5"). Your agent writes these islands **first**, then the stores pages (`pages-categories`, `pages-products`) that mount them — so the islands are on disk before the page code references them. The code here depends on the **design tokens** (read from `.wix/design-tokens.css` on disk) but NOT on page markup.
|
|
4
4
|
|
|
5
|
-
> **CSS
|
|
5
|
+
> **CSS is pre-copied, not authored.** `src/styles/components-stores.css` ships from the skill template, copied by the orchestrator in the build-wave pre-batch (see `./COMPONENTS_CSS.md`). This scope does NOT write the CSS file. Reference its contract class names from the design tokens here; the pre-copied stylesheet defines the rules.
|
|
6
6
|
|
|
7
7
|
## Scope
|
|
8
8
|
|
|
@@ -17,14 +17,15 @@ Files this agent MUST NOT touch:
|
|
|
17
17
|
- `src/styles/components-stores.css` — owned by the **`components-css`** sibling scope (see `./COMPONENTS_CSS.md`). Reference its class names; do not write the file.
|
|
18
18
|
- `src/utils/wix-image.ts` — **shared utility shipped by the build skill.** Import `resolveWixImageUrl` from `../utils/wix-image`; do NOT write your own copy (would shadow the shared util and drop other verticals' callers). The canonical source lives at `<SKILL_ROOT>/shared-utilities/wix-image.ts`; it's copied into projects by `seed-utilities.sh` during Setup.
|
|
19
19
|
- `src/components/CartView.tsx`, `src/components/CartBadge.tsx`, `src/utils/analytics.ts`, `src/styles/components-ecom.css` — owned by ecom
|
|
20
|
-
-
|
|
20
|
+
- `src/utils/back-in-stock.ts` — **pre-copied by the orchestrator** in the build-wave pre-batch (BUILD-astro.md § "Step 4.5"), same as `categories.ts`. Import `getBackInStockEnabled`/the app-id constants from `../utils/back-in-stock`; never `Write` it (see `./BACK_IN_STOCK.md`).
|
|
21
|
+
- Any `.astro` page — written by your agent's `pages-*` scopes (after the islands) or by another vertical
|
|
21
22
|
- `src/styles/global.css` — owned by designer foundation
|
|
22
23
|
- `src/layouts/Layout.astro` — owned by designer foundation (including the `components-stores.css` import line)
|
|
23
24
|
- Any designed component (`ProductCard.astro`, `Navigation.astro`, etc.) — owned by designers
|
|
24
25
|
|
|
25
26
|
## Coordination: design tokens
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
Read the design tokens from `.wix/design-tokens.css` (on disk, gate-verified present before the wave). The parent skill serializes your launch behind the designer foundation specifically so this file is already written when you start.
|
|
28
29
|
|
|
29
30
|
Reference the ACTUAL class names from the contract in React components (e.g. `className="add-to-cart-btn"`, not `className="addToCartButton"` or an invented name). See `references/shared/IMPLEMENTER.md` § "Contract class-name adaptation" for the full rule.
|
|
30
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
// ── Composer skeleton: src/components/Footer.astro ────────────────────────────
|
|
3
|
-
// Substitutions (see
|
|
3
|
+
// Substitutions (see compose.mjs):
|
|
4
4
|
// {{brand.name}} — brand name for the wordmark + copyright.
|
|
5
5
|
// {{shell.footerTagline}} — short brand-voice tagline from data.shell.
|
|
6
6
|
// {{nav.links}} — same inlined Navigation links array (mirror/subset);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// ── Composer skeleton: src/layouts/Layout.astro ──────────────────────────────
|
|
3
3
|
// Fully replaces the scaffold's bare stub. The <script> below and the View
|
|
4
4
|
// Transitions wiring are LITERAL fixed bulk — do not re-author. Composer's only
|
|
5
|
-
// substitutions (see
|
|
5
|
+
// substitutions (see compose.mjs):
|
|
6
6
|
// {{components-css-imports}} — one `import '../styles/components-<pack>.css';`
|
|
7
7
|
// per pack in "Packs with components" (omit entirely when none).
|
|
8
8
|
// {{fonts.googleHref}} — the Google Fonts <link> href built from designTokens
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
// ── Composer skeleton: src/components/Navigation.astro ────────────────────────
|
|
3
|
-
// Substitutions (see
|
|
3
|
+
// Substitutions (see compose.mjs):
|
|
4
4
|
// {{shell.navBrandMark}} — brand mark / wordmark text from data.shell.
|
|
5
5
|
// {{nav.links}} — one <a href={href}>{label}</a> per entry in the inlined
|
|
6
6
|
// Navigation links array, labels VERBATIM (no editorial rebrands). Render
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// scaffold's generated astro.config.mjs varies (integrations args, image.domains,
|
|
4
4
|
// vite.server settings differ run to run). Composer must NOT overwrite it with
|
|
5
5
|
// this file — it applies exactly two mutations to the scaffold's own config and
|
|
6
|
-
// preserves everything else (see
|
|
6
|
+
// preserves everything else (see compose.mjs):
|
|
7
7
|
//
|
|
8
8
|
// (1) register the Tailwind v4 Vite plugin → vite.plugins: [tailwindcss()]
|
|
9
9
|
// (2) fix the bare `process.env` reference → globalThis guard (TS-safe)
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { availabilityTimeSlots, eventTimeSlots } from "@wix/bookings";
|
|
3
|
+
import type { SelectedSlot } from "./bookingDriver";
|
|
4
|
+
|
|
5
|
+
// AvailabilityCalendar.tsx — client:only="react" island. A week calendar: a
|
|
6
|
+
// 7-day strip with week navigation, then the picked day's time slots. This is
|
|
7
|
+
// the usable shape — a flat list of every slot with time-only labels leaves the
|
|
8
|
+
// visitor unable to tell which day a slot is on.
|
|
9
|
+
//
|
|
10
|
+
// SDK calls run ambiently (the @wix/astro visitor client), like the ecom
|
|
11
|
+
// CartView island — no createClient/OAuthStrategy here. On an own/own-build SPA
|
|
12
|
+
// acquire a visitor client (OAuthStrategy) and call the same functions on it.
|
|
13
|
+
//
|
|
14
|
+
// Branches on serviceType:
|
|
15
|
+
// APPOINTMENT → availabilityTimeSlots.listAvailabilityTimeSlots() (serviceId is
|
|
16
|
+
// a single GUID string; slots carry scheduleId).
|
|
17
|
+
// CLASS → eventTimeSlots.listEventTimeSlots() (serviceIds is an array;
|
|
18
|
+
// slots carry eventInfo.eventId and NO scheduleId).
|
|
19
|
+
// Re-export SelectedSlot from bookingDriver so the form/driver share one shape.
|
|
20
|
+
export type { SelectedSlot } from "./bookingDriver";
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
serviceId: string;
|
|
24
|
+
serviceName: string;
|
|
25
|
+
serviceType: "APPOINTMENT" | "CLASS";
|
|
26
|
+
onSlotSelected: (slot: SelectedSlot) => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DAY_MS = 86_400_000;
|
|
30
|
+
const HORIZON_WEEKS = 13; // how far "check next availability" probes forward
|
|
31
|
+
|
|
32
|
+
const pad = (n: number) => String(n).padStart(2, "0");
|
|
33
|
+
// Local date string YYYY-MM-DDThh:mm:ss (no Z) — availability expects local time.
|
|
34
|
+
const localDateString = (d: Date) =>
|
|
35
|
+
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
36
|
+
const tz = () => Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
37
|
+
const dateKey = (iso: string) => iso.slice(0, 10); // group slots by calendar day
|
|
38
|
+
const timeLabel = (iso: string) =>
|
|
39
|
+
new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
40
|
+
|
|
41
|
+
const startOfDay = (d: Date) => { const n = new Date(d); n.setHours(0, 0, 0, 0); return n; };
|
|
42
|
+
// Monday-start week containing `d`.
|
|
43
|
+
const mondayOf = (d: Date) => {
|
|
44
|
+
const n = startOfDay(d);
|
|
45
|
+
const day = (n.getDay() + 6) % 7; // 0 = Monday
|
|
46
|
+
n.setDate(n.getDate() - day);
|
|
47
|
+
return n;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Fetch one week of availability and group the slots by calendar day.
|
|
51
|
+
const fetchWeek = async (
|
|
52
|
+
serviceId: string,
|
|
53
|
+
serviceType: "APPOINTMENT" | "CLASS",
|
|
54
|
+
weekStart: Date,
|
|
55
|
+
): Promise<Record<string, SelectedSlot[]>> => {
|
|
56
|
+
const from = startOfDay(weekStart);
|
|
57
|
+
const to = new Date(from.getTime() + 7 * DAY_MS);
|
|
58
|
+
const timeZone = tz();
|
|
59
|
+
let raw: any[] = [];
|
|
60
|
+
|
|
61
|
+
if (serviceType === "CLASS") {
|
|
62
|
+
const result = await eventTimeSlots.listEventTimeSlots({
|
|
63
|
+
serviceIds: [serviceId], // CLASS API takes an array
|
|
64
|
+
fromLocalDate: localDateString(from),
|
|
65
|
+
toLocalDate: localDateString(to),
|
|
66
|
+
timeZone,
|
|
67
|
+
includeNonBookable: false,
|
|
68
|
+
cursorPaging: { limit: 100 },
|
|
69
|
+
});
|
|
70
|
+
raw = (result.timeSlots ?? []).map((s: any) => ({
|
|
71
|
+
serviceType: "CLASS" as const,
|
|
72
|
+
serviceId,
|
|
73
|
+
localStartDate: s.localStartDate,
|
|
74
|
+
localEndDate: s.localEndDate,
|
|
75
|
+
timezone: result.timeZone ?? timeZone,
|
|
76
|
+
eventId: s.eventInfo?.eventId, // session id — no scheduleId on event slots
|
|
77
|
+
}));
|
|
78
|
+
} else {
|
|
79
|
+
const result = await availabilityTimeSlots.listAvailabilityTimeSlots({
|
|
80
|
+
serviceId, // single GUID string — NOT an array
|
|
81
|
+
fromLocalDate: localDateString(from),
|
|
82
|
+
toLocalDate: localDateString(to),
|
|
83
|
+
timeZone,
|
|
84
|
+
bookable: true,
|
|
85
|
+
cursorPaging: { limit: 100 },
|
|
86
|
+
});
|
|
87
|
+
raw = (result.timeSlots ?? []).map((s: any) => ({
|
|
88
|
+
serviceType: "APPOINTMENT" as const,
|
|
89
|
+
serviceId,
|
|
90
|
+
localStartDate: s.localStartDate,
|
|
91
|
+
localEndDate: s.localEndDate,
|
|
92
|
+
timezone: result.timeZone ?? timeZone,
|
|
93
|
+
scheduleId: s.scheduleId,
|
|
94
|
+
locationId: s.location?._id, // the id field is _id, not .id
|
|
95
|
+
locationType: s.location?.locationType,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const byDay: Record<string, SelectedSlot[]> = {};
|
|
100
|
+
for (const slot of raw) {
|
|
101
|
+
if (!slot.localStartDate) continue;
|
|
102
|
+
(byDay[dateKey(slot.localStartDate)] ||= []).push(slot);
|
|
103
|
+
}
|
|
104
|
+
return byDay;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default function AvailabilityCalendar({ serviceId, serviceName, serviceType, onSlotSelected }: Props) {
|
|
108
|
+
const thisMonday = useMemo(() => mondayOf(new Date()), []);
|
|
109
|
+
const [weekStart, setWeekStart] = useState<Date>(thisMonday);
|
|
110
|
+
const [byDay, setByDay] = useState<Record<string, SelectedSlot[]>>({});
|
|
111
|
+
const [selectedDay, setSelectedDay] = useState<string | null>(null);
|
|
112
|
+
const [selectedKey, setSelectedKey] = useState<string | null>(null);
|
|
113
|
+
const [status, setStatus] = useState<"loading" | "ready" | "error" | "searching">("loading");
|
|
114
|
+
|
|
115
|
+
const days = useMemo(
|
|
116
|
+
() => Array.from({ length: 7 }, (_, i) => new Date(weekStart.getTime() + i * DAY_MS)),
|
|
117
|
+
[weekStart],
|
|
118
|
+
);
|
|
119
|
+
const atFirstWeek = weekStart.getTime() <= thisMonday.getTime();
|
|
120
|
+
|
|
121
|
+
const load = useCallback(async (start: Date) => {
|
|
122
|
+
setStatus("loading"); setSelectedKey(null);
|
|
123
|
+
try {
|
|
124
|
+
const grouped = await fetchWeek(serviceId, serviceType, start);
|
|
125
|
+
setByDay(grouped);
|
|
126
|
+
const firstDayWithSlots = Object.keys(grouped).sort()[0] ?? null;
|
|
127
|
+
setSelectedDay(firstDayWithSlots);
|
|
128
|
+
setStatus("ready");
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error("[availability] list failed:", err);
|
|
131
|
+
setStatus("error");
|
|
132
|
+
}
|
|
133
|
+
}, [serviceId, serviceType]);
|
|
134
|
+
|
|
135
|
+
useEffect(() => { void load(weekStart); }, [weekStart, load]);
|
|
136
|
+
|
|
137
|
+
const shiftWeek = (deltaWeeks: number) =>
|
|
138
|
+
setWeekStart((prev) => startOfDay(new Date(prev.getTime() + deltaWeeks * 7 * DAY_MS)));
|
|
139
|
+
|
|
140
|
+
// Probe forward week-by-week for the next week that has any slots.
|
|
141
|
+
const checkNextAvailability = useCallback(async () => {
|
|
142
|
+
setStatus("searching");
|
|
143
|
+
let cursor = new Date(weekStart.getTime() + 7 * DAY_MS);
|
|
144
|
+
for (let i = 0; i < HORIZON_WEEKS; i++) {
|
|
145
|
+
try {
|
|
146
|
+
const grouped = await fetchWeek(serviceId, serviceType, cursor);
|
|
147
|
+
if (Object.keys(grouped).length > 0) {
|
|
148
|
+
setWeekStart(cursor); // triggers load() via the effect
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
} catch { /* keep probing */ }
|
|
152
|
+
cursor = new Date(cursor.getTime() + 7 * DAY_MS);
|
|
153
|
+
}
|
|
154
|
+
setStatus("ready"); // nothing found within the horizon
|
|
155
|
+
}, [serviceId, serviceType, weekStart]);
|
|
156
|
+
|
|
157
|
+
const handleSelect = (s: SelectedSlot) => {
|
|
158
|
+
const id = s.serviceType === "CLASS" ? s.eventId : s.scheduleId;
|
|
159
|
+
if (!s.localStartDate || !id) return;
|
|
160
|
+
setSelectedKey(`${s.localStartDate}|${id}`);
|
|
161
|
+
onSlotSelected(s);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const weekLabel = `${days[0].toLocaleDateString([], { month: "short", day: "numeric" })} – ${days[6].toLocaleDateString([], { month: "short", day: "numeric" })}`;
|
|
165
|
+
const daySlots = selectedDay ? byDay[selectedDay] ?? [] : [];
|
|
166
|
+
const weekIsEmpty = status === "ready" && Object.keys(byDay).length === 0;
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<div className="availability-calendar">
|
|
170
|
+
<div className="availability-week-nav">
|
|
171
|
+
<button type="button" className="availability-nav-btn" onClick={() => shiftWeek(-1)} disabled={atFirstWeek} aria-label="Previous week">← Prev week</button>
|
|
172
|
+
<span className="availability-week-label">{weekLabel}</span>
|
|
173
|
+
<button type="button" className="availability-nav-btn" onClick={() => shiftWeek(1)} aria-label="Next week">Next week →</button>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<div className="availability-day-strip" role="group" aria-label="Pick a day">
|
|
177
|
+
{days.map((d) => {
|
|
178
|
+
const key = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
179
|
+
const has = (byDay[key]?.length ?? 0) > 0;
|
|
180
|
+
const isSelected = key === selectedDay;
|
|
181
|
+
return (
|
|
182
|
+
<button
|
|
183
|
+
key={key}
|
|
184
|
+
type="button"
|
|
185
|
+
className={["availability-day", isSelected ? "availability-day--selected" : "", has ? "availability-day--has-slots" : "availability-day--empty"].filter(Boolean).join(" ")}
|
|
186
|
+
disabled={!has}
|
|
187
|
+
aria-pressed={isSelected}
|
|
188
|
+
onClick={() => { setSelectedDay(key); setSelectedKey(null); }}
|
|
189
|
+
>
|
|
190
|
+
<span className="availability-day-name">{d.toLocaleDateString([], { weekday: "short" })}</span>
|
|
191
|
+
<span className="availability-day-num">{d.getDate()}</span>
|
|
192
|
+
</button>
|
|
193
|
+
);
|
|
194
|
+
})}
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{status === "loading" && <p className="availability-loading">Checking availability…</p>}
|
|
198
|
+
{status === "searching" && <p className="availability-loading">Searching for the next available time…</p>}
|
|
199
|
+
{status === "error" && (
|
|
200
|
+
<>
|
|
201
|
+
<p className="availability-error">Could not load availability — please try again.</p>
|
|
202
|
+
<button type="button" className="availability-nav-btn" onClick={() => void load(weekStart)}>Retry</button>
|
|
203
|
+
</>
|
|
204
|
+
)}
|
|
205
|
+
{weekIsEmpty && (
|
|
206
|
+
<div className="availability-empty">
|
|
207
|
+
<p>No availability this week.</p>
|
|
208
|
+
<button type="button" className="availability-nav-btn" onClick={() => void checkNextAvailability()}>Check next availability</button>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
211
|
+
{status === "ready" && daySlots.length > 0 && (
|
|
212
|
+
<div className="availability-slots" role="group" aria-label={`Available times for ${serviceName}`}>
|
|
213
|
+
{daySlots.map((s) => {
|
|
214
|
+
const id = s.serviceType === "CLASS" ? s.eventId : s.scheduleId;
|
|
215
|
+
const key = `${s.localStartDate}|${id}`;
|
|
216
|
+
const isSelected = key === selectedKey;
|
|
217
|
+
return (
|
|
218
|
+
<button
|
|
219
|
+
key={key}
|
|
220
|
+
type="button"
|
|
221
|
+
className={["time-slot", isSelected ? "time-slot--selected" : "time-slot--available"].join(" ")}
|
|
222
|
+
aria-pressed={isSelected}
|
|
223
|
+
onClick={() => handleSelect(s)}
|
|
224
|
+
>
|
|
225
|
+
<span className="time-slot-time">{timeLabel(s.localStartDate)}</span>
|
|
226
|
+
</button>
|
|
227
|
+
);
|
|
228
|
+
})}
|
|
229
|
+
</div>
|
|
230
|
+
)}
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|