@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.
- package/README.md +4 -1
- package/package.json +1 -1
- package/skills/README.md +23 -0
- package/skills/wix-app/SKILL.md +10 -2
- package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
- package/skills/wix-app/references/CODE_QUALITY.md +1 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
- package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
- package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
- package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
- package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
- package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
- package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
- package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
- package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
- package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
- package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
- package/skills/wix-auth/SKILL.md +12 -0
- package/skills/wix-auth/references/device-flow.md +140 -0
- package/skills/wix-docs/SKILL.md +188 -0
- package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
- package/skills/wix-docs/references/EXTRACTING.md +120 -0
- package/skills/wix-headless/SKILL.md +84 -130
- package/skills/wix-headless/entry/bootstrap.mjs +93 -0
- package/skills/wix-headless/entry/skill.md +78 -0
- package/skills/wix-headless/references/AI_FEATURES.md +178 -0
- package/skills/wix-headless/references/CAPABILITIES.md +84 -0
- package/skills/wix-headless/references/DISCOVERY.md +34 -56
- package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
- package/skills/wix-headless/references/FEEDBACK.md +118 -0
- package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
- package/skills/wix-headless/references/SEED.md +44 -188
- package/skills/wix-headless/references/SETUP.md +32 -103
- package/skills/wix-headless/references/astro.md +98 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
- package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
- package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
- package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
- package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
- package/skills/wix-headless/references/managed/CONNECT.md +74 -0
- package/skills/wix-headless/references/managed/CREATE.md +130 -0
- package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
- package/skills/wix-headless/references/non-astro.md +59 -0
- package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
- package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
- package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
- package/skills/wix-manage/SKILL.md +24 -1
- package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
- package/skills/wix-vibe-headless/SKILL.md +136 -0
- package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
- package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
- package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
- package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
- package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
- package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
- package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
- package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
- package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
- package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
- package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
- package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
- package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
- package/skills/wix-headless/references/BUILD-astro.md +0 -253
- package/skills/wix-headless/references/BUILD-own-build.md +0 -167
- package/skills/wix-headless/references/BUILD.md +0 -105
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
- package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
- package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
- package/skills/wix-headless/references/PLAN-connect.md +0 -19
- package/skills/wix-headless/references/PLAN-create.md +0 -17
- package/skills/wix-headless/references/PLAN.md +0 -92
- package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
- package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
- package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
- package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
- package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
- package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
- package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
- package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
- package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
- package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
- package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
- package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
- package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
- package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
- package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
- package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
- package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
- package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
- package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
- package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
- package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
- package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
- package/skills/wix-headless/references/astro/templates/global.css +0 -288
- package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
- package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
- package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
- package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
- package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
- package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
- package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
- package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
- package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
- package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
- package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
- package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
- package/skills/wix-headless/references/bookings/FLOW.md +0 -246
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
- package/skills/wix-headless/references/commands/known-apps.json +0 -6
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
- package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
- package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
- package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
- package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
- package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
- package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
- package/skills/wix-headless/references/seed-recipes.md +0 -49
- package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
- package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
- package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
- package/skills/wix-headless/references/shared/STYLING.md +0 -140
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
- package/skills/wix-headless/references/verticals/_schema.json +0 -74
- package/skills/wix-headless/references/verticals/_schema.md +0 -95
- package/skills/wix-headless/references/verticals/blog.md +0 -31
- package/skills/wix-headless/references/verticals/bookings.md +0 -41
- package/skills/wix-headless/references/verticals/cms.md +0 -30
- package/skills/wix-headless/references/verticals/ecom.md +0 -25
- package/skills/wix-headless/references/verticals/forms.md +0 -26
- package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
- package/skills/wix-headless/references/verticals/stores.md +0 -33
- package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
- package/skills/wix-headless/scripts/compose.mjs +0 -520
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
- package/skills/wix-headless/scripts/flatten.sh +0 -61
- package/skills/wix-headless/scripts/generate-images.mjs +0 -242
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -154
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
- package/skills/wix-headless/scripts/scaffold.sh +0 -139
- package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
- package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
- package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
- package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
- package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// /category/[slug] — server-side filtered, cursor-paginated category
|
|
3
|
-
// landing. Renders the same product grid as /products, but constrained to
|
|
4
|
-
// one category, with breadcrumbs and a category-specific page header.
|
|
5
|
-
//
|
|
6
|
-
// The CategoryRail is shared with /products via transition:persist, so
|
|
7
|
-
// switching categories swaps only the grid and header.
|
|
8
|
-
import Layout from "../../layouts/Layout.astro";
|
|
9
|
-
import ProductCard from "../../components/ProductCard.astro";
|
|
10
|
-
import CategoryRail from "../../components/CategoryRail.astro";
|
|
11
|
-
import {
|
|
12
|
-
getCategoryBySlug,
|
|
13
|
-
listProductsInCategory,
|
|
14
|
-
listStoreCategories,
|
|
15
|
-
} from "../../utils/categories";
|
|
16
|
-
|
|
17
|
-
const PAGE_SIZE = 24;
|
|
18
|
-
const { slug } = Astro.params;
|
|
19
|
-
|
|
20
|
-
if (!slug) {
|
|
21
|
-
return Astro.redirect("/products");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const category = await getCategoryBySlug(slug);
|
|
25
|
-
if (!category) {
|
|
26
|
-
return new Response("Category not found", { status: 404 });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
|
|
30
|
-
const page = await listProductsInCategory(category.id, {
|
|
31
|
-
limit: PAGE_SIZE,
|
|
32
|
-
cursor,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Drop the Wix Gift Card app's auto-mirror products (DIGITAL stand-ins
|
|
36
|
-
// tagged "Gift Card") — real purchases happen via /gift-cards.
|
|
37
|
-
const productList = page.items.filter((p: any) => p.ribbon?.name !== "Gift Card");
|
|
38
|
-
|
|
39
|
-
const allCategories = await listStoreCategories();
|
|
40
|
-
|
|
41
|
-
const impressionContents = productList.map((p, index) => ({
|
|
42
|
-
id: p._id,
|
|
43
|
-
name: p.name,
|
|
44
|
-
price: Number(p.actualPriceRange?.minValue?.amount ?? 0),
|
|
45
|
-
currency: p.actualPriceRange?.minValue?.currency ?? undefined,
|
|
46
|
-
position: index + 1,
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
function pageHref(c: string | null): string | null {
|
|
50
|
-
if (!c) return null;
|
|
51
|
-
const params = new URLSearchParams();
|
|
52
|
-
params.set("cursor", c);
|
|
53
|
-
return `/category/${category!.slug}?${params.toString()}`;
|
|
54
|
-
}
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
<Layout
|
|
58
|
-
title={`${category.name}`}
|
|
59
|
-
description={category.description ?? `Browse our ${category.name.toLowerCase()} collection.`}
|
|
60
|
-
>
|
|
61
|
-
<section class="page-header">
|
|
62
|
-
<div class="container-page">
|
|
63
|
-
<nav class="breadcrumbs" aria-label="Breadcrumb">
|
|
64
|
-
<a href="/" data-astro-prefetch="hover">Home</a>
|
|
65
|
-
<span aria-hidden="true">·</span>
|
|
66
|
-
<a href="/products" data-astro-prefetch="hover">Shop</a>
|
|
67
|
-
<span aria-hidden="true">·</span>
|
|
68
|
-
<span aria-current="page">{category.name}</span>
|
|
69
|
-
</nav>
|
|
70
|
-
<h1 class="page-header-title">{category.name}</h1>
|
|
71
|
-
{category.description && (
|
|
72
|
-
<p class="page-header-lede">{category.description}</p>
|
|
73
|
-
)}
|
|
74
|
-
</div>
|
|
75
|
-
{category.imageUrl && (
|
|
76
|
-
<div class="page-header-image" aria-hidden="true">
|
|
77
|
-
<img
|
|
78
|
-
src={category.imageUrl}
|
|
79
|
-
alt=""
|
|
80
|
-
loading="lazy"
|
|
81
|
-
decoding="async"
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
)}
|
|
85
|
-
</section>
|
|
86
|
-
|
|
87
|
-
<CategoryRail
|
|
88
|
-
categories={allCategories}
|
|
89
|
-
activeSlug={category.slug}
|
|
90
|
-
prevHref={pageHref(page.prevCursor)}
|
|
91
|
-
nextHref={pageHref(page.nextCursor)}
|
|
92
|
-
/>
|
|
93
|
-
|
|
94
|
-
<section class="section-pad">
|
|
95
|
-
<div class="container-page">
|
|
96
|
-
{productList.length === 0 ? (
|
|
97
|
-
<p class="products-empty">
|
|
98
|
-
Nothing in {category.name} just now — please check back shortly.
|
|
99
|
-
</p>
|
|
100
|
-
) : (
|
|
101
|
-
<div class="product-grid">
|
|
102
|
-
{productList.map((product, idx) => (
|
|
103
|
-
<ProductCard product={product} index={idx} />
|
|
104
|
-
))}
|
|
105
|
-
</div>
|
|
106
|
-
)}
|
|
107
|
-
</div>
|
|
108
|
-
</section>
|
|
109
|
-
</Layout>
|
|
110
|
-
|
|
111
|
-
<script
|
|
112
|
-
type="application/json"
|
|
113
|
-
id="analytics-impressions"
|
|
114
|
-
is:inline
|
|
115
|
-
set:html={JSON.stringify(impressionContents)}
|
|
116
|
-
/>
|
|
117
|
-
<script>
|
|
118
|
-
import { trackEvent } from "../../utils/analytics";
|
|
119
|
-
function fireImpressions() {
|
|
120
|
-
const el = document.getElementById("analytics-impressions");
|
|
121
|
-
if (!el?.textContent) return;
|
|
122
|
-
trackEvent("AddProductImpression", {
|
|
123
|
-
contents: JSON.parse(el.textContent),
|
|
124
|
-
origin: "Category Page",
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
// astro:page-load fires on initial load AND after every <ClientRouter />
|
|
128
|
-
// navigation, so a single listener covers both fresh hits and swaps.
|
|
129
|
-
document.addEventListener("astro:page-load", fireImpressions);
|
|
130
|
-
</script>
|
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
/* src/styles/components-stores.css
|
|
2
|
-
*
|
|
3
|
-
* Stores-pack component CSS. Owned by the stores Phase 3 components agent.
|
|
4
|
-
*
|
|
5
|
-
* This file is the SINGLE source of truth for stores-component classes.
|
|
6
|
-
* The designer's global.css does NOT publish .product-card, .product-grid,
|
|
7
|
-
* .product-card-media, .product-card-ribbon, .product-card-index, or the
|
|
8
|
-
* .offer-callout family — those all live here. See references/shared/STYLING.md
|
|
9
|
-
* § "Component-specific CSS is owned by the component, not the designer".
|
|
10
|
-
*
|
|
11
|
-
* Class groups in this file:
|
|
12
|
-
* - .product-card / .product-grid / .product-card-* → product cards (ProductCard.astro), product listings (products/index.astro, category/[slug].astro), home grid (index.astro)
|
|
13
|
-
* - .offer-callout family → discount callout above ProductPurchase on /products/[slug]
|
|
14
|
-
* - .option-* / .stock-status / .modifier-text → ProductPurchase.tsx (variant pills, stock label, free-text modifier)
|
|
15
|
-
* - .quantity-* → ProductPurchase.tsx + CartView.tsx (quantity stepper)
|
|
16
|
-
* - .back-in-stock-* → BackInStockForm.tsx (out-of-stock subscribe)
|
|
17
|
-
*
|
|
18
|
-
* Uses the palette + typography custom properties declared in global.css.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/* =========================================================================
|
|
22
|
-
Product card + grid — owned here, NOT in global.css.
|
|
23
|
-
The .product-card uses overflow: hidden + border-radius, so inner padding
|
|
24
|
-
is the responsibility of THIS file (whoever sets the radius owns the
|
|
25
|
-
inset). Don't ship a stub rule and rely on the template to add padding
|
|
26
|
-
utilities — that's the leak this file was created to prevent.
|
|
27
|
-
========================================================================= */
|
|
28
|
-
.product-grid {
|
|
29
|
-
display: grid;
|
|
30
|
-
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
31
|
-
gap: 2rem;
|
|
32
|
-
transition: opacity 200ms ease;
|
|
33
|
-
}
|
|
34
|
-
body[data-navigating="true"] .product-grid {
|
|
35
|
-
opacity: 0.55;
|
|
36
|
-
pointer-events: none;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.product-card {
|
|
40
|
-
position: relative;
|
|
41
|
-
display: flex;
|
|
42
|
-
flex-direction: column;
|
|
43
|
-
gap: 1rem;
|
|
44
|
-
padding-bottom: 1rem;
|
|
45
|
-
background: var(--color-paper, var(--color-cream));
|
|
46
|
-
border-radius: var(--radius-xl);
|
|
47
|
-
overflow: hidden;
|
|
48
|
-
text-decoration: none;
|
|
49
|
-
color: inherit;
|
|
50
|
-
transition: transform 280ms ease, box-shadow 280ms ease;
|
|
51
|
-
box-shadow: var(--shadow-card, 0 4px 16px -8px rgba(0, 0, 0, 0.15));
|
|
52
|
-
}
|
|
53
|
-
.product-card:hover {
|
|
54
|
-
transform: translateY(-4px);
|
|
55
|
-
}
|
|
56
|
-
.product-card:hover .product-card-media > img {
|
|
57
|
-
transform: scale(1.04);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.product-card-media {
|
|
61
|
-
position: relative;
|
|
62
|
-
margin: 1rem;
|
|
63
|
-
aspect-ratio: 4 / 5;
|
|
64
|
-
background: var(--color-paper-warm, var(--color-cream));
|
|
65
|
-
border-radius: var(--radius-md);
|
|
66
|
-
overflow: hidden;
|
|
67
|
-
}
|
|
68
|
-
.product-card-media > img {
|
|
69
|
-
width: 100%;
|
|
70
|
-
height: 100%;
|
|
71
|
-
object-fit: cover;
|
|
72
|
-
transition: transform 600ms ease;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.product-card-body {
|
|
76
|
-
display: flex;
|
|
77
|
-
flex-direction: column;
|
|
78
|
-
gap: 0.5rem;
|
|
79
|
-
padding-inline: 1rem;
|
|
80
|
-
}
|
|
81
|
-
.product-card-name {
|
|
82
|
-
margin: 0;
|
|
83
|
-
font-family: var(--font-display);
|
|
84
|
-
font-size: 1.125rem;
|
|
85
|
-
line-height: 1.25;
|
|
86
|
-
color: var(--color-ink);
|
|
87
|
-
}
|
|
88
|
-
.product-card-price {
|
|
89
|
-
margin: 0;
|
|
90
|
-
font-family: var(--font-body);
|
|
91
|
-
font-size: 0.875rem;
|
|
92
|
-
letter-spacing: 0.02em;
|
|
93
|
-
color: var(--color-mute);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.product-card-ribbon {
|
|
97
|
-
position: absolute;
|
|
98
|
-
top: 1rem;
|
|
99
|
-
left: 1rem;
|
|
100
|
-
padding: 0.375rem 0.625rem;
|
|
101
|
-
background: var(--color-accent);
|
|
102
|
-
color: var(--color-ink);
|
|
103
|
-
font-family: var(--font-body);
|
|
104
|
-
font-size: 0.6875rem;
|
|
105
|
-
font-weight: 600;
|
|
106
|
-
letter-spacing: 0.08em;
|
|
107
|
-
text-transform: uppercase;
|
|
108
|
-
border-radius: var(--radius-sm);
|
|
109
|
-
z-index: 2;
|
|
110
|
-
}
|
|
111
|
-
.product-card-index {
|
|
112
|
-
position: absolute;
|
|
113
|
-
top: 1rem;
|
|
114
|
-
right: 1rem;
|
|
115
|
-
padding: 0.375rem 0.5rem;
|
|
116
|
-
background: rgba(255, 255, 255, 0.85);
|
|
117
|
-
color: var(--color-ink);
|
|
118
|
-
font-family: var(--font-display);
|
|
119
|
-
font-size: 0.75rem;
|
|
120
|
-
font-weight: 700;
|
|
121
|
-
letter-spacing: 0.04em;
|
|
122
|
-
border-radius: var(--radius-pill, 9999px);
|
|
123
|
-
z-index: 2;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/* =========================================================================
|
|
127
|
-
Offer callout — bordered panel above ProductPurchase on /products/[slug].
|
|
128
|
-
Compound multi-element pattern. The dashboard-authored offer string can
|
|
129
|
-
contain `\n` line breaks; -detail must preserve them via white-space.
|
|
130
|
-
========================================================================= */
|
|
131
|
-
.offer-callout {
|
|
132
|
-
background: var(--color-paper-warm, var(--color-cream));
|
|
133
|
-
border: 1px solid var(--color-rule);
|
|
134
|
-
border-left: 2px solid var(--color-accent);
|
|
135
|
-
padding: 1.5rem;
|
|
136
|
-
border-radius: var(--radius-md);
|
|
137
|
-
display: flex;
|
|
138
|
-
flex-direction: column;
|
|
139
|
-
gap: 1rem;
|
|
140
|
-
}
|
|
141
|
-
.offer-callout-item {
|
|
142
|
-
display: flex;
|
|
143
|
-
flex-direction: column;
|
|
144
|
-
gap: 0.5rem;
|
|
145
|
-
}
|
|
146
|
-
.offer-callout-item + .offer-callout-item {
|
|
147
|
-
padding-top: 1rem;
|
|
148
|
-
border-top: 1px solid var(--color-rule);
|
|
149
|
-
}
|
|
150
|
-
.offer-callout-badge {
|
|
151
|
-
align-self: flex-start;
|
|
152
|
-
padding: 0.25rem 0.5rem;
|
|
153
|
-
background: var(--color-ink);
|
|
154
|
-
color: var(--color-paper);
|
|
155
|
-
font-family: var(--font-body);
|
|
156
|
-
font-size: 0.625rem;
|
|
157
|
-
font-weight: 700;
|
|
158
|
-
letter-spacing: 0.1em;
|
|
159
|
-
text-transform: uppercase;
|
|
160
|
-
border-radius: var(--radius-sm);
|
|
161
|
-
}
|
|
162
|
-
.offer-callout-name {
|
|
163
|
-
font-family: var(--font-display);
|
|
164
|
-
font-size: 1rem;
|
|
165
|
-
color: var(--color-ink);
|
|
166
|
-
margin: 0;
|
|
167
|
-
}
|
|
168
|
-
.offer-callout-detail {
|
|
169
|
-
font-family: var(--font-body);
|
|
170
|
-
font-size: 0.875rem;
|
|
171
|
-
color: var(--color-ink-soft, var(--color-mute));
|
|
172
|
-
white-space: pre-line;
|
|
173
|
-
margin: 0;
|
|
174
|
-
}
|
|
175
|
-
.offer-callout-foot {
|
|
176
|
-
font-family: var(--font-body);
|
|
177
|
-
font-size: 0.75rem;
|
|
178
|
-
color: var(--color-mute);
|
|
179
|
-
text-transform: uppercase;
|
|
180
|
-
letter-spacing: 0.06em;
|
|
181
|
-
margin: 0;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
/* =========================================================================
|
|
186
|
-
Rules below use direct CSS (var(--token)) only — no `@apply`.
|
|
187
|
-
|
|
188
|
-
Tailwind v4 `@apply` in a non-entrypoint CSS file only works for utilities
|
|
189
|
-
whose theme keys the designer's `@theme` block declares. Earlier revisions
|
|
190
|
-
of this template used `@apply font-heading text-bark/70 bg-parchment …`,
|
|
191
|
-
which assumed a different token vocabulary than current designer output
|
|
192
|
-
(`paper`/`ink`/`font-display` …) and built-failed on every run that loaded
|
|
193
|
-
it. Direct `var(--color-paper)` / `0.75rem` calls work against
|
|
194
|
-
any designer-published token set as long as the core scales exist (they
|
|
195
|
-
always do). Use fallback chains (`var(--color-paper-warm, var(--color-cream))`)
|
|
196
|
-
when a token is sometimes-published.
|
|
197
|
-
========================================================================= */
|
|
198
|
-
|
|
199
|
-
/* --- Variant / option pills (ProductPurchase.tsx) --- */
|
|
200
|
-
.option-group {
|
|
201
|
-
display: flex;
|
|
202
|
-
flex-direction: column;
|
|
203
|
-
gap: 0.75rem;
|
|
204
|
-
margin-bottom: 1.5rem;
|
|
205
|
-
}
|
|
206
|
-
.option-label {
|
|
207
|
-
font-family: var(--font-display);
|
|
208
|
-
font-size: 0.875rem;
|
|
209
|
-
text-transform: uppercase;
|
|
210
|
-
letter-spacing: 0.05em;
|
|
211
|
-
color: var(--color-ink-soft, var(--color-mute));
|
|
212
|
-
}
|
|
213
|
-
.option-choices {
|
|
214
|
-
display: flex;
|
|
215
|
-
flex-wrap: wrap;
|
|
216
|
-
gap: 0.75rem;
|
|
217
|
-
}
|
|
218
|
-
.option-pill {
|
|
219
|
-
padding: 0.75rem 1rem;
|
|
220
|
-
border: 1px solid var(--color-ink);
|
|
221
|
-
background: transparent;
|
|
222
|
-
color: var(--color-ink);
|
|
223
|
-
font-family: var(--font-body);
|
|
224
|
-
border-radius: 9999px;
|
|
225
|
-
cursor: pointer;
|
|
226
|
-
transition: background-color 150ms ease, color 150ms ease;
|
|
227
|
-
}
|
|
228
|
-
.option-pill.selected {
|
|
229
|
-
background: var(--color-ink);
|
|
230
|
-
color: var(--color-paper);
|
|
231
|
-
}
|
|
232
|
-
.option-pill:disabled {
|
|
233
|
-
opacity: 0.4;
|
|
234
|
-
cursor: not-allowed;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/* --- Quantity stepper (ProductPurchase.tsx, CartView.tsx qty editing) --- */
|
|
238
|
-
.quantity-selector {
|
|
239
|
-
display: inline-flex;
|
|
240
|
-
align-items: center;
|
|
241
|
-
border: 1px solid var(--color-ink);
|
|
242
|
-
border-radius: var(--radius-md);
|
|
243
|
-
overflow: hidden;
|
|
244
|
-
}
|
|
245
|
-
.quantity-btn {
|
|
246
|
-
padding: 0.5rem 0.75rem;
|
|
247
|
-
background: transparent;
|
|
248
|
-
border: none;
|
|
249
|
-
cursor: pointer;
|
|
250
|
-
color: var(--color-ink);
|
|
251
|
-
font-family: var(--font-body);
|
|
252
|
-
}
|
|
253
|
-
.quantity-btn:disabled {
|
|
254
|
-
opacity: 0.4;
|
|
255
|
-
cursor: not-allowed;
|
|
256
|
-
}
|
|
257
|
-
.quantity-value {
|
|
258
|
-
padding: 0.75rem 1rem;
|
|
259
|
-
font-variant-numeric: tabular-nums;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/* --- Modifier free-text input (ProductPurchase.tsx, FREE_TEXT render type) --- */
|
|
263
|
-
.modifier-text {
|
|
264
|
-
width: 100%;
|
|
265
|
-
padding: 0.75rem;
|
|
266
|
-
font-family: var(--font-body);
|
|
267
|
-
font-size: 0.875rem;
|
|
268
|
-
border: 1px solid var(--color-rule);
|
|
269
|
-
border-radius: var(--radius-sm);
|
|
270
|
-
background: var(--color-paper-warm, var(--color-paper, var(--color-cream)));
|
|
271
|
-
color: var(--color-ink);
|
|
272
|
-
resize: vertical;
|
|
273
|
-
}
|
|
274
|
-
.modifier-text:focus {
|
|
275
|
-
outline: none;
|
|
276
|
-
border-color: var(--color-ink);
|
|
277
|
-
background: var(--color-paper, var(--color-cream));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/* --- Stock status (ProductPurchase.tsx) --- */
|
|
281
|
-
.stock-status {
|
|
282
|
-
font-size: 0.875rem;
|
|
283
|
-
color: var(--color-ink-soft, var(--color-mute));
|
|
284
|
-
font-style: italic;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/* --- Back-in-stock subscribe form (BackInStockForm.tsx) ---
|
|
288
|
-
* Rendered inside .purchase-area in three OOS branches when
|
|
289
|
-
* backInStockEnabled=true (probe in [slug].astro). */
|
|
290
|
-
.back-in-stock-form {
|
|
291
|
-
display: flex;
|
|
292
|
-
flex-direction: column;
|
|
293
|
-
gap: 1rem;
|
|
294
|
-
margin-top: 1rem;
|
|
295
|
-
padding: 1.5rem;
|
|
296
|
-
border: 1px solid var(--color-rule);
|
|
297
|
-
border-radius: var(--radius-md);
|
|
298
|
-
background: var(--color-paper, var(--color-cream));
|
|
299
|
-
}
|
|
300
|
-
.back-in-stock-headline {
|
|
301
|
-
display: flex;
|
|
302
|
-
flex-direction: column;
|
|
303
|
-
gap: 0.75rem;
|
|
304
|
-
}
|
|
305
|
-
.back-in-stock-eyebrow {
|
|
306
|
-
font-family: var(--font-display);
|
|
307
|
-
font-size: 0.75rem;
|
|
308
|
-
text-transform: uppercase;
|
|
309
|
-
letter-spacing: 0.05em;
|
|
310
|
-
color: var(--color-ink-soft, var(--color-mute));
|
|
311
|
-
}
|
|
312
|
-
.back-in-stock-lede {
|
|
313
|
-
font-family: var(--font-body);
|
|
314
|
-
font-size: 0.875rem;
|
|
315
|
-
color: var(--color-ink);
|
|
316
|
-
line-height: 1.5;
|
|
317
|
-
}
|
|
318
|
-
.back-in-stock-label {
|
|
319
|
-
font-family: var(--font-display);
|
|
320
|
-
font-size: 0.75rem;
|
|
321
|
-
text-transform: uppercase;
|
|
322
|
-
letter-spacing: 0.05em;
|
|
323
|
-
color: var(--color-ink-soft, var(--color-mute));
|
|
324
|
-
}
|
|
325
|
-
.back-in-stock-row {
|
|
326
|
-
display: flex;
|
|
327
|
-
flex-direction: row;
|
|
328
|
-
flex-wrap: wrap;
|
|
329
|
-
gap: 0.75rem;
|
|
330
|
-
}
|
|
331
|
-
.back-in-stock-input {
|
|
332
|
-
flex: 1;
|
|
333
|
-
padding: 0.75rem 1rem;
|
|
334
|
-
font-family: var(--font-body);
|
|
335
|
-
font-size: 0.875rem;
|
|
336
|
-
border: 1px solid var(--color-rule);
|
|
337
|
-
border-radius: var(--radius-sm);
|
|
338
|
-
background: var(--color-paper-warm, var(--color-paper, var(--color-cream)));
|
|
339
|
-
color: var(--color-ink);
|
|
340
|
-
min-width: 0;
|
|
341
|
-
transition: border-color 0.15s ease;
|
|
342
|
-
}
|
|
343
|
-
.back-in-stock-input:focus {
|
|
344
|
-
outline: none;
|
|
345
|
-
border-color: var(--color-ink);
|
|
346
|
-
}
|
|
347
|
-
.back-in-stock-submit {
|
|
348
|
-
padding: 0.75rem 1.5rem;
|
|
349
|
-
font-family: var(--font-display);
|
|
350
|
-
font-size: 0.75rem;
|
|
351
|
-
text-transform: uppercase;
|
|
352
|
-
letter-spacing: 0.05em;
|
|
353
|
-
background: var(--color-ink);
|
|
354
|
-
color: var(--color-paper);
|
|
355
|
-
border: 1px solid var(--color-ink);
|
|
356
|
-
border-radius: var(--radius-sm);
|
|
357
|
-
cursor: pointer;
|
|
358
|
-
transition: background-color 150ms ease;
|
|
359
|
-
}
|
|
360
|
-
.back-in-stock-submit:hover:not(:disabled) {
|
|
361
|
-
background: var(--color-ink-soft, var(--color-ink));
|
|
362
|
-
}
|
|
363
|
-
.back-in-stock-submit:disabled {
|
|
364
|
-
opacity: 0.5;
|
|
365
|
-
cursor: not-allowed;
|
|
366
|
-
}
|
|
367
|
-
.back-in-stock-error {
|
|
368
|
-
font-family: var(--font-body);
|
|
369
|
-
font-size: 0.875rem;
|
|
370
|
-
color: var(--color-error, var(--color-accent));
|
|
371
|
-
}
|
|
372
|
-
.back-in-stock-success {
|
|
373
|
-
margin-top: 1rem;
|
|
374
|
-
padding: 1.5rem;
|
|
375
|
-
border: 1px solid var(--color-rule);
|
|
376
|
-
border-radius: var(--radius-md);
|
|
377
|
-
background: var(--color-paper, var(--color-cream));
|
|
378
|
-
}
|
|
379
|
-
.back-in-stock-success-headline {
|
|
380
|
-
font-family: var(--font-display);
|
|
381
|
-
font-size: 1rem;
|
|
382
|
-
color: var(--color-ink);
|
|
383
|
-
margin: 0 0 0.5rem 0;
|
|
384
|
-
}
|
|
385
|
-
.back-in-stock-success-detail {
|
|
386
|
-
font-family: var(--font-body);
|
|
387
|
-
font-size: 0.875rem;
|
|
388
|
-
color: var(--color-ink);
|
|
389
|
-
line-height: 1.55;
|
|
390
|
-
margin: 0;
|
|
391
|
-
}
|
|
392
|
-
.stock-status.back-in-stock-alt {
|
|
393
|
-
margin-top: 0.75rem;
|
|
394
|
-
font-family: var(--font-body);
|
|
395
|
-
font-size: 0.875rem;
|
|
396
|
-
font-style: italic;
|
|
397
|
-
color: var(--color-ink-soft, var(--color-mute));
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/* Cart CSS (.cart-item-*, .qty-*) lives in components-ecom.css — not in this file. */
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// SSR only — productsV3 SDK needs request-context auth (tenant resolution,
|
|
3
|
-
// site headers). `export const prerender = true` / `getStaticPaths()` builds
|
|
4
|
-
// at compile time with no request, and `.queryProducts().limit()` short-
|
|
5
|
-
// circuits to "is not a function". Keep this page server-rendered; do NOT
|
|
6
|
-
// add prerender=true or getStaticPaths.
|
|
7
|
-
import Layout from "../../layouts/Layout.astro";
|
|
8
|
-
import ProductPurchase from "../../components/ProductPurchase.tsx";
|
|
9
|
-
import SeoTags from "../../components/SeoTags.astro";
|
|
10
|
-
import { productsV3, inventoryItemsV3 } from "@wix/stores";
|
|
11
|
-
import { resolveWixImageUrl } from "../../utils/wix-image";
|
|
12
|
-
import { getBackInStockEnabled } from "../../utils/back-in-stock";
|
|
13
|
-
|
|
14
|
-
// Tell Wix platform this route is the Stores "product" sub-page.
|
|
15
|
-
// Drives sitemap, dashboard SEO editor, deep links.
|
|
16
|
-
export const wixMetadata = {
|
|
17
|
-
appDefId: "1380b703-ce81-ff05-f115-39571d94dfcd",
|
|
18
|
-
pageIdentifier: "wix.stores.sub_pages.product",
|
|
19
|
-
identifiers: {
|
|
20
|
-
slug: "STORES.PRODUCT.SLUG",
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const { slug } = Astro.params;
|
|
25
|
-
|
|
26
|
-
// Wrap the SSR await; a throw here aborts the response stream.
|
|
27
|
-
let product: any = null;
|
|
28
|
-
try {
|
|
29
|
-
const result = await productsV3.getProductBySlug(slug!, {
|
|
30
|
-
fields: ["CURRENCY", "PLAIN_DESCRIPTION"],
|
|
31
|
-
});
|
|
32
|
-
product = result.product;
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error("[product-detail] getProductBySlug failed:", err);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!product) return Astro.redirect("/404");
|
|
38
|
-
|
|
39
|
-
// Live per-variant stock from inventoryItemsV3 — the authoritative source of
|
|
40
|
-
// truth for OOS gating. productsV3's variantsInfo[].inventoryStatus.inStock is
|
|
41
|
-
// a stale cached flag that does NOT reflect real-time stock changes; don't
|
|
42
|
-
// trust it for the add-to-cart gate. See SHARED_WIRING.md § "Variant OOS gate".
|
|
43
|
-
interface VariantStock { quantity: number; trackQuantity: boolean; preorderEnabled: boolean }
|
|
44
|
-
const inventoryByVariant: Record<string, VariantStock> = {};
|
|
45
|
-
try {
|
|
46
|
-
const inv: any = await inventoryItemsV3.queryInventoryItems({
|
|
47
|
-
filter: { productId: product._id },
|
|
48
|
-
});
|
|
49
|
-
for (const item of (inv?.items ?? inv?.inventoryItems ?? []) as any[]) {
|
|
50
|
-
if (!item.variantId) continue;
|
|
51
|
-
inventoryByVariant[item.variantId] = {
|
|
52
|
-
quantity: Number(item.quantity ?? 0),
|
|
53
|
-
trackQuantity: item.trackQuantity === true,
|
|
54
|
-
preorderEnabled: item.preorderInfo?.enabled === true,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
} catch (err) {
|
|
58
|
-
console.error("[product-detail] inventory query failed:", err);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const imageUrl = resolveWixImageUrl(product.media?.main?.image, 800, 1066);
|
|
62
|
-
const price = product.actualPriceRange?.minValue?.formattedAmount;
|
|
63
|
-
const priceAmount = Number(product.actualPriceRange?.minValue?.amount ?? 0);
|
|
64
|
-
const currency = product.actualPriceRange?.minValue?.currency;
|
|
65
|
-
const description = product.plainDescription?.replace(/<[^>]*>/g, "").trim();
|
|
66
|
-
|
|
67
|
-
// SSR probe — true only if the dashboard's "Start Collecting Requests" toggle
|
|
68
|
-
// is on for Wix Stores. Returns false on any error so the OOS subscribe form
|
|
69
|
-
// silently hides if the probe / auth fails. See references/BACK_IN_STOCK.md.
|
|
70
|
-
const backInStockEnabled = await getBackInStockEnabled();
|
|
71
|
-
|
|
72
|
-
// Merchant-edited SEO from dashboard (product settings → SEO).
|
|
73
|
-
// product.seoData.tags returned by default — no fields flag needed.
|
|
74
|
-
const seoTags = product.seoData?.tags ?? [];
|
|
75
|
-
const hasSeoTags = seoTags.some((t: any) => !t.disabled);
|
|
76
|
-
|
|
77
|
-
const viewContentPayload = {
|
|
78
|
-
id: product._id,
|
|
79
|
-
name: product.name,
|
|
80
|
-
price: priceAmount,
|
|
81
|
-
currency,
|
|
82
|
-
origin: "Product Page",
|
|
83
|
-
};
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
<Layout
|
|
87
|
-
title={product.name ?? "Product"}
|
|
88
|
-
description={description?.slice(0, 160)}
|
|
89
|
-
hasSeoTags={hasSeoTags}
|
|
90
|
-
>
|
|
91
|
-
{hasSeoTags && <SeoTags slot="head" tags={seoTags} />}
|
|
92
|
-
<main class="py-16">
|
|
93
|
-
<div class="max-w-wide mx-auto px-8">
|
|
94
|
-
<a href="/products" class="text-mute text-sm tracking-wide uppercase">← Back to products</a>
|
|
95
|
-
<div class="grid grid-cols-1 md:grid-cols-[7fr_5fr] gap-12 md:gap-24 mt-8 items-start">
|
|
96
|
-
<div class="aspect-[4/5] bg-cream rounded-sm overflow-hidden">
|
|
97
|
-
{imageUrl && <img src={imageUrl} alt={product.name ?? "Product"} class="w-full h-full object-cover" />}
|
|
98
|
-
</div>
|
|
99
|
-
<div class="flex flex-col gap-6 md:sticky md:top-12">
|
|
100
|
-
<h1 class="font-display text-4xl leading-tight">{product.name}</h1>
|
|
101
|
-
{price && <p class="text-xl text-ink-soft">{price}</p>}
|
|
102
|
-
{description && <p class="text-ink-soft leading-relaxed">{description}</p>}
|
|
103
|
-
<ProductPurchase
|
|
104
|
-
client:load
|
|
105
|
-
product={product}
|
|
106
|
-
inventoryByVariant={inventoryByVariant}
|
|
107
|
-
backInStockEnabled={backInStockEnabled}
|
|
108
|
-
priceAmount={priceAmount}
|
|
109
|
-
/>
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</main>
|
|
114
|
-
</Layout>
|
|
115
|
-
|
|
116
|
-
<script
|
|
117
|
-
type="application/json"
|
|
118
|
-
id="analytics-view-content"
|
|
119
|
-
is:inline
|
|
120
|
-
set:html={JSON.stringify(viewContentPayload)}
|
|
121
|
-
/>
|
|
122
|
-
<script>
|
|
123
|
-
import { trackEvent } from "../../utils/analytics";
|
|
124
|
-
const el = document.getElementById("analytics-view-content");
|
|
125
|
-
if (el?.textContent) {
|
|
126
|
-
trackEvent("ViewContent", JSON.parse(el.textContent));
|
|
127
|
-
}
|
|
128
|
-
</script>
|