@wix/agent-skills 1.20.1 → 1.22.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 +71 -113
- package/skills/wix-app/references/APP_TOOLS.md +2 -1
- package/skills/wix-app/references/BACKEND_EVENT.md +3 -3
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +41 -152
- package/skills/wix-app/references/DASHBOARD_MODAL.md +4 -4
- package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
- package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
- package/skills/wix-app/references/SDK_MODULE_MAP.md +44 -0
- package/skills/wix-app/references/SITE_PLUGIN.md +36 -190
- package/skills/wix-app/references/app-tools/TOOLS.md +3 -1
- package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +21 -0
- package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
- package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +17 -0
- package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
- package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
- package/skills/wix-app/references/dashboard-plugin/SLOTS.md +4 -18
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
- package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
- package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
- package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
- package/skills/wix-app/references/site-plugin/EXAMPLES.md +1 -1
- package/skills/wix-headless-fast/SKILL.md +144 -221
- package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
- package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +15 -15
- package/skills/wix-headless-fast/guides/existing-site.md +76 -0
- package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
- package/skills/wix-headless-fast/install/AGENTS.md +35 -0
- package/skills/wix-headless-fast/install/agents-md.mjs +39 -0
- package/skills/wix-headless-fast/install/attach.mjs +161 -86
- package/skills/wix-headless-fast/install/deploy.mjs +21 -60
- package/skills/wix-headless-fast/install/lock.mjs +55 -0
- package/skills/wix-headless-fast/install/setup.mjs +259 -0
- package/skills/wix-headless-fast/install/templates.mjs +168 -0
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +10 -19
- package/skills/wix-manage/references/events/create-wix-event.md +5 -1
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
- package/skills/wix-headless-fast/install/fast-path.mjs +0 -181
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -301
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
- package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
- package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
- package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
- package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -275
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
- package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
- package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -353
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
- package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
- package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
- package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -305
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
- package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
- package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
- package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
- package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
- package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -338
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
- package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
- package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
- package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -314
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
- package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
- package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
- package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
- package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
- package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -313
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
- package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -258
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -294
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
- package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
- package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -358
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
- package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
- package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
- package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -479
- package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
- package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
- package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
- package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
- package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
- package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -608
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -309
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -167
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
- package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
- package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -124
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -525
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// The blog feed as a framework-free store — the logic behind useBlogFeed, usable from React
|
|
2
|
-
// (useBlogFeed wraps it with useSyncExternalStore), from a static page or Vue/Svelte (subscribe and
|
|
3
|
-
// render), or as the specification for a port. State, actions, subscribe/getState, emit after every
|
|
4
|
-
// change — the same shape as storefront's shop-store.
|
|
5
|
-
//
|
|
6
|
-
// Category and tag filters are applied by Wix (fetchPosts), never to a page already in hand; the
|
|
7
|
-
// two are mutually exclusive — setting one clears the other. A changed filter starts a fresh cursor
|
|
8
|
-
// chain; a late response from a superseded query is dropped. Paging appends by cursor.
|
|
9
|
-
//
|
|
10
|
-
// SSR-friendly: seed with `initialPage` (and `initialCategories`/`initialTags`) and the first,
|
|
11
|
-
// unfiltered page renders at once with no client fetch; a SPA passes nothing and `start()` fetches.
|
|
12
|
-
// One store per mounted feed (a page can hold a feed and a "latest posts" rail): createBlogFeedStore().
|
|
13
|
-
import { fetchPosts } from "./posts";
|
|
14
|
-
import { fetchBlogCategories, fetchBlogTags } from "./taxonomy";
|
|
15
|
-
import type { BlogCategory, BlogTag, PostPage, PostSummary } from "./types";
|
|
16
|
-
|
|
17
|
-
export interface BlogFeedStoreOptions {
|
|
18
|
-
initialPage?: PostPage;
|
|
19
|
-
initialCategories?: BlogCategory[];
|
|
20
|
-
initialTags?: BlogTag[];
|
|
21
|
-
pageSize?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Everything a feed surface renders from. Read it with getState() or through a subscription. */
|
|
25
|
-
export interface BlogFeedState {
|
|
26
|
-
/** null while the first load is in flight — render skeletons, not an empty state. */
|
|
27
|
-
posts: PostSummary[] | null;
|
|
28
|
-
categories: BlogCategory[];
|
|
29
|
-
tags: BlogTag[];
|
|
30
|
-
activeCategoryId: string | null;
|
|
31
|
-
activeTagId: string | null;
|
|
32
|
-
/** True when another page exists — render a "load more" control on it. */
|
|
33
|
-
hasMore: boolean;
|
|
34
|
-
loadingMore: boolean;
|
|
35
|
-
error: string | null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface BlogFeedStore {
|
|
39
|
-
getState(): BlogFeedState;
|
|
40
|
-
subscribe(listener: () => void): () => void;
|
|
41
|
-
/** Fetch the taxonomy (unless seeded) and the first page (unless seeded and unfiltered). Call once when mounted. */
|
|
42
|
-
start(): void;
|
|
43
|
-
/** Stop reacting; drop late responses. */
|
|
44
|
-
stop(): void;
|
|
45
|
-
/** Server-side filter; clears the tag filter. */
|
|
46
|
-
setActiveCategoryId(id: string | null): void;
|
|
47
|
-
/** Server-side filter; clears the category filter. */
|
|
48
|
-
setActiveTagId(id: string | null): void;
|
|
49
|
-
loadMore(): Promise<void>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function createBlogFeedStore({ initialPage, initialCategories, initialTags, pageSize = 20 }: BlogFeedStoreOptions = {}): BlogFeedStore {
|
|
53
|
-
let posts: PostSummary[] | null = initialPage?.posts ?? null;
|
|
54
|
-
let cursor: string | null = initialPage?.nextCursor ?? null;
|
|
55
|
-
let categories: BlogCategory[] = initialCategories ?? [];
|
|
56
|
-
let tags: BlogTag[] = initialTags ?? [];
|
|
57
|
-
let activeCategoryId: string | null = null;
|
|
58
|
-
let activeTagId: string | null = null;
|
|
59
|
-
let loadingMore = false;
|
|
60
|
-
let error: string | null = null;
|
|
61
|
-
let started = false;
|
|
62
|
-
let generation = 0; // bumped by every filter change and stop(); a response from an older generation is dropped
|
|
63
|
-
const listeners = new Set<() => void>();
|
|
64
|
-
let snapshot: BlogFeedState | null = null;
|
|
65
|
-
const emit = () => { snapshot = null; for (const fn of listeners) fn(); };
|
|
66
|
-
|
|
67
|
-
function getState(): BlogFeedState {
|
|
68
|
-
if (snapshot) return snapshot;
|
|
69
|
-
snapshot = { posts, categories, tags, activeCategoryId, activeTagId, hasMore: cursor !== null, loadingMore, error };
|
|
70
|
-
return snapshot;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// The first page for the current filter. The unfiltered page may have come from the server —
|
|
74
|
-
// fetch only when it didn't, or when a filter is active (filters are server-side).
|
|
75
|
-
function query(): void {
|
|
76
|
-
if (!started) return;
|
|
77
|
-
const id = ++generation;
|
|
78
|
-
loadingMore = false;
|
|
79
|
-
if (activeCategoryId === null && activeTagId === null && initialPage) {
|
|
80
|
-
posts = initialPage.posts; cursor = initialPage.nextCursor; error = null;
|
|
81
|
-
emit();
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
posts = null; cursor = null; error = null;
|
|
85
|
-
emit();
|
|
86
|
-
fetchPosts({ limit: pageSize, categoryId: activeCategoryId, tagId: activeTagId })
|
|
87
|
-
.then((page) => {
|
|
88
|
-
if (generation !== id) return; // superseded — drop it
|
|
89
|
-
posts = page.posts; cursor = page.nextCursor;
|
|
90
|
-
emit();
|
|
91
|
-
})
|
|
92
|
-
.catch((e) => {
|
|
93
|
-
if (generation !== id) return;
|
|
94
|
-
posts = []; cursor = null;
|
|
95
|
-
error = e instanceof Error ? e.message : String(e);
|
|
96
|
-
emit();
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
getState,
|
|
102
|
-
subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); },
|
|
103
|
-
start() {
|
|
104
|
-
if (started) return;
|
|
105
|
-
started = true;
|
|
106
|
-
if (!initialCategories) fetchBlogCategories().then((c) => { if (started) { categories = c; emit(); } });
|
|
107
|
-
if (!initialTags) fetchBlogTags().then((t) => { if (started) { tags = t; emit(); } });
|
|
108
|
-
query();
|
|
109
|
-
},
|
|
110
|
-
stop() { started = false; generation++; },
|
|
111
|
-
setActiveCategoryId(id) {
|
|
112
|
-
if (id === activeCategoryId && activeTagId === null) return;
|
|
113
|
-
activeCategoryId = id; activeTagId = null;
|
|
114
|
-
query();
|
|
115
|
-
},
|
|
116
|
-
setActiveTagId(id) {
|
|
117
|
-
if (id === activeTagId && activeCategoryId === null) return;
|
|
118
|
-
activeTagId = id; activeCategoryId = null;
|
|
119
|
-
query();
|
|
120
|
-
},
|
|
121
|
-
async loadMore() {
|
|
122
|
-
if (!cursor || loadingMore) return;
|
|
123
|
-
const id = generation;
|
|
124
|
-
loadingMore = true; error = null; emit();
|
|
125
|
-
try {
|
|
126
|
-
const page = await fetchPosts({ limit: pageSize, cursor });
|
|
127
|
-
if (generation !== id) return;
|
|
128
|
-
posts = [...(posts ?? []), ...page.posts]; cursor = page.nextCursor;
|
|
129
|
-
} catch (e) {
|
|
130
|
-
if (generation !== id) return;
|
|
131
|
-
error = e instanceof Error ? e.message : String(e);
|
|
132
|
-
} finally {
|
|
133
|
-
if (generation === id) { loadingMore = false; emit(); }
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// One post as a framework-free store — the logic behind usePost, usable from React (usePost wraps
|
|
2
|
-
// it), from a static page's post view, from Vue/Svelte, or as the specification for a port. Loads
|
|
3
|
-
// the post by slug (unless seeded) and the FULL taxonomy lists (blog taxonomies are small, fetched
|
|
4
|
-
// once), and resolves the post's category/tag chips from them — never per-id lookups in a render.
|
|
5
|
-
//
|
|
6
|
-
// SSR-friendly: pass the server-fetched PostDetail as `initialPost` (and the taxonomy) and no client
|
|
7
|
-
// fetch happens; a SPA passes only the slug. One store per post surface: createPostStore().
|
|
8
|
-
import { fetchPostBySlug } from "./posts";
|
|
9
|
-
import { fetchBlogCategories, fetchBlogTags } from "./taxonomy";
|
|
10
|
-
import type { BlogCategory, BlogTag, PostDetail } from "./types";
|
|
11
|
-
|
|
12
|
-
export interface PostStoreOptions {
|
|
13
|
-
slug: string;
|
|
14
|
-
initialPost?: PostDetail;
|
|
15
|
-
initialCategories?: BlogCategory[];
|
|
16
|
-
initialTags?: BlogTag[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface PostState {
|
|
20
|
-
/** null while loading (render a skeleton) AND when not found — disambiguate via notFound. */
|
|
21
|
-
post: PostDetail | null;
|
|
22
|
-
/** True once the slug definitively resolved to nothing — render a not-found state. */
|
|
23
|
-
notFound: boolean;
|
|
24
|
-
/** This post's categories/tags, resolved to full objects (display .label, route by .slug). */
|
|
25
|
-
categories: BlogCategory[];
|
|
26
|
-
tags: BlogTag[];
|
|
27
|
-
error: string | null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface PostStore {
|
|
31
|
-
getState(): PostState;
|
|
32
|
-
subscribe(listener: () => void): () => void;
|
|
33
|
-
/** Fetch the post (unless `initialPost` matches the slug) and the taxonomy (unless seeded). Call once when mounted. */
|
|
34
|
-
start(): void;
|
|
35
|
-
stop(): void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function createPostStore({ slug, initialPost, initialCategories, initialTags }: PostStoreOptions): PostStore {
|
|
39
|
-
let post: PostDetail | null = initialPost ?? null;
|
|
40
|
-
let notFound = false;
|
|
41
|
-
let allCategories: BlogCategory[] = initialCategories ?? [];
|
|
42
|
-
let allTags: BlogTag[] = initialTags ?? [];
|
|
43
|
-
let error: string | null = null;
|
|
44
|
-
let started = false;
|
|
45
|
-
const listeners = new Set<() => void>();
|
|
46
|
-
let snapshot: PostState | null = null;
|
|
47
|
-
const emit = () => { snapshot = null; for (const fn of listeners) fn(); };
|
|
48
|
-
|
|
49
|
-
function getState(): PostState {
|
|
50
|
-
if (snapshot) return snapshot;
|
|
51
|
-
snapshot = {
|
|
52
|
-
post,
|
|
53
|
-
notFound,
|
|
54
|
-
categories: post ? allCategories.filter((c) => post!.categoryIds.includes(c.id)) : [],
|
|
55
|
-
tags: post ? allTags.filter((t) => post!.tagIds.includes(t.id)) : [],
|
|
56
|
-
error,
|
|
57
|
-
};
|
|
58
|
-
return snapshot;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
getState,
|
|
63
|
-
subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); },
|
|
64
|
-
start() {
|
|
65
|
-
if (started) return;
|
|
66
|
-
started = true;
|
|
67
|
-
if (!initialPost || initialPost.slug !== slug) {
|
|
68
|
-
post = null; notFound = false; emit();
|
|
69
|
-
fetchPostBySlug(slug)
|
|
70
|
-
.then((p) => { if (!started) return; if (p) post = p; else notFound = true; emit(); })
|
|
71
|
-
.catch((e) => { if (started) { error = e instanceof Error ? e.message : String(e); emit(); } });
|
|
72
|
-
}
|
|
73
|
-
if (!initialCategories) fetchBlogCategories().then((c) => { if (started) { allCategories = c; emit(); } });
|
|
74
|
-
if (!initialTags) fetchBlogTags().then((t) => { if (started) { allTags = t; emit(); } });
|
|
75
|
-
},
|
|
76
|
-
stop() { started = false; },
|
|
77
|
-
};
|
|
78
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// Post rules and DTO mapping — transport-agnostic, imported by BOTH transports: ./posts.ts (the
|
|
2
|
-
// SDK, managed Astro and React) and the REST twin in references/blog/rest/posts.ts (fetch, a static
|
|
3
|
-
// site or a port to another language). Every rule about dates, covers, the feed's sort and filters,
|
|
4
|
-
// and the body fieldsets lives HERE, once. A raw post may come from the SDK (`_id`, media as a
|
|
5
|
-
// `wix:image://` string, dates as Date) or from REST (`id`, media as an { id, url } object, dates
|
|
6
|
-
// as ISO strings); the mappers accept both and produce the same DTO. Imports are type-only so a
|
|
7
|
-
// strip to JS emits no imports.
|
|
8
|
-
import type { PostDetail, PostSummary } from "./types";
|
|
9
|
-
|
|
10
|
-
/** A raw Blog V3 entity as either transport returns it. */
|
|
11
|
-
export type Raw = Record<string, any>;
|
|
12
|
-
/** Media value + size → https URL. Injected: the SDK transport scales through @wix/sdk, REST through the URL form. */
|
|
13
|
-
export type ImgSrc = (value: any, width: number, height: number) => string;
|
|
14
|
-
|
|
15
|
-
/** The Wix Blog app id (Astro item-page routing; comments use it as appId). */
|
|
16
|
-
export const BLOG_APP_ID = "14bcded7-0066-7c35-14d7-466cb3f09103";
|
|
17
|
-
|
|
18
|
-
/** The body fieldsets — without them richContent and contentText come back undefined. */
|
|
19
|
-
export const DETAIL_FIELDSETS = ["RICH_CONTENT", "CONTENT_TEXT"] as const;
|
|
20
|
-
|
|
21
|
-
/** The feed's order: newest first; Wix places pinned posts first on its own. */
|
|
22
|
-
export const FEED_SORT = [{ fieldName: "firstPublishedDate", order: "DESC" }] as const;
|
|
23
|
-
|
|
24
|
-
/** Cover size every card and post header gets — 16:9, one scaled URL per post. */
|
|
25
|
-
export const COVER_WIDTH = 1200;
|
|
26
|
-
export const COVER_HEIGHT = 675;
|
|
27
|
-
|
|
28
|
-
export const rawId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A media value in the form imgSrc scales. The SDK hands over the `wix:image://v1/<file>/<name>#…`
|
|
32
|
-
* string; REST hands over the Image object { id, url, width, height, filename }. Rebuilding the
|
|
33
|
-
* wix:image form from the object makes both transports scale to the SAME URL — passing the object's
|
|
34
|
-
* `url` through would skip scaling and the two paths would disagree on coverUrl.
|
|
35
|
-
*/
|
|
36
|
-
export function mediaValue(value: unknown): string {
|
|
37
|
-
if (!value) return "";
|
|
38
|
-
if (typeof value === "string") return value;
|
|
39
|
-
const o = value as Raw;
|
|
40
|
-
if (o.id && !String(o.id).startsWith("http")) {
|
|
41
|
-
const size = o.width && o.height ? `#originWidth=${o.width}&originHeight=${o.height}` : "";
|
|
42
|
-
return `wix:image://v1/${o.id}/${o.filename ?? ""}${size}`;
|
|
43
|
-
}
|
|
44
|
-
return o.url ?? o.image ?? "";
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Display date + ISO date from either a Date (SDK) or an ISO string (REST); both "" when missing or invalid. */
|
|
48
|
-
export function dateParts(value: unknown): { dateLabel: string; dateISO: string } {
|
|
49
|
-
if (!value) return { dateLabel: "", dateISO: "" };
|
|
50
|
-
const d = value instanceof Date ? value : new Date(String(value));
|
|
51
|
-
if (Number.isNaN(d.getTime())) return { dateLabel: "", dateISO: "" };
|
|
52
|
-
return {
|
|
53
|
-
dateLabel: d.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" }),
|
|
54
|
-
dateISO: d.toISOString(),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** "Aug 27, 2026 · 4 min read" — the card's and header's meta line; either half alone, "" when neither is known. */
|
|
59
|
-
export function postMetaLine(post: Pick<PostSummary, "dateLabel" | "minutesToRead">): string {
|
|
60
|
-
return [post.dateLabel, post.minutesToRead > 0 ? `${post.minutesToRead} min read` : ""].filter(Boolean).join(" · ");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function toSummary(raw: Raw, imgSrc: ImgSrc): PostSummary {
|
|
64
|
-
return {
|
|
65
|
-
id: rawId(raw),
|
|
66
|
-
slug: raw.slug ?? "",
|
|
67
|
-
title: raw.title ?? "",
|
|
68
|
-
excerpt: raw.excerpt ?? "",
|
|
69
|
-
...dateParts(raw.firstPublishedDate),
|
|
70
|
-
minutesToRead: raw.minutesToRead ?? 0,
|
|
71
|
-
featured: raw.featured === true,
|
|
72
|
-
pinned: raw.pinned === true,
|
|
73
|
-
// The cover lives at media.wixMedia.image — a media string (SDK) or an Image object (REST).
|
|
74
|
-
coverUrl: imgSrc(mediaValue(raw.media?.wixMedia?.image), COVER_WIDTH, COVER_HEIGHT),
|
|
75
|
-
categoryIds: raw.categoryIds ?? [],
|
|
76
|
-
tagIds: raw.tagIds ?? [],
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function toDetail(raw: Raw, imgSrc: ImgSrc): PostDetail {
|
|
81
|
-
return {
|
|
82
|
-
...toSummary(raw, imgSrc),
|
|
83
|
-
richContent: raw.richContent ?? null,
|
|
84
|
-
// contentText is plain text — split on newlines for the fallback body.
|
|
85
|
-
paragraphs: String(raw.contentText ?? "")
|
|
86
|
-
.split("\n")
|
|
87
|
-
.map((s: string) => s.trim())
|
|
88
|
-
.filter(Boolean),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface FetchPostsOptions {
|
|
93
|
-
limit?: number;
|
|
94
|
-
/** `nextCursor` from a previous page. */
|
|
95
|
-
cursor?: string | null;
|
|
96
|
-
/** Server-side filters (first page only — the cursor carries them on later pages). */
|
|
97
|
-
categoryId?: string | null;
|
|
98
|
-
tagId?: string | null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* The feed query as one object — the REST body's `query`, and the rule the SDK builder in ./posts.ts
|
|
103
|
-
* spells with .descending()/.hasSome()/.skipTo(). A cursor encodes the original filter+sort, so a
|
|
104
|
-
* cursor request carries ONLY cursorPaging; the first page carries the sort and the filters.
|
|
105
|
-
*/
|
|
106
|
-
export function feedQuery({ limit = 20, cursor, categoryId, tagId }: FetchPostsOptions = {}): Raw {
|
|
107
|
-
if (cursor) return { cursorPaging: { limit, cursor } };
|
|
108
|
-
const filter: Raw = {};
|
|
109
|
-
if (categoryId) filter.categoryIds = { $hasSome: [categoryId] };
|
|
110
|
-
if (tagId) filter.tagIds = { $hasSome: [tagId] };
|
|
111
|
-
return { ...(Object.keys(filter).length ? { filter } : {}), sort: FEED_SORT, cursorPaging: { limit } };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** The by-slug query (REST body's `query`): exact slug, one row. */
|
|
115
|
-
export function slugQuery(slug: string): Raw {
|
|
116
|
-
return { filter: { slug: { $eq: slug } }, cursorPaging: { limit: 1 } };
|
|
117
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// Post reads (Wix Blog V3) over the SDK — the only file that touches raw post entities on this
|
|
2
|
-
// transport. Everything it returns is a plain DTO from ./types. The rules and mappers live in
|
|
3
|
-
// ./posts-core (shared with the REST twin in references/blog/rest/); this file is the transport
|
|
4
|
-
// only. Copy as-is; extend by adding functions, not by editing these. Blog posts are NOT CMS
|
|
5
|
-
// collections — always @wix/blog, never @wix/data.
|
|
6
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/query-posts.md
|
|
7
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/get-post-by-slug.md
|
|
8
|
-
import { posts as postsModule } from "@wix/blog";
|
|
9
|
-
import { wixModule } from "../sdk";
|
|
10
|
-
import { imgSrc } from "../media";
|
|
11
|
-
import { BLOG_APP_ID, DETAIL_FIELDSETS, postMetaLine, toDetail, toSummary, type FetchPostsOptions, type Raw } from "./posts-core";
|
|
12
|
-
import type { PostDetail, PostPage } from "./types";
|
|
13
|
-
|
|
14
|
-
export { BLOG_APP_ID, postMetaLine, type FetchPostsOptions };
|
|
15
|
-
|
|
16
|
-
const posts = wixModule(postsModule);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* One page of published posts, newest first (pinned posts lead). Only published posts come
|
|
20
|
-
* back to a visitor token — a "missing" post usually wasn't published, not a query bug.
|
|
21
|
-
* The builder below spells posts-core's feedQuery: sort + filters on the first page, the cursor alone after.
|
|
22
|
-
*/
|
|
23
|
-
export async function fetchPosts({ limit = 20, cursor, categoryId, tagId }: FetchPostsOptions = {}): Promise<PostPage> {
|
|
24
|
-
let q = posts.queryPosts().limit(limit);
|
|
25
|
-
if (cursor) {
|
|
26
|
-
// A cursor encodes the original filter+sort — re-sending them alongside it is rejected.
|
|
27
|
-
q = q.skipTo(cursor);
|
|
28
|
-
} else {
|
|
29
|
-
q = q.descending("firstPublishedDate");
|
|
30
|
-
if (categoryId) q = q.hasSome("categoryIds", [categoryId]);
|
|
31
|
-
if (tagId) q = q.hasSome("tagIds", [tagId]);
|
|
32
|
-
}
|
|
33
|
-
const res = await q.find();
|
|
34
|
-
return {
|
|
35
|
-
posts: (res.items ?? []).map((p: Raw) => toSummary(p, imgSrc)),
|
|
36
|
-
nextCursor: res.hasNext() ? (res.cursors?.next ?? null) : null,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Fetch one post by its URL slug with the full body (RICH_CONTENT + CONTENT_TEXT fieldsets —
|
|
42
|
-
* without them the body fields come back undefined). Null when not found.
|
|
43
|
-
*/
|
|
44
|
-
export async function fetchPostBySlug(slug: string): Promise<PostDetail | null> {
|
|
45
|
-
const res = await posts
|
|
46
|
-
.queryPosts({ fieldsets: [...DETAIL_FIELDSETS] as any })
|
|
47
|
-
.eq("slug", slug)
|
|
48
|
-
.limit(1)
|
|
49
|
-
.find();
|
|
50
|
-
const raw = res.items?.[0];
|
|
51
|
-
return raw ? toDetail(raw as Raw, imgSrc) : null;
|
|
52
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Category + tag rules and DTO mapping — transport-agnostic, imported by both ./taxonomy.ts (SDK)
|
|
2
|
-
// and the REST twin in references/blog/rest/taxonomy.ts (fetch). Raw entities may carry `_id`
|
|
3
|
-
// (SDK) or `id` (REST). Has its own rawId/mediaValue (copies of posts-core's) so it stands alone
|
|
4
|
-
// when stripped; imports are type-only.
|
|
5
|
-
import type { BlogCategory, BlogTag } from "./types";
|
|
6
|
-
import type { ImgSrc, Raw } from "./posts-core";
|
|
7
|
-
|
|
8
|
-
/** Menu order — displayPosition ascending; -1 (unplaced) sorts first, which is also what the SDK path shows. */
|
|
9
|
-
export const CATEGORY_SORT = [{ fieldName: "displayPosition", order: "ASC" }] as const;
|
|
10
|
-
/** Most-published-posts first. */
|
|
11
|
-
export const TAG_SORT = [{ fieldName: "publishedPostCount", order: "DESC" }] as const;
|
|
12
|
-
/** Blog taxonomies are small — one read of up to 100 is the whole list. */
|
|
13
|
-
export const TAXONOMY_LIMIT = 100;
|
|
14
|
-
|
|
15
|
-
const rawId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
|
|
16
|
-
|
|
17
|
-
// A copy of posts-core's mediaValue: the REST Image object → the wix:image form imgSrc scales.
|
|
18
|
-
function mediaValue(value: unknown): string {
|
|
19
|
-
if (!value) return "";
|
|
20
|
-
if (typeof value === "string") return value;
|
|
21
|
-
const o = value as Raw;
|
|
22
|
-
if (o.id && !String(o.id).startsWith("http")) {
|
|
23
|
-
const size = o.width && o.height ? `#originWidth=${o.width}&originHeight=${o.height}` : "";
|
|
24
|
-
return `wix:image://v1/${o.id}/${o.filename ?? ""}${size}`;
|
|
25
|
-
}
|
|
26
|
-
return o.url ?? o.image ?? "";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function toCategory(raw: Raw, imgSrc: ImgSrc): BlogCategory {
|
|
30
|
-
return {
|
|
31
|
-
id: rawId(raw),
|
|
32
|
-
slug: raw.slug ?? "",
|
|
33
|
-
label: raw.label ?? "", // the API's display name is `label`, never `name`
|
|
34
|
-
description: raw.description ?? "",
|
|
35
|
-
postCount: raw.postCount ?? 0,
|
|
36
|
-
coverUrl: imgSrc(mediaValue(raw.coverImage), 1200, 675),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function toTag(raw: Raw): BlogTag {
|
|
41
|
-
return {
|
|
42
|
-
id: rawId(raw),
|
|
43
|
-
slug: raw.slug ?? "",
|
|
44
|
-
label: raw.label ?? "",
|
|
45
|
-
postCount: raw.publishedPostCount ?? 0, // PUBLISHED posts — postCount also counts drafts
|
|
46
|
-
};
|
|
47
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
// Category + tag reads (Wix Blog V3) over the SDK — the only file that touches raw taxonomy
|
|
2
|
-
// entities on this transport. Everything it returns is a plain DTO from ./types. The mappers live
|
|
3
|
-
// in ./taxonomy-core (shared with the REST twin in references/blog/rest/); this file is the
|
|
4
|
-
// transport only. Copy as-is; extend by adding functions.
|
|
5
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/query-categories.md
|
|
6
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/query-tags.md
|
|
7
|
-
import { categories as categoriesModule, tags as tagsModule } from "@wix/blog";
|
|
8
|
-
import { wixModule } from "../sdk";
|
|
9
|
-
import { imgSrc } from "../media";
|
|
10
|
-
import { TAXONOMY_LIMIT, toCategory, toTag } from "./taxonomy-core";
|
|
11
|
-
import type { Raw } from "./posts-core";
|
|
12
|
-
import type { BlogCategory, BlogTag } from "./types";
|
|
13
|
-
|
|
14
|
-
const categories = wixModule(categoriesModule);
|
|
15
|
-
const tags = wixModule(tagsModule);
|
|
16
|
-
|
|
17
|
-
/** Categories in menu order (displayPosition) — non-fatal (empty array on failure). */
|
|
18
|
-
export async function fetchBlogCategories(): Promise<BlogCategory[]> {
|
|
19
|
-
try {
|
|
20
|
-
const res = await categories.queryCategories().ascending("displayPosition").limit(TAXONOMY_LIMIT).find();
|
|
21
|
-
return (res.items ?? []).map((c: Raw) => toCategory(c, imgSrc)).filter((c) => c.id);
|
|
22
|
-
} catch {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Tags, most-published-posts first — non-fatal (empty array on failure). */
|
|
28
|
-
export async function fetchBlogTags(): Promise<BlogTag[]> {
|
|
29
|
-
try {
|
|
30
|
-
const res = await tags.queryTags().descending("publishedPostCount").limit(TAXONOMY_LIMIT).find();
|
|
31
|
-
return (res.items ?? []).map((t: Raw) => toTag(t)).filter((t) => t.id);
|
|
32
|
-
} catch {
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// The two by-slug getters return DIFFERENT envelopes upstream ({ category } vs { tag } here;
|
|
38
|
-
// getTag(id) even returns the tag bare) — the mapping below absorbs that asymmetry once.
|
|
39
|
-
|
|
40
|
-
/** One category by its URL slug. Null when not found. */
|
|
41
|
-
export async function fetchCategoryBySlug(slug: string): Promise<BlogCategory | null> {
|
|
42
|
-
try {
|
|
43
|
-
const res = await categories.getCategoryBySlug(slug);
|
|
44
|
-
return res.category ? toCategory(res.category as Raw, imgSrc) : null;
|
|
45
|
-
} catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** One tag by its URL slug. Null when not found. */
|
|
51
|
-
export async function fetchTagBySlug(slug: string): Promise<BlogTag | null> {
|
|
52
|
-
try {
|
|
53
|
-
const res = await tags.getTagBySlug(slug);
|
|
54
|
-
return res.tag ? toTag(res.tag as Raw) : null;
|
|
55
|
-
} catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
// Blog DTOs — the serializable shapes every hook, component, and page consumes.
|
|
2
|
-
// Plain JSON: safe as Astro island props or across server/client boundaries. Cover images are
|
|
3
|
-
// resolved https URLs; dates are pre-formatted display strings plus an ISO value for <time>.
|
|
4
|
-
|
|
5
|
-
/** A post as a feed/grid tile needs it. */
|
|
6
|
-
export interface PostSummary {
|
|
7
|
-
id: string;
|
|
8
|
-
slug: string;
|
|
9
|
-
title: string;
|
|
10
|
-
/** Short summary (≤500 chars) — the card body. May be "". */
|
|
11
|
-
excerpt: string;
|
|
12
|
-
/** Display-ready publish date, e.g. "Aug 26, 2026" ("" when missing). */
|
|
13
|
-
dateLabel: string;
|
|
14
|
-
/** ISO publish date for <time datetime> ("" when missing). */
|
|
15
|
-
dateISO: string;
|
|
16
|
-
/** Estimated reading time in minutes (0 when unknown). */
|
|
17
|
-
minutesToRead: number;
|
|
18
|
-
featured: boolean;
|
|
19
|
-
/** Pinned posts lead the default feed order. */
|
|
20
|
-
pinned: boolean;
|
|
21
|
-
/** Resolved https cover URL ("" when the post has no cover). */
|
|
22
|
-
coverUrl: string;
|
|
23
|
-
categoryIds: string[];
|
|
24
|
-
tagIds: string[];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** A post as the post page needs it. */
|
|
28
|
-
export interface PostDetail extends PostSummary {
|
|
29
|
-
/**
|
|
30
|
-
* Ricos rich-content document (plain JSON) — the real post body. Render it ONLY through
|
|
31
|
-
* the shipped RichContent component (@wix/ricos viewer); it is not HTML and not text.
|
|
32
|
-
*/
|
|
33
|
-
richContent: Record<string, unknown> | null;
|
|
34
|
-
/** Plain-text body split into paragraphs — the honest fallback when richContent is null. */
|
|
35
|
-
paragraphs: string[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface BlogCategory {
|
|
39
|
-
id: string;
|
|
40
|
-
slug: string;
|
|
41
|
-
/** Display name (the API calls it `label`, never `name`). */
|
|
42
|
-
label: string;
|
|
43
|
-
description: string;
|
|
44
|
-
/** Number of posts in the category (hide empty categories with it). */
|
|
45
|
-
postCount: number;
|
|
46
|
-
/** Resolved https cover URL ("" when none). */
|
|
47
|
-
coverUrl: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface BlogTag {
|
|
51
|
-
id: string;
|
|
52
|
-
slug: string;
|
|
53
|
-
label: string;
|
|
54
|
-
/** Number of PUBLISHED posts with this tag. */
|
|
55
|
-
postCount: number;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** One feed page; pass `nextCursor` back to fetch the next (null → no more). */
|
|
59
|
-
export interface PostPage {
|
|
60
|
-
posts: PostSummary[];
|
|
61
|
-
nextCursor: string | null;
|
|
62
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// The site chrome for every blog page — THIS file (header/footer/nav) plus the @theme
|
|
3
|
-
// token block in src/styles/global.css are what you brand. Keep the <slot name="seo-tags" />
|
|
4
|
-
// in <head> and the global.css import. (If another vertical is also deployed, its SiteLayout
|
|
5
|
-
// won; merge a Blog nav link there instead.)
|
|
6
|
-
import "../styles/global.css";
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
title: string;
|
|
10
|
-
description?: string;
|
|
11
|
-
}
|
|
12
|
-
const { title, description } = Astro.props;
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
<!doctype html>
|
|
16
|
-
<html lang="en">
|
|
17
|
-
<head>
|
|
18
|
-
<meta charset="UTF-8" />
|
|
19
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
20
|
-
<title>{title}</title>
|
|
21
|
-
{description && <meta name="description" content={description} />}
|
|
22
|
-
<slot name="seo-tags" />
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
<header class="sticky top-0 z-40 border-b border-border bg-background/80 backdrop-blur">
|
|
26
|
-
<div class="mx-auto flex h-16 max-w-6xl items-center justify-between px-6">
|
|
27
|
-
<a href="/" class="text-base font-bold tracking-tight text-foreground no-underline">Brand Name</a>
|
|
28
|
-
<nav class="flex items-center gap-6 text-sm">
|
|
29
|
-
<a href="/blog" class="text-foreground no-underline transition-colors hover:text-muted-foreground">Blog</a>
|
|
30
|
-
</nav>
|
|
31
|
-
</div>
|
|
32
|
-
</header>
|
|
33
|
-
<main class="mx-auto max-w-6xl px-6 pb-24 pt-10">
|
|
34
|
-
<slot />
|
|
35
|
-
</main>
|
|
36
|
-
<footer class="border-t border-border px-6 py-10 text-center text-sm text-muted-foreground">
|
|
37
|
-
© Brand Name
|
|
38
|
-
</footer>
|
|
39
|
-
</body>
|
|
40
|
-
</html>
|