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